feat(accounts): the account page as a statement, all accounts instead of the audit report
Asset and liability pages open with opening plus income and money moved in, minus spending and money moved out, equals closing, then thirteen months of in and out next to the daily balance, and the statement with its balance column, day subtotals on ; and the last reconciled date. The audit report becomes one table of all accounts for the period.
This commit is contained in:
1 parent
b10a6bd21a
commit
f3a597d39c
11 files changed
+1118
-548
No files matched your search
@@ -1,96 +0,0 @@
|
||||
import type { Item, Split, TransactionGroup } from "#lib/api/types.js";
|
||||
|
||||
export interface LedgerRow {
|
||||
after: number;
|
||||
amount: number;
|
||||
before: number;
|
||||
created: string | null;
|
||||
group: string;
|
||||
split: Split;
|
||||
title: string | null;
|
||||
updated: string | null;
|
||||
}
|
||||
|
||||
export const AUDIT_COLUMNS = [
|
||||
{ key: "icon", label: "Icon" },
|
||||
{ key: "description", label: "Description" },
|
||||
{ key: "balance_before", label: "Balance before" },
|
||||
{ key: "amount", label: "Amount" },
|
||||
{ key: "balance_after", label: "Balance after" },
|
||||
{ key: "date", label: "Date" },
|
||||
{ key: "from", label: "From" },
|
||||
{ key: "to", label: "To" },
|
||||
{ key: "budget", label: "Budget" },
|
||||
{ key: "category", label: "Category" },
|
||||
{ key: "bill", label: "Subscription" },
|
||||
{ key: "created_at", label: "Created at" },
|
||||
{ key: "updated_at", label: "Updated at" },
|
||||
{ key: "notes", label: "Notes" },
|
||||
{ key: "interest_date", label: "Interest date" },
|
||||
{ key: "book_date", label: "Book date" },
|
||||
{ key: "process_date", label: "Processing date" },
|
||||
{ key: "due_date", label: "Due date" },
|
||||
{ key: "payment_date", label: "Payment date" },
|
||||
{ key: "invoice_date", label: "Invoice date" },
|
||||
] as const;
|
||||
|
||||
export type AuditColumn = (typeof AUDIT_COLUMNS)[number]["key"];
|
||||
|
||||
export const DEFAULT_AUDIT: AuditColumn[] = [
|
||||
"icon",
|
||||
"description",
|
||||
"balance_before",
|
||||
"amount",
|
||||
"balance_after",
|
||||
"date",
|
||||
"to",
|
||||
];
|
||||
|
||||
function signed(split: Split, account: string, code: string | undefined) {
|
||||
const foreign =
|
||||
split.foreign_amount !== null &&
|
||||
split.foreign_amount !== undefined &&
|
||||
split.foreign_currency_code === code &&
|
||||
split.currency_code !== code;
|
||||
const value = Number(foreign ? split.foreign_amount : split.amount);
|
||||
return String(split.source_id) === account ? -value : value;
|
||||
}
|
||||
|
||||
export function ledger(
|
||||
groups: Item<TransactionGroup>[],
|
||||
account: string,
|
||||
code: string | undefined,
|
||||
start: number
|
||||
): LedgerRow[] {
|
||||
const rows = groups.flatMap((group) =>
|
||||
group.attributes.transactions
|
||||
.filter(
|
||||
(split) =>
|
||||
String(split.source_id) === account ||
|
||||
String(split.destination_id) === account
|
||||
)
|
||||
.map((split) => ({ group, split }))
|
||||
);
|
||||
rows.sort(
|
||||
(a, b) =>
|
||||
a.split.date.localeCompare(b.split.date) ||
|
||||
Number(a.split.transaction_journal_id) -
|
||||
Number(b.split.transaction_journal_id)
|
||||
);
|
||||
let balance = start;
|
||||
return rows.map(({ group, split }) => {
|
||||
const amount = signed(split, account, code);
|
||||
const before = balance;
|
||||
balance += amount;
|
||||
return {
|
||||
after: balance,
|
||||
amount,
|
||||
before,
|
||||
created: group.attributes.created_at ?? null,
|
||||
group: group.id,
|
||||
split,
|
||||
title: group.attributes.group_title ?? null,
|
||||
updated: group.attributes.updated_at ?? null,
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
/// <reference types="bun" />
|
||||
import { expect, test } from "bun:test";
|
||||
import type { Item, Split, TransactionGroup } from "#lib/api/types.js";
|
||||
import { ledger } from "./audit.js";
|
||||
import {
|
||||
amountOf,
|
||||
bucketRange,
|
||||
@@ -171,16 +170,3 @@ test("currency exchanges between selected accounts are kept apart", () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("audit ledger runs the balance forward in the account currency", () => {
|
||||
const rows = ledger(groups, "1", "UAH", 1000);
|
||||
expect(rows.map((row) => [row.amount, row.after])).toEqual([
|
||||
[-100, 900],
|
||||
[-50, 850],
|
||||
[-4000, -3150],
|
||||
[300, -2850],
|
||||
[-20, -2870],
|
||||
]);
|
||||
const usd = ledger(groups, "2", "USD", 0);
|
||||
expect(usd.map((row) => row.amount)).toEqual([100]);
|
||||
});
|
||||
Reference in new issue
Block a user