[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [5941] Clone 'custom_io_0.?pp' (for further customization
From: |
Greg Chicares |
Subject: |
[lmi-commits] [5941] Clone 'custom_io_0.?pp' (for further customization soon) |
Date: |
Tue, 16 Sep 2014 14:18:45 +0000 |
Revision: 5941
http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=5941
Author: chicares
Date: 2014-09-16 14:18:44 +0000 (Tue, 16 Sep 2014)
Log Message:
-----------
Clone 'custom_io_0.?pp' (for further customization soon)
Modified Paths:
--------------
lmi/trunk/ChangeLog
lmi/trunk/Makefile.am
lmi/trunk/objects.make
Added Paths:
-----------
lmi/trunk/custom_io_1.cpp
lmi/trunk/custom_io_1.hpp
Modified: lmi/trunk/ChangeLog
===================================================================
--- lmi/trunk/ChangeLog 2014-09-15 19:43:35 UTC (rev 5940)
+++ lmi/trunk/ChangeLog 2014-09-16 14:18:44 UTC (rev 5941)
@@ -34093,3 +34093,11 @@
illustrator.cpp
Add some configurable settings, and rename others.
+20140916T1418Z <address@hidden> [533]
+
+ Makefile.am
+ custom_io_1.cpp [new file]
+ custom_io_1.hpp [new file]
+ objects.make
+Clone 'custom_io_0.?pp' (for further customization soon).
+
Modified: lmi/trunk/Makefile.am
===================================================================
--- lmi/trunk/Makefile.am 2014-09-15 19:43:35 UTC (rev 5940)
+++ lmi/trunk/Makefile.am 2014-09-16 14:18:44 UTC (rev 5941)
@@ -271,6 +271,7 @@
configurable_settings.cpp \
crc32.cpp \
custom_io_0.cpp \
+ custom_io_1.cpp \
data_directory.cpp \
database.cpp \
datum_base.cpp \
@@ -1044,6 +1045,7 @@
contains.hpp \
crc32.hpp \
custom_io_0.hpp \
+ custom_io_1.hpp \
data_directory.hpp \
database.hpp \
database_document.hpp \
Added: lmi/trunk/custom_io_1.cpp
===================================================================
--- lmi/trunk/custom_io_1.cpp (rev 0)
+++ lmi/trunk/custom_io_1.cpp 2014-09-16 14:18:44 UTC (rev 5941)
@@ -0,0 +1,417 @@
+// Custom interface number one.
+//
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifdef __BORLANDC__
+# include "pchfile.hpp"
+# pragma hdrstop
+#endif // __BORLANDC__
+
+#include "custom_io_1.hpp"
+
+#include "alert.hpp"
+#include "assert_lmi.hpp"
+#include "configurable_settings.hpp"
+#include "database.hpp"
+#include "dbnames.hpp"
+#include "et_vector.hpp"
+#include "input.hpp"
+#include "ledger.hpp"
+#include "ledger_invariant.hpp"
+#include "ledger_variant.hpp"
+#include "name_value_pairs.hpp"
+#include "platform_dependent.hpp" // access()
+#include "value_cast.hpp"
+#include "yare_input.hpp"
+
+#include <fstream>
+#include <vector>
+
+bool custom_io_1_file_exists()
+{
+ return 0 == access
+ (configurable_settings::instance().custom_input_1_filename().c_str()
+ ,F_OK
+ );
+}
+
+namespace
+{
+// Empty for the moment.
+} // Unnamed namespace.
+
+/// Read custom input for a particular customer.
+
+bool custom_io_1_read(Input& z, std::string const& filename)
+{
+ std::string actual_filename =
+ !filename.empty()
+ ? filename
+ : configurable_settings::instance().custom_input_1_filename()
+ ;
+ if(0 != access(actual_filename.c_str(), F_OK))
+ {
+ fatal_error()
+ << "File '"
+ << actual_filename
+ << "' is required but could not be found."
+ << LMI_FLUSH
+ ;
+ }
+
+ // Always use the current declared rate.
+ z["UseCurrentDeclaredRate"] = "Yes";
+
+ warning() << "Testing: simulation of reading custom input." << LMI_FLUSH;
+
+ return true;
+#if 0
+ name_value_pairs n_v_pairs(actual_filename);
+
+ // The list is not complete; other items may be required eventually.
+ z["InforceYear"] =
n_v_pairs.string_numeric_value("InforceYear");
+ z["InforceMonth"] =
n_v_pairs.string_numeric_value("InforceMonth");
+ z["InforceGeneralAccountValue"] =
n_v_pairs.string_numeric_value("InforceAVGenAcct");
+ z["InforceSeparateAccountValue"] =
n_v_pairs.string_numeric_value("InforceAVSepAcct");
+ z["InforceRegularLoanValue"] =
n_v_pairs.string_numeric_value("InforceAVRegLn");
+ z["InforcePreferredLoanValue"] =
n_v_pairs.string_numeric_value("InforceAVPrfLn");
+ z["InforceCumulativeNoLapsePremium"] =
n_v_pairs.string_numeric_value("InforceCumNoLapsePrem");
+ z["InforceCumulativeNoLapsePayments"]=
n_v_pairs.string_numeric_value("InforceCumPmts");
+
+// TRICKY !! Other input methods distinguish the insured's first, middle,
+// and last names. This method uses a single field to meet customer
+// requirements. Combining that single field with the middle and last
+// names works as long as we initialize the others to a nonempty string.
+ z["InsuredName"] = n_v_pairs.string_value("ApplicantName");
+// Not yet used, but might be wanted someday:
+// n_v_pairs.string_value("ApplicantDOB"); // ApplicantDOB=01/01/1968
+ z["IssueAge"] =
n_v_pairs.string_numeric_value("ApplicantIssueAge");
+ z["RetirementAge"] = "100";
+
+ std::string gender = n_v_pairs.string_value("ApplicantGender");
+ if("F" == gender)
+ {
+ z["Gender"] = "Female";
+ }
+ else if("M" == gender)
+ {
+ z["Gender"] = "Male";
+ }
+ else if("U" == gender)
+ {
+ z["Gender"] = "Unisex";
+ }
+ else
+ {
+ fatal_error()
+ << "ApplicantGender is '"
+ << gender
+ << "', but it must be 'F', 'M', or 'U'."
+ << LMI_FLUSH
+ ;
+ }
+
+ std::string tobacco = n_v_pairs.string_value("ApplicantTobacco");
+ if("Y" == tobacco)
+ {
+ z["Smoking"] = "Smoker";
+ }
+ else if("N" == tobacco)
+ {
+ z["Smoking"] = "Nonsmoker";
+ }
+ else if("U" == tobacco)
+ {
+ z["Smoking"] = "Unismoke";
+ }
+ else
+ {
+ fatal_error()
+ << "ApplicantTobacco is '"
+ << tobacco
+ << "', but it must be 'Y', 'N', or 'U'."
+ << LMI_FLUSH
+ ;
+ }
+
+ z["StateOfJurisdiction"] = n_v_pairs.string_value("ApplicantState");
+ z["PremiumTaxState"] = n_v_pairs.string_value("ApplicantState");
+
+// Not yet used, but might be wanted someday:
+// PaymentsPerYear=1
+
+ z["ProductName"] = n_v_pairs.string_value("ProductCode");
+
+ if("Standard" != z["UnderwritingClass"].str())
+ {
+ fatal_error()
+ << "Internal error: not initialized to standard rate class."
+ << LMI_FLUSH
+ ;
+ }
+
+ std::string undw = n_v_pairs.string_value("ProductOption");
+ if("P" == undw)
+ {
+ z["UnderwritingClass"] = "Preferred";
+ z["GroupUnderwritingType"] = "Medical";
+ }
+ else if("F" == undw)
+ {
+ z["GroupUnderwritingType"] = "Medical";
+ }
+ else if("S" == undw)
+ {
+ z["GroupUnderwritingType"] = "Simplified issue";
+ }
+ else if("G" == undw)
+ {
+ z["GroupUnderwritingType"] = "Guaranteed issue";
+ }
+ else
+ {
+ fatal_error()
+ << "ProductOption is '"
+ << undw
+ << "', but it must be 'P', 'F', 'S', or 'G'."
+ << LMI_FLUSH
+ ;
+ }
+
+ std::string dbopt = n_v_pairs.string_value("DeathBenefitOption");
+ if("L" == dbopt)
+ {
+ z["DeathBenefitOption"] = "a";
+ }
+ else if("I" == dbopt)
+ {
+ z["DeathBenefitOption"] = "b";
+ }
+ else if("ROP" == dbopt)
+ {
+ z["DeathBenefitOption"] = "rop";
+ }
+ else
+ {
+ fatal_error()
+ << "DeathBenefitOption is '"
+ << dbopt
+ << "', but it must be 'L', 'I', or 'ROP'."
+ << LMI_FLUSH
+ ;
+ }
+
+ // For single-premium cases, the specified amount would normally
+ // be calculated by using a "corridor" specified-amount strategy,
+ // but the customer wants to enter the specified amount explicitly.
+ z["SpecifiedAmount"] = n_v_pairs.string_value("FaceAmt");
+
+ // Zero out any default er premium.
+ z["CorporationPayment"] = "0";
+ // Assume single premium. Although the corporation pays it,
+ // treat it, contrary to fact, as paid by the insured; reason:
+ // consistency with GUI--see ChangeLog for 20050825T0122Z .
+ // SOMEDAY !! Revisit this later.
+ z["Payment"] = n_v_pairs.string_value("PremiumAmt") +
";0";
+
+// Not yet used, but might be wanted someday:
+//ExchangeAmt=0
+//PremiumYears=01 [single premium assumed for now]
+//Revised=N
+//Mortality=C
+
+// Table ratings: not yet used, but might be wanted someday:
+// ApplicantRating=
+// ApplicantThruAge=
+ z["SubstandardTable"] = n_v_pairs.string_value("ApplicantRating");
+
+ double permanent_flat =
n_v_pairs.numeric_value("PermFlatExtraAmt");
+ double temporary_flat =
n_v_pairs.numeric_value("TempFlatExtraAmt");
+ double temporary_flat_max_age =
n_v_pairs.numeric_value("TempFlatExtraThruAge");
+ if(z.issue_age() < temporary_flat_max_age)
+ {
+ z["FlatExtra"] =
+ value_cast<std::string>(permanent_flat + temporary_flat)
+ + "[0, @"
+ + value_cast<std::string>(temporary_flat_max_age)
+ + "); " // Apparently this ')' should be ']' for "ThruAge".
+ + value_cast<std::string>(permanent_flat)
+ ;
+ }
+
+ if("None" != z["SubstandardTable"].str())
+ {
+ z["UnderwritingClass"] = "Rated";
+ }
+
+ // The current declared rate isn't necessarily used: see function
+ // adjust_interest_rates() and its documentation.
+ z["UseCurrentDeclaredRate"] = "No";
+
+ yare_input const yip(z);
+ product_database database(yip);
+
+ double first_year_general_account_rate =
+ 0.01
+ * n_v_pairs.numeric_value("InterestRateFirstYr")
+ ;
+ double renewal_year_general_account_rate =
+ 0.01
+ * n_v_pairs.numeric_value("InterestRateOngoing")
+ ;
+
+ std::vector<double> declared_rate;
+ database.Query(declared_rate, DB_MaxGenAcctRate);
+ z["GeneralAccountRate"] = adjust_interest_rates
+ (first_year_general_account_rate
+ ,renewal_year_general_account_rate
+ ,declared_rate
+ );
+
+// Reenable this line to test the interest calculation when changing it.
+// This doesn't merit a formal, permanent unit test for now.
+// test_adjust_interest_rates();
+
+// TRICKY !! Other input methods distinguish the agent's first, middle,
+// and last names. This method uses a single field to meet customer
+// requirements. Combining that single field with the middle and last
+// names works only as long as we initialize the latter to a nonempty
+// string, which we do as a temporary workaround elsewhere; when that's
+// resolved, revisit this.
+ z["AgentName"] = n_v_pairs.string_value("AgentName");
+ z["AgentAddress"] = n_v_pairs.string_value("AgentAddress");
+ z["AgentCity"] = n_v_pairs.string_value("AgentCity");
+ z["AgentState"] = n_v_pairs.string_value("AgentState");
+ z["AgentZipCode"] = n_v_pairs.string_value("AgentZip");
+ z["AgentPhone"] = n_v_pairs.string_value("AgentPhone");
+ z["AgentId"] = n_v_pairs.string_value("AgentLicense");
+// Not yet used, but might be wanted someday:
+// AgentCompanyName
+// AgentLicense
+
+ double separate_account_rate =
+ 0.01
+ * n_v_pairs.numeric_value("InterestRateSepAcctFirstYr")
+ ;
+
+ z["SeparateAccountRate"] =
value_cast<std::string>(separate_account_rate);
+
+ // TRICKY !! We need to consider the unconverted string: if it's empty,
+ // it should be ignored, and must not be incorrectly converted to
+ // zero. Yet one might actually wish to set the multiplier to zero;
+ // that would be indicated by non-empty input evaluating to zero.
+ std::string coi_mult = n_v_pairs.string_value("COIMult");
+ if(!coi_mult.empty())
+ {
+ z["OverrideCoiMultiplier"] = "Yes";
+ z["CountryCoiMultiplier"] = coi_mult;
+ }
+
+ // "AutoClose": "Y" or "N". Either way, read the custom input file
+ // and write the custom output file. Then:
+ // if "Y", then exit;
+ // else, leave the GUI active.
+ // Ignored for command-line regression testing.
+ return "Y" == n_v_pairs.string_value("AutoClose");
+#endif // 0
+}
+
+/// Write custom output for a particular customer.
+///
+/// Assumptions:
+/// values are all as of EOY
+/// "interest earned" is net interest credited, net of any spread
+/// "mortality cost" is sum of actual COIs deducted throughout the year
+/// "load" is premium load including any sales load and premium-based
+/// loads for premium tax and dac tax, but excluding policy fee
+/// "minimum premium" is a required premium as is typical of interest
+/// sensitive whole life, and should be zero for flexible premium
+/// universal life
+/// "surrender cost" is account value minus cash surrender value; if
+/// there is any refund in the early years, this value can be negative
+
+void custom_io_1_write(Ledger const& ledger_values, std::string const&
filename)
+{
+ std::string actual_filename =
+ !filename.empty()
+ ? filename
+ : configurable_settings::instance().custom_output_1_filename()
+ ;
+ // Don't specify 'binary' here: the file is to be read by another
+ // program that probably expects platform-specific behavior.
+ std::ofstream os
+ (actual_filename.c_str()
+ ,std::ios_base::out | std::ios_base::trunc
+ );
+ if(!os.good())
+ {
+ fatal_error()
+ << "File '"
+ << actual_filename
+ << "' could not be opened for writing."
+ << LMI_FLUSH
+ ;
+ }
+
+ LedgerInvariant const& Invar = ledger_values.GetLedgerInvariant();
+ LedgerVariant const& Curr_ = ledger_values.GetCurrFull();
+
+ os
+ << "CashValu,SurrValu,DeathBen,IntEarned,"
+ << "MortCost,Load,MinPrem,SurrCost,PremAmt,IntRate\n"
+ ;
+
+ std::vector<double> surr_chg(Invar.GetLength());
+ assign(surr_chg, Curr_.AcctVal - Curr_.CSVNet);
+
+ std::vector<double> prem_load(Invar.GetLength());
+ assign(prem_load, Invar.GrossPmt - Curr_.NetPmt);
+
+ os.setf(std::ios_base::fixed, std::ios_base::floatfield);
+
+ int max_duration = static_cast<int>(Invar.EndtAge - Invar.Age);
+ for(int j = 0; j < max_duration; j++)
+ {
+ os
+ << std::setprecision(0)
+ << Curr_.AcctVal [j]
+ << ',' << Curr_.CSVNet [j]
+ << ',' << Curr_.EOYDeathBft [j]
+ << ',' << Curr_.NetIntCredited [j]
+ << ',' << Curr_.COICharge [j]
+// Column headers suggest that 'Load' should precede 'MinPrem',
+// but this order was accepted; perhaps both were always zero
+// in actual practice.
+ << ',' << 0 // 'MinPrem' always
zero.
+ << ',' << prem_load [j]
+ << ',' << surr_chg [j]
+ << ',' << Invar.GrossPmt [j]
+ << ',' << Curr_.AnnGAIntRate [j] * 10000.0 // 'IntRate' in bp.
+ << '\n'
+ ;
+ }
+ if(!os.good())
+ {
+ fatal_error() << "Error writing output file." << LMI_FLUSH;
+ }
+}
+
Property changes on: lmi/trunk/custom_io_1.cpp
___________________________________________________________________
Added: svn:keywords
+ Id
Added: lmi/trunk/custom_io_1.hpp
===================================================================
--- lmi/trunk/custom_io_1.hpp (rev 0)
+++ lmi/trunk/custom_io_1.hpp 2014-09-16 14:18:44 UTC (rev 5941)
@@ -0,0 +1,52 @@
+// Custom interface number one.
+//
+// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+// $Id$
+
+#ifndef custom_io_1_hpp
+#define custom_io_1_hpp
+
+#include "config.hpp"
+
+#include "so_attributes.hpp"
+
+#include <string>
+
+class Input;
+class Ledger;
+
+bool LMI_SO custom_io_1_file_exists();
+
+// These two functions take std::string arguments that either contain
+// filenames or are blank. If they're blank, as they normally are,
+// then the actual filenames are read from configurable settings. For
+// system testing, actual filenames are supplied.
+//
+// Usually it would be preferable to pass actual filenames in every
+// case. However, the general facility for emitting output assumes
+// that input and output files share a common stem; in this custom
+// situation, that need not be the case.
+
+bool LMI_SO custom_io_1_read (Input& , std::string const& filename);
+void LMI_SO custom_io_1_write(Ledger const&, std::string const& filename);
+
+#endif // custom_io_1_hpp
+
Property changes on: lmi/trunk/custom_io_1.hpp
___________________________________________________________________
Added: svn:keywords
+ Id
Modified: lmi/trunk/objects.make
===================================================================
--- lmi/trunk/objects.make 2014-09-15 19:43:35 UTC (rev 5940)
+++ lmi/trunk/objects.make 2014-09-16 14:18:44 UTC (rev 5941)
@@ -186,6 +186,7 @@
configurable_settings.o \
crc32.o \
custom_io_0.o \
+ custom_io_1.o \
data_directory.o \
database.o \
datum_base.o \
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [5941] Clone 'custom_io_0.?pp' (for further customization soon),
Greg Chicares <=