@@ -10,12 +10,13 @@ import (
1010// Account represents an asset account, e.g. a bank account.
1111type Account struct {
1212 Model
13- Name string `json:"name,omitempty"`
14- BudgetID uint64 `json:"budgetId"`
15- Budget Budget `json:"-"`
16- OnBudget bool `json:"onBudget"` // Always false when external: true
17- External bool `json:"external"`
18- Balance decimal.Decimal `json:"balance" gorm:"-"`
13+ Name string `json:"name,omitempty"`
14+ BudgetID uint64 `json:"budgetId"`
15+ Budget Budget `json:"-"`
16+ OnBudget bool `json:"onBudget"` // Always false when external: true
17+ External bool `json:"external"`
18+ Balance decimal.Decimal `json:"balance" gorm:"-"`
19+ ReconciledBalance decimal.Decimal `json:"reconciledBalance" gorm:"-"`
1920}
2021
2122// BeforeSave sets OnBudget to false when External is true.
@@ -26,11 +27,15 @@ func (a *Account) BeforeSave(tx *gorm.DB) (err error) {
2627 return nil
2728}
2829
29- // WithBalance returns a pointer to the account with the balance calculated.
30- func (a Account ) WithBalance () (* Account , error ) {
30+ // WithCalculations returns a pointer to the account with the balance calculated.
31+ func (a Account ) WithCalculations () (* Account , error ) {
3132 var err error
3233 a .Balance , err = a .getBalance ()
34+ if err != nil {
35+ return nil , err
36+ }
3337
38+ a .ReconciledBalance , err = a .SumReconciledTransactions ()
3439 if err != nil {
3540 return nil , err
3641 }
@@ -50,23 +55,59 @@ func (a Account) Transactions() []Transaction {
5055 return transactions
5156}
5257
58+ // Transactions returns all transactions for this account.
59+ func (a Account ) SumReconciledTransactions () (decimal.Decimal , error ) {
60+ var sourceSum , destinationSum decimal.NullDecimal
61+
62+ err := DB .Table ("transactions" ).
63+ Where (& Transaction {
64+ Reconciled : true ,
65+ SourceAccountID : a .ID ,
66+ }).
67+ Select ("SUM(amount)" ).
68+ Row ().
69+ Scan (& sourceSum )
70+ if err != nil {
71+ return decimal .NewFromFloat (0.0 ), fmt .Errorf ("getting transactions for account with id %d (source) failed: %w" , a .ID , err )
72+ }
73+
74+ err = DB .Table ("transactions" ).
75+ Where (& Transaction {
76+ Reconciled : true ,
77+ DestinationAccountID : a .ID ,
78+ }).
79+ Select ("SUM(amount)" ).
80+ Row ().
81+ Scan (& destinationSum )
82+
83+ if err != nil {
84+ return decimal .NewFromFloat (0.0 ), fmt .Errorf ("getting transactions for account with id %d (destination) failed: %w" , a .ID , err )
85+ }
86+
87+ return destinationSum .Decimal .Sub (sourceSum .Decimal ), nil
88+ }
89+
5390// GetBalance returns the balance of the account, including all transactions.
5491//
5592// Note that this will produce wrong results with sqlite as of now, see
5693// https://github.com/go-gorm/gorm/issues/5153 for details.
5794func (a Account ) getBalance () (decimal.Decimal , error ) {
5895 var sourceSum , destinationSum decimal.NullDecimal
5996
60- err := DB .Table ("transactions" ).Where ("source_account_id = ?" , a .ID ).Select (
61- "SUM(amount)" ,
62- ).Row ().Scan (& sourceSum )
97+ err := DB .Table ("transactions" ).
98+ Where (& Transaction {SourceAccountID : a .ID }).
99+ Select ("SUM(amount)" ).
100+ Row ().
101+ Scan (& sourceSum )
63102 if err != nil {
64103 return decimal .NewFromFloat (0.0 ), fmt .Errorf ("getting transactions for account with id %d (source) failed: %w" , a .ID , err )
65104 }
66105
67- err = DB .Table ("transactions" ).Where ("destination_account_id = ?" , a .ID ).Select (
68- "SUM(amount)" ,
69- ).Row ().Scan (& destinationSum )
106+ err = DB .Table ("transactions" ).
107+ Where (& Transaction {DestinationAccountID : a .ID }).
108+ Select ("SUM(amount)" ).
109+ Row ().
110+ Scan (& destinationSum )
70111 if err != nil {
71112 return decimal .NewFromFloat (0.0 ), fmt .Errorf ("getting transactions for account with id %d (destination) failed: %w" , a .ID , err )
72113 }
0 commit comments