Add support for fetching only desired transactions related to specified profile
This commit is contained in:
@@ -10,7 +10,7 @@ in
|
|||||||
pname = "actual-importer";
|
pname = "actual-importer";
|
||||||
version = "0.0.1";
|
version = "0.0.1";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
npmDepsHash = "sha256-yU3LzlExba2hq4EfuEb05TWaIS3gza1r8lu9Q/myXqE=";
|
npmDepsHash = "sha256-GHNfMeFg5UB/A031NYYjne9M8rXr1zeYCmBH2/FARt8=";
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
mkdir -p $out/lib/node_modules/actual-importer/public
|
mkdir -p $out/lib/node_modules/actual-importer/public
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ export type SubmitOptions =
|
|||||||
|
|
||||||
type ActualTransaction = {
|
type ActualTransaction = {
|
||||||
id?: string;
|
id?: string;
|
||||||
account?: string;
|
account: string;
|
||||||
date: string;
|
date: string;
|
||||||
amount?: number;
|
amount: number;
|
||||||
payee?: string;
|
payee?: string;
|
||||||
payee_name?: string;
|
payee_name?: string;
|
||||||
imported_payee?: string;
|
imported_payee?: string;
|
||||||
@@ -51,7 +51,7 @@ export class Actual {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#map(transaction: Transaction, accounts: ActualAccount[], payees: ActualPayee[]): ActualTransaction {
|
#map(transaction: Transaction, accounts: ActualAccount[], payees: ActualPayee[]): ActualTransaction {
|
||||||
const actualTransaction: ActualTransaction = {
|
const actualTransaction: Omit<ActualTransaction, 'account'> & { account?: string } = {
|
||||||
imported_id: transaction.id,
|
imported_id: transaction.id,
|
||||||
date: transaction.date,
|
date: transaction.date,
|
||||||
amount: utils.amountToInteger(transaction.amount),
|
amount: utils.amountToInteger(transaction.amount),
|
||||||
@@ -94,7 +94,7 @@ export class Actual {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return actualTransaction;
|
return actualTransaction as ActualTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #api<T>(fn: () => Promise<T>): Promise<T> {
|
async #api<T>(fn: () => Promise<T>): Promise<T> {
|
||||||
@@ -194,7 +194,8 @@ export class Actual {
|
|||||||
|
|
||||||
const query = api.q('transactions')
|
const query = api.q('transactions')
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.select(['*']);
|
.select(['*'])
|
||||||
|
.options({ splits: 'grouped' });
|
||||||
|
|
||||||
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
|
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
|
||||||
|
|
||||||
@@ -209,7 +210,8 @@ export class Actual {
|
|||||||
|
|
||||||
const query = api.q('transactions')
|
const query = api.q('transactions')
|
||||||
.filter({ date: [{ $gte: start }, { $lte: end }] })
|
.filter({ date: [{ $gte: start }, { $lte: end }] })
|
||||||
.select(['*']);
|
.select(['*'])
|
||||||
|
.options({ splits: 'grouped' });
|
||||||
|
|
||||||
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
|
const { data } = await api.runQuery(query) as { data: ActualTransaction[] };
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import express from "express";
|
|||||||
import multer from "multer";
|
import multer from "multer";
|
||||||
import { Readable } from "stream";
|
import { Readable } from "stream";
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import { Transaction } from "@/types/transaction";
|
||||||
|
|
||||||
|
|
||||||
export function serve(config: Config, port: number) {
|
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) => {
|
app.get("/servers/:server/transactions", async (req, res) => {
|
||||||
const { start, end } = req.query;
|
const { start, end } = req.query;
|
||||||
|
let data: Transaction[]|undefined;
|
||||||
|
|
||||||
if (start && end) {
|
if (start && end) {
|
||||||
const data = await getTransactionsFromRange(req.params.server, config, start.toString(), end.toString());
|
data = await getTransactionsFromRange(req.params.server, config, start.toString(), end.toString());
|
||||||
res.json(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
const limitParam = req.query.limit?.toString();
|
const limitParam = req.query.limit?.toString();
|
||||||
const limit = (limitParam && Number.parseInt(limitParam)) || undefined;
|
const limit = (limitParam && Number.parseInt(limitParam)) || undefined;
|
||||||
const data = await getTransactions(req.params.server, config, limit);
|
data = await getTransactions(req.params.server, config, limit);
|
||||||
res.json(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) => {
|
app.post("/prepare", upload.single("file"), async (req, res) => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export type ProfileConfig = {
|
|||||||
encoding?: string;
|
encoding?: string;
|
||||||
config?: ParserConfig;
|
config?: ParserConfig;
|
||||||
csv?: Record<string, unknown>;
|
csv?: Record<string, unknown>;
|
||||||
|
supportedAccounts?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ParserConfig = {
|
export type ParserConfig = {
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ buildNpmPackage {
|
|||||||
pname = "actual-importer-frontend";
|
pname = "actual-importer-frontend";
|
||||||
version = "0.0.1";
|
version = "0.0.1";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
npmDepsHash = "sha256-/G8OZBAkCuc0LTmpB1v8HTgaWdYd9AJfZTC0/eUQIx0=";
|
npmDepsHash = "sha256-Xh+zpYX8u+wKuvBjGc4hxUI2Ed4tiXKC3zk8kFExBbc=";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export default function PrepareTransactionsPage() {
|
|||||||
|
|
||||||
// If no "from" filter active, pull the latest 10 transactions
|
// If no "from" filter active, pull the latest 10 transactions
|
||||||
if (!debouncedUserFilter.from) {
|
if (!debouncedUserFilter.from) {
|
||||||
const transactions = await getLatestTransactions(state.server, 10);
|
const transactions = await getLatestTransactions(state.server, 10, state.profile);
|
||||||
setExistingTransactions(transactions);
|
setExistingTransactions(transactions);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -87,7 +87,7 @@ export default function PrepareTransactionsPage() {
|
|||||||
const start = debouncedUserFilter.from.format("YYYY-MM-DD");
|
const start = debouncedUserFilter.from.format("YYYY-MM-DD");
|
||||||
const end = (debouncedUserFilter.to ?? dayjs()).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);
|
setExistingTransactions(transactions);
|
||||||
}, [enabledExistingTransactions, state.server, debouncedUserFilter]);
|
}, [enabledExistingTransactions, state.server, debouncedUserFilter]);
|
||||||
|
|
||||||
|
|||||||
@@ -40,21 +40,29 @@ export async function submitTransactions(transactions: Transaction[], server: st
|
|||||||
return data as SubmitResponse;
|
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();
|
const params = new URLSearchParams();
|
||||||
params.append('limit', limit.toString());
|
params.append('limit', limit.toString());
|
||||||
|
|
||||||
|
if (profile !== undefined) {
|
||||||
|
params.append('profile', profile);
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(`/servers/${server}/transactions?${params.toString()}`);
|
const response = await fetch(`/servers/${server}/transactions?${params.toString()}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data as Transaction[];
|
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();
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
params.append('start', start);
|
params.append('start', start);
|
||||||
params.append('end', end);
|
params.append('end', end);
|
||||||
|
|
||||||
|
if (profile !== undefined) {
|
||||||
|
params.append('profile', profile);
|
||||||
|
}
|
||||||
|
|
||||||
const response = await fetch(`/servers/${server}/transactions?${params.toString()}`);
|
const response = await fetch(`/servers/${server}/transactions?${params.toString()}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data as Transaction[];
|
return data as Transaction[];
|
||||||
|
|||||||
Reference in New Issue
Block a user