brf/server/routes/api.ts
2025-11-27 12:22:51 +01:00

247 lines
6.3 KiB
TypeScript

import _ from 'lodash'
import { Type, type Static, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
import knex from '../lib/knex.ts'
import StatusError from '../lib/status_error.ts'
export const FinancialYear = Type.Object({
year: Type.Number(),
startDate: Type.String(),
endDate: Type.String(),
})
export type FinancialYearType = Static<typeof FinancialYear>
const apiRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
fastify.route({
url: '/financial-years',
method: 'GET',
handler() {
return knex('financialYear').select('*')
},
})
fastify.route({
url: '/invoices',
method: 'GET',
schema: {
querystring: Type.Object({
year: Type.Optional(Type.Number()),
supplier: Type.Optional(Type.Number()),
}),
},
async handler(req) {
let query: { financialYearId?: number; supplierId?: number } = {}
if (req.query.year) {
const year = await knex('financialYear').first('*').where('year', req.query.year)
if (!year) throw new StatusError(404, `Year ${req.query.year} not found.`)
query.financialYearId = year.id
}
if (req.query.supplier) {
query.supplierId = req.query.supplier
}
return knex('invoice AS i')
.select('*', {
files: knex
.select(knex.raw('json_agg(files)'))
.from(
knex
.select('id', 'filename')
.from('file AS f')
.innerJoin('filesToInvoice AS fi', 'f.id', 'fi.fileId')
.where('fi.invoiceId', knex.ref('i.id'))
.as('files'),
),
})
.where(query)
},
})
fastify.route({
url: '/invoices/:id',
method: 'GET',
schema: {
params: Type.Object({
id: Type.Number(),
}),
},
handler(req) {
return knex('invoice').first('*').where('id', req.params.id)
},
})
fastify.route({
url: '/invoices/by-supplier/:supplier',
method: 'GET',
schema: {
params: Type.Object({
supplier: Type.Number(),
}),
},
handler(req) {
return knex('invoice AS i')
.select('*', {
files: knex
.select(knex.raw('json_agg(files)'))
.from(
knex
.select('id', 'filename')
.from('file AS f')
.innerJoin('filesToInvoice AS fi', 'f.id', 'fi.fileId')
.where('fi.invoiceId', knex.ref('i.id'))
.as('files'),
),
})
.where('supplierId', req.params.supplier)
},
})
fastify.route({
url: '/invoices/by-year/:year',
method: 'GET',
schema: {
params: Type.Object({
year: Type.Number(),
}),
},
async handler(req) {
const year = await knex('financialYear').first('*').where('year', req.params.year)
if (!year) throw new StatusError(404, `Year ${req.params.year} not found.`)
return knex('invoice').select('*').where('financialYearId', year.id)
},
})
fastify.route({
url: '/objects',
method: 'GET',
handler() {
return knex('object AS o')
.select('o.id', 'o.number', 'o.name', 'd.number AS dimensionNumber', 'd.name AS dimensionName')
.innerJoin('dimension AS d', function () {
this.on('o.dimensionId', '=', 'd.id')
})
},
})
fastify.route({
url: '/objects/:id',
method: 'GET',
schema: {
params: Type.Object({
id: Type.Number(),
}),
},
async handler(req) {
// const object = knex('object').first('*').where('id', req.params.id)
// if (!object) throw new StatusError(404)
console.log(req.params.id)
return knex('transaction AS t')
.select('e.transactionDate', 't.accountNumber', 't.amount')
.innerJoin('transactions_to_objects AS to', function () {
this.on('t.id', 'to.transactionId')
})
.innerJoin('entry AS e', function () {
this.on('e.id', '=', 't.entryId')
})
.where('to.objectId', req.params.id)
},
})
fastify.route({
url: '/results',
method: 'GET',
async handler() {
const years = await knex('financialYear').select('*')
const accounts = await knex('account').select('*')
return Promise.all(
years.map((year) =>
knex('account AS a')
.select('a.number', 'a.description')
.sum('t.amount as amount')
.innerJoin('transaction AS t', function () {
this.on('t.accountNumber', '=', 'a.number')
})
.innerJoin('entry AS e', function () {
this.on('t.entryId', '=', 'e.id')
})
.groupBy('a.number', 'a.description')
.where('a.number', '>=', 3000)
.where('e.financialYearId', year.id)
.orderBy('a.number')
.then((result) => ({
startDate: year.startDate,
endDate: year.endDate,
result,
})),
),
).then((years) => ({
accounts,
years,
}))
},
})
fastify.route({
url: '/results/:year',
method: 'GET',
schema: {
params: Type.Object({
year: Type.Number(),
}),
},
async handler(req) {
const year = await knex('financialYear').first('*').where('year', req.params.year)
if (!year) return null
return knex('transaction AS t')
.select('t.accountNumber', 'a.description')
.sum('t.amount as amount')
.innerJoin('account AS a', function () {
this.on('t.accountNumber', '=', 'a.number')
})
.innerJoin('entry AS e', function () {
this.on('t.entryId', '=', 'e.id')
})
.groupBy('t.accountNumber', 'a.description')
.where('t.accountNumber', '>=', 3000)
.where('e.financialYearId', year.id)
.orderBy('t.accountNumber')
},
})
fastify.route({
url: '/suppliers',
method: 'GET',
async handler(req) {
return knex('supplier').select('*').orderBy('name')
},
})
fastify.route({
url: '/suppliers/:id',
method: 'GET',
schema: {
params: Type.Object({
id: Type.Number(),
}),
},
async handler(req) {
return knex('supplier').first('*').where('id', req.params.id)
},
})
done()
}
export default apiRoutes