@@ -29,11 +29,19 @@ type AccountCreate struct {
2929 Hidden bool `json:"hidden" example:"true" default:"false"`
3030}
3131
32- func (a Account ) WithCalculations (db * gorm.DB ) Account {
33- a .Balance = a .getBalance (db )
34- a .ReconciledBalance = a .SumReconciledTransactions (db )
32+ func (a Account ) WithCalculations (db * gorm.DB ) (Account , error ) {
33+ balance , _ , err := a .GetBalanceMonth (db , types .NewMonth (1 , 1 ))
34+ if err != nil {
35+ return Account {}, err
36+ }
37+ a .Balance = balance
38+
39+ a .ReconciledBalance , err = a .SumReconciled (db )
40+ if err != nil {
41+ return Account {}, err
42+ }
3543
36- return a
44+ return a , nil
3745}
3846
3947// BeforeSave sets OnBudget to false when External is true.
@@ -54,21 +62,33 @@ func (a Account) Transactions(db *gorm.DB) []Transaction {
5462}
5563
5664// Transactions returns all transactions for this account.
57- func (a Account ) SumReconciledTransactions (db * gorm.DB ) decimal.Decimal {
58- return a .InitialBalance .Add (TransactionsSum (db ,
59- Transaction {
60- TransactionCreate : TransactionCreate {
61- Reconciled : true ,
62- DestinationAccountID : a .ID ,
63- },
64- },
65- Transaction {
66- TransactionCreate : TransactionCreate {
67- Reconciled : true ,
68- SourceAccountID : a .ID ,
69- },
70- },
71- ))
65+ func (a Account ) SumReconciled (db * gorm.DB ) (balance decimal.Decimal , err error ) {
66+ var transactions []Transaction
67+
68+ err = db .
69+ Preload ("DestinationAccount" ).
70+ Preload ("SourceAccount" ).
71+ Where (
72+ db .Where (Transaction {TransactionCreate : TransactionCreate {DestinationAccountID : a .ID , Reconciled : true }}).
73+ Or (db .Where (Transaction {TransactionCreate : TransactionCreate {SourceAccountID : a .ID , Reconciled : true }}))).
74+ Find (& transactions ).Error
75+
76+ if err != nil {
77+ return decimal .Zero , err
78+ }
79+
80+ balance = a .InitialBalance
81+
82+ // Add incoming transactions, subtract outgoing transactions
83+ for _ , t := range transactions {
84+ if t .DestinationAccountID == a .ID {
85+ balance = balance .Add (t .Amount )
86+ } else {
87+ balance = balance .Sub (t .Amount )
88+ }
89+ }
90+
91+ return
7292}
7393
7494// GetBalanceMonth calculates the balance and available sums for a specific month.
@@ -78,20 +98,24 @@ func (a Account) SumReconciledTransactions(db *gorm.DB) decimal.Decimal {
7898func (a Account ) GetBalanceMonth (db * gorm.DB , month types.Month ) (balance , available decimal.Decimal , err error ) {
7999 var transactions []Transaction
80100
81- err = db .
101+ query : = db .
82102 Preload ("DestinationAccount" ).
83103 Preload ("SourceAccount" ).
84- Where ("transactions.date < date(?)" , month .AddDate (0 , 1 )).
85104 Where (
86105 db .Where (Transaction {TransactionCreate : TransactionCreate {DestinationAccountID : a .ID }}).
87- Or (db .Where (Transaction {TransactionCreate : TransactionCreate {SourceAccountID : a .ID }}))).
88- Find (& transactions ).
89- Error
106+ Or (db .Where (Transaction {TransactionCreate : TransactionCreate {SourceAccountID : a .ID }})))
107+
108+ // Limit to the month if it is specified
109+ if ! month .IsZero () {
110+ query = query .Where ("transactions.date < date(?)" , month .AddDate (0 , 1 ))
111+ }
112+
113+ err = query .Find (& transactions ).Error
90114 if err != nil {
91115 return decimal .Zero , decimal .Zero , err
92116 }
93117
94- if a .InitialBalanceDate != nil && month .AddDate (0 , 1 ).AfterTime (* a .InitialBalanceDate ) {
118+ if month . IsZero () || ( a .InitialBalanceDate != nil && month .AddDate (0 , 1 ).AfterTime (* a .InitialBalanceDate ) ) {
95119 balance = a .InitialBalance
96120 available = a .InitialBalance
97121 }
@@ -116,46 +140,6 @@ func (a Account) GetBalanceMonth(db *gorm.DB, month types.Month) (balance, avail
116140 return
117141}
118142
119- // getBalance returns the balance of the account calculated over all transactions.
120- func (a Account ) getBalance (db * gorm.DB ) decimal.Decimal {
121- return a .InitialBalance .Add (TransactionsSum (db ,
122- Transaction {
123- TransactionCreate : TransactionCreate {
124- DestinationAccountID : a .ID ,
125- },
126- },
127- Transaction {
128- TransactionCreate : TransactionCreate {
129- SourceAccountID : a .ID ,
130- },
131- },
132- ))
133- }
134-
135- // TransactionSums returns the sum of all transactions matching two Transaction structs
136- //
137- // The incoming Transactions fields is used to add the amount of all matching transactions to the overall sum
138- // The outgoing Transactions fields is used to subtract the amount of all matching transactions from the overall sum.
139- func TransactionsSum (db * gorm.DB , incoming , outgoing Transaction ) decimal.Decimal {
140- var outgoingSum , incomingSum decimal.NullDecimal
141-
142- _ = db .Table ("transactions" ).
143- Where (& outgoing ).
144- Where ("deleted_at is NULL" ).
145- Select ("SUM(amount)" ).
146- Row ().
147- Scan (& outgoingSum )
148-
149- _ = db .Table ("transactions" ).
150- Where (& incoming ).
151- Where ("deleted_at is NULL" ).
152- Select ("SUM(amount)" ).
153- Row ().
154- Scan (& incomingSum )
155-
156- return incomingSum .Decimal .Sub (outgoingSum .Decimal )
157- }
158-
159143// RecentEnvelopes returns the most common envelopes used in the last 10
160144// transactions where the account is the destination account.
161145//
0 commit comments