Add support for existing transactions
This commit is contained in:
@@ -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> {
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user