wip: recurring transactions
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 56s
Some checks failed
Build Docker Image / Build-Docker-Image (push) Failing after 56s
This commit is contained in:
@@ -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"),
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -5,58 +5,76 @@ import "spend-sparrow/template/svg"
|
||||
import "spend-sparrow/types"
|
||||
|
||||
templ TransactionRecurringItems(transactionsRecurring []*types.TransactionRecurring) {
|
||||
<div id="transaction-recurring-items" class="my-6">
|
||||
for _, transaction := range transactionsRecurring {
|
||||
@TransactionRecurringItem(transaction)
|
||||
}
|
||||
</div>
|
||||
<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)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
templ TransactionRecurringItem(transactionRecurring *types.TransactionRecurring) {
|
||||
<div id={ "transaction-recurring" + transactionRecurring.Id.String() } class="">
|
||||
<p class="text-sm text-gray-500">
|
||||
if transactionRecurring.Party != "" {
|
||||
{ transactionRecurring.Party }
|
||||
<tr id={ "transaction-recurring" + transactionRecurring.Id.String() } class="mx-20">
|
||||
<td>
|
||||
<p class="text-sm text-gray-500">
|
||||
if transactionRecurring.Party != "" {
|
||||
{ transactionRecurring.Party }
|
||||
} else {
|
||||
|
||||
}
|
||||
</p>
|
||||
</td>
|
||||
<td>
|
||||
<p class="text-sm text-gray-500">
|
||||
if transactionRecurring.Description != "" {
|
||||
{ transactionRecurring.Description }
|
||||
} else {
|
||||
|
||||
}
|
||||
</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>
|
||||
}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
if transactionRecurring.Description != "" {
|
||||
{ transactionRecurring.Description }
|
||||
} else {
|
||||
|
||||
}
|
||||
</p>
|
||||
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>
|
||||
}
|
||||
<button
|
||||
hx-get={ "/transaction-recurring/" + transactionRecurring.Id.String() + "?edit=true" }
|
||||
hx-target="closest #transaction"
|
||||
hx-swap="outerHTML"
|
||||
class="button button-neglect px-1 flex items-center gap-2"
|
||||
>
|
||||
@svg.Edit()
|
||||
<span>
|
||||
Edit
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
hx-delete={ "/transaction-recurring/" + transactionRecurring.Id.String() }
|
||||
hx-target="closest #transaction"
|
||||
hx-swap="outerHTML"
|
||||
hx-confirm="Are you sure you want to delete this transaction?"
|
||||
class="button button-neglect px-1 flex items-center gap-2"
|
||||
>
|
||||
@svg.Delete()
|
||||
<span>
|
||||
Delete
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<td class="flex gap-2">
|
||||
<button
|
||||
hx-get={ "/transaction-recurring/" + transactionRecurring.Id.String() + "?edit=true" }
|
||||
hx-target="closest #transaction"
|
||||
hx-swap="outerHTML"
|
||||
class="button button-neglect px-1 flex items-center gap-2"
|
||||
>
|
||||
@svg.Edit()
|
||||
<span>
|
||||
Edit
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
hx-delete={ "/transaction-recurring/" + transactionRecurring.Id.String() }
|
||||
hx-target="closest #transaction"
|
||||
hx-swap="outerHTML"
|
||||
hx-confirm="Are you sure you want to delete this transaction?"
|
||||
class="button button-neglect px-1 flex items-center gap-2"
|
||||
>
|
||||
@svg.Delete()
|
||||
<span>
|
||||
Delete
|
||||
</span>
|
||||
</button>
|
||||
</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()
|
||||
|
||||
@@ -95,20 +95,22 @@ templ EditTreasureChest(treasureChest *types.TreasureChest, parents []*types.Tre
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
<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-target="#transaction-recurring-items"
|
||||
hx-swap="afterbegin"
|
||||
class="button button-primary ml-auto px-2 flex items-center gap-2"
|
||||
>
|
||||
@svg.Plus()
|
||||
<p>New Monthly Transaction</p>
|
||||
</button>
|
||||
</div>
|
||||
@transactionsRecurring
|
||||
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?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"
|
||||
>
|
||||
@svg.Plus()
|
||||
<p>New Monthly Transaction</p>
|
||||
</button>
|
||||
</div>
|
||||
@transactionsRecurring
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user