- Readiness: all 18 checks (medicine lots, treatment log gaps, labels, harvest withdrawal), medicine subjects masked without veterinary-medicines:read, report PDF (counts only), summary cached 60 s, 409 codes READINESS_*. - Frontend: /compliance page with acknowledge/revoke, dashboard line and nav; veterinary medicine catalogue, lots, movement book with inventory and disposal; label designer check panel, print card with gap list and proof print, food business master data, product legal name. - Service worker: cacheability is path-based (the backend sends no-store on every answer); compliance, medicine, restriction, notice and label check/print paths and restricted document kinds are never cached. - ARCHITECTURE.md §2, §12.10–12.11, Annahmen 86–90. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { buildBook } from "./book";
|
|
import { lotDetail } from "./fixtures.spec-helper";
|
|
|
|
const movement = (id: string, createdAt: string, quantity: number, type = "TREATMENT" as const) => ({
|
|
id,
|
|
type,
|
|
quantity,
|
|
treatmentId: null,
|
|
reason: null,
|
|
userId: null,
|
|
createdAt,
|
|
});
|
|
|
|
describe("buildBook", () => {
|
|
it("lists the newest booking first and ends at the receipt", () => {
|
|
const rows = buildBook(
|
|
lotDetail({
|
|
quantity: 20,
|
|
movements: [movement("b", "2026-08-12T08:00:00.000Z", -3), movement("a", "2026-08-10T08:00:00.000Z", -8)],
|
|
}),
|
|
);
|
|
|
|
expect(rows.map((row) => row.label)).toEqual(["Behandlung", "Behandlung", "Eingang"]);
|
|
expect(rows.map((row) => row.balance)).toEqual([9, 12, 20]);
|
|
});
|
|
|
|
it("keeps the running rest exact to the thousandth", () => {
|
|
const rows = buildBook(
|
|
lotDetail({
|
|
quantity: 1,
|
|
movements: [movement("a", "2026-08-10T08:00:00.000Z", -0.1), movement("b", "2026-08-11T08:00:00.000Z", -0.2)],
|
|
}),
|
|
);
|
|
|
|
expect(rows[0].balance).toBe(0.7);
|
|
});
|
|
|
|
it("lets a rest fall below zero and keeps the sign", () => {
|
|
const rows = buildBook(lotDetail({ quantity: 2, movements: [movement("a", "2026-08-10T08:00:00.000Z", -5)] }));
|
|
|
|
expect(rows[0].balance).toBe(-3);
|
|
});
|
|
|
|
it("reads the day of a booking as the Berlin calendar day", () => {
|
|
const rows = buildBook(lotDetail({ movements: [movement("a", "2026-08-10T22:30:00.000Z", -1)] }));
|
|
|
|
expect(rows[0].day).toBe("2026-08-11");
|
|
});
|
|
});
|