70 lines
3.8 KiB
TypeScript
70 lines
3.8 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import test from "node:test"
|
|
import { PgDialect } from "drizzle-orm/pg-core"
|
|
import { normalizeBankAllocationDetails, validateBankAllocationCostCentre } from "../src/modules/bank-allocation-details"
|
|
import { prepareStatementAllocationInput } from "../src/mcp/statementAllocations"
|
|
import bankingRoutes from "../src/routes/banking"
|
|
import { statementallocations } from "../db/schema"
|
|
|
|
const costcentre = "57d31d62-11a2-47c5-b074-69f9c5ab8bba"
|
|
|
|
test("keeps cost centre and VAT key on the gross bank allocation through input preparation", () => {
|
|
const prepared = prepareStatementAllocationInput({ bankstatement: 42, account: 13, amount: -119, costcentre, datevTaxKey: " 9 " })
|
|
assert.equal(prepared.amount, -119)
|
|
assert.equal(prepared.costcentre, costcentre)
|
|
assert.equal(prepared.datevTaxKey, "9")
|
|
assert.deepEqual(normalizeBankAllocationDetails({ amount: -119, account: 13, bankstatement: 42 }), { costcentre: null, datevTaxKey: null })
|
|
})
|
|
|
|
test("rejects invalid cost centres, ambiguous document assignments and malformed tax keys", () => {
|
|
assert.throws(() => normalizeBankAllocationDetails({ costcentre: "invalid" }), /UUID/)
|
|
assert.throws(() => normalizeBankAllocationDetails({ costcentre, bankstatement: 1, account: 13, incominginvoice: 2 }), /direkte Bankbuchungen/)
|
|
assert.throws(() => normalizeBankAllocationDetails({ datevTaxKey: '9";evil' }), /Steuerschlüssel/)
|
|
})
|
|
|
|
test("cost centre lookup requires the active tenant and excludes archived centres", async () => {
|
|
let condition: any
|
|
const query = { from: () => query, where: (value: any) => { condition = value; return query }, limit: async () => [] }
|
|
await assert.rejects(validateBankAllocationCostCentre({ select: () => query }, 7, costcentre), /nicht gefunden oder ist archiviert/)
|
|
const sql = new PgDialect().sqlToQuery(condition)
|
|
assert.match(sql.sql, /"costcentres"\."tenant"/)
|
|
assert.match(sql.sql, /"costcentres"\."archived"/)
|
|
assert.deepEqual(sql.params, [costcentre, 7, false])
|
|
await validateBankAllocationCostCentre({ select: () => ({ ...query, from: () => ({ where: () => ({ limit: async () => [{ id: costcentre }] }) }) }) }, 7, costcentre)
|
|
await validateBankAllocationCostCentre({}, 7, null)
|
|
})
|
|
|
|
test("banking API persists the gross allocation with cost centre and VAT, and rejects unknown centres before writing", async () => {
|
|
const handlers = new Map<string, any>()
|
|
const saved: any[] = []
|
|
let centreExists = true
|
|
const lookup: any = { from: () => lookup, where: () => lookup, limit: async () => centreExists ? [{ id: costcentre }] : [] }
|
|
const server: any = {
|
|
get() {}, patch() {}, delete() {},
|
|
post: (url: string, handler: any) => handlers.set(url, handler),
|
|
db: {
|
|
select: () => lookup,
|
|
insert: (table: any) => ({ values: (value: any) => {
|
|
if (table === statementallocations) saved.push(value)
|
|
return { returning: async () => [{ id: "allocation", ...value }] }
|
|
} }),
|
|
},
|
|
}
|
|
await bankingRoutes(server)
|
|
const handler = handlers.get("/banking/statements")
|
|
const request = { user: { tenant_id: 7, user_id: "user" }, body: { data: { bankstatement: 42, account: 13, amount: -119, costcentre, datevTaxKey: "9" } } }
|
|
let status = 200
|
|
let response: any
|
|
const reply = { code: (code: number) => { status = code; return reply }, send: (body: any) => { response = body; return reply } }
|
|
await handler(request, reply)
|
|
assert.equal(status, 200)
|
|
assert.equal(response.amount, -119)
|
|
assert.equal(response.costcentre, costcentre)
|
|
assert.equal(response.datevTaxKey, "9")
|
|
assert.equal(saved[0].tenant, 7)
|
|
centreExists = false
|
|
await handler(request, reply)
|
|
assert.equal(status, 400)
|
|
assert.equal(saved.length, 1)
|
|
})
|