[Top][All Lists]

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

Re: [lmi] Group premium quotes

From: Vadim Zeitlin
Subject: Re: [lmi] Group premium quotes
Date: Sun, 21 Jun 2015 16:44:06 +0200

On Fri, 19 Jun 2015 23:30:37 +0000 Greg Chicares <address@hidden> wrote:

GC> On 2015-06-19 14:20, Vadim Zeitlin wrote:
GC> >  BTW, a somewhat related question: will the totals (for each column) be
GC> > computed by lmi or PDF generation code? Computing the sum is not a
GC> > difficult operation, as maths go, so I guess the PDF code could be trusted
GC> > with it, or do you still see it as too risky?
GC> It doesn't matter. Each premium in every column is already rounded to
GC> cents. Adding them together will give substantially the same result
GC> no matter where we do it.

 OK, great, then the PDF code can sum them up avoiding the need to make the
interface between it and lmi more complex.

GC> >  If not, then I think we do need some object which would be part of the
GC> > bigger struct describing the entire group premium document to generate.
GC> > I.e. I see something like this, in pseudo-C++:
GC> > 
GC> >   struct premium_document_description
GC> >   {
GC> >       string
GC> >           ,header_text
GC> >           ,header_image_file
GC> I want to postpone those two; we can hardcode something bland for now,
GC> and later it will become clear what to do.


GC> >           ,footer_text
GC> I'm not sure what this would mean

 For me it was everything following the logo below the main table. Which
makes me realize that I forgot to include a field specifying this logo. Of
course, just as with the header fields above, it's not a problem at all to
hard code something generic for now and make it configurable later.

GC> >           ,company
GC> >           ,prepared_by
GC> Input::CorporationName and Input::AgentName, respectively. The
GC> complication here is that, conceptually, there's
GC>  - a top level, multiple_cell_document::case_parms_, which should
GC>    represent input fields that are (again, conceptually) exactly
GC>    the same for all participants; and
GC>  - a detail level, multiple_cell_document::cell_parms_, at which
GC>    every input field is actually present and modifiable (because
GC>    that makes the system maximally flexible and powerful).
GC> Here, the end users want the top-level inputs, but they don't
GC> enter top-level data, and a custom GUI is out of the question
GC> for this "premium quotes" task.

 Sorry, I am missing something here: why would a custom UI be needed if,
AFAICS, both CorporationName and AgentName can already be edited using the
"Case default dialog" (Ctrl-Shift-E)?

GC> I think the best solution is to read these values from first cell
GC> (participant), and then assert that they match in every other
GC> cell--assertion failure being an error that prevents any PDF output
GC> from being generated.

 Again, I have a strong impression of missing the point here, but it
doesn't seem right to use an assertion to flag something that is not a
programmers error: if users can specify different values for these fields
for the different cells using the "Edit cell" (Ctrl-E) dialog, we should,
IMHO, display an error telling them that a group summary cannot be
generated in this case, but why should it be an assertion failure?

GC> >           ,summary_data
GC> Input::Comments
GC> Because this has to be explicitly entered somewhere, I think we
GC> should prescribe multiple_cell_document::case_parms_ as the place
GC> where it must be entered: ctrl-shift-E in lmi's GUI.

 This means that the "Comments" text control would need to be made multi
line and given some reasonable height, i.e. be made tall enough to contain
4-5 lines of text. The problem with this is that it is inevitably going to
make the dialog bigger and it might not fit 800*600 screens any more. Of
course, I was the first one to say in the past that 800*600 shouldn't
matter nowadays and I still believe it doesn't, but I wanted to mention

 I also have to admit that I still don't quite understand why can't a new
field be added to contain this summary data instead of (ab)using comments
for this. If we could put a multiline "summary fields" text into e.g.
"Reports" tab of this dialog, it would fit nicely there (currently this
page is rather underwhelming, compared to most of the other ones)...

GC> >       {
GC> >           string name;
GC> >           int age;
GC> Input::InsuredName, Input::IssueAge
GC> >           double
GC> >               ,income
GC> >               ,face_amount
GC> Input::ProjectedSalary, Input::SpecifiedAmount
GC> Here's a complication that we must sidestep: these are input sequences,
GC> but we aren't going to "realize" them by calling RealizeProjectedSalary()
GC> or RealizeSpecifiedAmount(). In the one and only use case, these are
GC> (string representations of) numeric scalars. Any other use constitutes
GC> undefined behavior as defined in the language standard, with no diagnostic
GC> required. If you enter "100000, 3; 50000" then we just copy that string to
GC> output; or, if you like, we convert it to a numeric scalar, reformat it as
GC> a string, and no tears if an exception gets thrown for unconvertible input.

 Is this equivalent to just parsing the first number in this string and
ignoring the rest? And, if so, what should happen if the first token is not
a number but one of the keywords ("corridor"...)?

GC> As an alternative, we might call Input::RealizeAllSequenceInput() and then
GC> construct a yare_input object and use that. I'll probably do that if it's
GC> handy for the premium calculations. In that case, I guess we'd just select
GC> the first element of each input sequence: yare_input::ProjectedSalary[0]
GC> for example;

 If this allows to deal with the keywords too, it would seem preferable,
but I'm not sure at all that I understand this right.

GC> optionally, we could assert that all elements of that vector are equal.

 And even less sure about what is the right thing to do in this case...

GC> >               ,premium
GC> >               ,premium_with_waiver
GC> >               ,premium_with_adb
GC> >               ,premium_with_waiver_and_adb
GC> I will need to calculate these explicitly; I haven't yet worked out exactly
GC> how I want to do that.
GC> >       vector<participant> participants;
GC> This brings us back to the question whether, as we iterate through
GC> multiple_cell_document::cell_parms_, we want to
GC>  - populate such an intermediate structure, through which we'll later
GC>      iterate to write PDF rows; or
GC>  - write PDF rows as we process each cell_parms_ element.
GC> This is discussed in more detail below.

[...discussion snipped but stored for future reference...]

GC> Now we could organize the whole either this way:
GC> void do_everything(...filename...)
GC> {
GC>    intermediate_struct z = foo(filename);
GC>    // total every column somewhere...
GC>    do_pdf_stuff(z);
GC> }
GC> or by intermingling foo() with PDF stuff in a single function. Is this
GC> concrete enough for you to see which way we should do this so that we
GC> don't wind up building a "Psychobilly Cadillac"?

 I prefer to have an intermediate struct and do_everything() function. The
only drawback of this approach I can see is that copying data around is not
as efficient as using it directly, but I don't believe we're going to have
performance problems because of this, we just don't operate with that much
data here.

 Other than this I can see only advantages in using this struct:

- The function building it can be tested independently, we don't need to
  dump the data to any ostringstream inside the function itself which might
  be cheap but is not free and also distracts from the main point of the
  function. If it just returns the struct, it can be dumped/verified in the
  test code.

- Similarly, the function producing the PDF can be tested much easier as we
  don't need to rewrite any driving function in the test, instead we can
  just populate the struct (which is much simpler) and pass it on.

- There are fewer constraints over both the struct creating and the PDF
  generating code if they can write/read this struct in any way they want
  instead of having to do it row by row. E.g. the PDF function might look
  at the total number of rows to determine the total table height and the
  number of pages (this is just an example, I don't think we need to do it
  right now, but it's still good to have the possibility to do it if
  needed). Similarly, perhaps the creating function might be more naturally
  written if it computed the basic premiums for all rows first and then the
  other ones, instead of having to do it strictly row by row.

 So I (still) think that using an intermediate struct is the way to go. I
could live with a pdf_generator class (it would have to be a class though,
not a set of functions, as it would definitely need to keep some state
inside it) with methods such as begin_document(), make_summary(),
begin_table(), add_row(), end_table(), ... but I don't see what would we
gain from having such class compared to a single generate_pdf_summary()
function. If I was really forced to come up with a justification for such
class, I would mumble something about providing other implementations of
the premiums summary reports in the future (e.g. in HTML or ODF or maybe
just a differently formatted PDF), but if we don't have any such plans, I
don't think it would sound very convincing.

 Please let me know if you see any problems with using a simple struct for
the data and a function generating a PDF using this data.


reply via email to

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