WIP more auth work and convert to kysely
This commit is contained in:
parent
2c18a61315
commit
04e50a3021
15
.bruno/BRF/Admissions.bru
Normal file
15
.bruno/BRF/Admissions.bru
Normal file
@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: Admissions
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{base_url}}/api/admissions
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
15
.bruno/BRF/Invites.bru
Normal file
15
.bruno/BRF/Invites.bru
Normal file
@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: Invites
|
||||
type: http
|
||||
seq: 8
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:4040/api/invites
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
15
.bruno/BRF/Roles.bru
Normal file
15
.bruno/BRF/Roles.bru
Normal file
@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: Roles
|
||||
type: http
|
||||
seq: 17
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{base_url}}/api/roles
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
15
.bruno/BRF/Users.bru
Normal file
15
.bruno/BRF/Users.bru
Normal file
@ -0,0 +1,15 @@
|
||||
meta {
|
||||
name: Users
|
||||
type: http
|
||||
seq: 9
|
||||
}
|
||||
|
||||
get {
|
||||
url: http://localhost:4040/api/users
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
|
||||
headers {
|
||||
Accept: application/json
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/balances
|
||||
type: http
|
||||
seq: 15
|
||||
seq: 3
|
||||
}
|
||||
|
||||
get {
|
||||
@ -12,4 +12,5 @@ get {
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/entries/:id
|
||||
type: http
|
||||
seq: 4
|
||||
seq: 5
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/entries
|
||||
type: http
|
||||
seq: 3
|
||||
seq: 4
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/financial-years
|
||||
type: http
|
||||
seq: 5
|
||||
seq: 6
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/invoices/:id
|
||||
type: http
|
||||
seq: 8
|
||||
seq: 10
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -5,11 +5,17 @@ meta {
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{base_url}}/api/invoices/total-amount
|
||||
url: {{base_url}}/api/invoices/total-amount?supplier=150
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
supplier: 150
|
||||
:
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/invoices
|
||||
type: http
|
||||
seq: 8
|
||||
seq: 9
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/objects/:id
|
||||
type: http
|
||||
seq: 6
|
||||
seq: 7
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/objects
|
||||
type: http
|
||||
seq: 7
|
||||
seq: 8
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/results/:year
|
||||
type: http
|
||||
seq: 12
|
||||
seq: 14
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
meta {
|
||||
name: /api/results
|
||||
type: http
|
||||
seq: 11
|
||||
seq: 12
|
||||
}
|
||||
|
||||
get {
|
||||
|
||||
@ -6,10 +6,21 @@ meta {
|
||||
|
||||
post {
|
||||
url: {{base_url}}/api/suppliers/merge
|
||||
body: none
|
||||
body: json
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"ids": [ 105, 203 ]
|
||||
}
|
||||
}
|
||||
|
||||
body:multipart-form {
|
||||
ids: [
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
meta {
|
||||
name: /api/suppliers
|
||||
type: http
|
||||
seq: 10
|
||||
seq: 11
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{base_url}}/
|
||||
url: {{base_url}}/api/suppliers
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
meta {
|
||||
name: /api/transactions
|
||||
type: http
|
||||
seq: 14
|
||||
seq: 16
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{base_url}}/api/transactions
|
||||
url: {{base_url}}/api/transactions?year=2020&accountNumber=4800
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
params:query {
|
||||
year: 2020
|
||||
accountNumber: 4800
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
}
|
||||
|
||||
@ -20,7 +20,8 @@
|
||||
"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:server": "node --env-file .env.testing --no-warnings --test ./server/**/*.test.ts",
|
||||
"types": "tsgo --skipLibCheck"
|
||||
"types": "tsgo --skipLibCheck",
|
||||
"types:tsc": "tsc --skipLibCheck"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bmp/console": "^0.1.0",
|
||||
@ -37,8 +38,10 @@
|
||||
"fastify": "^5.6.2",
|
||||
"fastify-plugin": "^5.1.0",
|
||||
"fastify-session-redis-store": "^7.1.2",
|
||||
"fastify-type-provider-zod": "^6.1.0",
|
||||
"ioredis": "^5.8.2",
|
||||
"knex": "^3.1.0",
|
||||
"kysely": "^0.28.9",
|
||||
"lodash": "^4.17.21",
|
||||
"lowline": "^0.4.2",
|
||||
"mini-qs": "^0.2.0",
|
||||
@ -48,7 +51,8 @@
|
||||
"preact": "^10.28.0",
|
||||
"preact-iso": "^2.11.0",
|
||||
"preact-router": "^4.1.2",
|
||||
"rek": "^0.8.1"
|
||||
"rek": "^0.8.1",
|
||||
"zod": "^4.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.26.10",
|
||||
|
||||
66
pnpm-lock.yaml
generated
66
pnpm-lock.yaml
generated
@ -50,12 +50,18 @@ importers:
|
||||
fastify-session-redis-store:
|
||||
specifier: ^7.1.2
|
||||
version: 7.1.2(@fastify/session@11.1.1)
|
||||
fastify-type-provider-zod:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0(@fastify/swagger@9.6.1)(fastify@5.6.2)(openapi-types@12.1.3)(zod@4.2.1)
|
||||
ioredis:
|
||||
specifier: ^5.8.2
|
||||
version: 5.8.2
|
||||
knex:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0(pg@8.16.3)
|
||||
kysely:
|
||||
specifier: ^0.28.9
|
||||
version: 0.28.9
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
@ -86,6 +92,9 @@ importers:
|
||||
rek:
|
||||
specifier: ^0.8.1
|
||||
version: 0.8.1
|
||||
zod:
|
||||
specifier: ^4.2.1
|
||||
version: 4.2.1
|
||||
devDependencies:
|
||||
'@babel/core':
|
||||
specifier: ^7.26.10
|
||||
@ -642,6 +651,9 @@ packages:
|
||||
'@fastify/static@8.3.0':
|
||||
resolution: {integrity: sha512-yKxviR5PH1OKNnisIzZKmgZSus0r2OZb8qCSbqmw34aolT4g3UlzYfeBRym+HJ1J471CR8e2ldNub4PubD1coA==}
|
||||
|
||||
'@fastify/swagger@9.6.1':
|
||||
resolution: {integrity: sha512-fKlpJqFMWoi4H3EdUkDaMteEYRCfQMEkK0HJJ0eaf4aRlKd8cbq0pVkOfXDXmtvMTXYcnx3E+l023eFDBsA1HA==}
|
||||
|
||||
'@fastify/type-provider-typebox@6.1.0':
|
||||
resolution: {integrity: sha512-k29cOitDRcZhMXVjtRq0+caKxdWoArz7su+dQWGzGWnFG+fSKhevgiZ7nexHWuXOEEQzgJlh6cptIMu69beaTA==}
|
||||
peerDependencies:
|
||||
@ -1382,6 +1394,14 @@ packages:
|
||||
peerDependencies:
|
||||
'@fastify/session': '>=10'
|
||||
|
||||
fastify-type-provider-zod@6.1.0:
|
||||
resolution: {integrity: sha512-Sl19VZFSX4W/+AFl3hkL5YgWk3eDXZ4XYOdrq94HunK+o7GQBCAqgk7+3gPXoWkF0bNxOiIgfnFGJJ3i9a2BtQ==}
|
||||
peerDependencies:
|
||||
'@fastify/swagger': '>=9.5.1'
|
||||
fastify: ^5.5.0
|
||||
openapi-types: ^12.1.3
|
||||
zod: '>=4.1.5'
|
||||
|
||||
fastify@5.6.2:
|
||||
resolution: {integrity: sha512-dPugdGnsvYkBlENLhCgX8yhyGCsCPrpA8lFWbTNU428l+YOnLgYHR69hzV8HWPC79n536EqzqQtvhtdaCE0dKg==}
|
||||
|
||||
@ -1655,6 +1675,10 @@ packages:
|
||||
json-schema-ref-resolver@3.0.0:
|
||||
resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==}
|
||||
|
||||
json-schema-resolver@3.0.0:
|
||||
resolution: {integrity: sha512-HqMnbz0tz2DaEJ3ntsqtx3ezzZyDE7G56A/pPY/NGmrPu76UzsWquOpHFRAf5beTNXoH2LU5cQePVvRli1nchA==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
json-schema-traverse@1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
@ -1694,6 +1718,10 @@ packages:
|
||||
kolorist@1.8.0:
|
||||
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
|
||||
|
||||
kysely@0.28.9:
|
||||
resolution: {integrity: sha512-3BeXMoiOhpOwu62CiVpO6lxfq4eS6KMYfQdMsN/2kUCRNuF2YiEr7u0HLHaQU+O4Xu8YXE3bHVkwaQ85i72EuA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
light-my-request@6.6.0:
|
||||
resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==}
|
||||
|
||||
@ -1818,6 +1846,9 @@ packages:
|
||||
resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
openapi-types@12.1.3:
|
||||
resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==}
|
||||
|
||||
oxlint@1.29.0:
|
||||
resolution: {integrity: sha512-YqUVUhTYDqazV2qu3QSQn/H4Z1OP+fTnedgZWDk1/lDZxGfR0b1MqRVaEm3rRjBMLHP0zXlriIWUx+DD6UMaPA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@ -2384,6 +2415,9 @@ packages:
|
||||
engines: {node: '>= 14.6'}
|
||||
hasBin: true
|
||||
|
||||
zod@4.2.1:
|
||||
resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@acemir/cssom@0.9.23': {}
|
||||
@ -2785,6 +2819,16 @@ snapshots:
|
||||
fastq: 1.19.1
|
||||
glob: 11.1.0
|
||||
|
||||
'@fastify/swagger@9.6.1':
|
||||
dependencies:
|
||||
fastify-plugin: 5.1.0
|
||||
json-schema-resolver: 3.0.0
|
||||
openapi-types: 12.1.3
|
||||
rfdc: 1.4.1
|
||||
yaml: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@fastify/type-provider-typebox@6.1.0(typebox@1.0.55)':
|
||||
dependencies:
|
||||
typebox: 1.0.55
|
||||
@ -3487,6 +3531,14 @@ snapshots:
|
||||
dependencies:
|
||||
'@fastify/session': 11.1.1
|
||||
|
||||
fastify-type-provider-zod@6.1.0(@fastify/swagger@9.6.1)(fastify@5.6.2)(openapi-types@12.1.3)(zod@4.2.1):
|
||||
dependencies:
|
||||
'@fastify/error': 4.2.0
|
||||
'@fastify/swagger': 9.6.1
|
||||
fastify: 5.6.2
|
||||
openapi-types: 12.1.3
|
||||
zod: 4.2.1
|
||||
|
||||
fastify@5.6.2:
|
||||
dependencies:
|
||||
'@fastify/ajv-compiler': 4.0.5
|
||||
@ -3790,6 +3842,14 @@ snapshots:
|
||||
dependencies:
|
||||
dequal: 2.0.3
|
||||
|
||||
json-schema-resolver@3.0.0:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
fast-uri: 3.1.0
|
||||
rfdc: 1.4.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
json-schema-traverse@1.0.0: {}
|
||||
|
||||
json5@2.2.3: {}
|
||||
@ -3817,6 +3877,8 @@ snapshots:
|
||||
|
||||
kolorist@1.8.0: {}
|
||||
|
||||
kysely@0.28.9: {}
|
||||
|
||||
light-my-request@6.6.0:
|
||||
dependencies:
|
||||
cookie: 1.0.2
|
||||
@ -3937,6 +3999,8 @@ snapshots:
|
||||
dependencies:
|
||||
mimic-function: 5.0.1
|
||||
|
||||
openapi-types@12.1.3: {}
|
||||
|
||||
oxlint@1.29.0:
|
||||
optionalDependencies:
|
||||
'@oxlint/darwin-arm64': 1.29.0
|
||||
@ -4470,3 +4534,5 @@ snapshots:
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yaml@2.8.1: {}
|
||||
|
||||
zod@4.2.1: {}
|
||||
|
||||
17
server/lib/kysely.ts
Normal file
17
server/lib/kysely.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// @ts-ignore
|
||||
import { Pool } from 'pg'
|
||||
import { Kysely, PostgresDialect } from 'kysely'
|
||||
import env from '../env.ts'
|
||||
import type { DB } from '../../shared/types.db.ts'
|
||||
|
||||
const dialect = new PostgresDialect({
|
||||
pool: new Pool({
|
||||
database: env.PGDATABASE,
|
||||
host: env.PGHOST,
|
||||
password: env.PGPASSWORD,
|
||||
user: env.PGUSER,
|
||||
port: env.PGPORT,
|
||||
}),
|
||||
})
|
||||
|
||||
export default new Kysely<DB>({ dialect })
|
||||
47
server/lib/kysely_helpers.ts
Normal file
47
server/lib/kysely_helpers.ts
Normal file
@ -0,0 +1,47 @@
|
||||
// import type { QueryBuilder } from 'knex'
|
||||
import type { SelectQueryBuilder } from 'kysely'
|
||||
import _ from 'lodash'
|
||||
|
||||
// export function convertToReturning(obj: Record<string, string>) {
|
||||
// return _.map(obj, (value, key) => _.isString(value) && `${value} as ${key}`).filter(_.identity)
|
||||
// }
|
||||
|
||||
// export function columnAs(name: string, table: string, transformer = _.snakeCase) {
|
||||
// const transformed = transformer(name)
|
||||
|
||||
// if (transformed !== name) {
|
||||
// // knex automagically wraps everything in ", so they are not needed around ${name}
|
||||
// return `${table ? table + '.' : ''}${transformed} as ${name}`
|
||||
// }
|
||||
|
||||
// return table ? `${table}.${name}` : name
|
||||
// }
|
||||
|
||||
// export function columnBuilder(builder: QueryBuilder, columns: Record<string, string>, columnNames: string[]) {
|
||||
// for (const columnName of columnNames) {
|
||||
// const column = columns[columnName]
|
||||
|
||||
// if (column) {
|
||||
// // @ts-ignore
|
||||
// builder.column(column)
|
||||
// }
|
||||
// }
|
||||
|
||||
// return builder
|
||||
// }
|
||||
|
||||
export function where<DB, TB extends keyof DB, O>(builder: SelectQueryBuilder<DB, TB, O>, json: Record<string, ANY>) {
|
||||
return _.reduce(
|
||||
json,
|
||||
(builder, value, key) => {
|
||||
if (value === null) {
|
||||
return builder.where(key, 'is', null)
|
||||
} else if (Array.isArray(value)) {
|
||||
return builder.where(key, 'in', value)
|
||||
}
|
||||
|
||||
return builder.where(key, '=', value)
|
||||
},
|
||||
builder,
|
||||
)
|
||||
}
|
||||
78
server/lib/kysely_queries.ts
Normal file
78
server/lib/kysely_queries.ts
Normal file
@ -0,0 +1,78 @@
|
||||
// @ts-nocheck
|
||||
// import { type Knex } from 'kysely'
|
||||
// import _ from 'lodash'
|
||||
|
||||
// import { where } from './kysely_helpers.ts'
|
||||
|
||||
// type QueryName =
|
||||
// | 'create'
|
||||
// | 'createMany'
|
||||
// | 'find'
|
||||
// | 'findOne'
|
||||
// | 'findById'
|
||||
// | 'getAll'
|
||||
// | 'paginate'
|
||||
// | 'remove'
|
||||
// | 'removeById'
|
||||
// | 'replace'
|
||||
// | 'update'
|
||||
|
||||
// interface Options {
|
||||
// kysely: Knex
|
||||
// emitter?: ANY
|
||||
// pick?: QueryName[]
|
||||
// omit?: QueryName[]
|
||||
// columns: string[]
|
||||
// table: string
|
||||
// selects?: Record<string, ANY>
|
||||
// }
|
||||
|
||||
// export const count = ({ kysely, table, columns }: Pick<Options, 'kysely' | 'table' | 'columns'>) =>
|
||||
// function count(query: Record<string, ANY>, client = kysely) {
|
||||
// let builder = client.table(table)
|
||||
|
||||
// if (!_.isEmpty(query)) {
|
||||
// builder = where(builder, _.pick(query, columns))
|
||||
// }
|
||||
|
||||
// return builder.count().then((count) => parseInt(count[0].count, 10))
|
||||
// }
|
||||
|
||||
export const find = ({
|
||||
kysely,
|
||||
table,
|
||||
columns,
|
||||
allSelects,
|
||||
defaults = {},
|
||||
}: Pick<Options, 'kysely' | 'table' | 'columns'> & { allSelects: string[]; defaults: Record<string, any> }) =>
|
||||
function find(json, select, client: Knex) {
|
||||
if (!client) {
|
||||
// TODO figure out if better, eg instanceof, check is possible
|
||||
if (select && select.andWhereNotBetween) {
|
||||
client = select
|
||||
select = null
|
||||
} else {
|
||||
client = kysely
|
||||
}
|
||||
}
|
||||
|
||||
const { offset = defaults.offset, limit = defaults.limit, sort = defaults.sort, ...query } = json
|
||||
|
||||
let builder = client.table(table).select(select ? _.pick(allSelects, select) : allSelects)
|
||||
|
||||
if (!_.isEmpty(query)) {
|
||||
builder = where(builder, _.pick(query, columns))
|
||||
}
|
||||
|
||||
builder = builder.orderBy(sort || 'id', sort?.startsWith('-') ? 'desc' : 'asc')
|
||||
|
||||
if (limit) {
|
||||
builder = builder.limit(limit)
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
builder = builder.offset(offset)
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
17
server/plugins/db.ts
Normal file
17
server/plugins/db.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import type { FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
|
||||
import type { Kysely } from 'kysely'
|
||||
import type { DB } from '../../shared/types.db.ts'
|
||||
import fp from 'fastify-plugin'
|
||||
|
||||
const dbPlugin: FastifyPluginCallbackTypebox<{ kysely: Kysely<DB> }> = (fastify, { kysely }, done) => {
|
||||
fastify.decorate('db', kysely)
|
||||
|
||||
fastify.addHook('onClose', () => kysely.destroy())
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
export default fp(dbPlugin, {
|
||||
fastify: '5.x',
|
||||
name: 'dbPlugin',
|
||||
})
|
||||
@ -10,6 +10,7 @@ import journals from './api/journals.ts'
|
||||
import objects from './api/objects.ts'
|
||||
import process from './api/process.ts'
|
||||
import results from './api/results.ts'
|
||||
import roles from './api/roles.ts'
|
||||
import suppliers from './api/suppliers.ts'
|
||||
import transactions from './api/transactions.ts'
|
||||
|
||||
@ -23,6 +24,7 @@ const apiRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
fastify.register(objects, { prefix: '/objects' })
|
||||
fastify.register(process, { prefix: '/process' })
|
||||
fastify.register(results, { prefix: '/results' })
|
||||
fastify.register(roles, { prefix: '/roles' })
|
||||
fastify.register(suppliers, { prefix: '/suppliers' })
|
||||
fastify.register(transactions, { prefix: '/transactions' })
|
||||
|
||||
|
||||
@ -1,103 +1,152 @@
|
||||
import { Type, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
|
||||
import knex from '../../lib/knex.ts'
|
||||
import Queries from '../../services/roles/queries.ts'
|
||||
import _ from 'lodash'
|
||||
import * as z from 'zod'
|
||||
import { type FastifyPluginCallbackZod } from 'fastify-type-provider-zod'
|
||||
// import knex from '../../lib/knex.ts'
|
||||
// import Queries from '../../services/roles/queries.ts'
|
||||
|
||||
export const RoleFullSchema = Type.Object({
|
||||
id: Type.Number(),
|
||||
name: Type.String(),
|
||||
createdAt: Type.String(),
|
||||
createdById: Type.Number(),
|
||||
modifiedAt: Type.String(),
|
||||
modifiedById: Type.Number(),
|
||||
})
|
||||
import { RoleSchema } from '../../schemas/db.ts'
|
||||
|
||||
export const RoleSchema = Type.Pick(RoleFullSchema, ['id', 'name'])
|
||||
// export const RoleFullSchema = Type.Object({
|
||||
// id: Type.Number(),
|
||||
// name: Type.String(),
|
||||
// createdAt: Type.String(),
|
||||
// createdById: Type.Number(),
|
||||
// modifiedAt: Type.String(),
|
||||
// modifiedById: Type.Number(),
|
||||
// })
|
||||
|
||||
export const RoleVariableSchema = Type.Pick(RoleFullSchema, ['name', 'createdById'])
|
||||
// console.log(RoleFullSchema)
|
||||
|
||||
const rolesPlugin: FastifyPluginCallbackTypebox = (fastify, _options, done) => {
|
||||
const queries = Queries({ knex })
|
||||
// export const RoleSchema = Type.Pick(RoleFullSchema, ['id', 'name'])
|
||||
|
||||
fastify.addHook('onRequest', fastify.auth)
|
||||
// export const RoleVariableSchema = Type.Pick(RoleFullSchema, ['name', 'createdById'])
|
||||
|
||||
const rolesPlugin: FastifyPluginCallbackZod = (fastify, _options, done) => {
|
||||
// const queries = Queries({ knex })
|
||||
const { db } = fastify
|
||||
|
||||
// fastify.addHook('onRequest', fastify.auth)
|
||||
|
||||
fastify.route({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
schema: {
|
||||
querystring: RoleFullSchema,
|
||||
querystring: RoleSchema.partial().extend({
|
||||
limit: z.number().optional(),
|
||||
sort: z.keyof(RoleSchema).optional(),
|
||||
offset: z.number().optional(),
|
||||
}),
|
||||
response: {
|
||||
200: Type.Array(RoleFullSchema),
|
||||
200: z.array(RoleSchema),
|
||||
},
|
||||
},
|
||||
handler(request) {
|
||||
return queries.find(request.query)
|
||||
},
|
||||
})
|
||||
// if (!client) {
|
||||
// // TODO figure out if better, eg instanceof, check is possible
|
||||
// if (select && select.andWhereNotBetween) {
|
||||
// client = select
|
||||
// select = null
|
||||
// } else {
|
||||
// client = kysely
|
||||
// }
|
||||
// }
|
||||
|
||||
fastify.route({
|
||||
url: '/',
|
||||
method: 'POST',
|
||||
schema: {
|
||||
body: RoleVariableSchema,
|
||||
response: {
|
||||
201: RoleFullSchema,
|
||||
},
|
||||
},
|
||||
async handler(request, reply) {
|
||||
const newRole = request.session.userId
|
||||
? {
|
||||
...request.body,
|
||||
createdById: request.session.userId,
|
||||
const { offset, limit, sort, ...query } = request.query
|
||||
|
||||
let builder = db.selectFrom('role').selectAll()
|
||||
|
||||
// if (!_.isEmpty(query)) {
|
||||
// builder = where(builder, _.pick(query, columns))
|
||||
// }
|
||||
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value === null) {
|
||||
builder = builder.where(key, 'is', null)
|
||||
} else if (Array.isArray(value)) {
|
||||
builder = builder.where(key, 'in', value)
|
||||
} else {
|
||||
builder = builder.where(key, '=', value)
|
||||
}
|
||||
: request.body
|
||||
|
||||
return queries.create(newRole).then((row) => {
|
||||
return reply.header('Location', `${request.url}/${row.id}`).status(201).send(row)
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
url: '/:id',
|
||||
method: 'DELETE',
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
id: Type.Number(),
|
||||
}),
|
||||
response: {
|
||||
204: {},
|
||||
404: {},
|
||||
},
|
||||
},
|
||||
handler(request, reply) {
|
||||
return queries.removeById(request.params.id).then((count) => reply.status(count > 0 ? 204 : 404).send())
|
||||
},
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
url: '/:id',
|
||||
method: 'PATCH',
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
id: Type.Number(),
|
||||
}),
|
||||
body: RoleVariableSchema,
|
||||
response: {
|
||||
204: {},
|
||||
},
|
||||
},
|
||||
async handler(request) {
|
||||
const patch = request.session.userId
|
||||
? {
|
||||
...request.body,
|
||||
modifiedById: request.session.userId,
|
||||
}
|
||||
: request.body
|
||||
|
||||
return queries.update(request.params.id, patch)
|
||||
builder = builder.orderBy(sort || 'id', sort?.startsWith('-') ? 'desc' : 'asc')
|
||||
|
||||
if (limit) {
|
||||
builder = builder.limit(limit)
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
builder = builder.offset(offset)
|
||||
}
|
||||
|
||||
return builder.execute()
|
||||
},
|
||||
})
|
||||
|
||||
// fastify.route({
|
||||
// url: '/',
|
||||
// method: 'POST',
|
||||
// schema: {
|
||||
// body: RoleVariableSchema,
|
||||
// response: {
|
||||
// 201: RoleFullSchema,
|
||||
// },
|
||||
// },
|
||||
// async handler(request, reply) {
|
||||
// const newRole = request.session.userId
|
||||
// ? {
|
||||
// ...request.body,
|
||||
// createdById: request.session.userId,
|
||||
// }
|
||||
// : request.body
|
||||
|
||||
// return queries.create(newRole).then((row) => {
|
||||
// return reply.header('Location', `${request.url}/${row.id}`).status(201).send(row)
|
||||
// })
|
||||
// },
|
||||
// })
|
||||
|
||||
// fastify.route({
|
||||
// url: '/:id',
|
||||
// method: 'DELETE',
|
||||
// schema: {
|
||||
// params: Type.Object({
|
||||
// id: Type.Number(),
|
||||
// }),
|
||||
// response: {
|
||||
// 204: {},
|
||||
// 404: {},
|
||||
// },
|
||||
// },
|
||||
// handler(request, reply) {
|
||||
// return queries.removeById(request.params.id).then((count) => reply.status(count > 0 ? 204 : 404).send())
|
||||
// },
|
||||
// })
|
||||
|
||||
// fastify.route({
|
||||
// url: '/:id',
|
||||
// method: 'PATCH',
|
||||
// schema: {
|
||||
// params: Type.Object({
|
||||
// id: Type.Number(),
|
||||
// }),
|
||||
// body: RoleVariableSchema,
|
||||
// response: {
|
||||
// 204: {},
|
||||
// },
|
||||
// },
|
||||
// async handler(request) {
|
||||
// const patch = request.session.userId
|
||||
// ? {
|
||||
// ...request.body,
|
||||
// modifiedById: request.session.userId,
|
||||
// }
|
||||
// : request.body
|
||||
|
||||
// return queries.update(request.params.id, patch)
|
||||
// },
|
||||
// })
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,21 @@
|
||||
import _ from 'lodash'
|
||||
import { Type, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
|
||||
import knex from '../../lib/knex.ts'
|
||||
import type { FastifyPluginCallbackZod } from 'fastify-type-provider-zod'
|
||||
import z from 'zod'
|
||||
import { SupplierSchema } from '../../schemas/db.ts'
|
||||
|
||||
const supplierRoutes: FastifyPluginCallbackZod = (fastify, _, done) => {
|
||||
const { db } = fastify
|
||||
|
||||
const journalRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
fastify.route({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
async handler() {
|
||||
return knex('supplier').select('*').orderBy('name')
|
||||
schema: {
|
||||
response: {
|
||||
200: z.array(SupplierSchema),
|
||||
},
|
||||
},
|
||||
handler() {
|
||||
return db.selectFrom('supplier').selectAll().orderBy('name').execute()
|
||||
},
|
||||
})
|
||||
|
||||
@ -15,12 +23,13 @@ const journalRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
url: '/:id',
|
||||
method: 'GET',
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
id: Type.Number(),
|
||||
}),
|
||||
params: z.object({ id: z.number() }),
|
||||
response: {
|
||||
200: SupplierSchema,
|
||||
},
|
||||
async handler(req) {
|
||||
return knex('supplier').first('*').where('id', req.params.id)
|
||||
},
|
||||
handler(req) {
|
||||
return db.selectFrom('supplier').selectAll().where('id', '=', req.params.id).executeTakeFirst()
|
||||
},
|
||||
})
|
||||
|
||||
@ -28,20 +37,23 @@ const journalRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
url: '/merge',
|
||||
method: 'POST',
|
||||
schema: {
|
||||
body: Type.Object({
|
||||
ids: Type.Array(Type.Number()),
|
||||
body: z.object({
|
||||
ids: z.array(z.number()),
|
||||
}),
|
||||
},
|
||||
async handler(req) {
|
||||
const suppliers = await knex('supplier').select('*').whereIn('id', req.body.ids)
|
||||
const suppliers = await db.selectFrom('supplier').selectAll().where('id', 'in', req.body.ids).execute()
|
||||
|
||||
const trx = await knex.transaction()
|
||||
const trx = await db.startTransaction().execute()
|
||||
|
||||
await trx('invoice').update('supplierId', req.body.ids[0]).whereIn('supplierId', req.body.ids.slice(1))
|
||||
await trx('supplier').delete().whereIn('id', req.body.ids.slice(1))
|
||||
// 556744-4301
|
||||
await trx
|
||||
.updateTable('invoice')
|
||||
.set('supplierId', req.body.ids[0])
|
||||
.where('supplierId', 'in', req.body.ids.slice(1))
|
||||
.execute()
|
||||
await trx.deleteFrom('supplier').where('id', 'in', req.body.ids.slice(1)).execute()
|
||||
|
||||
trx.commit()
|
||||
await trx.commit().execute()
|
||||
|
||||
return suppliers
|
||||
},
|
||||
@ -50,4 +62,4 @@ const journalRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
done()
|
||||
}
|
||||
|
||||
export default journalRoutes
|
||||
export default supplierRoutes
|
||||
|
||||
@ -1,25 +1,32 @@
|
||||
import _ from 'lodash'
|
||||
import { Type, type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox'
|
||||
import knex from '../../lib/knex.ts'
|
||||
import * as z from 'zod'
|
||||
import type { FastifyPluginCallbackZod } from 'fastify-type-provider-zod'
|
||||
import StatusError from '../../lib/status_error.ts'
|
||||
|
||||
const transactionRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
const transactionRoutes: FastifyPluginCallbackZod = (fastify, _, done) => {
|
||||
const { db } = fastify
|
||||
|
||||
fastify.route({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
schema: {
|
||||
querystring: Type.Object({
|
||||
year: Type.Optional(Type.Number()),
|
||||
accountNumber: Type.Optional(Type.Number()),
|
||||
querystring: z.object({
|
||||
year: z.optional(z.coerce.number()),
|
||||
accountNumber: z.optional(z.coerce.number()),
|
||||
}),
|
||||
},
|
||||
async handler(req) {
|
||||
const query: { financialYearId?: number; accountNumber?: number } = {}
|
||||
|
||||
if (req.query.year) {
|
||||
const year = await knex('financialYear').first('*').where('year', req.query.year)
|
||||
const year = await db
|
||||
.selectFrom('financialYear')
|
||||
.selectAll()
|
||||
.where('year', '=', req.query.year)
|
||||
.executeTakeFirst()
|
||||
|
||||
if (!year) throw new StatusError(404, `Year ${req.query.year} not found.`)
|
||||
|
||||
query.financialYearId = year.id
|
||||
}
|
||||
|
||||
@ -27,18 +34,20 @@ const transactionRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
query.accountNumber = req.query.accountNumber
|
||||
}
|
||||
|
||||
return knex('transaction AS t')
|
||||
.select(
|
||||
return db
|
||||
.selectFrom('transaction as t')
|
||||
.innerJoin('entry as e', 't.entryId', 'e.id')
|
||||
.select([
|
||||
't.accountNumber',
|
||||
'e.transactionDate',
|
||||
't.entryId',
|
||||
't.amount',
|
||||
't.description',
|
||||
't.invoiceId',
|
||||
'e.description AS entryDescription',
|
||||
)
|
||||
.innerJoin('entry AS e', 't.entryId', 'e.id')
|
||||
.where(query)
|
||||
'e.description as entryDescription',
|
||||
])
|
||||
.where((eb) => eb.and(query))
|
||||
.execute()
|
||||
},
|
||||
})
|
||||
|
||||
@ -46,12 +55,12 @@ const transactionRoutes: FastifyPluginCallbackTypebox = (fastify, _, done) => {
|
||||
url: '/:id',
|
||||
method: 'GET',
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
id: Type.Number(),
|
||||
params: z.object({
|
||||
id: z.number(),
|
||||
}),
|
||||
},
|
||||
async handler(req) {
|
||||
return knex('transaction').first('*').where('id', req.params.id)
|
||||
handler(req) {
|
||||
return db.selectFrom('transaction').selectAll().where('id', '=', req.params.id).execute()
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
22
server/schemas/db.ts
Normal file
22
server/schemas/db.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
export const RoleSchema = z.object({
|
||||
id: z.number().int().optional(),
|
||||
name: z.string(),
|
||||
createdAt: z.string().optional(),
|
||||
createdById: z.number().int().nullable().optional(),
|
||||
modifiedAt: z.string().nullable().optional(),
|
||||
modifiedById: z.number().int().nullable().optional(),
|
||||
})
|
||||
|
||||
export const SupplierSchema = z.object({
|
||||
id: z.number().int().optional(),
|
||||
name: z.string().nullable().optional(),
|
||||
supplierTypeId: z.number().int(),
|
||||
taxId: z.string().nullable().optional(),
|
||||
})
|
||||
|
||||
export const SupplierTypeSchema = z.object({
|
||||
id: z.number().int().optional(),
|
||||
name: z.string(),
|
||||
})
|
||||
@ -3,12 +3,15 @@ import fcookie from '@fastify/cookie'
|
||||
import fsession from '@fastify/session'
|
||||
import fstatic from '@fastify/static'
|
||||
import RedisStore from 'fastify-session-redis-store'
|
||||
import { serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod'
|
||||
import { Redis } from 'ioredis'
|
||||
import kysely from './lib/kysely.ts'
|
||||
|
||||
import StatusError from './lib/status_error.ts'
|
||||
import env from './env.ts'
|
||||
import ErrorHandler from './handlers/error.ts'
|
||||
import authPlugin from './plugins/auth.ts'
|
||||
import dbPlugin from './plugins/db.ts'
|
||||
import vitePlugin from './plugins/vite.ts'
|
||||
import apiRoutes from './routes/api.ts'
|
||||
import templateAdmin from './templates/admin.ts'
|
||||
@ -17,6 +20,9 @@ import templatePublic from './templates/public.ts'
|
||||
export default async (options?: FastifyServerOptions) => {
|
||||
const server = fastify(options)
|
||||
|
||||
server.setValidatorCompiler(validatorCompiler)
|
||||
server.setSerializerCompiler(serializerCompiler)
|
||||
|
||||
server.register(fcookie)
|
||||
server.register(fsession, {
|
||||
cookie: {
|
||||
@ -27,6 +33,7 @@ export default async (options?: FastifyServerOptions) => {
|
||||
secret: env.SESSION_SECRET,
|
||||
store: env.NODE_ENV !== 'testing' ? new RedisStore({ client: new Redis(env.REDIS_HOST) }) : undefined,
|
||||
})
|
||||
server.register(dbPlugin, { kysely })
|
||||
|
||||
server.setNotFoundHandler(() => {
|
||||
throw new StatusError(404)
|
||||
|
||||
21
server/tests/suppliers.test.ts
Normal file
21
server/tests/suppliers.test.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { test, type TestContext } from 'node:test'
|
||||
|
||||
import supplierPlugin from '../routes/api/suppliers.ts'
|
||||
import fastify from 'fastify'
|
||||
|
||||
test('/api/suppliers', async (t: TestContext) => {
|
||||
const server = fastify()
|
||||
|
||||
// server.decorate('auth', (_request, _reply, done) => done())
|
||||
|
||||
server.register(supplierPlugin, { prefix: '/api/suppliers' })
|
||||
|
||||
const res = await server.inject({
|
||||
method: 'GET',
|
||||
url: '/api/suppliers',
|
||||
})
|
||||
|
||||
t.assert.equal(res.statusCode, 200)
|
||||
|
||||
await server.close()
|
||||
})
|
||||
3
shared/global.d.ts
vendored
3
shared/global.d.ts
vendored
@ -1,5 +1,7 @@
|
||||
import 'fastify'
|
||||
import type { onRequestHookHandler } from 'fastify'
|
||||
import { DB } from './types.db.ts'
|
||||
import type { Kysely } from 'kysely'
|
||||
|
||||
import { ViteDevServer } from 'vite'
|
||||
|
||||
@ -16,6 +18,7 @@ declare module 'fastify' {
|
||||
|
||||
interface FastifyInstance {
|
||||
auth: onRequestHookHandler
|
||||
db: Kysely<DB>
|
||||
devServer: ViteDevServer
|
||||
}
|
||||
|
||||
|
||||
261
shared/types.db.ts
Normal file
261
shared/types.db.ts
Normal file
@ -0,0 +1,261 @@
|
||||
/**
|
||||
* This file was generated by kysely-codegen.
|
||||
* Please do not edit it manually.
|
||||
*/
|
||||
|
||||
import type { ColumnType } from 'kysely'
|
||||
|
||||
export type Generated<T> =
|
||||
T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>
|
||||
|
||||
export type Json = JsonValue
|
||||
|
||||
export type JsonArray = JsonValue[]
|
||||
|
||||
export type JsonObject = {
|
||||
[x: string]: JsonValue | undefined
|
||||
}
|
||||
|
||||
export type JsonPrimitive = boolean | number | string | null
|
||||
|
||||
export type JsonValue = JsonArray | JsonObject | JsonPrimitive
|
||||
|
||||
export type Numeric = ColumnType<string, number | string, number | string>
|
||||
|
||||
export type Timestamp = ColumnType<Date, Date | string, Date | string>
|
||||
|
||||
export interface Account {
|
||||
description: string
|
||||
financialYearId: number
|
||||
id: Generated<number>
|
||||
number: number
|
||||
sru: number | null
|
||||
}
|
||||
|
||||
export interface AccountBalance {
|
||||
accountNumber: number
|
||||
financialYearId: number
|
||||
in: Generated<Numeric>
|
||||
inQuantity: number | null
|
||||
out: Generated<Numeric>
|
||||
outQuantity: number | null
|
||||
}
|
||||
|
||||
export interface Admission {
|
||||
createdAt: Generated<Timestamp | null>
|
||||
createdById: number
|
||||
id: Generated<number>
|
||||
modifiedAt: Timestamp | null
|
||||
modifiedById: number | null
|
||||
regex: string
|
||||
}
|
||||
|
||||
export interface AdmissionsRoles {
|
||||
admissionId: number
|
||||
roleId: number
|
||||
}
|
||||
|
||||
export interface AliasesToSupplier {
|
||||
alias: string
|
||||
id: Generated<number>
|
||||
supplierId: number
|
||||
}
|
||||
|
||||
export interface Dimension {
|
||||
id: Generated<number>
|
||||
name: string | null
|
||||
number: number
|
||||
}
|
||||
|
||||
export interface EmailToken {
|
||||
cancelledAt: Timestamp | null
|
||||
consumedAt: Timestamp | null
|
||||
createdAt: Generated<Timestamp>
|
||||
email: string
|
||||
id: Generated<number>
|
||||
token: string
|
||||
userId: number
|
||||
}
|
||||
|
||||
export interface Entry {
|
||||
description: string | null
|
||||
entryDate: Timestamp
|
||||
financialYearId: number
|
||||
id: Generated<number>
|
||||
journalId: number
|
||||
number: number
|
||||
signature: string | null
|
||||
transactionDate: Timestamp
|
||||
}
|
||||
|
||||
export interface Error {
|
||||
createdAt: Timestamp | null
|
||||
details: Json | null
|
||||
headers: Json | null
|
||||
id: Generated<number>
|
||||
ip: string | null
|
||||
message: string | null
|
||||
method: string | null
|
||||
path: string | null
|
||||
reqId: string | null
|
||||
stack: string | null
|
||||
statusCode: number | null
|
||||
type: string | null
|
||||
}
|
||||
|
||||
export interface File {
|
||||
filename: string
|
||||
id: Generated<number>
|
||||
}
|
||||
|
||||
export interface FilesToInvoice {
|
||||
fileId: number
|
||||
invoiceId: number
|
||||
}
|
||||
|
||||
export interface FinancialYear {
|
||||
endDate: Timestamp
|
||||
id: Generated<number>
|
||||
startDate: Timestamp
|
||||
year: number
|
||||
}
|
||||
|
||||
export interface Invite {
|
||||
consumedAt: Timestamp | null
|
||||
consumedById: number | null
|
||||
createdAt: Generated<Timestamp>
|
||||
createdById: number | null
|
||||
email: string
|
||||
id: Generated<number>
|
||||
modifiedAt: Timestamp | null
|
||||
modifiedById: number | null
|
||||
token: string
|
||||
}
|
||||
|
||||
export interface InvitesRoles {
|
||||
invitedId: number
|
||||
roleId: number
|
||||
}
|
||||
|
||||
export interface Invoice {
|
||||
amount: Numeric | null
|
||||
dueDate: Timestamp | null
|
||||
financialYearId: number | null
|
||||
fiskenNumber: number | null
|
||||
id: Generated<number>
|
||||
invoiceDate: Timestamp | null
|
||||
invoiceNumber: string | null
|
||||
ocr: string | null
|
||||
phmNumber: number | null
|
||||
supplierId: number
|
||||
}
|
||||
|
||||
export interface Journal {
|
||||
description: string | null
|
||||
id: Generated<number>
|
||||
identifier: string
|
||||
}
|
||||
|
||||
export interface Object {
|
||||
dimensionId: number
|
||||
id: Generated<number>
|
||||
name: string | null
|
||||
number: number
|
||||
}
|
||||
|
||||
export interface PasswordToken {
|
||||
cancelledAt: Timestamp | null
|
||||
consumedAt: Timestamp | null
|
||||
createdAt: Generated<Timestamp>
|
||||
id: Generated<number>
|
||||
token: string
|
||||
userId: number
|
||||
}
|
||||
|
||||
export interface Role {
|
||||
createdAt: Generated<Timestamp>
|
||||
createdById: number | null
|
||||
id: Generated<number>
|
||||
modifiedAt: Timestamp | null
|
||||
modifiedById: number | null
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface Supplier {
|
||||
id: Generated<number>
|
||||
name: string | null
|
||||
supplierTypeId: number
|
||||
taxId: string | null
|
||||
}
|
||||
|
||||
export interface SupplierType {
|
||||
id: Generated<number>
|
||||
name: string
|
||||
}
|
||||
|
||||
export interface Transaction {
|
||||
accountNumber: number
|
||||
amount: Numeric
|
||||
description: string | null
|
||||
entryId: number
|
||||
id: Generated<number>
|
||||
invoiceId: number | null
|
||||
objectId: number | null
|
||||
quantity: Numeric | null
|
||||
signature: string | null
|
||||
transactionDate: Timestamp | null
|
||||
}
|
||||
|
||||
export interface TransactionsToObjects {
|
||||
objectId: number
|
||||
transactionId: number
|
||||
}
|
||||
|
||||
export interface User {
|
||||
bannedAt: Timestamp | null
|
||||
bannedById: number | null
|
||||
blockedAt: Timestamp | null
|
||||
blockedById: number | null
|
||||
createdAt: Generated<Timestamp>
|
||||
email: string
|
||||
emailVerifiedAt: Timestamp | null
|
||||
id: Generated<number>
|
||||
lastActivityAt: Timestamp | null
|
||||
lastLoginAt: Timestamp | null
|
||||
lastLoginAttemptAt: Timestamp | null
|
||||
loginAttempts: Generated<number | null>
|
||||
password: string
|
||||
}
|
||||
|
||||
export interface UsersRoles {
|
||||
roleId: number
|
||||
userId: number
|
||||
}
|
||||
|
||||
export interface DB {
|
||||
account: Account
|
||||
accountBalance: AccountBalance
|
||||
admission: Admission
|
||||
admissions_roles: AdmissionsRoles
|
||||
aliasesToSupplier: AliasesToSupplier
|
||||
dimension: Dimension
|
||||
emailToken: EmailToken
|
||||
entry: Entry
|
||||
error: Error
|
||||
file: File
|
||||
filesToInvoice: FilesToInvoice
|
||||
financialYear: FinancialYear
|
||||
invite: Invite
|
||||
invites_roles: InvitesRoles
|
||||
invoice: Invoice
|
||||
journal: Journal
|
||||
object: Object
|
||||
passwordToken: PasswordToken
|
||||
role: Role
|
||||
supplier: Supplier
|
||||
supplierType: SupplierType
|
||||
transaction: Transaction
|
||||
transactionsToObjects: TransactionsToObjects
|
||||
user: User
|
||||
users_roles: UsersRoles
|
||||
}
|
||||
144
shared/types.ts
144
shared/types.ts
@ -1,85 +1,85 @@
|
||||
export type Account = {
|
||||
id: number
|
||||
number: number
|
||||
description: string
|
||||
}
|
||||
// export type Account = {
|
||||
// id: number
|
||||
// number: number
|
||||
// description: string
|
||||
// }
|
||||
|
||||
export type Balance = {
|
||||
accountNumber: string
|
||||
description: string
|
||||
} & Record<number, number>
|
||||
// export type Balance = {
|
||||
// accountNumber: string
|
||||
// description: string
|
||||
// } & Record<number, number>
|
||||
|
||||
export interface Entry {
|
||||
id: number
|
||||
journal: string
|
||||
number: number
|
||||
amount: number
|
||||
description: string
|
||||
transactionDate: string
|
||||
entryDate: string
|
||||
transactions: {
|
||||
accountNumber: number
|
||||
description: string
|
||||
amount: number
|
||||
}[]
|
||||
}
|
||||
// export interface Entry {
|
||||
// id: number
|
||||
// journal: string
|
||||
// number: number
|
||||
// amount: number
|
||||
// description: string
|
||||
// transactionDate: string
|
||||
// entryDate: string
|
||||
// transactions: {
|
||||
// accountNumber: number
|
||||
// description: string
|
||||
// amount: number
|
||||
// }[]
|
||||
// }
|
||||
|
||||
export type FinancialYear = {
|
||||
year: number
|
||||
startDate: string
|
||||
endDate: string
|
||||
}
|
||||
// export type FinancialYear = {
|
||||
// year: number
|
||||
// startDate: string
|
||||
// endDate: string
|
||||
// }
|
||||
|
||||
export type Invoice = {
|
||||
id: number
|
||||
fiskenNumber?: number
|
||||
phmNumber?: number
|
||||
invoiceDate: string
|
||||
dueDate: string
|
||||
invoiceNumber: number
|
||||
amount: number
|
||||
files?: { filename: string }[]
|
||||
transactions?: {
|
||||
accountNumber: number
|
||||
amount: number
|
||||
description: number
|
||||
entryId: number
|
||||
}[]
|
||||
}
|
||||
// export type Invoice = {
|
||||
// id: number
|
||||
// fiskenNumber?: number
|
||||
// phmNumber?: number
|
||||
// invoiceDate: string
|
||||
// dueDate: string
|
||||
// invoiceNumber: number
|
||||
// amount: number
|
||||
// files?: { filename: string }[]
|
||||
// transactions?: {
|
||||
// accountNumber: number
|
||||
// amount: number
|
||||
// description: number
|
||||
// entryId: number
|
||||
// }[]
|
||||
// }
|
||||
|
||||
export type Journal = {
|
||||
id: number
|
||||
identifier: string
|
||||
}
|
||||
// export type Journal = {
|
||||
// id: number
|
||||
// identifier: string
|
||||
// }
|
||||
|
||||
export type Object = {
|
||||
id: number
|
||||
dimensionName: string
|
||||
name: string
|
||||
}
|
||||
// export type Object = {
|
||||
// id: number
|
||||
// dimensionName: string
|
||||
// name: string
|
||||
// }
|
||||
|
||||
export type Result = {
|
||||
accountNumber: number
|
||||
description?: string
|
||||
} & Record<number, number>
|
||||
// export type Result = {
|
||||
// accountNumber: number
|
||||
// description?: string
|
||||
// } & Record<number, number>
|
||||
|
||||
export type Supplier = {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
// export type Supplier = {
|
||||
// id: number
|
||||
// name: string
|
||||
// }
|
||||
|
||||
export interface Transaction {
|
||||
accountNumber: number
|
||||
description: string
|
||||
amount: number
|
||||
entryId: number
|
||||
}
|
||||
// export interface Transaction {
|
||||
// accountNumber: number
|
||||
// description: string
|
||||
// amount: number
|
||||
// entryId: number
|
||||
// }
|
||||
|
||||
export interface TransactionFull extends Transaction {
|
||||
transactionDate: string
|
||||
invoiceId: number
|
||||
entryDescription: string
|
||||
}
|
||||
// export interface TransactionFull extends Transaction {
|
||||
// transactionDate: string
|
||||
// invoiceId: number
|
||||
// entryDescription: string
|
||||
// }
|
||||
|
||||
export interface Route {
|
||||
path: string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user