Skip to content

Commit ea3ed1c

Browse files
authored
feat: add budget sum calculation (#290)
1 parent d793a2c commit ea3ed1c

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

pkg/controllers/budget.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ func getBudgetObject(c *gin.Context, id uuid.UUID) (Budget, error) {
351351
}
352352

353353
return Budget{
354-
resource,
354+
resource.WithCalculations(),
355355
getBudgetLinks(c, resource.ID),
356356
}, nil
357357
}

pkg/models/budget.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package models
22

33
import (
4+
"fmt"
45
"time"
56

7+
"github.com/envelope-zero/backend/internal/database"
68
"github.com/google/uuid"
79
"github.com/shopspring/decimal"
810
)
@@ -29,3 +31,23 @@ type BudgetMonth struct {
2931
Month time.Time `json:"month" example:"2006-05-01T00:00:00.000000Z"` // This is always set to 00:00 UTC on the first of the month.
3032
Envelopes []EnvelopeMonth `json:"envelopes"`
3133
}
34+
35+
// WithCalculations computes all the calculated values.
36+
func (b Budget) WithCalculations() Budget {
37+
// Get all OnBudget accounts for the budget
38+
var accounts []Account
39+
_ = database.DB.Where(&Account{
40+
AccountCreate: AccountCreate{
41+
BudgetID: b.ID,
42+
OnBudget: true,
43+
},
44+
}).Find(&accounts)
45+
46+
// Add all their balances to the budget's balance
47+
for _, account := range accounts {
48+
fmt.Println(account.WithCalculations().Balance)
49+
b.Balance = b.Balance.Add(account.WithCalculations().Balance)
50+
}
51+
52+
return b
53+
}

pkg/models/budget_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package models_test
2+
3+
import (
4+
"github.com/envelope-zero/backend/internal/database"
5+
"github.com/envelope-zero/backend/pkg/models"
6+
"github.com/shopspring/decimal"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func (suite *TestSuiteEnv) TestBudgetCalculations() {
11+
budget := models.Budget{}
12+
err := database.DB.Save(&budget).Error
13+
if err != nil {
14+
suite.Assert().Fail("Resource could not be saved", err)
15+
}
16+
17+
bankAccount := models.Account{
18+
AccountCreate: models.AccountCreate{
19+
BudgetID: budget.ID,
20+
OnBudget: true,
21+
External: false,
22+
},
23+
}
24+
err = database.DB.Save(&bankAccount).Error
25+
if err != nil {
26+
suite.Assert().Fail("Resource could not be saved", err)
27+
}
28+
29+
cashAccount := models.Account{
30+
AccountCreate: models.AccountCreate{
31+
BudgetID: budget.ID,
32+
OnBudget: true,
33+
External: false,
34+
},
35+
}
36+
err = database.DB.Save(&cashAccount).Error
37+
if err != nil {
38+
suite.Assert().Fail("Resource could not be saved", err)
39+
}
40+
41+
employerAccount := models.Account{
42+
AccountCreate: models.AccountCreate{
43+
BudgetID: budget.ID,
44+
External: true,
45+
},
46+
}
47+
err = database.DB.Save(&employerAccount).Error
48+
if err != nil {
49+
suite.Assert().Fail("Resource could not be saved", err)
50+
}
51+
52+
groceryAccount := models.Account{
53+
AccountCreate: models.AccountCreate{
54+
BudgetID: budget.ID,
55+
External: true,
56+
},
57+
}
58+
err = database.DB.Save(&groceryAccount).Error
59+
if err != nil {
60+
suite.Assert().Fail("Resource could not be saved", err)
61+
}
62+
63+
category := models.Category{
64+
CategoryCreate: models.CategoryCreate{
65+
BudgetID: budget.ID,
66+
},
67+
}
68+
err = database.DB.Save(&category).Error
69+
if err != nil {
70+
suite.Assert().Fail("Resource could not be saved", err)
71+
}
72+
73+
envelope := models.Envelope{
74+
EnvelopeCreate: models.EnvelopeCreate{
75+
CategoryID: category.ID,
76+
},
77+
}
78+
err = database.DB.Save(&envelope).Error
79+
if err != nil {
80+
suite.Assert().Fail("Resource could not be saved", err)
81+
}
82+
83+
salaryTransaction := models.Transaction{
84+
TransactionCreate: models.TransactionCreate{
85+
BudgetID: budget.ID,
86+
EnvelopeID: &envelope.ID,
87+
SourceAccountID: employerAccount.ID,
88+
DestinationAccountID: bankAccount.ID,
89+
Reconciled: true,
90+
Amount: decimal.NewFromFloat(2857.51),
91+
},
92+
}
93+
err = database.DB.Save(&salaryTransaction).Error
94+
if err != nil {
95+
suite.Assert().Fail("Resource could not be saved", err)
96+
}
97+
98+
outgoingTransactionBank := models.Transaction{
99+
TransactionCreate: models.TransactionCreate{
100+
BudgetID: budget.ID,
101+
EnvelopeID: &envelope.ID,
102+
SourceAccountID: bankAccount.ID,
103+
DestinationAccountID: groceryAccount.ID,
104+
Amount: decimal.NewFromFloat(87.45),
105+
},
106+
}
107+
err = database.DB.Save(&outgoingTransactionBank).Error
108+
if err != nil {
109+
suite.Assert().Fail("Resource could not be saved", err)
110+
}
111+
112+
outgoingTransactionCash := models.Transaction{
113+
TransactionCreate: models.TransactionCreate{
114+
BudgetID: budget.ID,
115+
EnvelopeID: &envelope.ID,
116+
SourceAccountID: cashAccount.ID,
117+
DestinationAccountID: groceryAccount.ID,
118+
Amount: decimal.NewFromFloat(23.17),
119+
},
120+
}
121+
err = database.DB.Save(&outgoingTransactionCash).Error
122+
if err != nil {
123+
suite.Assert().Fail("Resource could not be saved", err)
124+
}
125+
126+
budget = budget.WithCalculations()
127+
128+
shouldBalance := decimal.NewFromFloat(2746.89)
129+
assert.True(suite.T(), budget.Balance.Equal(shouldBalance), "Balance for budget is not correct. Should be %s, is %s", shouldBalance, budget.Balance)
130+
}

0 commit comments

Comments
 (0)