feat(transaction-recurring): #100 add summary for recurring transactions
This commit was merged in pull request #131.
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
|||||||
"spend-sparrow/utils"
|
"spend-sparrow/utils"
|
||||||
|
|
||||||
"github.com/a-h/templ"
|
"github.com/a-h/templ"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TreasureChest interface {
|
type TreasureChest interface {
|
||||||
@@ -51,7 +52,15 @@ func (h TreasureChestImpl) handleTreasureChestPage() http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
comp := t.TreasureChest(treasureChests)
|
transactionsRecurring, err := h.transactionRecurring.GetAll(user)
|
||||||
|
if err != nil {
|
||||||
|
handleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
monthlySums := h.calculateMonthlySums(treasureChests, transactionsRecurring)
|
||||||
|
|
||||||
|
comp := t.TreasureChest(treasureChests, monthlySums)
|
||||||
h.r.RenderLayout(r, w, comp, user)
|
h.r.RenderLayout(r, w, comp, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,7 +103,8 @@ func (h TreasureChestImpl) handleTreasureChestItemComp() http.HandlerFunc {
|
|||||||
if r.URL.Query().Get("edit") == "true" {
|
if r.URL.Query().Get("edit") == "true" {
|
||||||
comp = t.EditTreasureChest(treasureChest, treasureChests, transactionsRec)
|
comp = t.EditTreasureChest(treasureChest, treasureChests, transactionsRec)
|
||||||
} else {
|
} else {
|
||||||
comp = t.TreasureChestItem(treasureChest)
|
monthlySums := h.calculateMonthlySums(treasureChests, transactionsRecurring)
|
||||||
|
comp = t.TreasureChestItem(treasureChest, monthlySums)
|
||||||
}
|
}
|
||||||
h.r.Render(r, w, comp)
|
h.r.Render(r, w, comp)
|
||||||
}
|
}
|
||||||
@@ -129,7 +139,16 @@ func (h TreasureChestImpl) handleUpdateTreasureChest() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
comp := t.TreasureChestItem(treasureChest)
|
transactionsRecurring, err := h.transactionRecurring.GetAllByTreasureChest(user, treasureChest.Id.String())
|
||||||
|
if err != nil {
|
||||||
|
handleError(w, r, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
treasureChests := make([]*types.TreasureChest, 1)
|
||||||
|
treasureChests[0] = treasureChest
|
||||||
|
monthlySums := h.calculateMonthlySums(treasureChests, transactionsRecurring)
|
||||||
|
comp := t.TreasureChestItem(treasureChest, monthlySums)
|
||||||
h.r.Render(r, w, comp)
|
h.r.Render(r, w, comp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,3 +170,19 @@ func (h TreasureChestImpl) handleDeleteTreasureChest() http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h TreasureChestImpl) calculateMonthlySums(
|
||||||
|
treasureChests []*types.TreasureChest,
|
||||||
|
transactionsRecurring []*types.TransactionRecurring,
|
||||||
|
) map[uuid.UUID]int64 {
|
||||||
|
monthlySums := make(map[uuid.UUID]int64)
|
||||||
|
for _, tc := range treasureChests {
|
||||||
|
monthlySums[tc.Id] = 0
|
||||||
|
}
|
||||||
|
for _, t := range transactionsRecurring {
|
||||||
|
if t.TreasureChestId != nil && t.Value > 0 && t.IntervalMonths > 0 {
|
||||||
|
monthlySums[*t.TreasureChestId] += t.Value / t.IntervalMonths
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return monthlySums
|
||||||
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ var (
|
|||||||
type TransactionRecurring interface {
|
type TransactionRecurring interface {
|
||||||
Add(user *types.User, transactionRecurring types.TransactionRecurringInput) (*types.TransactionRecurring, error)
|
Add(user *types.User, transactionRecurring types.TransactionRecurringInput) (*types.TransactionRecurring, error)
|
||||||
Update(user *types.User, transactionRecurring types.TransactionRecurringInput) (*types.TransactionRecurring, error)
|
Update(user *types.User, transactionRecurring types.TransactionRecurringInput) (*types.TransactionRecurring, error)
|
||||||
|
GetAll(user *types.User) ([]*types.TransactionRecurring, error)
|
||||||
GetAllByAccount(user *types.User, accountId string) ([]*types.TransactionRecurring, error)
|
GetAllByAccount(user *types.User, accountId string) ([]*types.TransactionRecurring, error)
|
||||||
GetAllByTreasureChest(user *types.User, treasureChestId string) ([]*types.TransactionRecurring, error)
|
GetAllByTreasureChest(user *types.User, treasureChestId string) ([]*types.TransactionRecurring, error)
|
||||||
Delete(user *types.User, id string) error
|
Delete(user *types.User, id string) error
|
||||||
@@ -158,6 +159,27 @@ func (s TransactionRecurringImpl) Update(
|
|||||||
return transactionRecurring, nil
|
return transactionRecurring, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s TransactionRecurringImpl) GetAll(user *types.User) ([]*types.TransactionRecurring, error) {
|
||||||
|
transactionRecurringMetric.WithLabelValues("get_all_by_account").Inc()
|
||||||
|
if user == nil {
|
||||||
|
return nil, ErrUnauthorized
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionRecurrings := make([]*types.TransactionRecurring, 0)
|
||||||
|
err := s.db.Select(&transactionRecurrings, `
|
||||||
|
SELECT *
|
||||||
|
FROM transaction_recurring
|
||||||
|
WHERE user_id = ?
|
||||||
|
ORDER BY created_at DESC`,
|
||||||
|
user.Id)
|
||||||
|
err = db.TransformAndLogDbError("transactionRecurring GetAll", nil, err)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionRecurrings, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s TransactionRecurringImpl) GetAllByAccount(user *types.User, accountId string) ([]*types.TransactionRecurring, error) {
|
func (s TransactionRecurringImpl) GetAllByAccount(user *types.User, accountId string) ([]*types.TransactionRecurring, error) {
|
||||||
transactionRecurringMetric.WithLabelValues("get_all_by_account").Inc()
|
transactionRecurringMetric.WithLabelValues("get_all_by_account").Inc()
|
||||||
if user == nil {
|
if user == nil {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import "spend-sparrow/template/svg"
|
|||||||
import "spend-sparrow/types"
|
import "spend-sparrow/types"
|
||||||
import "github.com/google/uuid"
|
import "github.com/google/uuid"
|
||||||
|
|
||||||
templ TreasureChest(treasureChests []*types.TreasureChest) {
|
templ TreasureChest(treasureChests []*types.TreasureChest, monthlySums map[uuid.UUID]int64) {
|
||||||
<div class="max-w-6xl mt-10 mx-auto">
|
<div class="max-w-6xl mt-10 mx-auto">
|
||||||
<button
|
<button
|
||||||
hx-get="/treasurechest/new"
|
hx-get="/treasurechest/new"
|
||||||
@@ -18,7 +18,7 @@ templ TreasureChest(treasureChests []*types.TreasureChest) {
|
|||||||
</button>
|
</button>
|
||||||
<div id="treasurechest-items" class="my-6 flex flex-col">
|
<div id="treasurechest-items" class="my-6 flex flex-col">
|
||||||
for _, treasureChest := range treasureChests {
|
for _, treasureChest := range treasureChests {
|
||||||
@TreasureChestItem(treasureChest)
|
@TreasureChestItem(treasureChest, monthlySums)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,7 +114,7 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.Tre
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
templ TreasureChestItem(treasureChest *types.TreasureChest) {
|
templ TreasureChestItem(treasureChest *types.TreasureChest, monthlySums map[uuid.UUID]int64) {
|
||||||
{{
|
{{
|
||||||
var indentation string
|
var indentation string
|
||||||
viewTransactions := ""
|
viewTransactions := ""
|
||||||
@@ -128,11 +128,16 @@ templ TreasureChestItem(treasureChest *types.TreasureChest) {
|
|||||||
<div id={ "treasurechest-" + treasureChest.Id.String() } class={ "border-1 border-gray-300 p-4 bg-gray-50 rounded-lg" + indentation }>
|
<div id={ "treasurechest-" + treasureChest.Id.String() } class={ "border-1 border-gray-300 p-4 bg-gray-50 rounded-lg" + indentation }>
|
||||||
<div class="text-xl flex justify-end items-center gap-4">
|
<div class="text-xl flex justify-end items-center gap-4">
|
||||||
<p class="mr-auto">{ treasureChest.Name }</p>
|
<p class="mr-auto">{ treasureChest.Name }</p>
|
||||||
|
<p class="mr-20 text-gray-600">
|
||||||
|
if treasureChest.ParentId != nil {
|
||||||
|
+ { displayBalance(monthlySums[treasureChest.Id]) } <span class="text-gray-500 text-sm"> per month</span>
|
||||||
|
}
|
||||||
|
</p>
|
||||||
if treasureChest.ParentId != nil {
|
if treasureChest.ParentId != nil {
|
||||||
if treasureChest.CurrentBalance < 0 {
|
if treasureChest.CurrentBalance < 0 {
|
||||||
<p class="mr-20 text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
<p class="mr-20 min-w-20 text-right text-red-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
||||||
} else {
|
} else {
|
||||||
<p class="mr-20 text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
<p class="mr-20 min-w-20 text-right text-green-700">{ displayBalance(treasureChest.CurrentBalance) }</p>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<a
|
<a
|
||||||
|
|||||||
Reference in New Issue
Block a user