Add support for fetching only desired transactions related to specified profile

This commit is contained in:
2025-07-08 12:45:43 +02:00
parent 9b24a1d737
commit 32b8d50e5b
7 changed files with 33 additions and 16 deletions

View File

@@ -10,7 +10,7 @@ in
pname = "actual-importer";
version = "0.0.1";
src = ./.;
npmDepsHash = "sha256-yU3LzlExba2hq4EfuEb05TWaIS3gza1r8lu9Q/myXqE=";
npmDepsHash = "sha256-GHNfMeFg5UB/A031NYYjne9M8rXr1zeYCmBH2/FARt8=";
postInstall = ''
mkdir -p $out/lib/node_modules/actual-importer/public

View File

@@ -14,9 +14,9 @@ export type SubmitOptions =
type ActualTransaction = {
id?: string;
account?: string;
account: string;
date: string;
amount?: number;
amount: number;
payee?: string;
payee_name?: string;
imported_payee?: string;
@@ -51,7 +51,7 @@ export class Actual {
}
#map(transaction: Transaction, accounts: ActualAccount[], payees: ActualPayee[]): ActualTransaction {
const actualTransaction: ActualTransaction = {
const actualTransaction: Omit<ActualTransaction, 'account'> & { account?: string } = {
imported_id: transaction.id,
date: transaction.date,
amount: utils.amountToInteger(transaction.amount),
@@ -94,7 +94,7 @@ export class Actual {
break;
}
return actualTransaction;
return actualTransaction as ActualTransaction;
}
async #api<T>(fn: () => Promise<T>): Promise<T> {
@@ -194,7 +194,8 @@ export class Actual {
const query = api.q('transactions')
.limit(limit)
.select(['*']);
.select(['*'])
.options({ splits: 'grouped' });
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
@@ -209,7 +210,8 @@ export class Actual {
const query = api.q('transactions')
.filter({ date: [{ $gte: start }, { $lte: end }] })
.select(['*']);
.select(['*'])
.options({ splits: 'grouped' });
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };

View File

@@ -4,6 +4,7 @@ import express from "express";
import multer from "multer";
import { Readable } from "stream";
import path from 'path';
import { Transaction } from "@/types/transaction";
export function serve(config: Config, port: number) {
@@ -22,18 +23,23 @@ export function serve(config: Config, port: number) {
app.get("/servers/:server/transactions", async (req, res) => {
const { start, end } = req.query;
let data: Transaction[]|undefined;
if (start && end) {
const data = await getTransactionsFromRange(req.params.server, config, start.toString(), end.toString());
res.json(data);
data = await getTransactionsFromRange(req.params.server, config, start.toString(), end.toString());
}
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);
data = await getTransactions(req.params.server, config, limit);
}
const profile = req.query.profile?.toString() || undefined;
const supportedAccounts = profile !== undefined ? config.profiles[profile].supportedAccounts : undefined;
const filterAccounts = supportedAccounts !== undefined ? (t: Transaction) => supportedAccounts.includes(t.from) || supportedAccounts.includes(t.to) : () => true;
res.json(data.filter(filterAccounts))
});
app.post("/prepare", upload.single("file"), async (req, res) => {

View File

@@ -11,6 +11,7 @@ export type ProfileConfig = {
encoding?: string;
config?: ParserConfig;
csv?: Record<string, unknown>;
supportedAccounts?: string[];
};
export type ParserConfig = {

View File

@@ -7,5 +7,5 @@ buildNpmPackage {
pname = "actual-importer-frontend";
version = "0.0.1";
src = ./.;
npmDepsHash = "sha256-/G8OZBAkCuc0LTmpB1v8HTgaWdYd9AJfZTC0/eUQIx0=";
npmDepsHash = "sha256-Xh+zpYX8u+wKuvBjGc4hxUI2Ed4tiXKC3zk8kFExBbc=";
}

View File

@@ -79,7 +79,7 @@ export default function PrepareTransactionsPage() {
// If no "from" filter active, pull the latest 10 transactions
if (!debouncedUserFilter.from) {
const transactions = await getLatestTransactions(state.server, 10);
const transactions = await getLatestTransactions(state.server, 10, state.profile);
setExistingTransactions(transactions);
return;
}
@@ -87,7 +87,7 @@ export default function PrepareTransactionsPage() {
const start = debouncedUserFilter.from.format("YYYY-MM-DD");
const end = (debouncedUserFilter.to ?? dayjs()).format("YYYY-MM-DD");
const transactions = await getDateRangedTransactions(state.server, start, end);
const transactions = await getDateRangedTransactions(state.server, start, end, state.profile);
setExistingTransactions(transactions);
}, [enabledExistingTransactions, state.server, debouncedUserFilter]);

View File

@@ -40,21 +40,29 @@ export async function submitTransactions(transactions: Transaction[], server: st
return data as SubmitResponse;
}
export async function getLatestTransactions(server: string, limit: number = 5): Promise<Transaction[]> {
export async function getLatestTransactions(server: string, limit: number = 5, profile?: string): Promise<Transaction[]> {
const params = new URLSearchParams();
params.append('limit', limit.toString());
if (profile !== undefined) {
params.append('profile', profile);
}
const response = await fetch(`/servers/${server}/transactions?${params.toString()}`);
const data = await response.json();
return data as Transaction[];
}
export async function getDateRangedTransactions(server: string, start: string, end: string): Promise<Transaction[]> {
export async function getDateRangedTransactions(server: string, start: string, end: string, profile?: string): Promise<Transaction[]> {
const params = new URLSearchParams();
params.append('start', start);
params.append('end', end);
if (profile !== undefined) {
params.append('profile', profile);
}
const response = await fetch(`/servers/${server}/transactions?${params.toString()}`);
const data = await response.json();
return data as Transaction[];