add balances

This commit is contained in:
Linus Miller 2025-12-04 21:30:59 +01:00
parent e5bbd266e9
commit ae23e9fbd1
6 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,15 @@
meta {
name: /api/balances
type: http
seq: 15
}
get {
url: {{base_url}}/api/balances
body: none
auth: inherit
}
settings {
encodeUrl: true
}

View File

@ -0,0 +1,9 @@
.table {
a {
text-decoration: none;
color: black;
&:hover {
font-weight: bold;
}
}
}

View File

@ -0,0 +1,59 @@
import { h } from 'preact'
import { useEffect, useState } from 'preact/hooks'
import cn from 'classnames'
import rek from 'rek'
import Head from './head.ts'
import Balance from './balance.tsx'
import Balances from './balances.tsx'
import { formatNumber } from '../utils/format_number.ts'
import s from './balances_page.module.scss'
const BalancesPage = () => {
const [balances, setBalances] = useState([])
const [years, setYears] = useState<number[]>([])
useEffect(() => {
rek(`/api/balances`).then(setBalances)
rek(`/api/financial-years`).then((years) => setYears(years.map((fy) => fy.year)))
}, [])
return (
<section>
<Head>
<title> : Balances</title>
</Head>
<h1>Balances</h1>
{years.length && balances.length && (
<table className={cn('grid', s.table)}>
<thead>
<tr>
<th>Account</th>
<th>Description</th>
{years.map((year) => (
<th>{year}</th>
))}
</tr>
</thead>
<tbody>
{balances.map((balance) => (
<tr>
<td>{balance.accountNumber}</td>
<td>{balance.description}</td>
{years.map((year) => (
<td className='tar'>
<a href={`/transactions?year=${year}&accountNumber=${balance.accountNumber}`}>
{formatNumber(balance[year])}
</a>
</td>
))}
</tr>
))}
</tbody>
</table>
)}
</section>
)
}
export default BalancesPage

View File

@ -1,4 +1,5 @@
import Accounts from './components/accounts_page.tsx'
import Balances from './components/balances_page.tsx'
import Entries from './components/entries_page.tsx'
import Entry from './components/entry_page.tsx'
import Invoice from './components/invoice_page.tsx'
@ -61,6 +62,12 @@ export default [
component: InvoicesBySupplier,
nav: false,
},
{
path: '/balances',
name: 'balances',
title: 'Balances',
component: Balances,
},
{
path: '/results',
name: 'results',

View File

@ -3,6 +3,7 @@ import { Type, type Static, type FastifyPluginCallbackTypebox } from '@fastify/t
import knex from '../lib/knex.ts'
import accounts from './api/accounts.ts'
import balances from './api/balances.ts'
import entries from './api/entries.ts'
import financialYears from './api/financial_years.ts'
import invoices from './api/invoices.ts'
@ -22,6 +23,7 @@ export type FinancialYearType = Static<typeof FinancialYear>
const apiRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
fastify.register(accounts, { prefix: '/accounts' })
fastify.register(balances, { prefix: '/balances' })
fastify.register(entries, { prefix: '/entries' })
fastify.register(financialYears, { prefix: '/financial-years' })
fastify.register(invoices, { prefix: '/invoices' })

View File

@ -0,0 +1,36 @@
import _ from 'lodash'
import { Type, type Static, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
import knex from '../../lib/knex.ts'
const balanceRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
fastify.route({
url: '/',
method: 'GET',
async handler() {
const financialYears = await knex('financialYear').select('*').orderBy('year', 'asc')
return knex('accountBalance AS ab')
.select(
'ab.accountNumber',
'a.description',
Object.fromEntries(
financialYears.map((fy) => [
fy.year,
knex.raw(`SUM(CASE WHEN fy.year = ${fy.year} THEN ab."out" ELSE 0 END)`),
]),
),
)
.innerJoin('financialYear AS fy', 'fy.id', 'ab.financialYearId')
.innerJoin('account AS a', function () {
this.on('ab.accountNumber', '=', 'a.number')
})
.groupBy('ab.accountNumber', 'a.description')
.where('ab.accountNumber', '<', 3000)
.orderBy('ab.accountNumber')
},
})
done()
}
export default balanceRoutes