void Input::redintegrate_ex_post (int file_version ,std::map<std::string, std::string> const& detritus_map ,std::list<std::string> const& residuary_names ) { if(class_version() == file_version) { return; } if(0 == file_version) { // An older version with no distinct 'file_version' didn't // have 'DefinitionOfMaterialChange', whose default value is // unacceptable for GPT. if(contains(residuary_names, "DefinitionOfMaterialChange")) { DefinitionOfMaterialChange = mce_gpt == DefinitionOfLifeInsurance ? mce_adjustment_event : mce_earlier_of_increase_or_unnecessary_premium ; } operator[]("AgentName" ) = full_name (map_lookup(detritus_map, "AgentFirstName" ) ,map_lookup(detritus_map, "AgentMiddleName") ,map_lookup(detritus_map, "AgentLastName" ) ); operator[]("InsuredName") = full_name (map_lookup(detritus_map, "FirstName" ) ,map_lookup(detritus_map, "MiddleName" ) ,map_lookup(detritus_map, "LastName" ) ); } if(file_version < 2) { // 'UseCurrentDeclaredRate' was introduced 20071017T1454Z; its // default value of "Yes" would break backward compatibility. if(contains(residuary_names, "UseCurrentDeclaredRate")) { UseCurrentDeclaredRate = "No"; } // 'LastCoiReentryDate' was introduced 20071017T1454Z; its // default value may be inappropriate for files saved earlier. LastCoiReentryDate = std::min (LastCoiReentryDate.value() ,add_years(EffectiveDate.value(), InforceYear.value(), true) ); } if(1 == file_version) { // Solve 'Year' values were saved in solve 'Time' entities, // apparently in this version only. // // However, default values for // SolveTargetTime // SolveEndTime // didn't work correctly with contemporary versions of the // program. Users had to change them in order to make solves // work correctly. For saved cases with unchanged defaults, // limiting the two offending variables to the maturity // duration produces a result consonant with the palpable // intention of the quondam defaults. // SolveTargetYear = std::min(years_to_maturity(), SolveTargetTime.value()); SolveBeginYear = SolveBeginTime .value() ; SolveEndYear = std::min(years_to_maturity(), SolveEndTime .value()); SolveTargetTime = issue_age() + SolveTargetYear.value(); SolveBeginTime = issue_age() + SolveBeginYear .value(); SolveEndTime = issue_age() + SolveEndYear .value(); } if(file_version < 5) { InforceAsOfDate = add_years_and_months (EffectiveDate.value() ,InforceYear .value() ,InforceMonth .value() ,true ); LastMaterialChangeDate = add_years_and_months (EffectiveDate.value() ,InforceYear .value() - InforceContractYear .value() ,InforceMonth .value() - InforceContractMonth.value() ,true ); } // Defectively, some admin-system extracts lack various elements. // All deficient extracts happen to lack <AgentPhone>: they don't // even have an empty <AgentPhone/>; but that field is present in // every input file ever saved by any version of lmi. bool const deficient_extract = contains(residuary_names, "AgentPhone"); // One state governs everything except premium tax, which may be // paid to a different state, e.g. on cases with more than five // hundred lives with a common (employer) issue state; see: // http://www.naic.org/documents/frs_summit_presentations_03.pdf // http://www.naic.org/documents/committees_e_app_blanks_adopted_2007-42BWG_Modified.pdf // Prior to version 6, a single state was used for all purposes, // and it was determined as either employee or employer state, // depending on the value of DB_PremTaxState. The determination is // complex (what if a case was issued with 498 lives and then // grew to 502?), and starting with version 6 both states are // input fields. // // 'StateOfJurisdiction' has always been in lmi, but was never // meaningfully used prior to version 6. // // 'FilingApprovalState' and 'PremiumTaxState' were unknown before // version 6, and would not ordinarily occur in older versions. // However, certain admin-system extracts that are always marked // as version 5 were to have been modified to add these two fields // (yet were not so modified). if(file_version < 6) { bool const b0 = contains(detritus_map, "FilingApprovalState"); bool const b1 = !contains(residuary_names, "PremiumTaxState"); if(b0 || b1) { fatal_error() << "Unexpected 'state' fields." << LMI_FLUSH; // deficient_extract LMI_ASSERT(b0 && b1 && 5 == file_version); StateOfJurisdiction = map_lookup(detritus_map, "FilingApprovalState"); } else { product_database db (ProductName .value() ,Gender .value() ,UnderwritingClass .value() ,Smoking .value() ,IssueAge .value() ,GroupUnderwritingType.value() ,mce_s_CT // Dummy initialization. ); // Deemed state must not depend on itself. if(db.varies_by_state(DB_PremTaxState)) { fatal_error() << "Database invalid: circular dependency." << " State of jurisdiction depends on itself." << LMI_FLUSH ; } switch(static_cast<int>(db.Query(DB_PremTaxState))) { case oe_ee_state: { StateOfJurisdiction = State; PremiumTaxState = State; } break; case oe_er_state: { StateOfJurisdiction = CorporationState; PremiumTaxState = CorporationState; } break; default: { fatal_error() << "Cannot determine state of jurisdiction." << LMI_FLUSH ; } break; } } } // For "deficient" extracts, these required elements are missing. if(file_version < 6 && !deficient_extract) { LMI_ASSERT(contains(residuary_names, "SolveFromWhich")); LMI_ASSERT(contains(residuary_names, "SolveTgtAtWhich")); LMI_ASSERT(contains(residuary_names, "SolveToWhich")); LMI_ASSERT(contains(residuary_names, "UseDOB")); SolveFromWhich = map_lookup(detritus_map, "DeprecatedSolveFromWhich"); SolveTgtAtWhich = map_lookup(detritus_map, "DeprecatedSolveTgtAtWhich"); SolveToWhich = map_lookup(detritus_map, "DeprecatedSolveToWhich"); UseDOB = map_lookup(detritus_map, "DeprecatedUseDOB"); } if(file_version < 7) { // Version 7 renamed these elements. LMI_ASSERT(contains(residuary_names, "ContractNumber")); LMI_ASSERT(contains(residuary_names, "External1035ExchangeTaxBasis")); LMI_ASSERT(contains(residuary_names, "Inforce7702AAmountsPaidHistory")); LMI_ASSERT(contains(residuary_names, "InforceCumulativeNoLapsePayments")); LMI_ASSERT(contains(residuary_names, "Internal1035ExchangeTaxBasis")); LMI_ASSERT(contains(residuary_names, "MasterContractNumber")); LMI_ASSERT(contains(residuary_names, "SolveExpenseGeneralAccountBasis")); ContractNumber = map_lookup(detritus_map, "PolicyNumber"); External1035ExchangeTaxBasis = map_lookup(detritus_map, "External1035ExchangeBasis"); InforceCumulativeNoLapsePayments = map_lookup(detritus_map, "InforceCumulativePayments"); Internal1035ExchangeTaxBasis = map_lookup(detritus_map, "Internal1035ExchangeBasis"); MasterContractNumber = map_lookup(detritus_map, "Franchise"); // Some (but not all) variants of version 0 lacked // 'PremiumHistory'; all later versions should include it. if(!contains(detritus_map, "PremiumHistory")) { LMI_ASSERT(0 == file_version); } else { Inforce7702AAmountsPaidHistory = map_lookup(detritus_map, "PremiumHistory"); } // "Deficient" extracts lack 'SolveBasis'. if(!deficient_extract) { SolveExpenseGeneralAccountBasis = map_lookup(detritus_map, "SolveBasis"); } } if(file_version < 7) { // Prior to version 7, 'InforceCumulativePayments' was used // for no-lapse, GPT, and ROP, so set them all equal here // for backward compatibility. This matters little for new // business, but is so cheap that it may as well be done // unconditionally. InforceCumulativeGptPremiumsPaid = InforceCumulativeNoLapsePayments.value(); InforceCumulativeRopPayments = InforceCumulativeNoLapsePayments.value(); } if(file_version < 7 && contains(detritus_map, "SpecamtHistory")) { // Merge obsolete 'SpecamtHistory' into 'SpecifiedAmount'. // // Prior to version 7, 'SpecamtHistory' and 'SpecifiedAmount' // were distinct. Some version-0 files had the history entity, // but others did not; if it's not present, then of course it // cannot be merged. // // Function must_overwrite_specamt_with_obsolete_history(), // called below, requires 'InforceYear' and 'InforceMonth', // which some "deficient" extracts omit. DoTransmogrify() // sets those members downstream (at least before any // illustration is produced), but the "obsolete history" // function needs them now. This requires version 5, which // introduced 'InforceAsOfDate'; no "deficient" extract // should have an earlier version. // // set_inforce_durations_from_dates() does the same and more; // but, because it does more, it can't simply be called here. if(deficient_extract && EffectiveDate.value() != InforceAsOfDate.value()) { LMI_ASSERT(4 < file_version); std::pair<int,int> ym0 = years_and_months_since (EffectiveDate .value() ,InforceAsOfDate.value() ); InforceYear = ym0.first; InforceMonth = ym0.second; } // Requiring 'deficient_extract' here wouldn't be right, // because an extract file that has been modified and saved // is no longer detectably "deficient". // // This idiom for distinguishing inforce from new business is // avoided in new code, but retained in backward-compatibility // code that, by its nature, should rarely be modernized. if(0 != InforceYear || 0 != InforceMonth) { if (must_overwrite_specamt_with_obsolete_history (SpecifiedAmount.value() ,map_lookup(detritus_map, "SpecamtHistory") ) ) { SpecifiedAmount = map_lookup(detritus_map, "SpecamtHistory"); } } } if(file_version < 7 && EffectiveDate.value() != InforceAsOfDate.value()) { // Version 7 introduced 'InforceSpecAmtLoadBase'; previously, // the first element of 'SpecamtHistory' had been used in its // place, which would have disregarded any term rider. RealizeSpecifiedAmount(); InforceSpecAmtLoadBase = TermRiderAmount.value() + SpecifiedAmountRealized_[0].value(); } }
inline Gregorian operator + (detail::packaged_year y) { return add_years(*this, y.nYears_); }