invoices
This commit is contained in:
parent
347bce3fd6
commit
ac61674b69
15
.bruno/BRF/Invoice.bru
Normal file
15
.bruno/BRF/Invoice.bru
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
meta {
|
||||||
|
name: Invoice
|
||||||
|
type: http
|
||||||
|
seq: 7
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{base_url}}/
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
}
|
||||||
15
.bruno/BRF/Invoices.bru
Normal file
15
.bruno/BRF/Invoices.bru
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
meta {
|
||||||
|
name: Invoices
|
||||||
|
type: http
|
||||||
|
seq: 6
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{base_url}}/api/invoices
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
}
|
||||||
15
.bruno/BRF/api-suppliers.bru
Normal file
15
.bruno/BRF/api-suppliers.bru
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
meta {
|
||||||
|
name: /api/suppliers
|
||||||
|
type: http
|
||||||
|
seq: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{base_url}}/
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
}
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
/dump
|
/dump
|
||||||
/sie
|
/sie
|
||||||
|
/invoices
|
||||||
|
/uploads
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
|||||||
64
bin/add_fisken_invoices.ts
Normal file
64
bin/add_fisken_invoices.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import fs from 'node:fs/promises'
|
||||||
|
import { existsSync } from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
import knex from '../server/lib/knex.ts'
|
||||||
|
|
||||||
|
const dirs = process.argv.slice(2)
|
||||||
|
|
||||||
|
// 172-972, 2020-01-08, Great Security Sverige AB.pdf'
|
||||||
|
const rFileName = /^172-(\d+),\s(\d{4,4}-\d{2,2}-\d{2,2}), (.*)\.pdf$/
|
||||||
|
|
||||||
|
for await (const dir of dirs) {
|
||||||
|
await readdir(dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
knex.destroy()
|
||||||
|
|
||||||
|
async function readdir(dir: string) {
|
||||||
|
const files = (await fs.readdir(dir)).toSorted((a: string, b: string) => {
|
||||||
|
const [, aNum] = a.match(rFileName)
|
||||||
|
const [, bNum] = b.match(rFileName)
|
||||||
|
|
||||||
|
if (parseInt(aNum) > parseInt(bNum)) {
|
||||||
|
return 1
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const trx = await knex.transaction()
|
||||||
|
|
||||||
|
for await (const originalFilename of files) {
|
||||||
|
const result = originalFilename.match(rFileName)
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new Error(originalFilename)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, fiskenNumber, invoiceDate, supplierName] = result
|
||||||
|
|
||||||
|
let supplier = await trx('supplier').first('*').where('name', supplierName)
|
||||||
|
|
||||||
|
if (!supplier) {
|
||||||
|
supplier = (await trx('supplier').insert({ name: supplierName, supplierTypeId: 1 }).returning('*'))[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const invoice = (
|
||||||
|
await trx('invoice').insert({ fiskenNumber, invoiceDate, supplierId: supplier.id }).returning('*')
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
const ext = path.extname(originalFilename)
|
||||||
|
const filename = `${invoiceDate}_fisken_${fiskenNumber}_${supplierName.split(/[\s/]/).join('_').split(/[']/).join('')}${ext}`
|
||||||
|
const pathname = path.join('uploads', 'invoices', filename)
|
||||||
|
|
||||||
|
if (!existsSync(pathname)) {
|
||||||
|
console.info(filename)
|
||||||
|
await fs.copyFile(path.join(dir, originalFilename), pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = (await trx('file').insert({ filename }).returning('id'))[0]
|
||||||
|
await trx('filesToInvoice').insert({ fileId: file.id, invoiceId: invoice.id })
|
||||||
|
}
|
||||||
|
|
||||||
|
await trx.commit()
|
||||||
|
}
|
||||||
73
bin/add_phm_invoices.ts
Normal file
73
bin/add_phm_invoices.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import fs from 'node:fs/promises'
|
||||||
|
import { existsSync } from 'node:fs'
|
||||||
|
import path from 'node:path'
|
||||||
|
import knex from '../server/lib/knex.ts'
|
||||||
|
import split from '../server/lib/split.ts'
|
||||||
|
import { csvParseRows } from 'd3-dsv'
|
||||||
|
|
||||||
|
const csvFilename = process.argv[2]
|
||||||
|
const csvString = await fs.readFile(csvFilename, { encoding: 'utf8' })
|
||||||
|
const rows = csvParseRows(csvString)
|
||||||
|
|
||||||
|
const trx = await knex.transaction()
|
||||||
|
|
||||||
|
for (const row of rows.toReversed()) {
|
||||||
|
const [
|
||||||
|
phmNumber,
|
||||||
|
type,
|
||||||
|
supplierId,
|
||||||
|
supplierName,
|
||||||
|
invoiceDate,
|
||||||
|
dueDate,
|
||||||
|
invoiceNumber,
|
||||||
|
ocr,
|
||||||
|
amount,
|
||||||
|
vat,
|
||||||
|
balance,
|
||||||
|
currency,
|
||||||
|
status,
|
||||||
|
filesString,
|
||||||
|
] = row
|
||||||
|
|
||||||
|
let supplier = await trx('supplier').first('*').where('name', supplierName)
|
||||||
|
|
||||||
|
if (!supplier) {
|
||||||
|
supplier = (await trx('supplier').insert({ name: supplierName, supplierTypeId: 1 }).returning('*'))[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const invoice = (
|
||||||
|
await trx('invoice')
|
||||||
|
.insert({
|
||||||
|
invoiceDate,
|
||||||
|
supplierId: supplier.id,
|
||||||
|
dueDate,
|
||||||
|
ocr,
|
||||||
|
invoiceNumber,
|
||||||
|
phmNumber,
|
||||||
|
amount,
|
||||||
|
})
|
||||||
|
.returning('id')
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
const filenames = filesString.split(',').map((filename) => filename.trim())
|
||||||
|
|
||||||
|
// TODO handle names if multiple files with same extension (otherwise they will have the same name)
|
||||||
|
for (const originalFilename of filenames) {
|
||||||
|
const ext = path.extname(originalFilename)
|
||||||
|
const filename = `${invoiceDate}_phm_${phmNumber}_${supplierName.split(/[\s/]/).join('_').split(/[']/).join('')}${ext}`
|
||||||
|
const pathname = path.join('uploads', 'invoices', filename)
|
||||||
|
|
||||||
|
if (!existsSync(pathname)) {
|
||||||
|
console.info(filename)
|
||||||
|
await fs.copyFile(path.join('invoices', 'phm', originalFilename), pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = (await trx('file').insert({ filename }).returning('id'))[0]
|
||||||
|
|
||||||
|
trx('filesToInvoice').insert({ fileId: file.id, invoiceId: invoice.id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trx.commit()
|
||||||
|
|
||||||
|
knex.destroy()
|
||||||
@ -8,6 +8,8 @@ for await (const file of process.argv.slice(2)) {
|
|||||||
console.log(`- parsing file: ${file}`)
|
console.log(`- parsing file: ${file}`)
|
||||||
|
|
||||||
await parseStream(fh.readableWebStream())
|
await parseStream(fh.readableWebStream())
|
||||||
|
|
||||||
|
await fh.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
knex.destroy()
|
knex.destroy()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { h } from 'preact'
|
import { h } from 'preact'
|
||||||
import { Router } from 'preact-router'
|
import { LocationProvider, Route, Router } from 'preact-iso'
|
||||||
import Head from './head.ts'
|
import Head from './head.ts'
|
||||||
import Footer from './footer.tsx'
|
import Footer from './footer.tsx'
|
||||||
import Header from './header.tsx'
|
import Header from './header.tsx'
|
||||||
@ -10,27 +10,28 @@ import s from './app.module.scss'
|
|||||||
|
|
||||||
export default function App({ error, url, title }) {
|
export default function App({ error, url, title }) {
|
||||||
return (
|
return (
|
||||||
<div id='app' className={s.base}>
|
<LocationProvider>
|
||||||
<Head>
|
<div id='app' className={s.base}>
|
||||||
<title>{title || 'Untitled'}</title>
|
<Head>
|
||||||
</Head>
|
<title>{title || 'Untitled'}</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
<Header routes={routes} />
|
<Header routes={routes} />
|
||||||
|
|
||||||
<main className={s.main}>
|
<main className={s.main}>
|
||||||
{error ? (
|
{error ? (
|
||||||
<ErrorPage error={error} />
|
<ErrorPage error={error} />
|
||||||
) : (
|
) : (
|
||||||
<Router url={url}>
|
<Router>
|
||||||
{routes.map((route) => (
|
{routes.map((route) => (
|
||||||
// @ts-ignore
|
<Route key={route.path} route={route} path={route.path} component={route.component} />
|
||||||
<route.component key={route.path} path={route.path} route={route} />
|
))}
|
||||||
))}
|
</Router>
|
||||||
</Router>
|
)}
|
||||||
)}
|
</main>
|
||||||
</main>
|
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
</LocationProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,13 @@ const Header = ({ routes }) => (
|
|||||||
<h1>BRF Tegeltrasten</h1>
|
<h1>BRF Tegeltrasten</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
{routes.map((route) => (
|
{routes.map((route) =>
|
||||||
<li key={route.path}>
|
route.nav !== false ? (
|
||||||
<a href={route.path}>{route.title}</a>
|
<li key={route.path}>
|
||||||
</li>
|
<a href={route.path}>{route.title}</a>
|
||||||
))}
|
</li>
|
||||||
|
) : null,
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
31
client/public/components/invoice.tsx
Normal file
31
client/public/components/invoice.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { h, type FunctionalComponent } from 'preact'
|
||||||
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import rek from 'rek'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
year: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Invoices: FunctionalComponent<Props> = ({ year }) => {
|
||||||
|
const [invoices, setInvoices] = useState([])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
rek(`/api/invoices/by-year/${year}`).then(setInvoices)
|
||||||
|
}, [year])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{invoices.map((invoice) => (
|
||||||
|
<tr>
|
||||||
|
<td>{invoice.accountNumber}</td>
|
||||||
|
<td>{invoice.description}</td>
|
||||||
|
<td>{invoice.amount}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Invoices
|
||||||
0
client/public/components/invoices.tsx
Normal file
0
client/public/components/invoices.tsx
Normal file
65
client/public/components/invoices_by_supplier_page.tsx
Normal file
65
client/public/components/invoices_by_supplier_page.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { h } from 'preact'
|
||||||
|
import Format from 'easy-tz/format'
|
||||||
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import { useRoute } from 'preact-iso'
|
||||||
|
import rek from 'rek'
|
||||||
|
import Head from './head.ts'
|
||||||
|
|
||||||
|
const format = Format.bind(null, null, 'YYYY.MM.DD')
|
||||||
|
|
||||||
|
const InvoicesPage = () => {
|
||||||
|
const [supplier, setSupplier] = useState(null)
|
||||||
|
const [invoices, setInvoices] = useState([])
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
rek(`/api/suppliers/${route.params.supplier}`).then((supplier) => setSupplier(supplier))
|
||||||
|
rek(`/api/invoices?supplier=${route.params.supplier}`).then((invoices) => setInvoices(invoices))
|
||||||
|
}, [route.params.supplier])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<Head>
|
||||||
|
<title> : Invoices : {supplier?.name}</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<h1>Invoices for {supplier?.name}</h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Fisken</th>
|
||||||
|
<th>PHM</th>
|
||||||
|
<th>Invoice Date</th>
|
||||||
|
<th>Due Date</th>
|
||||||
|
<th>Number</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Files</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{invoices.map((invoice) => (
|
||||||
|
<tr>
|
||||||
|
<td>{invoice.id}</td>
|
||||||
|
<td>{invoice.fiskenNumber}</td>
|
||||||
|
<td>{invoice.phmNumber}</td>
|
||||||
|
<td>{format(invoice.invoiceDate)}</td>
|
||||||
|
<td>{invoice.dueDate && format(invoice.dueDate)}</td>
|
||||||
|
<td>{invoice.invoiceNumber}</td>
|
||||||
|
<td>{invoice.amount}</td>
|
||||||
|
<td>
|
||||||
|
{invoice.files?.map((file) => (
|
||||||
|
<a href={`/uploads/invoices/${file.filename}`}>{file.filename}</a>
|
||||||
|
))}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InvoicesPage
|
||||||
39
client/public/components/invoices_page.tsx
Normal file
39
client/public/components/invoices_page.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { h } from 'preact'
|
||||||
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import rek from 'rek'
|
||||||
|
import Head from './head.ts'
|
||||||
|
import Invoice from './invoice.tsx'
|
||||||
|
|
||||||
|
const InvoicesPage = () => {
|
||||||
|
const [suppliers, setSuppliers] = useState([])
|
||||||
|
const [financialYears, setFinancialYears] = useState([])
|
||||||
|
const [currentYear, setCurrentYear] = useState<number>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
rek('/api/suppliers').then((suppliers) => setSuppliers(suppliers))
|
||||||
|
// rek('/api/financial-years').then((financialYears) => {
|
||||||
|
// setFinancialYears(financialYears)
|
||||||
|
// setCurrentYear(financialYears[financialYears.length - 1].year)
|
||||||
|
// })
|
||||||
|
}, [])
|
||||||
|
console.log(suppliers)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<Head>
|
||||||
|
<title> : Invoices</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
<h1>Invoices</h1>
|
||||||
|
<ul>
|
||||||
|
{suppliers?.map((supplier) => (
|
||||||
|
<li>
|
||||||
|
<a href={`/invoices/by-supplier/${supplier.id}`}>{supplier.name}</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InvoicesPage
|
||||||
@ -1,4 +1,6 @@
|
|||||||
import Start from './components/start_page.tsx'
|
import Start from './components/start_page.tsx'
|
||||||
|
import Invoices from './components/invoices_page.tsx'
|
||||||
|
import InvoicesBySupplier from './components/invoices_by_supplier_page.tsx'
|
||||||
import Objects from './components/objects_page.tsx'
|
import Objects from './components/objects_page.tsx'
|
||||||
import Results from './components/results_page.tsx'
|
import Results from './components/results_page.tsx'
|
||||||
|
|
||||||
@ -15,6 +17,19 @@ export default [
|
|||||||
title: 'Objects',
|
title: 'Objects',
|
||||||
component: Objects,
|
component: Objects,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/invoices',
|
||||||
|
name: 'invoices',
|
||||||
|
title: 'Invoices',
|
||||||
|
component: Invoices,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/invoices/by-supplier/:supplier',
|
||||||
|
name: 'invoices',
|
||||||
|
title: 'Invoices',
|
||||||
|
nav: false,
|
||||||
|
component: InvoicesBySupplier,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/results',
|
path: '/results',
|
||||||
name: 'results',
|
name: 'results',
|
||||||
|
|||||||
@ -17,6 +17,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./client:/home/node/brf_books/client
|
- ./client:/home/node/brf_books/client
|
||||||
- ./server:/home/node/brf_books/server
|
- ./server:/home/node/brf_books/server
|
||||||
|
- ./uploads:/home/node/brf_books/uploads
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
- redis
|
- redis
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
-- PostgreSQL database dump
|
-- PostgreSQL database dump
|
||||||
--
|
--
|
||||||
|
|
||||||
\restrict H2xBPQq6I6IQHZkAgiuKoY9lao4r4KAPtiyNvDE9oc0DN75cJ1gNbkoGFqutWDp
|
\restrict x1LNwo1MrXgJU7KVXELaKlpEPpIZLjRGuaweMIify4ofZcwqTGzXVX5DkRI11Hx
|
||||||
|
|
||||||
-- Dumped from database version 18.1
|
-- Dumped from database version 18.1
|
||||||
-- Dumped by pg_dump version 18.1
|
-- Dumped by pg_dump version 18.1
|
||||||
@ -156,6 +156,46 @@ CREATE SEQUENCE public.entry_id_seq
|
|||||||
ALTER SEQUENCE public.entry_id_seq OWNED BY public.entry.id;
|
ALTER SEQUENCE public.entry_id_seq OWNED BY public.entry.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: file; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.file (
|
||||||
|
id integer NOT NULL,
|
||||||
|
filename text CONSTRAINT file_file_not_null NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: file_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.file_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: file_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.file_id_seq OWNED BY public.file.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: files_to_invoice; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.files_to_invoice (
|
||||||
|
invoice_id integer NOT NULL,
|
||||||
|
file_id integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: financial_year; Type: TABLE; Schema: public; Owner: -
|
-- Name: financial_year; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -188,6 +228,44 @@ CREATE SEQUENCE public.financial_year_id_seq
|
|||||||
ALTER SEQUENCE public.financial_year_id_seq OWNED BY public.financial_year.id;
|
ALTER SEQUENCE public.financial_year_id_seq OWNED BY public.financial_year.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.invoice (
|
||||||
|
id integer NOT NULL,
|
||||||
|
financial_year_id integer,
|
||||||
|
supplier_id integer NOT NULL,
|
||||||
|
fisken_number integer,
|
||||||
|
phm_number integer,
|
||||||
|
invoice_number text,
|
||||||
|
invoice_date date CONSTRAINT invoice_date_not_null NOT NULL,
|
||||||
|
due_date date,
|
||||||
|
ocr text,
|
||||||
|
amount numeric(12,2)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.invoice_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.invoice_id_seq OWNED BY public.invoice.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: journal; Type: TABLE; Schema: public; Owner: -
|
-- Name: journal; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -251,6 +329,67 @@ CREATE SEQUENCE public.object_id_seq
|
|||||||
ALTER SEQUENCE public.object_id_seq OWNED BY public.object.id;
|
ALTER SEQUENCE public.object_id_seq OWNED BY public.object.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.supplier (
|
||||||
|
id integer NOT NULL,
|
||||||
|
name text,
|
||||||
|
supplier_type_id integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.supplier_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.supplier_id_seq OWNED BY public.supplier.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_type; Type: TABLE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE public.supplier_type (
|
||||||
|
id integer NOT NULL,
|
||||||
|
name text NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_type_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.supplier_type_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_type_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE public.supplier_type_id_seq OWNED BY public.supplier_type.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: transaction; Type: TABLE; Schema: public; Owner: -
|
-- Name: transaction; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -264,7 +403,8 @@ CREATE TABLE public.transaction (
|
|||||||
description text,
|
description text,
|
||||||
transaction_date date,
|
transaction_date date,
|
||||||
quantity numeric(12,2),
|
quantity numeric(12,2),
|
||||||
signature text
|
signature text,
|
||||||
|
invoice_id integer
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -319,6 +459,13 @@ ALTER TABLE ONLY public.dimension ALTER COLUMN id SET DEFAULT nextval('public.di
|
|||||||
ALTER TABLE ONLY public.entry ALTER COLUMN id SET DEFAULT nextval('public.entry_id_seq'::regclass);
|
ALTER TABLE ONLY public.entry ALTER COLUMN id SET DEFAULT nextval('public.entry_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: file id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.file ALTER COLUMN id SET DEFAULT nextval('public.file_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: financial_year id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: financial_year id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -326,6 +473,13 @@ ALTER TABLE ONLY public.entry ALTER COLUMN id SET DEFAULT nextval('public.entry_
|
|||||||
ALTER TABLE ONLY public.financial_year ALTER COLUMN id SET DEFAULT nextval('public.financial_year_id_seq'::regclass);
|
ALTER TABLE ONLY public.financial_year ALTER COLUMN id SET DEFAULT nextval('public.financial_year_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.invoice ALTER COLUMN id SET DEFAULT nextval('public.invoice_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: journal id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: journal id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -340,6 +494,20 @@ ALTER TABLE ONLY public.journal ALTER COLUMN id SET DEFAULT nextval('public.jour
|
|||||||
ALTER TABLE ONLY public.object ALTER COLUMN id SET DEFAULT nextval('public.object_id_seq'::regclass);
|
ALTER TABLE ONLY public.object ALTER COLUMN id SET DEFAULT nextval('public.object_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.supplier ALTER COLUMN id SET DEFAULT nextval('public.supplier_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_type id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.supplier_type ALTER COLUMN id SET DEFAULT nextval('public.supplier_type_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: transaction id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: transaction id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -387,6 +555,22 @@ ALTER TABLE ONLY public.entry
|
|||||||
ADD CONSTRAINT entry_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT entry_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: file file_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.file
|
||||||
|
ADD CONSTRAINT file_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: files_to_invoice files_to_invoice_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.files_to_invoice
|
||||||
|
ADD CONSTRAINT files_to_invoice_pkey PRIMARY KEY (invoice_id, file_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: financial_year financial_year_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: financial_year financial_year_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -411,6 +595,14 @@ ALTER TABLE ONLY public.financial_year
|
|||||||
ADD CONSTRAINT financial_year_year_key UNIQUE (year);
|
ADD CONSTRAINT financial_year_year_key UNIQUE (year);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice invoice_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.invoice
|
||||||
|
ADD CONSTRAINT invoice_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: journal journal_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: journal journal_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -435,6 +627,22 @@ ALTER TABLE ONLY public.object
|
|||||||
ADD CONSTRAINT object_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT object_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier supplier_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.supplier
|
||||||
|
ADD CONSTRAINT supplier_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_type supplier_type_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.supplier_type
|
||||||
|
ADD CONSTRAINT supplier_type_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: transaction transaction_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: transaction transaction_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -451,6 +659,38 @@ ALTER TABLE ONLY public.transactions_to_objects
|
|||||||
ADD CONSTRAINT transactions_to_objects_transaction_id_object_id_key UNIQUE (transaction_id, object_id);
|
ADD CONSTRAINT transactions_to_objects_transaction_id_object_id_key UNIQUE (transaction_id, object_id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: files_to_invoice files_to_invoice_file_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.files_to_invoice
|
||||||
|
ADD CONSTRAINT files_to_invoice_file_id_fkey FOREIGN KEY (file_id) REFERENCES public.file(id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: files_to_invoice files_to_invoice_invoice_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.files_to_invoice
|
||||||
|
ADD CONSTRAINT files_to_invoice_invoice_id_fkey FOREIGN KEY (invoice_id) REFERENCES public.invoice(id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice invoice_financial_year_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.invoice
|
||||||
|
ADD CONSTRAINT invoice_financial_year_id_fkey FOREIGN KEY (financial_year_id) REFERENCES public.financial_year(id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice invoice_supplier_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.invoice
|
||||||
|
ADD CONSTRAINT invoice_supplier_id_fkey FOREIGN KEY (supplier_id) REFERENCES public.supplier(id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: object object_dimension_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: object object_dimension_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -459,6 +699,14 @@ ALTER TABLE ONLY public.object
|
|||||||
ADD CONSTRAINT object_dimension_id_fkey FOREIGN KEY (dimension_id) REFERENCES public.dimension(id);
|
ADD CONSTRAINT object_dimension_id_fkey FOREIGN KEY (dimension_id) REFERENCES public.dimension(id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier supplier_supplier_type_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.supplier
|
||||||
|
ADD CONSTRAINT supplier_supplier_type_id_fkey FOREIGN KEY (supplier_type_id) REFERENCES public.supplier_type(id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: transaction transaction_entry_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: transaction transaction_entry_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -467,6 +715,14 @@ ALTER TABLE ONLY public.transaction
|
|||||||
ADD CONSTRAINT transaction_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES public.entry(id);
|
ADD CONSTRAINT transaction_entry_id_fkey FOREIGN KEY (entry_id) REFERENCES public.entry(id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: transaction transaction_invoice_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.transaction
|
||||||
|
ADD CONSTRAINT transaction_invoice_id_fkey FOREIGN KEY (invoice_id) REFERENCES public.invoice(id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: transaction transaction_object_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: transaction transaction_object_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -495,5 +751,5 @@ ALTER TABLE ONLY public.transactions_to_objects
|
|||||||
-- PostgreSQL database dump complete
|
-- PostgreSQL database dump complete
|
||||||
--
|
--
|
||||||
|
|
||||||
\unrestrict H2xBPQq6I6IQHZkAgiuKoY9lao4r4KAPtiyNvDE9oc0DN75cJ1gNbkoGFqutWDp
|
\unrestrict x1LNwo1MrXgJU7KVXELaKlpEPpIZLjRGuaweMIify4ofZcwqTGzXVX5DkRI11Hx
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
--
|
||||||
|
-- PostgreSQL database dump
|
||||||
|
--
|
||||||
|
|
||||||
|
\restrict bwzPcLzyW22uigCF5UMc3FAcSU9hliUs5ZBJ4ZpwZeegYAG8Md8d7l0M55Czl7h
|
||||||
|
|
||||||
|
-- Dumped from database version 18.1
|
||||||
|
-- Dumped by pg_dump version 18.1
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET lock_timeout = 0;
|
||||||
|
SET idle_in_transaction_session_timeout = 0;
|
||||||
|
SET transaction_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = on;
|
||||||
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET xmloption = content;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET row_security = off;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Data for Name: supplier_type; Type: TABLE DATA; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
COPY public.supplier_type (id, name) FROM stdin;
|
||||||
|
1 Company
|
||||||
|
2 Person
|
||||||
|
\.
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: supplier_type_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT pg_catalog.setval('public.supplier_type_id_seq', 2, true);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- PostgreSQL database dump complete
|
||||||
|
--
|
||||||
|
|
||||||
|
\unrestrict bwzPcLzyW22uigCF5UMc3FAcSU9hliUs5ZBJ4ZpwZeegYAG8Md8d7l0M55Czl7h
|
||||||
|
|
||||||
@ -20,7 +20,7 @@
|
|||||||
"test": "pnpm run test:client && pnpm run test:server",
|
"test": "pnpm run test:client && pnpm run test:server",
|
||||||
"test:client": "node --no-warnings --import=./client/test/jsdom_polyfills.ts --import=./client/test/register_tsx_hook.ts --test ./client/**/*.test.ts{,x}",
|
"test:client": "node --no-warnings --import=./client/test/jsdom_polyfills.ts --import=./client/test/register_tsx_hook.ts --test ./client/**/*.test.ts{,x}",
|
||||||
"test:server": "node --no-warnings --test ./server/**/*.test.ts",
|
"test:server": "node --no-warnings --test ./server/**/*.test.ts",
|
||||||
"types": "tsgo"
|
"types": "tsgo --skipLibCheck"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bmp/console": "^0.1.0",
|
"@bmp/console": "^0.1.0",
|
||||||
@ -29,6 +29,7 @@
|
|||||||
"@fastify/static": "^8.3.0",
|
"@fastify/static": "^8.3.0",
|
||||||
"@fastify/type-provider-typebox": "^6.1.0",
|
"@fastify/type-provider-typebox": "^6.1.0",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
|
"easy-tz": "^0.2.0",
|
||||||
"fastify": "^5.6.2",
|
"fastify": "^5.6.2",
|
||||||
"fastify-plugin": "^5.1.0",
|
"fastify-plugin": "^5.1.0",
|
||||||
"knex": "^3.1.0",
|
"knex": "^3.1.0",
|
||||||
@ -38,7 +39,7 @@
|
|||||||
"pg-protocol": "^1.10.3",
|
"pg-protocol": "^1.10.3",
|
||||||
"pino-abstract-transport": "^3.0.0",
|
"pino-abstract-transport": "^3.0.0",
|
||||||
"preact": "^10.27.2",
|
"preact": "^10.27.2",
|
||||||
"preact-router": "^4.1.2",
|
"preact-iso": "^2.11.0",
|
||||||
"rek": "^0.8.1"
|
"rek": "^0.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -48,6 +49,7 @@
|
|||||||
"@types/lodash": "^4.17.16",
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
"@typescript/native-preview": "7.0.0-dev.20251126.1",
|
"@typescript/native-preview": "7.0.0-dev.20251126.1",
|
||||||
|
"d3-dsv": "^3.0.1",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
|
|||||||
58
pnpm-lock.yaml
generated
58
pnpm-lock.yaml
generated
@ -26,6 +26,9 @@ importers:
|
|||||||
chalk:
|
chalk:
|
||||||
specifier: ^5.6.2
|
specifier: ^5.6.2
|
||||||
version: 5.6.2
|
version: 5.6.2
|
||||||
|
easy-tz:
|
||||||
|
specifier: ^0.2.0
|
||||||
|
version: 0.2.0
|
||||||
fastify:
|
fastify:
|
||||||
specifier: ^5.6.2
|
specifier: ^5.6.2
|
||||||
version: 5.6.2
|
version: 5.6.2
|
||||||
@ -53,9 +56,9 @@ importers:
|
|||||||
preact:
|
preact:
|
||||||
specifier: ^10.27.2
|
specifier: ^10.27.2
|
||||||
version: 10.27.2
|
version: 10.27.2
|
||||||
preact-router:
|
preact-iso:
|
||||||
specifier: ^4.1.2
|
specifier: ^2.11.0
|
||||||
version: 4.1.2(preact@10.27.2)
|
version: 2.11.0(preact-render-to-string@6.6.3(preact@10.27.2))(preact@10.27.2)
|
||||||
rek:
|
rek:
|
||||||
specifier: ^0.8.1
|
specifier: ^0.8.1
|
||||||
version: 0.8.1
|
version: 0.8.1
|
||||||
@ -78,6 +81,9 @@ importers:
|
|||||||
'@typescript/native-preview':
|
'@typescript/native-preview':
|
||||||
specifier: 7.0.0-dev.20251126.1
|
specifier: 7.0.0-dev.20251126.1
|
||||||
version: 7.0.0-dev.20251126.1
|
version: 7.0.0-dev.20251126.1
|
||||||
|
d3-dsv:
|
||||||
|
specifier: ^3.0.1
|
||||||
|
version: 3.0.1
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.27.0
|
specifier: ^0.27.0
|
||||||
version: 0.27.0
|
version: 0.27.0
|
||||||
@ -1114,6 +1120,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==}
|
resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
commander@7.2.0:
|
||||||
|
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@ -1144,6 +1154,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==}
|
resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
d3-dsv@3.0.1:
|
||||||
|
resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
data-urls@6.0.0:
|
data-urls@6.0.0:
|
||||||
resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==}
|
resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
@ -1217,6 +1232,9 @@ packages:
|
|||||||
eastasianwidth@0.2.0:
|
eastasianwidth@0.2.0:
|
||||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||||
|
|
||||||
|
easy-tz@0.2.0:
|
||||||
|
resolution: {integrity: sha512-Mf+tTNHaAUBqEMo9mvIdCIV5kXCazRCxGKH16itMxefrHy/FtHS5tnfOOS0DKMWU7rl/MnN9PzjdFfn8JCYqxg==}
|
||||||
|
|
||||||
electron-to-chromium@1.5.259:
|
electron-to-chromium@1.5.259:
|
||||||
resolution: {integrity: sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==}
|
resolution: {integrity: sha512-I+oLXgpEJzD6Cwuwt1gYjxsDmu/S/Kd41mmLA3O+/uH2pFRO/DvOjUyGozL8j3KeLV6WyZ7ssPwELMsXCcsJAQ==}
|
||||||
|
|
||||||
@ -1848,10 +1866,16 @@ packages:
|
|||||||
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
preact-router@4.1.2:
|
preact-iso@2.11.0:
|
||||||
resolution: {integrity: sha512-uICUaUFYh+XQ+6vZtQn1q+X6rSqwq+zorWOCLWPF5FAsQh3EJ+RsDQ9Ee+fjk545YWQHfUxhrBAaemfxEnMOUg==}
|
resolution: {integrity: sha512-oThWJQcgcnaWh6UKy1qrBkxIWp5CkqvnHiFdLiDUxfNkGdpQ5veGQw9wOVS0NDp7X8xo98wxE4wng5jLv1e9Ug==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
preact: '>=10'
|
preact: '>=10 || >= 11.0.0-0'
|
||||||
|
preact-render-to-string: '>=6.4.0'
|
||||||
|
|
||||||
|
preact-render-to-string@6.6.3:
|
||||||
|
resolution: {integrity: sha512-7oHG7jzjriqsFPkSPiPnzrQ0GcxFm6wOkYWNdStK5Ks9YlWSQQXKGBRAX4nKDdqX7HAQuRvI4pZNZMycK4WwDw==}
|
||||||
|
peerDependencies:
|
||||||
|
preact: '>=10 || >= 11.0.0-0'
|
||||||
|
|
||||||
preact@10.27.2:
|
preact@10.27.2:
|
||||||
resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==}
|
resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==}
|
||||||
@ -1933,6 +1957,9 @@ packages:
|
|||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
rw@1.3.3:
|
||||||
|
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
|
||||||
|
|
||||||
safe-buffer@5.2.1:
|
safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
@ -3093,6 +3120,8 @@ snapshots:
|
|||||||
|
|
||||||
commander@14.0.2: {}
|
commander@14.0.2: {}
|
||||||
|
|
||||||
|
commander@7.2.0: {}
|
||||||
|
|
||||||
content-disposition@0.5.4:
|
content-disposition@0.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@ -3128,6 +3157,12 @@ snapshots:
|
|||||||
'@csstools/css-syntax-patches-for-csstree': 1.0.17
|
'@csstools/css-syntax-patches-for-csstree': 1.0.17
|
||||||
css-tree: 3.1.0
|
css-tree: 3.1.0
|
||||||
|
|
||||||
|
d3-dsv@3.0.1:
|
||||||
|
dependencies:
|
||||||
|
commander: 7.2.0
|
||||||
|
iconv-lite: 0.6.3
|
||||||
|
rw: 1.3.3
|
||||||
|
|
||||||
data-urls@6.0.0:
|
data-urls@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-mimetype: 4.0.0
|
whatwg-mimetype: 4.0.0
|
||||||
@ -3211,6 +3246,8 @@ snapshots:
|
|||||||
|
|
||||||
eastasianwidth@0.2.0: {}
|
eastasianwidth@0.2.0: {}
|
||||||
|
|
||||||
|
easy-tz@0.2.0: {}
|
||||||
|
|
||||||
electron-to-chromium@1.5.259: {}
|
electron-to-chromium@1.5.259: {}
|
||||||
|
|
||||||
emoji-regex@10.6.0: {}
|
emoji-regex@10.6.0: {}
|
||||||
@ -3881,7 +3918,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
xtend: 4.0.2
|
xtend: 4.0.2
|
||||||
|
|
||||||
preact-router@4.1.2(preact@10.27.2):
|
preact-iso@2.11.0(preact-render-to-string@6.6.3(preact@10.27.2))(preact@10.27.2):
|
||||||
|
dependencies:
|
||||||
|
preact: 10.27.2
|
||||||
|
preact-render-to-string: 6.6.3(preact@10.27.2)
|
||||||
|
|
||||||
|
preact-render-to-string@6.6.3(preact@10.27.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
preact: 10.27.2
|
preact: 10.27.2
|
||||||
|
|
||||||
@ -3973,6 +4015,8 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc': 4.53.3
|
'@rollup/rollup-win32-x64-msvc': 4.53.3
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
rw@1.3.3: {}
|
||||||
|
|
||||||
safe-buffer@5.2.1: {}
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
safe-regex-test@1.1.0:
|
safe-regex-test@1.1.0:
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import _ from 'lodash'
|
||||||
import { Type, type Static, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
|
import { Type, type Static, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
|
||||||
import knex from '../lib/knex.ts'
|
import knex from '../lib/knex.ts'
|
||||||
import StatusError from '../lib/status_error.ts'
|
import StatusError from '../lib/status_error.ts'
|
||||||
@ -19,6 +20,102 @@ const apiRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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({
|
fastify.route({
|
||||||
url: '/objects',
|
url: '/objects',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@ -122,6 +219,27 @@ const apiRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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()
|
done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import fastify, { type FastifyServerOptions } from 'fastify'
|
import fastify, { type FastifyServerOptions } from 'fastify'
|
||||||
|
import fstatic from '@fastify/static'
|
||||||
import StatusError from './lib/status_error.ts'
|
import StatusError from './lib/status_error.ts'
|
||||||
import env from './env.ts'
|
import env from './env.ts'
|
||||||
import ErrorHandler from './handlers/error.ts'
|
import ErrorHandler from './handlers/error.ts'
|
||||||
@ -13,7 +14,10 @@ export default async (options: FastifyServerOptions) => {
|
|||||||
throw new StatusError(404)
|
throw new StatusError(404)
|
||||||
})
|
})
|
||||||
|
|
||||||
console.dir(env)
|
server.register(fstatic, {
|
||||||
|
root: new URL('../uploads', import.meta.url),
|
||||||
|
prefix: '/uploads/',
|
||||||
|
})
|
||||||
|
|
||||||
server.register(vitePlugin, {
|
server.register(vitePlugin, {
|
||||||
mode: env.NODE_ENV,
|
mode: env.NODE_ENV,
|
||||||
|
|||||||
@ -12,5 +12,5 @@
|
|||||||
"erasableSyntaxOnly": true,
|
"erasableSyntaxOnly": true,
|
||||||
"allowArbitraryExtensions": true
|
"allowArbitraryExtensions": true
|
||||||
},
|
},
|
||||||
"include": ["global.d.ts", "client", "server"]
|
"include": ["global.d.ts", "bin", "client", "server"]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user