GnuCashew ~ Web Application compatible with GnuCash sql data files.
GCW
Loading...
Searching...
No Matches
TransactionManager.cpp
Go to the documentation of this file.
1#line 2 "src/Eng/TransactionManager.cpp"
2
3#define INCLUDE_TOOL_TIP_ON_DESCRIPTION
4
5#include "../Glb/Core.h"
6#include "../Gui/AccountRegister/Model.h"
8
10Manager()
11: m_prefrenceItem( GCW::Dbo::Prefrences::get() )
12{
13
14} // endManager()
15
18: m_model( _model ),
19 m_prefrenceItem( GCW::Dbo::Prefrences::get() )
20{
21
22} // endManager()
23
24auto
26newTransaction( const std::string & _accountGuid1, const std::string & _accountGuid2, const Wt::WDate & _date, GCW_NUMERIC _value, const std::string & _description )-> void
27{
28#ifndef NEVER
29 std::cout << __FILE__ << ":" << __LINE__
30 << "\n acct1: " << GCW::Dbo::Accounts::fullName( _accountGuid1 )
31 << "\n acct2: " << GCW::Dbo::Accounts::fullName( _accountGuid2 )
32 << "\n date: '" << _date.toString() << "'"
33 << "\n value: " << _value
34 << "\n desc: " << _description
35 << std::endl;
36#endif
37
38 /*!
39 ** The process begins by loading up the two accounts.
40 */
41 auto accountItem1 = GCW::Dbo::Accounts::load( _accountGuid1 );
42
43 /*
44 ** create a new transaction with two splits
45 */
46 m_transactionItem = GCW::Dbo::Transactions::add( GCW::Core::newGuid() );
47
48 /*
49 ** hook everything together
50 */
51 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
52 // transaction
53 m_transactionItem.modify()-> set_currency_guid( accountItem1-> commodity_guid() );
54 m_transactionItem.modify()-> set_enter_date( Wt::WDate::currentDate() );
55 m_transactionItem.modify()-> set_post_date( _date );
56 m_transactionItem.modify()-> set_description( _description );
57 // Split1
59 split1.modify()-> set_tx_guid ( m_transactionItem-> guid() );
60 split1.modify()-> set_account_guid ( _accountGuid1 );
61 split1.modify()-> set_reconcile_state ( GCW_RECONCILE_NO );
62 split1.modify()-> set_reconcile_date ( GCW_DEFAULT_DATE );
63 split1.modify()-> set_value ( _value );
64 split1.modify()-> set_quantity ( _value ); // qty set also?
65 // Split2
67 split2.modify()-> set_tx_guid ( m_transactionItem-> guid() );
68 split2.modify()-> set_account_guid ( _accountGuid2 );
69 split2.modify()-> set_reconcile_state ( GCW_RECONCILE_NO );
70 split2.modify()-> set_reconcile_date ( GCW_DEFAULT_DATE );
71 split2.modify()-> set_value ( -_value );
72 split2.modify()-> set_quantity ( -_value ); // qty set also?
73
74 /*!
75 ** \todo query why qty used here
76 **
77 ** this transaction posting shows that .value. as well as .quantity. are
78 ** set at the same time. If .quantity. is not set, then when re-opening
79 ** the sql file in gnucash native causes the gnucash to take a very long
80 ** time to load. This only happens once, and upon examining the database
81 ** afterwords, all the splits have the same .value. set to .quantity. So,
82 ** some sort of massive update is happening there on file-open. Therefore,
83 ** we will set .quantity. along with .value. Doing so seems to mitigate
84 ** the long/slow load time.
85 **
86 */
87
88 /*
89 ** remember the splits
90 */
91 m_splits.push_back( split1 );
92 m_splits.push_back( split2 );
93
94} // endnewTransaction()-> void
95
96
97auto
99loadTransaction( const std::string & _transactionGuid )-> void
100{
101 /*
102 ** set the transaction
103 */
104 m_transactionItem = GCW::Dbo::Transactions::load( _transactionGuid );
105
106 /*
107 ** set the splits
108 */
109 m_splits = GCW::Dbo::Splits::byTransaction( m_transactionItem-> guid() );
110
111} // endloadTransaction( const std::string & _transactionGuid )-> void
112
113auto
115deleteTransaction()-> bool
116{
117
118 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
119 m_transactionItem.remove();
120 for( auto & splitItem : m_splits )
121 splitItem.remove();
122
123 return true;
124
125} // enddeleteTransaction()-> void
126
127auto
129setSplitItem( GCW::Dbo::Splits::Item::Ptr _splitItem )-> void
130{
131 if( !_splitItem )
132 return;
133
134 loadSplit( _splitItem-> guid() );
135
136} // endsetSplitItem( GCW::Dbo::Splits::Item::Ptr _splitItem )-> void
137
138auto
140loadSplit( const std::string & _splitGuid )-> void
141{
142 if( _splitGuid == "" )
143 return;
144
145 /*
146 ** in the words of spock: 'remember'
147 */
148 m_splitGuid = _splitGuid;
149
150 /*
151 ** get the split so we can grab the transaction
152 */
153 auto splitItem = GCW::Dbo::Splits::load( _splitGuid );
154
155 /*
156 ** set the transaction
157 */
158 loadTransaction( splitItem-> tx_guid() );
159
160} // endloadSplit( const std::string & _splitGuid )-> void
161
162auto
164otherGuid() const-> std::string
165{
166 for( auto & splitItem : m_splits )
167 if( splitItem-> guid() != m_splitGuid )
168 return splitItem-> guid();
169
170 return "";
171
172} // endotherGuid()-> std::string
173
174auto
176split( const std::string & _splitGuid ) const-> GCW::Dbo::Splits::Item::Ptr
177{
178 for( auto & splitItem : m_splits )
179 if( splitItem-> guid() == _splitGuid )
180 return splitItem;
181
183
184} // endsplit( const std::string & _splitGuid ) const-> GCW::Dbo::Splits::Item::Ptr
185
186auto
188thisSplit() const-> GCW::Dbo::Splits::Item::Ptr
189{
190 return split( m_splitGuid );
191
192} // endthisSplit() const-> GCW::Dbo::Splits::Item::Ptr
193
194auto
196thatSplit() const-> GCW::Dbo::Splits::Item::Ptr
197{
198 return split( otherGuid() );
199
200} // endthatSplit() const-> GCW::Dbo::Splits::Item::Ptr
201
202auto
204fromSplit() const-> GCW::Dbo::Splits::Item::Ptr
205{
206 for( auto split : m_splits )
207 {
208 if( split-> value() < 0 )
209 return split;
210 }
211
213
214} // endfromSplit() const-> GCW::Dbo::Splits::Item::Ptr
215
216auto
218toSplit() const-> GCW::Dbo::Splits::Item::Ptr
219{
220 for( auto split : m_splits )
221 if( split-> value() > 0 )
222 return split;
223
225
226} // endtoSplit() const-> GCW::Dbo::Splits::Item::Ptr
227
228namespace {
229
230auto
231makeTip( const GCW::Dbo::Splits::Item::Ptr & _split )-> std::string
232{
233 return
235 (
236 "split: {1}\n"
237 "account: {2}\n"
238 "txn: {3}"
239 )
240 .arg( _split-> guid() )
241 .arg( _split-> account_guid() )
242 .arg( _split-> tx_guid() )
243 .toUTF8()
244 ;
245
246} // endmakeTip( const GCW::Dbo::Splits::Item::Ptr & _split )-> std::string
247
248}
249
250
251
252
253auto
255getFromAccount() const-> std::string
256{
257 if( fromSplit() )
258 {
259 return
260 Wt::WString("<span title=\"{2}\">{1}</span>")
261 .arg( GCW::Dbo::Accounts::fullName( fromSplit()-> account_guid() ) )
262 .arg( makeTip( fromSplit() ) )
263 .toUTF8()
264 ;
265
266 }
267
268 return TR8( "gcw.unassigned" );
269
270} // endgetFromAccount() const-> std::string
271
272auto
274getToAccount() const-> std::string
275{
276 if( toSplit() )
277 {
278 return
279 Wt::WString("<span title=\"{2}\">{1}</span>")
280 .arg( GCW::Dbo::Accounts::fullName( toSplit()-> account_guid() ) )
281 .arg( makeTip( toSplit() ) )
282 .toUTF8()
283 ;
284
285 }
286
287 return TR8( "gcw.unassigned" );
288
289} // endgetToAccount() const-> std::string
290
291
292auto
294forAccountSplit( const std::string & _accountGuid ) const-> GCW::Dbo::Splits::Item::Ptr
295{
297
298 for( auto & split : m_splits )
299 if( split-> account_guid() == _accountGuid )
300 retVal = split;
301
302 return retVal;
303
304} // endforAccount( const std::string * _accountGuid ) const-> GCW::Dbo::Splits::Item::Ptr
305
306auto
308getDate() const-> Wt::WDateTime
309{
310 return m_transactionItem-> post_date_as_date();
311
312} // endgetDate() const-> Wt::WDateTime &;
313
314auto
316getDateAsString() const-> Wt::WString
317{
318 return getDate().toString( GCW_DATE_FORMAT_DISPLAY );
319
320} // endgetDate() const-> Wt::WDateTime &;
321
322auto
324setDate( const Wt::WDateTime & _value )-> void
325{
326 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
327 m_transactionItem.modify()-> set_post_date( _value );
328
329} // endsetDate( const Wt::WDateTime & _value )-> void
330
331auto
333setDate( const Wt::WDate & _value )-> void
334{
335 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
336 m_transactionItem.modify()-> set_post_date( Wt::WDateTime( _value ) );
337
338} // endsetDate( const Wt::WDateTime & _value )-> void
339
340
341
342auto
344setAction( const std::string & _value )-> void
345{
346 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
347 m_transactionItem.modify()-> set_num( _value );
348
349} // endsetAction( const std::string & _value )-> void
350
351auto
353getDescription() const-> std::string
354{
355 return m_transactionItem-> description();
356
357} // endgetDescription() const-> std::string &
358
359auto
361setDescription( const std::string & _value )-> void
362{
363 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
364 m_transactionItem.modify()-> set_description( _value );
365
366} // endsetDescription( const std::string & _value )-> void
367
368auto
370setDescription( const Wt::WString & _value )-> void
371{
372 setDescription( _value.toUTF8() );
373
374} // ensetDescription( const Wt::WString & _value )-> void
375
376auto
378getNum() const-> std::string
379{
380 return m_transactionItem-> num();
381
382} // endgetDescription() const-> std::string &
383
384auto
386setNum( const std::string & _value )-> void
387{
388 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
389 m_transactionItem.modify()-> set_num( _value );
390
391} // endsetDescription( const std::string & _value )-> void
392
393auto
395setNum( const Wt::WString & _value )-> void
396{
397 setNum( _value.toUTF8() );
398
399} // ensetDescription( const Wt::WString & _value )-> void
400
401auto
403setTransferGuid( const std::string & _value )-> void
404{
405 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
406 thatSplit().modify()-> set_account_guid( _value );
407
408} // endsetTransferGuid( const std::string & _value )-> void
409
410auto
412setReconcile( const std::string & _value )-> void
413{
414 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
415 thisSplit().modify()-> set_reconcile_state( _value );
416
417} // endsetReconcile( const std::string & _value )-> void
418
419auto
421getValue() const-> GCW_NUMERIC
422{
423 return thisSplit()-> value();
424
425} // endgetValue() const-> GCW_NUMERIC
426
427auto
429getValueAsString() const-> std::string
430{
431 return thisSplit()-> valueAsString();
432
433} // endgetValue() const-> GCW_NUMERIC
434
435auto
437setValue( GCW_NUMERIC _value )-> void
438{
439 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
440 thisSplit().modify()-> set_value( _value );
441 thatSplit().modify()-> set_value( _value * -1 );
442
443} // endsetDebit( GCW_NUMERIC _value )-> void
444
445auto
447setValue( const std::string & _acctGuid, GCW_NUMERIC _value )-> void
448{
449 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
450 forAccountSplit( _acctGuid ).modify()-> set_value( _value );
451
452} // endsetValue( const std::string & _acctGuid, GCW_NUMERIC _value )-> void
453
454auto
456setNotes( const std::string & _acctGuid, const std::string & _value )-> void
457{
458 Wt::Dbo::Transaction t( GCW::app()-> gnucashew_session() );
459 forAccountSplit( _acctGuid ).modify()-> set_memo( _value );
460
461} // endsetNotes( const std::string & _value )-> void
462
463
464auto
466otherSplits() const-> GCW::Dbo::Splits::Item::Vector
467{
468 return GCW::Dbo::Splits::bySplitExcept( m_splitGuid );
469
470} // endotherSplits() const-> GCW::Dbo::Splits::Item::Vector
471
472auto
474setReadOnly( bool _value )-> void
475{
476
477} // endsetReadOnly( bool _value )-> void
478
479auto
481flags( bool _editable ) const-> Wt::WFlags< Wt::ItemFlag >
482{
484
486
487 if( _editable )
488 retVal |= Wt::ItemFlag::Editable;
489
490 return retVal;
491
492} // endflags( bool _editable ) const-> Wt::WFlags< Wt::ItemFlag >
493
494auto
496createText( const std::string & _text ) const-> std::unique_ptr< Wt::WStandardItem >
497{
498 auto retVal = std::make_unique< Wt::WStandardItem >( _text );
499
500 retVal-> setStyleClass( "blank" );
501 retVal-> setFlags( flags( false ) );
502
503 return std::move( retVal );
504
505} // endcreateBlank() const-> std::unique_ptr< Wt::WStandardItem >
506
507auto
509createBlank() const-> std::unique_ptr< Wt::WStandardItem >
510{
511 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
512
513 retVal-> setStyleClass( "blank" );
514 retVal-> setFlags( flags( false ) );
515
516 return std::move( retVal );
517
518} // endcreateBlank() const-> std::unique_ptr< Wt::WStandardItem >
519
520auto
522createEmpty() const-> std::unique_ptr< Wt::WStandardItem >
523{
524 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
525
526 retVal-> setStyleClass( "empty" );
527 retVal-> setFlags( flags( false ) );
528
529 return std::move( retVal );
530
531} // endcreateEmpty() const-> std::unique_ptr< Wt::WStandardItem >
532
533auto
535createDate( const TxItem & _txItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
536{
537 auto retVal = std::make_unique< Wt::WStandardItem >();
538
539 retVal-> setStyleClass( "date" );
540 retVal-> setFlags( flags( _editable ) );
541
542 /*!
543 ** \note The post_date column (col-0) also carries with it the guid of the split
544 ** item itself, so that the originating split can be located from the table
545 ** view. The guid can be accessed by;
546 **
547 ** \code
548 ** Wt::WString splitRowGuid = Wt::asString( standardItem.data( Wt::ItemDataRole::User ) )
549 ** \endcode
550 **
551 ** \sa getSplitGuid
552 */
553// auto tip =
554// Wt::WString
555// (
556// "row: {1}\n"
557// "acg: {2}\n"
558// "spg: {3}\n"
559// )
560// .arg( m_model-> rowCount() )
561// .arg( thisSplit()-> account_guid() )
562// .arg( thisSplit()-> guid() )
563// ;
564
565 /*
566 ** if there is a split, set the date value
567 */
568 if( thisSplit() )
569 {
570 if( transactionItem() )
571 retVal-> setData( transactionItem()-> post_date_as_date(), Wt::ItemDataRole::Edit );
572
573 if( thisSplit() )
574 retVal-> setData( thisSplit()-> guid(), Wt::ItemDataRole::User );
575
576 }
577
578 /*
579 ** there is no split, so default to today's date
580 */
581 else
582 {
584 retVal-> setData( dateTime, Wt::ItemDataRole::Edit );
585 }
586
587// retVal-> setToolTip( tip );
588
589 return std::move( retVal );
590
591} // endcreateDate() const-> std::unique_ptr< Wt::WStandardItem > ;
592
593auto
595createNum( const TxItem & _txItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
596{
597 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
598 retVal-> setStyleClass( "txnum" );
599 retVal-> setFlags( flags( _editable ) );
600
601 if( thisSplit() )
602 {
603 if( _txItem )
604 {
605 retVal-> setText( _txItem-> num() );
606 }
607 }
608
609 return std::move( retVal );
610
611} // endcreateNum() const-> std::unique_ptr< Wt::WStandardItem >
612
613
614auto
616createNum( const SpItem & _spItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
617{
618 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
619 retVal-> setStyleClass( "spnum" );
620 retVal-> setFlags( flags( _editable ) );
621
622 if( thisSplit() )
623 {
624 if( _spItem )
625 {
626 retVal-> setText( _spItem-> action() );
627 }
628 }
629
630 return std::move( retVal );
631
632} // endcreateNum() const-> std::unique_ptr< Wt::WStandardItem >
633
634
635auto
637createDescription( const TxItem & _txItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
638{
639 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
640 retVal-> setStyleClass( "txdesc" );
641 retVal-> setFlags( flags( _editable ) );
642
643 if( thisSplit() )
644 {
645 if( _txItem )
646 {
647 /*
648 ** set the text
649 */
650 retVal-> setText( _txItem -> description() );
651
652#ifdef INCLUDE_TOOL_TIP_ON_DESCRIPTION
653 /*
654 ** this makes the tool-tip show whatever is on
655 ** the various splits (just two for now)
656 ** it's a bit of a hack
657 */
658 std::string toolTip;
659 if( thisSplit()-> memo() != "" )
660 toolTip = thisSplit()-> memo();
661
662 if( thatSplit() )
663 {
664 if( thatSplit()-> memo() != ""
665 && toolTip != "" )
666 toolTip += " :: ";
667
668 toolTip += thatSplit() -> memo();
669 }
670
671 /*
672 ** set the tooltip
673 */
674 retVal-> setToolTip( toolTip );
675#endif
676
677 }
678 }
679
680 return std::move( retVal );
681
682} // endcreateDescription() const-> std::unique_ptr< Wt::WStandardItem >
683
684
685auto
687createDescription( const SpItem & _spItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
688{
689 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
690 retVal-> setStyleClass( "spdesc" );
691 retVal-> setFlags( flags( _editable ) );
692
693 if( _spItem )
694 {
695 retVal-> setText( _spItem-> memo() );
696 }
697
698 return std::move( retVal );
699
700} // endcreateDescription() const-> std::unique_ptr< Wt::WStandardItem >
701
702#ifdef NEVER
703auto
705createAccount( const SpItem & _splitItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
706{
707 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
708 retVal-> setStyleClass( "acct" );
709 retVal-> setFlags( flags( _editable ) );
710
711 /*!
712 ** The 'account' text depends on the
713 ** target account defined in the split. There are three
714 ** possibilities here;
715 **
716 ** -# no splits... this shows up as an <b>'imbalance'</b> (this is an error condition)
717 ** -# 1 split... this just shows the split account on the same single line
718 ** -# >1 split... this is more than one target account, so just indicate 'split'
719 */
720 switch( otherSplits().size() )
721 {
722 /*!
723 ** \par Imbalance
724 ** This is actually a problem... We don't have another split, and
725 ** according to 'generally accepted accounting practices' we
726 ** should! So, just plop an 'imbalance' indicator in the view.
727 ** A style-class is also applied to the item to allow the rendering
728 ** in the view to highlight this problem.
729 */
730 case 0:
731 {
732 retVal-> setText( TR("gcw.AccountRegister.account.imbalanceUSD") ); // account
733 retVal-> setStyleClass( retVal-> styleClass() + " errval" );
734 retVal-> setToolTip( TR("gcw.AccountRegister.account.imbalanceUSD.toolTip") );
735 break;
736 }
737
738 /*!
739 ** \par Normal Split
740 ** This is a straight and simple 1:1 split transaction, so we can pull
741 ** the account name from the other side of the split and pop that in
742 ** to the model directly.
743 */
744 case 1:
745 {
746 auto txSplitItem = *otherSplits().begin();
747 auto splitAccountItem = GCW::Dbo::Accounts::byGuid( txSplitItem-> account_guid() );
748
749 // yes, we have one account item
750 if( splitAccountItem )
751 {
752 retVal-> setText( GCW::Dbo::Accounts::fullName( splitAccountItem-> guid() ) );
753
754 auto tip =
756 (
757 "spa:{1}\n"
758 "txi:{2}\n"
759 )
760 .arg( splitAccountItem-> guid() )
761 .arg( txSplitItem-> guid() )
762 ;
763 retVal-> setToolTip( tip );
764 }
765
766 // no, we don't have an account item
767 else
768 {
769 /*!
770 ** \par Another Imbalance
771 ** This is another problem... We have another split, but the account
772 ** we are split-to doesn't exist. This is a problem and should not
773 ** happen and represents an error in the database. This means the
774 ** account containing this guid nolonger exists. That should never
775 ** happen.
776 */
777 retVal-> setText( TR("gcw.AccountRegister.account.imbalanceUSD") );
778 retVal-> setStyleClass( retVal-> styleClass() + " errval" );
779
780 auto toolTip =
781 Wt::WString("target guid:{1}\n{2}")
782 .arg( txSplitItem-> account_guid() )
783 .arg( TR("gcw.AccountRegister.account.invalidTarget.toolTip") )
784 .toUTF8()
785 ;
786
787 retVal-> setToolTip( toolTip );
788
789 } // endelse no account item
790
791 break;
792
793 } // endcase 1:
794
795 /*!
796 ** \par Multi-Split
797 ** When we have more than one split then we cannot display
798 ** all of the split accounts on just one line, so just pop
799 ** a message that indicates that we're in a multisplit
800 ** transaction.
801 */
802 default:
803 {
804 retVal-> setText( TR("gcw.AccountRegister.account.multisplit") ); // account
805 }
806
807 } // endswitch( transMan.otherSplits().size() )
808
809
810 return std::move( retVal );
811
812} // endcreateAccount() const-> std::unique_ptr< Wt::WStandardItem >
813#endif
814
815auto
817createAccount( const SpItem & _splitItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
818{
819 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
820 retVal-> setStyleClass( "acct" );
821 retVal-> setFlags( flags( _editable ) );
822
823 if( _splitItem )
824 {
825 auto splitAccountItem = GCW::Dbo::Accounts::byGuid( _splitItem-> account_guid() );
826
827 // yes, we have one account item
828 if( splitAccountItem )
829 {
830 retVal-> setText( GCW::Dbo::Accounts::fullName( splitAccountItem-> guid() ) );
831
832 auto tip =
834 (
835 "account:{1}\n"
836 "split:{2}\n"
837 "txn:{3}"
838 )
839 .arg( splitAccountItem-> guid() )
840 .arg( _splitItem-> guid() )
841 .arg( _splitItem-> tx_guid() )
842 ;
843 retVal-> setToolTip( tip );
844 }
845
846 // no, we don't have an account item
847 else
848 {
849 /*!
850 ** \par Another Imbalance
851 ** This is another problem... We have another split, but the account
852 ** we are split-to doesn't exist. This is a problem and should not
853 ** happen and represents an error in the database. This means the
854 ** account containing this guid nolonger exists. That should never
855 ** happen.
856 */
857 retVal-> setText( TR("gcw.AccountRegister.account.imbalanceUSD") );
858 retVal-> setStyleClass( retVal-> styleClass() + " errval" );
859
860 auto toolTip =
861 Wt::WString("target guid:{1}\n{2}")
862 .arg( _splitItem-> account_guid() )
863 .arg( TR("gcw.AccountRegister.account.invalidTarget.toolTip") )
864 .toUTF8()
865 ;
866 retVal-> setToolTip( toolTip );
867
868 } // endelse no account item
869
870 } // endif( _splitItem )
871
872 return std::move( retVal );
873
874} // endcreateAccount() const-> std::unique_ptr< Wt::WStandardItem >
875
876auto
878createReconcile( const SpItem & _splitItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
879{
880 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
881 retVal-> setStyleClass( "rec" );
882 retVal-> setFlags( flags( _editable ) );
883
884 if( _splitItem )
885 {
886 retVal-> setText( _splitItem-> reconcile_state() );
887 }
888
889 return std::move( retVal );
890
891} // endcreateReconcile() const-> std::unique_ptr< Wt::WStandardItem >
892
893auto
895createDebit( const SpItem & _splitItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
896{
897 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
898 retVal-> setStyleClass( "dr" );
899 retVal-> setFlags( flags( _editable ) );
900
901 if( _splitItem )
902 {
903 /*
904 ** debits are always positive
905 */
906 if( _splitItem-> value() > 0 )
907 {
908 retVal -> setText( _splitItem-> valueAsString() );
909 }
910 }
911
912 return std::move( retVal );
913
914} // endcreateDebit() const-> std::unique_ptr< Wt::WStandardItem >
915
916auto
918createCredit( const SpItem & _splitItem, bool _editable ) const-> std::unique_ptr< Wt::WStandardItem >
919{
920 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
921 retVal-> setStyleClass( "cr" );
922 retVal-> setFlags( flags( _editable ) );
923
924 if( _splitItem )
925 {
926 /*
927 ** credit are always negative
928 */
929 if( _splitItem-> value() < 0 )
930 {
931 /*
932 ** set the value and invert(true) the sign
933 */
934 retVal -> setText( _splitItem-> valueAsString( true ) );
935 }
936 }
937
938 return std::move( retVal );
939
940} // endcreateCredit() const-> std::unique_ptr< Wt::WStandardItem >
941
942auto
944createBalance() const-> std::unique_ptr< Wt::WStandardItem >
945{
946 auto retVal = std::make_unique< Wt::WStandardItem >( "" );
947 retVal-> setStyleClass( "bal" );
948 retVal-> setFlags( flags( false ) );
949
950 if( thisSplit() )
951 {
952 retVal-> setText( toString( model()-> m_balance, GCW::Cfg::decimal_format() ) );
953 }
954
955 return std::move( retVal );
956
957} // endcreateBalance() const-> std::unique_ptr< Wt::WStandardItem >
958
959auto
961highlightNegativeBalance( RowItem & _row ) const-> void
962{
963 /*
964 ** if the balance is negative, highlight the row
965 */
966 if( model()-> m_balance < 0 )
967 {
968 if( prefrenceItem().accountRegisterHighlight( GCW::Dbo::Prefrences::AccountRegisterHighlight::NEGVAL_EXTRA ) )
969 {
970 for( int col = 0; col< _row.size(); col++ )
971 _row.at( col )-> setStyleClass( _row.at( col )-> styleClass() + " negval" );
972 }
973
974 if( prefrenceItem().accountRegisterHighlight( GCW::Dbo::Prefrences::AccountRegisterHighlight::NORMAL ) )
975 {
976 _row.at( _row.size()-1 )-> setStyleClass( _row.at( _row.size()-1 )-> styleClass() + " negval" );
977 }
978
979 } // endif( model()-> m_balance < 0 )
980
981
982} // endhighlightNegativeBalance() const-> void
983
984auto
986appendBasicLedger( bool _editable ) const-> void
987{
988 RowItem row ;
989
990 bool ed = true;
991 if( thisSplit() )
992 ed = thisSplit()-> reconcile_state() == GCW_RECONCILE_NO;
993
994 row.push_back( createDate ( transactionItem() , ed ) );
995 row.push_back( createNum ( transactionItem() , ed ) );
996 row.push_back( createDescription ( transactionItem() , ed ) );
997 row.push_back( createAccount ( thatSplit() , ed ) );
998 row.push_back( createReconcile ( thisSplit() , ed ) );
999 row.push_back( createDebit ( thisSplit() , ed ) );
1000 row.push_back( createCredit ( thisSplit() , ed ) );
1001 row.push_back( createBalance ( ) );
1002
1003 highlightNegativeBalance( row );
1004
1005 /*
1006 ** set alternating row colors (rowbl == row-basic-ledger)
1007 */
1008 for( int col=0; col< row.size(); col++ )
1009 row.at(col)-> setStyleClass( row.at(col)-> styleClass() + " rowbl" );
1010
1011 model()-> appendRow( std::move( row ) );
1012
1013} // endappendBasicLedger() const-> void
1014
1015auto
1017appendAutosplitLedger( bool _editable ) const-> void
1018{
1019} // endappendAutosplitLedger() const-> void
1020
1021auto
1023appendTransactionJournal( bool _editable ) const-> void
1024{
1025 /*
1026 ** set the first line
1027 */
1028 {
1029 RowItem row ;
1030
1031 row.push_back( createDate ( transactionItem(), _editable ) );
1032 row.push_back( createNum ( transactionItem(), _editable ) );
1033 row.push_back( createDescription ( transactionItem(), _editable ) );
1034 row.push_back( createEmpty ( ) ); // account is empty on this row
1035 row.push_back( createEmpty ( ) ); // reconcile is empty on this row
1036 row.push_back( createDebit ( thisSplit() , false ) ); // debit cannot be edited here
1037 row.push_back( createCredit ( thisSplit() , false ) ); // credit cannot be edited here
1038 row.push_back( createBalance ( ) );
1039
1040 highlightNegativeBalance( row );
1041
1042 /*
1043 ** set static row color (rowtj == row-transaction-journal)
1044 */
1045 for( int col=0; col< row.size(); col++ )
1046 row.at(col)-> setStyleClass( row.at(col)-> styleClass() + " rowtj" );
1047
1048 model()-> appendRow( std::move( row ) );
1049 }
1050
1051 /*
1052 ** set another line, one for each split
1053 */
1054 for( auto splitItem : splits() )
1055 {
1056 auto ed = splitItem-> reconcile_state() == GCW_RECONCILE_NO;
1057 RowItem row ;
1058 row.push_back( createEmpty ( ) );
1059 row.push_back( createNum ( splitItem, ed ) );
1060 row.push_back( createDescription ( splitItem, ed ) );
1061 row.push_back( createAccount ( splitItem, ed ) );
1062 row.push_back( createReconcile ( splitItem, ed ) );
1063 row.push_back( createDebit ( splitItem, ed ) );
1064 row.push_back( createCredit ( splitItem, ed ) );
1065 row.push_back( createEmpty ( ) );
1066
1067 for( int col=0; col< row.size(); col++ )
1068 row.at(col)-> setStyleClass( row.at(col)-> styleClass() + " rowtd" );
1069
1070 model()-> appendRow( std::move( row ) );
1071 }
1072
1073} // endappendTransactionJournal() const-> void
1074
1075auto
1077appendGeneralJournal( bool _editable ) const-> void
1078{
1079} // endappendGeneralJournal() const-> void
1080
1081
1082
1083auto
1085appendRow( bool _editable )-> void
1086{
1087 /*
1088 ** calculate the running balance
1089 */
1090 if( thisSplit() )
1091 model()-> m_balance += thisSplit()-> value();
1092
1093 /*
1094 ** build a row depending on the view mode
1095 */
1096 switch( model()-> viewMode() )
1097 {
1099 {
1100 appendBasicLedger( _editable );
1101 break;
1102 }
1103
1105 {
1106 appendAutosplitLedger( _editable );
1107 break;
1108 }
1109
1111 {
1112 appendTransactionJournal( _editable );
1113 break;
1114 }
1115
1117 {
1118 appendGeneralJournal( _editable );
1119 break;
1120 }
1121
1122 } // endswitch( model()-> viewMode() )
1123
1124 if( model()-> doubleLine() )
1125 {
1126 RowItem row ;
1127 row.push_back( createEmpty() );
1128 row.push_back( createEmpty() );
1129 row.push_back( createEmpty() );
1130 row.push_back( createEmpty() );
1131 row.push_back( createEmpty() );
1132 row.push_back( createEmpty() );
1133 row.push_back( createEmpty() );
1134 row.push_back( createEmpty() );
1135
1136 for( int col=0; col< row.size(); col++ )
1137 row.at(col)-> setStyleClass( row.at(col)-> styleClass() + " rowte" );
1138
1139 model()-> appendRow( std::move( row ) );
1140 }
1141
1142} // endappendRow()-> void
1143
1144
1145auto
1147appendEmptyRow( bool _editable )-> void
1148{
1149
1150 m_splitGuid = "";
1151 m_splits.clear();
1152
1153 appendRow( _editable );
1154
1155} // endappendRow()-> void
1156
1157auto
1159insertDoubleLine( int _row )-> void
1160{
1161// if( model()-> doubleLine() )
1162 {
1163 RowItem row ;
1164 row.push_back( createEmpty() );
1165 row.push_back( createEmpty() );
1166 row.push_back( createEmpty() );
1167 row.push_back( createEmpty() );
1168 row.push_back( createEmpty() );
1169 row.push_back( createEmpty() );
1170 row.push_back( createEmpty() );
1171 row.push_back( createEmpty() );
1172
1173 for( int col=0; col< row.size(); col++ )
1174 row.at(col)-> setStyleClass( row.at(col)-> styleClass() + " rowdl" );
1175
1176 model()-> insertRow( _row, std::move( row ) );
1177 }
1178
1179} // endinsertDoubleLine( int row )-> void
1180
1181
static std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Definition Core.cpp:26
Wt::Dbo::ptr< Item > Ptr
Definition BaseItem.h:39
auto createBalance() const -> std::unique_ptr< Wt::WStandardItem >
auto highlightNegativeBalance(RowItem &_row) const -> void
auto appendAutosplitLedger(bool _editable) const -> void
auto setTransferGuid(const std::string &_value) -> void
Set Transfer GUID.
auto deleteTransaction() -> bool
Delete Transaction.
auto insertDoubleLine(int _row) -> void
auto createAccount(const SpItem &_spItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
auto forAccountSplit(const std::string &_accountGuid) const -> GCW::Dbo::Splits::Item::Ptr
Load Split for Account.
auto setReconcile(const std::string &_value) -> void
auto getToAccount() const -> std::string
auto toSplit() const -> GCW::Dbo::Splits::Item::Ptr
auto getDateAsString() const -> Wt::WString
auto appendBasicLedger(bool _editable) const -> void
auto createDescription(const TxItem &_txItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
auto getDescription() const -> std::string
Set Description.
auto setSplitItem(GCW::Dbo::Splits::Item::Ptr _splitItem) -> void
auto thisSplit() const -> GCW::Dbo::Splits::Item::Ptr
auto getDate() const -> Wt::WDateTime
Set Date.
auto createBlank() const -> std::unique_ptr< Wt::WStandardItem >
auto setDescription(const std::string &_value) -> void
auto appendRow(bool _editable) -> void
auto createCredit(const SpItem &_spItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
auto getValue() const -> GCW_NUMERIC
auto getNum() const -> std::string
Set Num.
auto fromSplit() const -> GCW::Dbo::Splits::Item::Ptr
auto createReconcile(const SpItem &_spItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
GCW::Dbo::Splits::Item::Ptr SpItem
std::vector< std::unique_ptr< Wt::WStandardItem > > RowItem
auto otherGuid() const -> std::string
Other GUID.
auto setNum(const std::string &_value) -> void
auto setDate(const Wt::WDateTime &_value) -> void
auto loadSplit(const std::string &_splitGuid) -> void
Set Split.
auto split(const std::string &_splitGuid) const -> GCW::Dbo::Splits::Item::Ptr
auto setAction(const std::string &_value) -> void
Set Action.
auto setNotes(const std::string &_acctGuid, const std::string &_value) -> void
auto setReadOnly(bool _value) -> void
auto setValue(GCW_NUMERIC _value) -> void
auto appendGeneralJournal(bool _editable) const -> void
auto createDebit(const SpItem &_spItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
auto getValueAsString() const -> std::string
auto thatSplit() const -> GCW::Dbo::Splits::Item::Ptr
auto createDate(const TxItem &_txItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
auto otherSplits() const -> GCW::Dbo::Splits::Item::Vector
auto createEmpty() const -> std::unique_ptr< Wt::WStandardItem >
auto appendTransactionJournal(bool _editable) const -> void
auto createNum(const TxItem &_txItem, bool _editable) const -> std::unique_ptr< Wt::WStandardItem >
auto getFromAccount() const -> std::string
auto flags(bool _editable) const -> Wt::WFlags< Wt::ItemFlag >
auto createText(const std::string &_text) const -> std::unique_ptr< Wt::WStandardItem >
auto appendEmptyRow(bool _editable) -> void
auto loadTransaction(const std::string &_transactionGuid) -> void
Set Transaction.
auto newTransaction(const std::string &_accountGuid1, const std::string &_accountGuid2, const Wt::WDate &_date=Wt::WDate::currentDate(), GCW_NUMERIC _value=GCW_NUMERIC(0), const std::string &_description="") -> void
New Transaction.
Account Register Model.
Definition Model.h:30
static constexpr const int User
static constexpr const int Edit
static WDate currentDate()
std::string toUTF8() const
WString & arg(const std::wstring &value)
#define TR8(X)
Definition define.h:18
#define TR(X)
Definition define.h:17
#define GCW_RECONCILE_NO
Definition gcwglobal.h:29
#define GCW_DEFAULT_DATE
Definition gcwglobal.h:28
#define GCW_DATE_DEFAULT_TIME
Default Time.
Definition gcwglobal.h:27
#define GCW_DATE_FORMAT_DISPLAY
Definition gcwglobal.h:16
#define GCW_NUMERIC
Internal Numeric Type.
Definition gcwglobal.h:40
DECIMAL::decimal_format decimal_format()
Decimal Format Specifier.
Definition GnuCashew.cpp:21
auto newGuid() -> std::string
Generate new GUID string value.
Definition Core.cpp:245
auto load(const std::string &_guid) -> Item::Ptr
Load Account by GUID.
auto byGuid(const std::string &_guid) -> Item::Ptr
Load Account by GUID.
auto fullName(const std::string &_guid) -> std::string
Account Fullname via GUID.
@ NORMAL
normal handling - neg values are red
@ NEGVAL_EXTRA
extra handling - neg values are gold-background-full-line
auto byTransaction(const std::string &_txGuid) -> Item::Vector
Load Splits by Transaction.
Definition Splits.cpp:193
auto add(const std::string &_splitGuid) -> Item::Ptr
Add a single split.
Definition Splits.cpp:65
auto bySplitExcept(const std::string &_splitGuid) -> Item::Vector
Load Splits by Split.
Definition Splits.cpp:144
auto load(const std::string &_splitGuid) -> Item::Ptr
Load a single split.
Definition Splits.cpp:14
auto add(const std::string &_txGuid) -> Item::Ptr
Add Transaction with Guid.
auto load(const std::string &_txGuid) -> Item::Ptr
Load Transaction by Guid.
@ GENERAL_JOURNAL
multi-line ledger that shows all accounts and no balances
@ BASIC_LEDGER
basic one-line per transaction
@ AUTOSPLIT_LEDGER
one-line ledger that auto-opens to multi-line for each selected row
@ TRANSACTION_JOURNAL
multi-line ledger for every row
Definition App.h:18
App * app()
Definition App.cpp:75