From 5e4033a1e299ab0f9a6978adb2d351623cd43b94 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Sat, 16 Nov 2024 15:33:21 +1100 Subject: [PATCH] Implement account transactions view --- src/GeneralLedgerView.vue | 54 ++++--------- src/HomeView.vue | 4 +- src/TransactionsView.vue | 160 ++++++++++++++++++++++++++++++++++++++ src/TrialBalanceView.vue | 2 +- src/db.ts | 57 ++++++++++++++ src/main.ts | 10 +-- 6 files changed, 237 insertions(+), 50 deletions(-) create mode 100644 src/TransactionsView.vue diff --git a/src/GeneralLedgerView.vue b/src/GeneralLedgerView.vue index 8410968..4a984b4 100644 --- a/src/GeneralLedgerView.vue +++ b/src/GeneralLedgerView.vue @@ -57,53 +57,25 @@ import { onUnmounted, ref } from 'vue'; import { asCost } from './commodities.ts'; - import { db } from './db.ts'; + import { JoinedTransactionPosting, Transaction, db, joinedToTransactions } from './db.ts'; import { pp, ppWithCommodity } from './display.ts'; const commodityDetail = ref(false); - interface _Transaction { - id: number, - dt: string, - description: string, - postings: _Posting[] - } - - interface _Posting { - id: number, - description: string, - account: string, - quantity: number, - commodity: string - } - - const transactions: _Transaction[] = []; + let transactions: Transaction[] = []; let clusterize: Clusterize | null = null; async function load() { const session = await db.load(); - const transactionsRaw: {transaction_id: number, dt: string, transaction_description: string, id: number, description: string, account: string, quantity: number, commodity: string}[] = await session.select('SELECT transaction_id, dt, transactions.description AS transaction_description, postings.id, postings.description, account, quantity, commodity FROM transactions LEFT JOIN postings ON transactions.id = postings.transaction_id ORDER BY dt DESC, transaction_id DESC, postings.id'); + const joinedTransactionPostings: JoinedTransactionPosting[] = await session.select( + `SELECT transaction_id, dt, transactions.description AS transaction_description, postings.id, postings.description, account, quantity, commodity + FROM transactions + JOIN postings ON transactions.id = postings.transaction_id + ORDER BY dt DESC, transaction_id DESC, postings.id` + ); - // Group postings into transactions - for (const transactionRaw of transactionsRaw) { - if (transactions.length === 0 || transactions.at(-1)!.id !== transactionRaw.transaction_id) { - transactions.push({ - id: transactionRaw.transaction_id, - dt: transactionRaw.dt, - description: transactionRaw.transaction_description, - postings: [] - }); - } - - transactions.at(-1)!.postings.push({ - id: transactionRaw.id, - description: transactionRaw.description, - account: transactionRaw.account, - quantity: transactionRaw.quantity, - commodity: transactionRaw.commodity - }); - } + transactions = joinedToTransactions(joinedTransactionPostings); renderTable(); } @@ -125,9 +97,9 @@ rows.push( ` - ${ posting.description || '' } + ${ posting.description ?? '' } ${ posting.quantity >= 0 ? 'Dr' : 'Cr' } - ${ posting.account } + ${ posting.account } ${ posting.quantity >= 0 ? ppWithCommodity(posting.quantity, posting.commodity) : '' } @@ -140,9 +112,9 @@ rows.push( ` - ${ posting.description || '' } + ${ posting.description ?? '' } ${ posting.quantity >= 0 ? 'Dr' : 'Cr' } - ${ posting.account } + ${ posting.account } ${ posting.quantity >= 0 ? pp(asCost(posting.quantity, posting.commodity)) : '' } diff --git a/src/HomeView.vue b/src/HomeView.vue index 1dd33ad..a4dffd9 100644 --- a/src/HomeView.vue +++ b/src/HomeView.vue @@ -31,8 +31,8 @@

General reports

diff --git a/src/TransactionsView.vue b/src/TransactionsView.vue new file mode 100644 index 0000000..5365456 --- /dev/null +++ b/src/TransactionsView.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/src/TrialBalanceView.vue b/src/TrialBalanceView.vue index bc57cca..c68ba38 100644 --- a/src/TrialBalanceView.vue +++ b/src/TrialBalanceView.vue @@ -31,7 +31,7 @@ - {{ account.account }} + {{ account.account }} diff --git a/src/db.ts b/src/db.ts index 0293998..0c78ce4 100644 --- a/src/db.ts +++ b/src/db.ts @@ -68,3 +68,60 @@ export async function totalBalances(session: Database): Promise<{account: string JOIN postings p4 ON p3.account = p4.account AND p3.max_tid = p4.transaction_id ORDER BY account `); } + +// Type definitions + +export interface Transaction { + id: number, + dt: string, + description: string, + postings: Posting[] +} + +export interface Posting { + id: number, + description: string, + account: string, + quantity: number, + commodity: string, + running_balance?: number +} + +export interface JoinedTransactionPosting { + transaction_id: number, + dt: string, + transaction_description: string, + id: number, + description: string, + account: string, + quantity: number, + commodity: string, + running_balance?: number +} + +export function joinedToTransactions(joinedTransactionPostings: JoinedTransactionPosting[]): Transaction[] { + // Group postings into transactions + const transactions: Transaction[] = []; + + for (const joinedTransactionPosting of joinedTransactionPostings) { + if (transactions.length === 0 || transactions.at(-1)!.id !== joinedTransactionPosting.transaction_id) { + transactions.push({ + id: joinedTransactionPosting.transaction_id, + dt: joinedTransactionPosting.dt, + description: joinedTransactionPosting.transaction_description, + postings: [] + }); + } + + transactions.at(-1)!.postings.push({ + id: joinedTransactionPosting.id, + description: joinedTransactionPosting.description, + account: joinedTransactionPosting.account, + quantity: joinedTransactionPosting.quantity, + commodity: joinedTransactionPosting.commodity, + running_balance: joinedTransactionPosting.running_balance + }); + } + + return transactions; +} diff --git a/src/main.ts b/src/main.ts index c0fdd63..b994737 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,18 +22,16 @@ import { createApp } from 'vue'; import { createRouter, createWebHistory } from 'vue-router'; import App from './App.vue'; -import HomeView from './HomeView.vue'; -import GeneralLedgerView from './GeneralLedgerView.vue'; -import TrialBalanceView from './TrialBalanceView.vue'; import { db } from './db.ts'; async function initApp() { // Init router const routes = [ - { path: '/', component: HomeView }, - { path: '/general-ledger', component: GeneralLedgerView }, - { path: '/trial-balance', component: TrialBalanceView }, + { path: '/', name: 'index', component: () => import('./HomeView.vue') }, + { path: '/general-ledger', name: 'general-ledger', component: () => import('./GeneralLedgerView.vue') }, + { path: '/transactions/:account', name: 'transactions', component: () => import('./TransactionsView.vue') }, + { path: '/trial-balance', name: 'trial-balance', component: () => import('./TrialBalanceView.vue') }, ]; const router = createRouter({ history: createWebHistory(),