Add support for existing transactions

This commit is contained in:
2025-05-21 22:52:48 +02:00
parent e1dc42c254
commit cc208dd748
9 changed files with 275 additions and 30 deletions

View File

@@ -186,6 +186,72 @@ export class Actual {
return this.#doSubmit(prepared, opts);
});
}
async getTransactions(limit: number): Promise<Transaction[]> {
return this.#api(async () => {
const accounts: ActualAccount[] = await api.getAccounts();
const payees: ActualPayee[] = await api.getPayees();
const query = api.q('transactions')
.limit(limit)
.select(['*']);
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
return this.#mapActualTransactionsToTransactions(data, accounts, payees);
});
}
async getTransactionsFromRange(start: string, end: string): Promise<Transaction[]> {
return this.#api(async () => {
const accounts: ActualAccount[] = await api.getAccounts();
const payees: ActualPayee[] = await api.getPayees();
const query = api.q('transactions')
.filter({ date: [{ $gte: start }, { $lte: end }] })
.select(['*']);
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
return this.#mapActualTransactionsToTransactions(data, accounts, payees);
});
}
#mapActualTransactionsToTransactions(transactions: ActualTransaction[], accounts: ActualAccount[], payees: ActualPayee[]): Transaction[] {
const transfers: string[] = [];
return transactions.map(t => {
const account = accounts.find(a => a.id === t.account)?.name ?? t.account ?? "--unknown--";
const payee = payees.find(p => p.id === t.payee)?.name ?? t.payee ?? "--unknown--";
let from = account;
let to = payee;
if (t.amount && t.amount > 0) {
from = payee;
to = account;
}
if (t.transfer_id) {
if (transfers.includes(t.id!!)) {
return undefined;
}
transfers.push(t.transfer_id);
}
return {
kind: t.transfer_id ? 'transfer' : 'regular',
date: t.date,
from,
to,
fromDetails: from,
toDetails: to,
amount: (t.amount ?? 0)/100,
title: t.notes
} as Transaction;
}).filter(t => t !== undefined);
}
}
async function sleep(ms: number): Promise<void> {

View File

@@ -15,6 +15,29 @@ export type ImportResult = PrepareResult & {
result: ActualImportResult;
};
export const getTransactions = async (server: string, config: Config, limit: number = 5): Promise<Transaction[]> => {
const serverConfig = config.servers[server];
if(!serverConfig) {
throw new Error(`Unknown server: ${server}`);
}
const actualServer = new Actual(serverConfig);
return await actualServer.getTransactions(limit);
};
export const getTransactionsFromRange = async (server: string, config: Config, start: string, end: string): Promise<Transaction[]> => {
const serverConfig = config.servers[server];
if(!serverConfig) {
throw new Error(`Unknown server: ${server}`);
}
const actualServer = new Actual(serverConfig);
return await actualServer.getTransactionsFromRange(start, end);
};
export const prepareTransactions = async (stream: Readable, profile: string, server: string, config: Config): Promise<PrepareResult> => new Promise((resolve, reject) => {
const profileConfig = config.profiles[profile];

View File

@@ -1,4 +1,4 @@
import { prepareTransactions, submitTransactions } from "@/runner";
import { getTransactions, getTransactionsFromRange, prepareTransactions, submitTransactions } from "@/runner";
import { Config } from "@/types/config";
import express from "express";
import multer from "multer";
@@ -20,6 +20,22 @@ export function serve(config: Config, port: number) {
});
});
app.get("/servers/:server/transactions", async (req, res) => {
const { start, end } = req.query;
if (start && end) {
const data = await getTransactionsFromRange(req.params.server, config, start.toString(), end.toString());
res.json(data);
}
else {
const limitParam = req.query.limit?.toString();
const limit = (limitParam && Number.parseInt(limitParam)) || undefined;
const data = await getTransactions(req.params.server, config, limit);
res.json(data);
}
});
app.post("/prepare", upload.single("file"), async (req, res) => {
if (!req.file) {
throw new Error("No file to upload");