[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] odd/mst-in-product-db 952b242 2/2: Embed {{MST}} and

From: Greg Chicares
Subject: [lmi-commits] [lmi] odd/mst-in-product-db 952b242 2/2: Embed {{MST}} and <html> in product database
Date: Thu, 18 Jul 2019 10:39:47 -0400 (EDT)

branch: odd/mst-in-product-db
commit 952b2428040ddf17e86f77c5588dddeec2308f0d
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>

    Embed {{MST}} and <html> in product database
    Motivating example:
      "<br><b>Definition #1:</b><br>{{phrase_1a}} some words {{phrase2a}}."
    For instance, product_data::GuarMortalityFootnote says essentially:
      "This [policy|contract|certificate] has guaranteed COIs
      based on the [1980|2001|2017] CSO table"
    and at present the database of proprietary products has distinct hard-
    coded strings for all possibilities:
    one of which is specified for each of about 140 products. That's
    redundant because the product database already has variables that hold
    the variant components like "certificate" and "2017":
      product_data::ContractName --> LedgerInvariant::ContractName
      DBDictionary::CsoEra [to be mapped to a LedgerInvariant member soon]
    The goal is to have a single "GuarMortalityFootnote" string for all
    products, with the variant parts filled in automatically. There are
    about a hundred footnote strings like this, and the evolving practice
    (at least for one insurer) is to use exactly the same terminology as the
    corresponding policy form, instead of generic wording like:
      "This product has guaranteed COIs based on the applicable CSO table"
    Often such "footnotes" embody definitions of terms such as
      AttainedAgeFootnote = "The [insured|annuitant]'s age at the end of
        the illustrated [policy|contract|certificate] year."
    and the evolving practice is to format that thus:
      <b>End of Year Age:</b> &nbsp; {{AttainedAgeFootnote}}
    In theory, such a string could be hard-coded OAOO in each '.mst' file.
    In practice, that approach has grown unworkable. For example, suppose
    that a PDF resulting from
      A.policy + A.database + X.mst --> AX.pdf
    is formally filed with regulators; later, when a different product B
      B.policy + B.database + X.mst --> BX.pdf
    is to be filed, an arbitrary difference such as
    - <b>End of Year Age:</b> &nbsp; {{AttainedAgeFootnote}}
    + <b>Age at End of Year:</b> &nbsp; {{AttainedAgeFootnote}}
    may be considered necessary, simply because B's contract defined a
    trivially different term for the same concept; but modifying template
    X.mst potentially changes the already-filed AX.pdf, which is forbidden.
    Virtualizing the name:
      <b>{{EndOfYearAgeTerminology}}</b> &nbsp; {{AttainedAgeFootnote}}
    might seem like a good idea, but really isn't, because that's just one
    of an infinitude of possible variations, e.g.:
      "...at the end of the illustrated [policy|contract|certificate] year."
      "...at the end of the depicted [policy|contract|certificate] year."
    which might be demanded for "business reasons".
    Instead, ideally, footnotes could be consolidated into a handful of
    multiple-paragraph blurbs:
      std::string blurb1 = "term0: {{defn0}}<br>term1:{{defn1}}<br>...";
    which would be held in '.policy' files, with html markup and mustache
    substitutions realized when a PDF is generated. IOW, the vision is to
    change the contents of '.policy' files from flat text to something like
    mustache "partials" (even if the {{>partial}} syntax isn't used).
    Test case:
      File | New | Illustration [defaults to 'sample' product']
      File | Print to PDF
    This appears toward the top of page 3 of 10:
      Guaranteed mortality column definition: [only that line in boldface]
      Superior Life Insurance Company guarantees that this contract's
      mortality charges will never exceed the applicable CSO mortality
      tables...blah blah blah.
    This demonstration does work, but it's ugly. The de-html-ization code
    is terse, but presumably slow; and calling interpolate_string() twice
    can't be optimal.
 pdf_command_wx.cpp | 23 ++++++++++++++++++++++-
 product_data.cpp   |  6 ++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/pdf_command_wx.cpp b/pdf_command_wx.cpp
index bfcbf95..b5ef4d1 100644
--- a/pdf_command_wx.cpp
+++ b/pdf_command_wx.cpp
@@ -58,6 +58,7 @@
 #include <fstream>
 #include <map>
 #include <memory>                       // make_unique(), unique_ptr
+#include <regex>
 #include <sstream>
 #include <stdexcept>
 #include <string>
@@ -143,6 +144,14 @@ class html_interpolator
         throw std::runtime_error("invalid lookup kind");
+    static std::string dehtmlize(std::string const& raw_text)
+    {
+        std::string z = raw_text;
+        z = std::regex_replace(z, std::regex("&lt;"), "<");
+        z = std::regex_replace(z, std::regex("&gt;"), ">");
+        return z;
+    }
     // A function which can be used to interpolate an HTML string containing
     // references to the variables defined for this illustration. The general
     // syntax is the same as in the global interpolate_string() function, i.e.
@@ -156,9 +165,21 @@ class html_interpolator
     // variables explicitly defined by add_variable() calls.
     html::text operator()(char const* s) const
+        std::string z =
+            interpolate_string
+                (s
+                ,[this]
+                    (std::string const& str
+                    ,interpolate_lookup_kind kind
+                    )
+                    {
+                        return interpolation_func(str, kind);
+                    }
+                )
+            ;
         return html::text::from_html
-                (s
+                (dehtmlize(z).c_str()
                     (std::string const& str
                     ,interpolate_lookup_kind kind
diff --git a/product_data.cpp b/product_data.cpp
index f0507f3..e6564d9 100644
--- a/product_data.cpp
+++ b/product_data.cpp
@@ -537,6 +537,12 @@ sample::sample()
     item("GroupQuoteFooterMandatory")  = glossed_string("The employer pays all 
     item("GroupQuoteFooterVoluntary")  = glossed_string("The employee pays all 
     item("GroupQuoteFooterFusion")     = glossed_string("The employer and 
employee pay their respective premiums.");
+    // Experimental.
+    item("GuarMortalityFootnote") =
+        "<br><b>Guaranteed mortality column definition:</b><br>{{InsCoName}}"
+        " guarantees that this {{ContractName}}'s mortality charges will"
+        " never exceed the applicable CSO mortality tables...blah blah blah."
+        ;
 /// The 'sample2*' products are designed to facilitate testing.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]