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 8dab5dce..f181a3f8 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountDb.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountDb.java @@ -4,9 +4,15 @@ import de.srsoftware.umbrella.core.model.Account; import de.srsoftware.umbrella.core.model.Transaction; import java.util.Collection; +import java.util.List; public interface AccountDb { Collection listAccounts(long userId); + + Account loadAccount(long accountId); + + List loadTransactions(Account account); + Account save(Account account); Transaction save(Transaction transaction); 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 4966563e..a57edfd3 100644 --- a/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java +++ b/accounting/src/main/java/de/srsoftware/umbrella/accounting/AccountingModule.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneOffset; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import static de.srsoftware.tools.Optionals.nullIfEmpty; @@ -53,10 +55,13 @@ public class AccountingModule extends BaseHandler implements AccountingService { var head = path.pop(); return switch (head) { case null -> getAccounts(user.get(),ex); - default -> super.doGet(path,ex); + default -> { + try { + yield getAccount(user.get(),Long.parseLong(head),ex); + } catch (NumberFormatException ignored) {} + yield super.doGet(path,ex); + } }; - } catch (NumberFormatException e){ - return sendContent(ex,HTTP_BAD_REQUEST,"Invalid project id"); } catch (UmbrellaException e){ return send(ex,e); } @@ -74,13 +79,41 @@ public class AccountingModule extends BaseHandler implements AccountingService { case null -> postEntry(user.get(),ex); default -> super.doPost(path,ex); }; - } catch (NumberFormatException e){ - return sendContent(ex,HTTP_BAD_REQUEST,"Invalid project id"); } catch (UmbrellaException e){ return send(ex,e); } } + private boolean getAccount(UmbrellaUser user, long accountId, HttpExchange ex) throws IOException { + var account = accountDb.loadAccount(accountId); + var transactions = accountDb.loadTransactions(account); + var userMap = new HashMap(); + var foundRequestingUser = false; + for (var i=0; i listAccounts(long userId) { try { var accountIds = new HashSet(); - var rs = Query.select("DISTINCT " + Field.ACCOUNT).from(TABLE_TRANSACTIONS).where(Field.SOURCE, equal(userId)).exec(db); + var rs = select("DISTINCT " + Field.ACCOUNT).from(TABLE_TRANSACTIONS).where(Field.SOURCE, equal(userId)).exec(db); while (rs.next()) accountIds.add(rs.getLong(1)); rs.close(); - rs = Query.select("DISTINCT " + Field.ACCOUNT).from(TABLE_TRANSACTIONS).where(Field.DESTINATION, equal(userId)).exec(db); + rs = select("DISTINCT " + Field.ACCOUNT).from(TABLE_TRANSACTIONS).where(Field.DESTINATION, equal(userId)).exec(db); while (rs.next()) accountIds.add(rs.getLong(1)); rs.close(); var accounts = new HashSet(); - rs = Query.select(ALL).from(TABLE_ACCOUNTS).where(Field.ID, Condition.in(accountIds.toArray())).exec(db); + rs = select(ALL).from(TABLE_ACCOUNTS).where(Field.ID, Condition.in(accountIds.toArray())).exec(db); while (rs.next()) accounts.add(Account.of(rs)); rs.close(); return accounts; @@ -96,6 +99,33 @@ public class SqliteDb extends BaseDb implements AccountDb { } } + @Override + public Account loadAccount(long accountId) { + try { + var rs = select(ALL).from(TABLE_ACCOUNTS).where(Field.ID,equal(accountId)).exec(db); + Account account = null; + if (rs.next()) account = Account.of(rs); + rs.close(); + if (account==null) throw failedToLoadObject(Text.ACCOUNT,accountId); + return account; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public List loadTransactions(Account account) { + try { + var list = new ArrayList(); + var rs = select(ALL).from(TABLE_TRANSACTIONS).where(Field.ACCOUNT,equal(account.id())).exec(db); + while (rs.next()) list.add(Transaction.of(rs)); + rs.close(); + return list; + } catch (SQLException e) { + throw failedToLoadMembers(account); + } + } + @Override public Account save(Account account) { if (account.id() == 0) try { // new account diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java index 53600c1d..77550b1c 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Field.java @@ -175,6 +175,7 @@ public class Field { public static final String TO = "to"; public static final String TOKEN = "token"; public static final String TOTAL_PRIO = "total_prio"; + public static final String TRANSACTIONS = "transactions"; public static final String TYPE = "type"; public static final String TYPE_ID = "type_id"; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java b/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java index 8a4d3ab4..5665ef6f 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/constants/Text.java @@ -5,6 +5,7 @@ package de.srsoftware.umbrella.core.constants; * This is a collection of messages that appear throughout the project */ public class Text { + public static final String ACCOUNT = "account"; public static final String ACCOUNTING = "accounting"; public static final String BOOKMARK = "bookmark"; 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 f2cd50af..dcbcca55 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 @@ -3,13 +3,27 @@ package de.srsoftware.umbrella.core.model; import de.srsoftware.tools.Mappable; import de.srsoftware.umbrella.core.constants.Field; +import java.sql.ResultSet; +import java.sql.SQLException; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.Map; import static de.srsoftware.umbrella.core.ModuleRegistry.userService; public record Transaction(long accountId, LocalDateTime date, String source, String destination, double amount, String purpose) implements Mappable { + public static Transaction of(ResultSet rs) throws SQLException { + var accountId = rs.getLong(Field.ACCOUNT); + var timestamp = rs.getLong(Field.TIMESTAMP); + var date = LocalDateTime.ofEpochSecond(timestamp,0, ZoneOffset.UTC); + var source = rs.getString(Field.SOURCE); + var destination = rs.getString(Field.DESTINATION); + var amount = rs.getDouble(Field.AMOUNT); + var purpose = rs.getString(Field.DESCRIPTION); + return new Transaction(accountId,date,source,destination,amount,purpose); + } + @Override public Map toMap() { var source = this.source; @@ -27,7 +41,7 @@ public record Transaction(long accountId, LocalDateTime date, String source, Str } catch (NumberFormatException ignored) {} return Map.of( - Field.ID, accountId, + Field.ACCOUNT, accountId, Field.DATE, date.toLocalDate(), Field.SOURCE, source, Field.DESTINATION, destination, diff --git a/frontend/src/routes/accounting/account.svelte b/frontend/src/routes/accounting/account.svelte index 93839853..8d0d6010 100644 --- a/frontend/src/routes/accounting/account.svelte +++ b/frontend/src/routes/accounting/account.svelte @@ -1,5 +1,50 @@ -

Account {id}

\ No newline at end of file +{#if account} +
+ {account.name} + + + + + + + + + + + + {#each transactions as transaction, i} + + + + + + + + {/each} + +
{t('date')}{t('source')}{t('destination')}{t('amount')}{t('purpose')}
{transaction.date}{transaction.source}{transaction.destination}{transaction.amount} {account.currency}{transaction.purpose}
+
+{/if} \ No newline at end of file diff --git a/frontend/src/routes/accounting/index.svelte b/frontend/src/routes/accounting/index.svelte index 494f9f74..e69022eb 100644 --- a/frontend/src/routes/accounting/index.svelte +++ b/frontend/src/routes/accounting/index.svelte @@ -43,7 +43,7 @@