wip: recurring transactions
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 56s

This commit is contained in:
2025-05-23 09:29:03 +02:00
parent 95be988862
commit 96b1ec2264
4 changed files with 110 additions and 77 deletions

View File

@@ -82,7 +82,6 @@ func (h TransactionRecurringImpl) handleUpdateTransactionRecurring() http.Handle
input := types.TransactionRecurringInput{
Id: r.PathValue("id"),
IntervalMonths: r.FormValue("interval-months"),
LastExecution: r.FormValue("last-execution"),
Active: r.FormValue("active"),
Party: r.FormValue("party"),
Description: r.FormValue("description"),

View File

@@ -127,7 +127,6 @@ func (s TransactionRecurringImpl) Update(user *types.User, input types.Transacti
UPDATE transaction_recurring
SET
interval_months = :interval_months,
last_execution = :last_execution,
active = :active,
party = :party,
description = :description,
@@ -340,7 +339,6 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
updatedAt *time.Time
updatedBy uuid.UUID
intervalMonths int64
active bool
err error
rowCount int
@@ -362,6 +360,8 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
updatedBy = userId
}
hasAccount := false
hasTreasureChest := false
if input.AccountId != "" {
temp, err := uuid.Parse(input.AccountId)
if err != nil {
@@ -379,6 +379,7 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
return nil, fmt.Errorf("account not found: %w", ErrBadRequest)
}
hasAccount = true
}
if input.TreasureChestId != "" {
@@ -400,6 +401,16 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
if treasureChest.ParentId == nil {
return nil, fmt.Errorf("treasure chest is a group: %w", ErrBadRequest)
}
hasTreasureChest = true
}
if !hasAccount && !hasTreasureChest {
log.Error("transactionRecurring validate: %v", err)
return nil, fmt.Errorf("either account or treasure chest is required: %w", ErrBadRequest)
}
if hasAccount && hasTreasureChest {
log.Error("transactionRecurring validate: %v", err)
return nil, fmt.Errorf("either account or treasure chest is required, not both: %w", ErrBadRequest)
}
valueFloat, err := strconv.ParseFloat(input.Value, 64)
@@ -430,10 +441,9 @@ func (s TransactionRecurringImpl) validateAndEnrichTransactionRecurring(
log.Error("transactionRecurring validate: %v", err)
return nil, fmt.Errorf("intervalMonths needs to be greater than 0: %w", ErrBadRequest)
}
active, err = strconv.ParseBool(input.Active)
if err != nil {
log.Error("transactionRecurring validate: %v", err)
return nil, fmt.Errorf("could not parse active: %w", ErrBadRequest)
active := false
if input.Active == "on" {
active = true
}
transactionRecurring := types.TransactionRecurring{

View File

@@ -5,15 +5,26 @@ import "spend-sparrow/template/svg"
import "spend-sparrow/types"
templ TransactionRecurringItems(transactionsRecurring []*types.TransactionRecurring) {
<div id="transaction-recurring-items" class="my-6">
<table id="transaction-recurring-items" class="gap-2 w-full my-6 border-collapse border-spacing-20">
<thead>
<tr>
<th class="text-left text-sm text-gray-500">Party</th>
<th class="text-left text-sm text-gray-500">Description</th>
<th class="text-right text-sm text-gray-500">Value (€)</th>
<th class="text-right text-sm text-gray-500">Actions</th>
</tr>
</thead>
<tbody>
for _, transaction := range transactionsRecurring {
@TransactionRecurringItem(transaction)
}
</div>
</tbody>
</table>
}
templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring) {
<div id={ "transaction-recurring" + transactionRecurring.Id.String() } class="">
<tr id={ "transaction-recurring" + transactionRecurring.Id.String() } class="mx-20">
<td>
<p class="text-sm text-gray-500">
if transactionRecurring.Party != "" {
{ transactionRecurring.Party }
@@ -21,6 +32,8 @@ templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring)
&nbsp;
}
</p>
</td>
<td>
<p class="text-sm text-gray-500">
if transactionRecurring.Description != "" {
{ transactionRecurring.Description }
@@ -28,11 +41,15 @@ templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring)
&nbsp;
}
</p>
</td>
<td>
if transactionRecurring.Value < 0 {
<p class="mr-8 min-w-22 text-right text-red-700">{ displayBalance(transactionRecurring.Value)+" €" }</p>
} else {
<p class="mr-8 w-22 text-right text-green-700">{ displayBalance(transactionRecurring.Value)+" €" }</p>
}
</td>
<td class="flex gap-2">
<button
hx-get={ "/transaction-recurring/" + transactionRecurring.Id.String() + "?edit=true" }
hx-target="closest #transaction"
@@ -56,7 +73,8 @@ templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring)
Delete
</span>
</button>
</div>
</td>
</tr>
}
templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring, accountId, treasureChestId string) {
@@ -68,13 +86,13 @@ templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring,
party := ""
description := ""
value := "0.00"
intervalMonth := "1"
active := false
intervalMonths := "1"
active := true
if transactionRecurring == nil {
id = "new"
cancelUrl = "/empty"
} else {
intervalMonth = fmt.Sprintf("%d", transactionRecurring.IntervalMonths)
intervalMonths = fmt.Sprintf("%d", transactionRecurring.IntervalMonths)
active = transactionRecurring.Active
party = transactionRecurring.Party
description = transactionRecurring.Description
@@ -97,16 +115,16 @@ templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring,
name="active"
id="active"
type="checkbox"
value={ active }
checked?={ active }
class="bg-white input"
/>
<label for="active" class="select-none text-sm text-gray-800">Active</label>
</div>
<label for="interval-month" class="text-sm text-gray-500">Interval Month</label>
<label for="interval-months" class="text-sm text-gray-500">Interval Months</label>
<input
name="interval-month"
name="interval-months"
type="number"
value={ intervalMonth }
value={ intervalMonths }
class="bg-white input"
/>
<label for="party" class="text-sm text-gray-500">Party</label>
@@ -131,8 +149,12 @@ templ EditTransactionRecurring(transactionRecurring *types.TransactionRecurring,
value={ value }
class="bg-white input"
/>
<!-- <label for="account-id" class="text-sm text-gray-500">Account</label> -->
<!-- <label for="treasure-chest-id" class="text-sm text-gray-500">Treasure Chest</label> -->
if accountId != "" {
<input type="text" name="account-id" class="hidden text-sm text-gray-500" value={ accountId }/>
}
if treasureChestId != "" {
<input type="text" name="treasure-chest-id" class="hidden text-sm text-gray-500" value={ treasureChestId }/>
}
</div>
<button type="submit" class="button button-neglect px-1 flex items-center gap-2">
@svg.Save()

View File

@@ -95,11 +95,12 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.Tre
</span>
</button>
</form>
if id != "new" {
<div class="m-10 border-b-gray-400 border-b-1"></div>
<div class="flex">
<h3 class="text-sm text-gray-500">Monthly Transactions</h3>
<button
hx-get="/transaction-recurring/new"
hx-get={ "/transaction-recurring/new?treasure-chest-id=" + id }
hx-target="#transaction-recurring-items"
hx-swap="afterbegin"
class="button button-primary ml-auto px-2 flex items-center gap-2"
@@ -109,6 +110,7 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.Tre
</button>
</div>
@transactionsRecurring
}
</div>
}