From 1b6f65e1232d5ab7832c0309a0efe4467e4002fe Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Tue, 14 Apr 2026 22:37:19 +0200 Subject: [PATCH] implemented removal of transactions Signed-off-by: Stephan Richter --- .../umbrella/accounting/AccountingModule.java | 10 ++++++- .../umbrella/accounting/SqliteDb.java | 12 +++++--- .../umbrella/core/model/Transaction.java | 2 +- frontend/src/routes/accounting/account.svelte | 29 +++++++++++++++++-- .../src/routes/accounting/transaction.svelte | 13 +++++++-- 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java index 2ae25f6a..c55feffb 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java @@ -297,7 +297,15 @@ public class AccountingModule extends BaseHandler implements AccountingService { var key = body(ex); var tags = accountDb.searchTagsContaining(key,accountId); if (tags.size()<10) tags.addAll(tagService().search(key,user)); - return sendContent(ex,tags); + return sendContent(ex,egalize(tags,key)); + } + + private List egalize(Set tags, String key) { + var result = new HashSet(); + var lower = key.toLowerCase(); + var len = key.length(); + for (var tag : tags) result.add(tag.toLowerCase().startsWith(lower) ? key + tag.substring(len) : tag); + return result.stream().sorted(String.CASE_INSENSITIVE_ORDER).toList(); } private boolean postToAccount(long accountId, Path path, UmbrellaUser user, HttpExchange ex) throws IOException { diff --git a/accounting/src/main/java/de/srsoftware/umbrella/accounting/SqliteDb.java b/accounting/src/main/java/de/srsoftware/umbrella/accounting/SqliteDb.java index 6b865ca5..e9161147 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/SqliteDb.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/SqliteDb.java @@ -223,7 +223,7 @@ public class SqliteDb extends BaseDb implements AccountDb { var timestamp = transaction.date().toEpochSecond(ZoneOffset.UTC); if (transaction.id() == 0) { try { - var rs = Query.insertInto(TABLE_TRANSACTIONS, Field.ACCOUNT, Field.TIMESTAMP, Field.SOURCE, Field.DESTINATION, Field.AMOUNT, Field.DESCRIPTION) + var rs = insertInto(TABLE_TRANSACTIONS, Field.ACCOUNT, Field.TIMESTAMP, Field.SOURCE, Field.DESTINATION, Field.AMOUNT, Field.DESCRIPTION) .values(transaction.accountId(), timestamp, transaction.source().value(), transaction.destination().value(), transaction.amount(), transaction.purpose()) .execute(db).getGeneratedKeys(); if (rs.next()) transaction = transaction.withId(rs.getLong(1)); @@ -233,9 +233,13 @@ public class SqliteDb extends BaseDb implements AccountDb { } } else if (transaction.isDirty()) { try { - Query.replaceInto(TABLE_TRANSACTIONS, Field.ID, Field.ACCOUNT, Field.TIMESTAMP, Field.SOURCE, Field.DESTINATION, Field.AMOUNT, Field.DESCRIPTION) - .values(transaction.id(), transaction.accountId(), timestamp, transaction.source().value(), transaction.destination().value(), transaction.amount(), transaction.purpose()) - .execute(db).close(); + if (transaction.amount() == 0) { + delete().from(TABLE_TRANSACTIONS).where(Field.ID, equal(transaction.id())).where(ACCOUNT, equal(transaction.accountId())).execute(db); + } else { + replaceInto(TABLE_TRANSACTIONS, Field.ID, Field.ACCOUNT, Field.TIMESTAMP, Field.SOURCE, Field.DESTINATION, Field.AMOUNT, Field.DESCRIPTION) + .values(transaction.id(), transaction.accountId(), timestamp, transaction.source().value(), transaction.destination().value(), transaction.amount(), transaction.purpose()) + .execute(db).close(); + } return transaction.clearDirtyState(); } catch (SQLException e) { throw failedToStoreObject(transaction); diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Transaction.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Transaction.java index 37095118..07472574 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Transaction.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Transaction.java @@ -131,7 +131,7 @@ public class Transaction implements Mappable { Field.DESTINATION, destination.toMap(), Field.AMOUNT, amount, Field.PURPOSE, purpose, - Field.TAGS, tags + Field.TAGS, tags.stream().sorted().toList() ); } diff --git a/frontend/src/routes/accounting/account.svelte b/frontend/src/routes/accounting/account.svelte index f79061ce..8a2f141d 100644 --- a/frontend/src/routes/accounting/account.svelte +++ b/frontend/src/routes/accounting/account.svelte @@ -9,9 +9,9 @@ let { id } = $props(); let account = $state(null); + let filter = $state([]); let transactions = $state([]); let users = {}; - let sums = {}; function calcSums(){ @@ -27,6 +27,18 @@ } } + function addToFilter(tag){ + filter.push(tag); + } + + function checker(taglist, filter){ + return filter.every(tag => taglist.includes(tag)); + } + + function dropTag(tag){ + filter = filter.filter(x => x != tag); + } + async function load(){ let url = api(`accounting/${id}`); let res = await get(url); @@ -51,6 +63,17 @@ .amount{ text-align: right } +{#if filter.length > 0} +
+ {t('filter by tags')} +
+ {#each filter as tag,i} + {tag}  + {/each} +
+
+ +{/if} {#if account}
{account.name} @@ -68,7 +91,9 @@ {#each transactions as transaction, i} - + {#if checker(transaction.tags,filter)} + + {/if} {/each} diff --git a/frontend/src/routes/accounting/transaction.svelte b/frontend/src/routes/accounting/transaction.svelte index 5968308d..29065314 100644 --- a/frontend/src/routes/accounting/transaction.svelte +++ b/frontend/src/routes/accounting/transaction.svelte @@ -4,7 +4,9 @@ import { api, drop, patch, post } from '../../urls.svelte'; import { error, yikes } from '../../warn.svelte'; + import { t } from '../../translations.svelte'; let { account, addToFilter = tag => {}, transaction, users } = $props(); + let hidden = $state(false); async function dropTag(tag){ var url = api(`accounting/transaction/${transaction.id}/tag`) @@ -47,6 +49,7 @@ if (res.ok) { yikes(); transaction.tags.push(tag.display); + transaction.tags.sort(); return true; } error(res); @@ -54,7 +57,9 @@ } async function setAmount(amount){ - return await update({amount}); + let result = await update({amount}); + hidden = (amount == 0); + return result; } async function setDate(date){ return await update({date}); @@ -85,6 +90,7 @@ } +{#if !hidden} @@ -92,10 +98,10 @@ {#each Object.entries(users) as [id,user]} {#if id == transaction.source.id} - - {account.currency} + - {account.currency} {/if} {#if id == transaction.destination.id} -  {account.currency} +  {account.currency} {/if} {/each} @@ -121,3 +127,4 @@ +{/if} \ No newline at end of file