From b5b361514d219c1049799e9a9b00bb05b00077d5 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Sat, 30 May 2026 22:19:29 +0200 Subject: [PATCH] re-implemented new transaction form Signed-off-by: Stephan Richter --- .../umbrella/accounting/AccountDb.java | 2 +- .../umbrella/accounting/AccountingModule.java | 9 +- .../umbrella/accounting/SqliteDb.java | 32 ++- frontend/src/routes/accounting/account.svelte | 4 +- .../routes/accounting/add_entry_new.svelte | 205 ++++++++++++++++++ 5 files changed, 238 insertions(+), 14 deletions(-) create mode 100644 frontend/src/routes/accounting/add_entry_new.svelte diff --git a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountDb.java b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountDb.java index b025c70c..9c4b8850 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountDb.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountDb.java @@ -16,7 +16,7 @@ public interface AccountDb { Collection getMembers(long accountId); - Optional lastTransaction(long accountId, String source, String dest, double amount); + Optional lastTransaction(long accountId, String source, String destination, Double amount); Collection listAccounts(long userId); 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 bc2e7a8e..f2421dc2 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java @@ -311,12 +311,11 @@ public class AccountingModule extends BaseHandler implements AccountingService { var source = src.get(src.has(Field.ID) ? Field.ID : Field.DISPLAY).toString(); if (!json.has(Field.DESTINATION)) throw missingField(Field.DESTINATION); if (!(json.get(Field.DESTINATION) instanceof JSONObject dst)) throw invalidField(Field.SOURCE,JSON); - var dest = dst.get(dst.has(Field.ID) ? Field.ID : Field.DISPLAY).toString(); - if (!json.has(Field.AMOUNT)) throw missingField(Field.AMOUNT); - if (!(json.get(Field.AMOUNT) instanceof Number amt)) throw invalidField(Field.AMOUNT,Text.NUMBER); - var amount = amt.doubleValue(); + String destination = dst.has(Field.ID) ? dst.get(Field.ID).toString() : dst.has(Field.DISPLAY) ? dst.get(Field.DISPLAY).toString() : null; + Double amount = null; + if (json.has(Field.AMOUNT) && json.get(Field.AMOUNT) instanceof Number amt) amount = amt.doubleValue(); - var transaction = accountDb.lastTransaction(accountId, source, dest, amount); + var transaction = accountDb.lastTransaction(accountId, source, destination, amount); return transaction.isPresent() ? sendContent(ex,transaction.get()) : notFound(ex); } 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 844de420..8fe43af4 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/SqliteDb.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/SqliteDb.java @@ -170,22 +170,42 @@ public class SqliteDb extends BaseDb implements AccountDb { } @Override - public Optional lastTransaction(long accountId, String source, String dest, double amount) { + public Optional lastTransaction(long accountId, String source, String destination, Double amount) { try { - var rs = select(ALL).from(TABLE_TRANSACTIONS) - .where(ACCOUNT,equal(accountId)).where(SOURCE,equal(source)).where(DESTINATION,equal(dest)).where(AMOUNT,equal(amount)) - .sort(ID+" DESC") - .limit(1) - .exec(db); + var query = select(ALL).from(TABLE_TRANSACTIONS).where(ACCOUNT,equal(accountId)); + if (source != null) query = query.where(SOURCE,equal(source)); + if (destination != null) query = query.where(DESTINATION,equal(destination)); + if (amount != null) query = query.where(AMOUNT,equal(amount)); + var rs = query.sort(ID+" DESC").limit(1).exec(db); Transaction ta = null; if (rs.next()) ta = Transaction.of(rs); rs.close(); + + if (ta == null && amount != null) { // try to search by amount, ignore source and dest + rs = select(ALL).from(TABLE_TRANSACTIONS).where(ACCOUNT, equal(accountId)).where(AMOUNT, equal(amount)) + .sort(ID + " DESC").limit(1).exec(db); + if (rs.next()) ta = Transaction.of(rs); + rs.close(); + } + + if (ta == null && source != null && destination != null) { // try to search by amount, ignore source and dest + rs = select(ALL).from(TABLE_TRANSACTIONS) + .where(SOURCE,equal(source)) + .where(DESTINATION,equal(destination)) + .where(ACCOUNT, equal(accountId)) + .sort(ID + " DESC").limit(1).exec(db); + if (rs.next()) ta = Transaction.of(rs); + rs.close(); + } + + if (ta != null){ var tags = ta.tags(); rs = select(TAG).from(TABLE_TAGS_TRANSACTIONS).leftJoin(TAG_ID,TABLE_TAGS,ID).where(TRANSACTION_ID,equal(ta.id())).exec(db); while (rs.next()) tags.add(rs.getString(1)); rs.close(); } + return nullable(ta); } catch (SQLException e) { throw failedToSearchDb(t(Text.ACCOUNTING)); diff --git a/frontend/src/routes/accounting/account.svelte b/frontend/src/routes/accounting/account.svelte index 2384e133..ca0529d8 100644 --- a/frontend/src/routes/accounting/account.svelte +++ b/frontend/src/routes/accounting/account.svelte @@ -4,7 +4,7 @@ import { error, yikes } from '../../warn.svelte'; import { t } from '../../translations.svelte'; - import EntryForm from './add_entry.svelte'; + import EntryForm from './add_entry_new.svelte'; import Transaction from './transaction.svelte'; let { id } = $props(); @@ -173,5 +173,5 @@ - + {/if} \ No newline at end of file diff --git a/frontend/src/routes/accounting/add_entry_new.svelte b/frontend/src/routes/accounting/add_entry_new.svelte new file mode 100644 index 00000000..90627146 --- /dev/null +++ b/frontend/src/routes/accounting/add_entry_new.svelte @@ -0,0 +1,205 @@ + + + + +
+ {#if new_account} + {t('create_new_object',{object:t('account')})} + + {t('account name')} + + + + {t('currency')} + + + +
+ {t('first transaction')} + {:else} + {t('add_object',{object:t('transaction')})} + + {/if} + + {t('date')} + + + + + {t('amount')} + + focusOnEnter(e,'source-input')} /> {entry.account.currency} + + + {t('source')} + + + {t('destination')} + + + + {t('purpose')} + + + {t('tags')} + + + + + + +