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
54setDate( int _month, int _year )-> 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, _year );
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" ); // double-underline
124 m_table-> elementAt( row-1, 0 )-> setStyleClass( "su" ); // single-underline
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} // endsetDate( int _month, int _year )-> void
244#endif
245
246
247#ifdef VERSION_SOSO
248auto
249GCW::Gui::BillPay::SummaryWidget::
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, int _year )
435: m_month( _month ),
436 m_year( _year )
437{
438 /*
439 ** get all the transactions that happened for this account for this month
440 */
442
443 /*
444 ** if transactions happened, get them open and see if they should be in the summary report
445 */
446 for( auto txItem : txItems )
447 {
448 /*
449 ** loop through all the splits
450 */
451 for( auto split : GCW::Dbo::Splits::byTransaction( txItem-> guid() ) )
452 {
453 /*
454 ** We want the pay-from account.
455 */
456 if( split-> value() < 0 )
457 {
458 m_splitGuids.push_back( split-> guid() );
459
460 } // endif( ..pay-from account.. )
461
462 } // endfor( auto split : GCW::Dbo::Splits::byTransaction( txItem-> guid() ) )
463
464 } // endfor( auto txItem : txItems )
465
466} // endSplits( int _month )
467
468
469auto
471splitGuids() const-> const std::vector< std::string > &
472{
473 return m_splitGuids;
474
475} // endsplitGuids() const-> std::vector< std::string >
476
477
478auto
480days() const-> std::set< int >
481{
482 std::set< int > retVal;
483
484 /*
485 ** loop through all the splits and produce a set
486 ** of days that payments were made
487 */
488 for( auto splitGuid : splitGuids() )
489 {
490 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
491 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
492
493 retVal.insert( txItem-> post_date_as_date().date().day() );
494
495 } // endfor( auto splitGuid : splitGuids() )
496
497 return retVal;
498
499} // enddays() const-> std::set< int >
500
501
502auto
504payFroms() const-> std::set< std::string >
505{
506 std::set< std::string > retVal;
507
508 /*
509 ** loop throught all the splits and produce a set
510 ** of 'account name' that were used to make payments
511 */
512 for( auto splitGuid : splitGuids() )
513 {
514 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
515 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
516
517 retVal.insert( acctItem-> name() );
518
519 } // endfor( auto splitGuid : splitGuids() )
520
521 return retVal;
522
523} // enddays() const-> std::set< int >
524
525
526auto
528payFromDays( const std::string & _payFrom ) const-> std::set< int >
529{
530 std::set< int > retVal;
531
532 /*
533 ** loop through all the splits and produce a set of
534 ** days that an account made payments on
535 */
536 for( auto splitGuid : splitGuids() )
537 {
538 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
539 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
540 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
541
542 if( acctItem-> name() == _payFrom )
543 retVal.insert( txItem-> post_date_as_date().date().day() );
544
545 } // endfor( auto splitGuid : splitGuids() )
546
547 return retVal;
548
549} // enddays() const-> std::set< int >
550
551
552auto
554paymentSplits( const std::string & _payFrom, int _day ) const-> std::vector< std::string >
555{
556 std::vector< std::string > retVal;
557
558 /*
559 ** loop through all the splits and produce a vector
560 ** of all the splits used from an account on specific
561 ** day
562 */
563 for( auto splitGuid : splitGuids() )
564 {
565 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
566 auto acctItem = GCW::Dbo:: Accounts ::byGuid( splitItem-> account_guid() );
567 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
568
569 if( acctItem-> name() == _payFrom
570 && txItem-> post_date_as_date().date().day() == _day
571 )
572 retVal.push_back( splitGuid );
573
574 } // endfor( auto splitGuid : splitGuids() )
575
576 return retVal;
577
578} // endpaymentSplits( const std::string & _payFrom, int _day ) const-> std::vector< std::string >
579
580
581auto
583dayPayments( int _day ) const-> std::vector< std::string >
584{
585 std::vector< std::string > retVal;
586
587 /*
588 ** loop through all the splits and produce a list of
589 ** splits that were on a specific day.
590 */
591 for( auto splitGuid : splitGuids() )
592 {
593 auto splitItem = GCW::Dbo:: Splits ::byGuid( splitGuid );
594 auto txItem = GCW::Dbo:: Transactions ::byGuid( splitItem-> tx_guid() );
595
596 if( txItem-> post_date_as_date().date().day() == _day )
597 retVal.push_back( splitGuid );
598
599 } // endfor( auto splitGuid : splitGuids() )
600
601 return retVal;
602
603} // enddayPayments( int _day ) const-> std::vector< std::string >
604
605
static std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Definition Core.cpp:26
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 setDate(int _month, int _year) -> 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:40
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:187
auto byNumDate(const std::string &_num, int _month, int _year) -> Item::Vector
Load Transactions for 'num' and Month and Year.
auto toString(int _value) -> std::string
Convert Integer to String.
Definition BillPay.cpp:55
App * app()
Definition App.cpp:75