GnuCashew ~ Web Application compatible with GnuCash sql data files.
GCW
Loading...
Searching...
No Matches
SummaryWidget.cpp
Go to the documentation of this file.
1#line 2 "src/Gui/BillPay/SummaryWidget.cpp"
2
3//#define VERSION_SOSO
4#define VERSION_LITTLEBETTER
5
6#include <Wt/WMenuItem.h>
7#include <Wt/WVBoxLayout.h>
8#include <Wt/WMessageBox.h>
9
10#include "../../Eng/AccountComboModel.h"
11#include "../../Glb/Core.h"
12#include "BillPay.h"
13
16: Wt::WContainerWidget()
17{
18 addStyleClass( "SummaryWidget" );
19
20 m_title = addWidget( std::make_unique< Wt::WText >() );
21 m_table = addWidget( std::make_unique< Wt::WTable >() );
22
23} // endSummaryWidget( const std::string & _accountGuid )
24
25namespace {
26
27auto ordinalSuffix( int number )-> std::string
28{
29 int lastTwo = number % 100;
30 int lastOne = number % 10;
31
32 if( lastTwo >= 11
33 && lastTwo <= 13
34 )
35 return "th";
36
37 switch( lastOne )
38 {
39 case 1: return "st";
40 case 2: return "nd";
41 case 3: return "rd";
42 default: return "th";
43 }
44
45 return "";
46
47} // endauto ordinalSuffix( int number )-> std::string
48
49} // endnamespace {
50
51#ifdef VERSION_LITTLEBETTER
52auto
54setMonth( int _month )-> void
55{
56 /*
57 ** open a transaction, helps all the queries to run faster
58 */
59 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
60
61 /*
62 ** reset the report
63 */
64 m_table-> clear();
65 m_table-> setStyleClass( "SummaryTable" );
66
67 /*
68 ** post the month we're in
69 */
70 m_month = _month;
71 m_title->
72 setText
73 (
74 Wt::WString( TR("gcw.billPay.lbl.selectedMonth") )
75 .arg( TR("gcw.billPay.ttp." + toString( m_month ) ) )
76 );
77
78 /*
79 ** gather up all the payment splits and process them
80 ** in to the report
81 */
82 Splits splits( _month );
83 int row = 0;
84 std::vector< DayTotal_t > dayTotals;
85 for( auto payFromAcct : splits.payFroms() )
86 {
87 /*
88 ** all payFromDay
89 */
90 for( auto payFromDay : splits.payFromDays( payFromAcct ) )
91 {
92 auto acctDay =
93 Wt::WString("<span style=\"border-bottom:1px solid black;\">{1}<sup>{3}</sup> ~ {2}</span>")
94 .arg( payFromDay )
95 .arg( payFromAcct )
96 .arg( ordinalSuffix( payFromDay ) )
97 .toUTF8()
98 ;
99
100 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( acctDay );
101 m_table-> elementAt( row, 0 )-> setStyleClass( "acctDay" );
102 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
103 row++;
104
105 GCW_NUMERIC subTotal(0);
107 for( auto paymentSplit : splits.paymentSplits( payFromAcct, payFromDay ) )
108 {
109 auto splitItem = GCW::Dbo:: Splits ::byGuid( paymentSplit );
110 acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
111 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
112
113 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( splitItem -> valueAsString( true ) );
114 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( txItem -> description() );
115 m_table-> elementAt( row, 1 )-> clicked().connect( [=](){ m_clicked.emit( txItem-> description() ); } );
116 row++;
117
118 subTotal += splitItem-> value( true );
119
120 } // endfor( ..all payments.. )
121
122 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( subTotal, GCW::Cfg::decimal_format() ) ) );
123 m_table-> elementAt( row, 0 )-> setStyleClass( "du" );
124 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" );
125 row++;
126
127 /*
128 ** record the day total for the subsequent report
129 **
130 ** \todo total unbelievable hack
131 **
132 ** This 'hack' causes this summary report to print ~only~ the values
133 ** that are considered payments that came from a 'bank' or some type
134 ** of ASSET account. Note, that bills can also be paid with LIABILITY
135 ** account types, but we don't want those accounts to appear in the
136 ** transfer totals since the transfer totals are for showing how much
137 ** money needs to be transferred out of the checking account(s).
138 */
140 {
141 DayTotal_t dayTotal;
142 dayTotal.day = payFromDay;
143 dayTotal.bank = payFromAcct;
144 dayTotal.value = subTotal;
145 dayTotals.push_back( dayTotal );
146 }
147
148 } // endall payFromDay
149
150 } // endfor( ..all payFroms.. )
151
152 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( TR("gcw.billPay.lbl.transfers") );
153 m_table-> elementAt( row, 0 )-> setStyleClass( "acctDay" );
154 m_table-> elementAt( row, 0 )-> setAttributeValue( "style", "text-align:center;border-bottom: 1px solid black;" );
155 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
156 row++;
157
158 std::sort
159 (
160 dayTotals.begin(),
161 dayTotals.end(),
162 []( DayTotal_t a, DayTotal_t b )
163 {
164 return a.day < b.day;
165 }
166 );
167
168 GCW_NUMERIC grand(0);
169 GCW_NUMERIC sum(0);
170 int day = 0;
171 for( auto dayTotal : dayTotals )
172 {
173 if( day != dayTotal.day )
174 {
175 auto payDay =
176 Wt::WString("<u>{1}<sup>{2}</sup></u>")
177 .arg( day )
178 .arg( ordinalSuffix( day ) )
179 .toUTF8()
180 ;
181
182 if( day != 0 )
183 {
184 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}") .arg( toString( sum, GCW::Cfg::decimal_format() ) ) );
185 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( Wt::WString(TR("gcw.billPay.lbl.totalfor")) .arg( payDay ) );
186 m_table-> elementAt( row, 0 )-> setStyleClass( "du" );
187 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" );
188 row++;
189 grand += sum;
190 sum = 0;
191
192 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "" );
193 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
194 m_table-> elementAt( row, 0 )-> setAttributeValue( "style", "border-bottom:1px solid black;" );
195 row++;
196
197 } // endif( day != 0 )
198
199 day = dayTotal.day;
200
201 } // endif( day != dayTotal.day )
202
203 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( dayTotal.value, GCW::Cfg::decimal_format() ) ) );
204 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( dayTotal.bank );
205 row++;
206
207 sum += dayTotal.value;
208
209 } // endfor( auto day : splits.dayTotals() )
210
211 if( day != 0 )
212 {
213 auto payDay =
214 Wt::WString("<u>{1}<sup>{2}</sup></u>")
215 .arg( day )
216 .arg( ordinalSuffix( day ) )
217 .toUTF8()
218 ;
219
220 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( sum, GCW::Cfg::decimal_format() ) ) );
221 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( Wt::WString(TR("gcw.billPay.lbl.totalfor")).arg( payDay ) );
222 m_table-> elementAt( row, 0 )-> setStyleClass( "du" ); // double-underline
223 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" ); // single-underline
224 row++;
225 grand += sum;
226 sum = 0;
227 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "" );
228 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
229 m_table-> elementAt( row, 0 )-> setAttributeValue( "style", "border-bottom:1px double black;" );
230 row++;
231
232 } // endif( day != 0 )
233
234 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( grand, GCW::Cfg::decimal_format() ) ) );
235 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( Wt::WString(TR("gcw.billPay.lbl.totalfor")).arg( TR("gcw.billPay.ttp." + toString( m_month ) ) ) );
236 row++;
237
238 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "" );
239 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
240 m_table-> elementAt( row, 0 )-> setAttributeValue( "style", "border-bottom:1px double black;" );
241 row++;
242
243} // endsetMonth( int _month )-> void
244#endif
245
246
247#ifdef VERSION_SOSO
248auto
250setMonth( int _month )-> void
251{
252 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
253
254 /*
255 ** reset the report
256 */
257 m_table-> clear();
258 m_table-> setStyleClass( "SummaryTable" );
259
260 /*
261 ** post the month we're in
262 */
263 m_month = _month;
264 m_title-> setText( Wt::WString( TR(gcw.billPay.lbl.selectedMonth) ).arg( m_month ) );
265
266 /*
267 ** gather up all the payment splits and process them
268 ** in to the report
269 */
270 Splits splits( _month );
271 int row = 0;
272 std::vector< DayTotal_t > dayTotals;
273 for( auto payFromAcct : splits.payFroms() )
274 {
275 for( auto payFromDay : splits.payFromDays( payFrom ) )
276 {
277 auto acctDay =
278 Wt::WString("{1}<sup>{3}</sup> ~ {2}")
279 .arg( payFromDay )
280 .arg( payFromAcct )
281 .arg( ordinalSuffix( payFromDay ) )
282 .toUTF8()
283 ;
284
285 m_table-> elementAt( row, 0 )-> setAttributeValue( "style", "padding-top: 10px;" );
286 m_table-> elementAt( row, 1 )-> setAttributeValue( "style", "padding-top: 10px;" );
287
288 GCW_NUMERIC subTotal(0);
289 for( auto paymentSplit : splits.paymentSplits( payFromAcct, payFromDay ) )
290 {
291 auto splitItem = GCW::Dbo:: Splits ::byGuid( paymentSplit );
292 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
293 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
294
295 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( splitItem -> valueAsString( true ) );
296 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( txItem -> description() );
297 row++;
298
299 subTotal += splitItem-> value( true );
300
301 } // endfor( ..all payments.. )
302
303 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( subTotal, GCW::Cfg::decimal_format() ) ) );
304 m_table-> elementAt( row, 0 )-> setStyleClass( "du" );
305 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" );
306 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( acctDay );
307 row++;
308
309 /*
310 ** record the day total for the subsequent report
311 */
312 DayTotal_t dayTotal;
313 dayTotal.day = payFromDay;
314 dayTotal.bank = payFromAcct;
315 dayTotal.value = subTotal;
316 dayTotals.push_back( dayTotal );
317
318 } // endfor( ..all payFromDays.. )
319
320 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "------------------------------------" );
321 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
322 row++;
323
324 } // endfor( ..all payFroms.. )
325
326 std::sort
327 (
328 dayTotals.begin(),
329 dayTotals.end(),
330 []( DayTotal_t a, DayTotal_t b )
331 {
332 return a.day < b.day;
333 }
334 );
335
336 GCW_NUMERIC grand(0);
337 GCW_NUMERIC sum(0);
338 int day = 0;
339 for( auto dayTotal : dayTotals )
340 {
341 if( day != dayTotal.day )
342 {
343 auto payDay =
344 Wt::WString("{1}<sup>{2}</sup>")
345 .arg( day )
346 .arg( ordinalSuffix( day ) )
347 .toUTF8()
348 ;
349
350 if( day != 0 )
351 {
352 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( sum, GCW::Cfg::decimal_format() ) ) );
353 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( Wt::WString("Total for {1}").arg( payDay ) );
354 m_table-> elementAt( row, 0 )-> setStyleClass( "du" );
355 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" );
356 row++;
357 grand += sum;
358 sum = 0;
359
360 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "------------------------------------" );
361 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
362 row++;
363
364
365 }
366
367 day = dayTotal.day;
368 }
369
370 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( dayTotal.value, GCW::Cfg::decimal_format() ) ) );
371 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( dayTotal.bank );
372 row++;
373
374 sum += dayTotal.value;
375
376#ifdef NEVER
377 if( day != dayTotal.day )
378 {
379 std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
380
381 if( day != 0 )
382 {
383 std::cout << __FILE__ << ":" << __LINE__ << " " << std::endl;
384
385 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( sum, GCW::Cfg::decimal_format() ) ) );
386 m_table-> elementAt( row, 0 )-> setStyleClass( "du" );
387 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" );
388 row++;
389 sum = 0;
390 }
391
392 day = dayTotal.day;
393 }
394#endif
395
396 } // endfor( auto day : splits.dayTotals() )
397
398 if( day != 0 )
399 {
400 auto payDay =
401 Wt::WString("{1}<sup>{2}</sup>")
402 .arg( day )
403 .arg( ordinalSuffix( day ) )
404 .toUTF8()
405 ;
406
407 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( sum, GCW::Cfg::decimal_format() ) ) );
408 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( Wt::WString("Total for {1}").arg( payDay ) );
409 m_table-> elementAt( row, 0 )-> setStyleClass( "du" );
410 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" );
411 row++;
412 grand += sum;
413 sum = 0;
414 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "------------------------------------" );
415 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
416 row++;
417
418 }
419
420 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( Wt::WString("{1}").arg( toString( grand, GCW::Cfg::decimal_format() ) ) );
421 m_table-> elementAt( row, 1 )-> addNew< Wt::WText >( Wt::WString("Total for {1}").arg( TR("gcw.billPay.ttp." + toString( m_month ) ) ) );
422 row++;
423
424 m_table-> elementAt( row, 0 )-> addNew< Wt::WText >( "********************************" );
425 m_table-> elementAt( row, 0 )-> setColumnSpan( 2 );
426 row++;
427
428
429} // endsetMonth( int _month )-> void
430#endif
431
432
434Splits( int _month )
435: m_month( _month )
436{
437 /*
438 ** get all the transactions that happened for this account for this month
439 */
441
442 /*
443 ** if transactions happened, get them open and see if they should be in the summary report
444 */
445 for( auto txItem : txItems )
446 {
447 /*
448 ** loop through all the splits
449 */
450 for( auto split : GCW::Dbo::Splits::byTransaction( txItem-> guid() ) )
451 {
452 /*
453 ** We want the pay-from account.
454 */
455 if( split-> value() < 0 )
456 {
457 m_splitGuids.push_back( split-> guid() );
458
459 } // endif( ..pay-from account.. )
460
461 } // endfor( auto split : GCW::Dbo::Splits::byTransaction( txItem-> guid() ) )
462
463 } // endfor( auto txItem : txItems )
464
465} // endSplits( int _month )
466
467
468auto
470splitGuids() const-> const std::vector< std::string > &
471{
472 return m_splitGuids;
473
474} // endsplitGuids() const-> std::vector< std::string >
475
476
477auto
479days() const-> std::set< int >
480{
481 std::set< int > retVal;
482
483 /*
484 ** loop through all the splits and produce a set
485 ** of days that payments were made
486 */
487 for( auto splitGuid : splitGuids() )
488 {
489 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
490 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
491
492 retVal.insert( txItem-> post_date_as_date().date().day() );
493
494 } // endfor( auto splitGuid : splitGuids() )
495
496 return retVal;
497
498} // enddays() const-> std::set< int >
499
500
501auto
503payFroms() const-> std::set< std::string >
504{
505 std::set< std::string > retVal;
506
507 /*
508 ** loop throught all the splits and produce a set
509 ** of 'account name' that were used to make payments
510 */
511 for( auto splitGuid : splitGuids() )
512 {
513 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
514 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
515
516 retVal.insert( acctItem-> name() );
517
518 } // endfor( auto splitGuid : splitGuids() )
519
520 return retVal;
521
522} // enddays() const-> std::set< int >
523
524
525auto
527payFromDays( const std::string & _payFrom ) const-> std::set< int >
528{
529 std::set< int > retVal;
530
531 /*
532 ** loop through all the splits and produce a set of
533 ** days that an account made payments on
534 */
535 for( auto splitGuid : splitGuids() )
536 {
537 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
538 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
539 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
540
541 if( acctItem-> name() == _payFrom )
542 retVal.insert( txItem-> post_date_as_date().date().day() );
543
544 } // endfor( auto splitGuid : splitGuids() )
545
546 return retVal;
547
548} // enddays() const-> std::set< int >
549
550
551auto
553paymentSplits( const std::string & _payFrom, int _day ) const-> std::vector< std::string >
554{
555 std::vector< std::string > retVal;
556
557 /*
558 ** loop through all the splits and produce a vector
559 ** of all the splits used from an account on specific
560 ** day
561 */
562 for( auto splitGuid : splitGuids() )
563 {
564 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
565 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
566 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
567
568 if( acctItem-> name() == _payFrom
569 && txItem-> post_date_as_date().date().day() == _day
570 )
571 retVal.push_back( splitGuid );
572
573 } // endfor( auto splitGuid : splitGuids() )
574
575 return retVal;
576
577} // endpaymentSplits( const std::string & _payFrom, int _day ) const-> std::vector< std::string >
578
579
580auto
582dayPayments( int _day ) const-> std::vector< std::string >
583{
584 std::vector< std::string > retVal;
585
586 /*
587 ** loop through all the splits and produce a list of
588 ** splits that were on a specific day.
589 */
590 for( auto splitGuid : splitGuids() )
591 {
592 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
593 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
594
595 if( txItem-> post_date_as_date().date().day() == _day )
596 retVal.push_back( splitGuid );
597
598 } // endfor( auto splitGuid : splitGuids() )
599
600 return retVal;
601
602} // enddayPayments( int _day ) const-> std::vector< std::string >
603
604
static std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Definition Core.cpp:16
auto payFromDays(const std::string &_payFrom) const -> std::set< int >
auto payFroms() const -> std::set< std::string >
std::vector< std::string > m_splitGuids
auto splitGuids() const -> const std::vector< std::string > &
auto dayPayments(int _day) const -> std::vector< std::string >
auto paymentSplits(const std::string &_payFrom, int _day) const -> std::vector< std::string >
auto days() const -> std::set< int >
auto setMonth(int _month) -> void
Widget * addNew(Args &&...args)
virtual void addWidget(std::unique_ptr< WWidget > widget)
std::string toUTF8() const
WString & arg(const std::wstring &value)
virtual void addStyleClass(const WString &styleClass, bool force=false) override
#define TR(X)
Definition define.h:17
#define GCW_NUMERIC
Internal Numeric Type.
Definition gcwglobal.h:38
DECIMAL::decimal_format decimal_format()
Decimal Format Specifier.
Definition GnuCashew.cpp:21
@ ASSET
02 ~ generic generalized asset account
auto isType(const Item::Ptr _acctItem, GCW::Dbo::Accounts::Type _type) -> bool
Is Account Type.
auto byTransaction(const std::string &_txGuid) -> Item::Vector
Load Splits by Transaction.
Definition Splits.cpp:244
auto byNumMonth(const std::string &_num, int _month) -> Item::Vector
auto toString(int _value) -> std::string
Convert Integer to String.
Definition BillPay.cpp:55
App * app()
Definition App.cpp:75