Skip to content

Commit f576b79

Browse files
committed
feat: add total income calculation
1 parent c0dc37c commit f576b79

File tree

2 files changed

+73
-3
lines changed

2 files changed

+73
-3
lines changed

pkg/models/budget.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,28 @@ func (b Budget) Income(t time.Time) (decimal.Decimal, error) {
8181

8282
return income.Decimal, nil
8383
}
84+
85+
// TotalIncome calculates the total income over all time.
86+
func (b Budget) TotalIncome() (decimal.Decimal, error) {
87+
var income decimal.NullDecimal
88+
err := database.DB.
89+
Select("SUM(amount)").
90+
Joins("JOIN accounts source_account ON transactions.source_account_id = source_account.id AND source_account.deleted_at IS NULL").
91+
Joins("JOIN accounts destination_account ON transactions.destination_account_id = destination_account.id AND destination_account.deleted_at IS NULL").
92+
Where("source_account.external = 1").
93+
Where("destination_account.external = 0").
94+
Where("transactions.envelope_id IS NULL").
95+
Table("transactions").
96+
Find(&income).
97+
Error
98+
if err != nil {
99+
return decimal.Zero, err
100+
}
101+
102+
// If no transactions are found, the value is nil
103+
if !income.Valid {
104+
return decimal.NewFromFloat(0), nil
105+
}
106+
107+
return income.Decimal, nil
108+
}

pkg/models/budget_test.go

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,30 @@ func (suite *TestSuiteEnv) TestBudgetCalculations() {
9292
SourceAccountID: employerAccount.ID,
9393
DestinationAccountID: bankAccount.ID,
9494
Reconciled: true,
95-
Amount: decimal.NewFromFloat(2857.51),
95+
Amount: decimal.NewFromFloat(2800),
9696
},
9797
}
9898
err = database.DB.Save(&salaryTransaction).Error
9999
if err != nil {
100100
suite.Assert().Fail("Resource could not be saved", err)
101101
}
102102

103+
salaryTransactionApril := models.Transaction{
104+
TransactionCreate: models.TransactionCreate{
105+
Date: marchFifteenthTwentyTwentyTwo.AddDate(0, 1, 0),
106+
BudgetID: budget.ID,
107+
EnvelopeID: nil,
108+
SourceAccountID: employerAccount.ID,
109+
DestinationAccountID: bankAccount.ID,
110+
Reconciled: true,
111+
Amount: decimal.NewFromFloat(2800),
112+
},
113+
}
114+
err = database.DB.Save(&salaryTransactionApril).Error
115+
if err != nil {
116+
suite.Assert().Fail("Resource could not be saved", err)
117+
}
118+
103119
outgoingTransactionBank := models.Transaction{
104120
TransactionCreate: models.TransactionCreate{
105121
BudgetID: budget.ID,
@@ -130,11 +146,40 @@ func (suite *TestSuiteEnv) TestBudgetCalculations() {
130146

131147
budget = budget.WithCalculations()
132148

133-
shouldBalance := decimal.NewFromFloat(2746.89)
149+
shouldBalance := decimal.NewFromFloat(5489.38)
134150
assert.True(suite.T(), budget.Balance.Equal(shouldBalance), "Balance for budget is not correct. Should be %s, is %s", shouldBalance, budget.Balance)
135151

136-
shouldIncome := decimal.NewFromFloat(2857.51)
152+
shouldIncome := decimal.NewFromFloat(2800)
137153
income, err := budget.Income(marchFifteenthTwentyTwentyTwo)
138154
assert.Nil(suite.T(), err)
139155
assert.True(suite.T(), income.Equal(shouldIncome), "Income is %s, should be %s", income, shouldIncome)
156+
157+
shouldIncomeTotal := decimal.NewFromFloat(5600)
158+
income, err = budget.TotalIncome()
159+
assert.Nil(suite.T(), err)
160+
assert.True(suite.T(), income.Equal(shouldIncomeTotal), "Income is %s, should be %s", income, shouldIncomeTotal)
161+
}
162+
163+
func (suite *TestSuiteEnv) TestMonthIncomeNoTransactions() {
164+
budget := models.Budget{}
165+
err := database.DB.Save(&budget).Error
166+
if err != nil {
167+
suite.Assert().Fail("Resource could not be saved", err)
168+
}
169+
170+
income, err := budget.Income(time.Date(2022, 3, 15, 0, 0, 0, 0, time.UTC))
171+
assert.Nil(suite.T(), err)
172+
assert.True(suite.T(), income.IsZero(), "Income is %s, should be 0", income)
173+
}
174+
175+
func (suite *TestSuiteEnv) TestTotalIncomeNoTransactions() {
176+
budget := models.Budget{}
177+
err := database.DB.Save(&budget).Error
178+
if err != nil {
179+
suite.Assert().Fail("Resource could not be saved", err)
180+
}
181+
182+
income, err := budget.TotalIncome()
183+
assert.Nil(suite.T(), err)
184+
assert.True(suite.T(), income.IsZero(), "Income is %s, should be 0", income)
140185
}

0 commit comments

Comments
 (0)