implemented loading of accounts

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2026-04-02 13:39:35 +02:00
parent c0ab71d71d
commit 44fb120891
5 changed files with 82 additions and 5 deletions

View File

@@ -3,7 +3,11 @@ package de.srsoftware.umbrella.accounting;
import de.srsoftware.umbrella.core.model.Account;
import de.srsoftware.umbrella.core.model.Transaction;
import java.util.Collection;
public interface AccountDb {
Collection<Account> listAccounts(long userId);
Account save(Account account);
Transaction save(Transaction transaction);
}

View File

@@ -42,6 +42,25 @@ public class AccountingModule extends BaseHandler implements AccountingService {
ModuleRegistry.add(this);
}
@Override
public boolean doGet(Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> token = SessionToken.from(ex).map(Token::of);
var user = userService().loadUser(token);
if (user.isEmpty()) return unauthorized(ex);
var head = path.pop();
return switch (head) {
case null -> getAccounts(user.get(),ex);
default -> super.doGet(path,ex);
};
} catch (NumberFormatException e){
return sendContent(ex,HTTP_BAD_REQUEST,"Invalid project id");
} catch (UmbrellaException e){
return send(ex,e);
}
}
@Override
public boolean doPost(Path path, HttpExchange ex) throws IOException {
addCors(ex);
@@ -61,6 +80,12 @@ public class AccountingModule extends BaseHandler implements AccountingService {
}
}
private boolean getAccounts(UmbrellaUser user, HttpExchange ex) throws IOException {
return sendContent(ex,accountDb.listAccounts(user.id()));
}
private boolean postEntry(UmbrellaUser user, HttpExchange ex) throws IOException {
var json = json(ex);
if (!json.has(Field.ACCOUNT)) throw missingField(Field.ACCOUNT);

View File

@@ -1,20 +1,24 @@
package de.srsoftware.umbrella.accounting;
import de.srsoftware.tools.jdbc.Condition;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.BaseDb;
import de.srsoftware.umbrella.core.constants.Field;
import de.srsoftware.umbrella.core.constants.Text;
import de.srsoftware.umbrella.core.model.Account;
import de.srsoftware.umbrella.core.model.Transaction;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.ZoneOffset;
import java.util.HashSet;
import static de.srsoftware.tools.NotImplemented.notImplemented;
import static de.srsoftware.tools.jdbc.Condition.equal;
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
import static de.srsoftware.umbrella.accounting.Constants.TABLE_ACCOUNTS;
import static de.srsoftware.umbrella.accounting.Constants.TABLE_TRANSACTIONS;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToCreateTable;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.failedToStoreObject;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static java.text.MessageFormat.format;
public class SqliteDb extends BaseDb implements AccountDb {
@@ -72,6 +76,26 @@ public class SqliteDb extends BaseDb implements AccountDb {
}
}
@Override
public HashSet<Account> listAccounts(long userId) {
try {
var accountIds = new HashSet<Long>();
var rs = Query.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);
while (rs.next()) accountIds.add(rs.getLong(1));
rs.close();
var accounts = new HashSet<Account>();
rs = Query.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;
} catch (SQLException e){
throw failedToLoadObject(Text.ACCOUNTING).causedBy(e);
}
}
@Override
public Account save(Account account) {
if (account.id() == 0) try { // new account

View File

@@ -3,13 +3,19 @@ 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.util.Map;
import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
public record Account(long id, String name, String currency, long ownerId) implements Mappable {
public Account withId(long newId) {
return new Account(newId,name,currency,ownerId);
public static Account of(ResultSet rs) throws SQLException {
var id = rs.getLong(Field.ID);
var name = rs.getString(Field.NAME);
var owner = rs.getLong(Field.OWNER);
var currency = rs.getString(Field.CURRENCY);
return new Account(id,name,currency,owner);
}
@Override
@@ -22,4 +28,8 @@ public record Account(long id, String name, String currency, long ownerId) imple
Field.OWNER, owner.toMap()
);
}
public Account withId(long newId) {
return new Account(newId,name,currency,ownerId);
}
}

View File

@@ -1,14 +1,28 @@
<script>
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { t } from '../../translations.svelte';
import { api, get } from '../../urls.svelte';
import { error, yikes } from '../../warn.svelte';
const router = useTinyRouter();
let accounts = [];
async function load(){
let url = api('accounting');
let res = await get(url);
if (res.ok){
yikes();
accounts = await res.json();
} else error(res);
}
function newAccount(){
router.navigate('/accounting/new');
}
onMount(load);
</script>
<fieldset>