- Added an audit trail feature that logs every create, update, and delete action on delivery notes and orders, capturing detailed changes per field. - Introduced the `AuditTimeline` component to display the history of changes for delivery notes and orders, enhancing traceability. - Updated the `page.tsx` files for delivery notes and orders to fetch and display audit logs, ensuring users can view the history of modifications. - Enhanced the `package.json` with a new migration script for setting up the audit log functionality. This feature improves accountability and transparency in the management of delivery notes and orders.
84 lines
3 KiB
TypeScript
84 lines
3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { readItemInvoiceNumber, summarizeOrderInvoices } from "./order-invoices";
|
|
|
|
const qbDetails = (number: string, date = "2026-09-25") => ({
|
|
invoice: {
|
|
number,
|
|
date,
|
|
qbInvoiceLink: `https://app.qbo.intuit.com/app/invoice?txnId=${number}`,
|
|
billingCompany: "CNL",
|
|
setByName: "David Els",
|
|
},
|
|
});
|
|
|
|
describe("readItemInvoiceNumber", () => {
|
|
it("prefers the Invoicing-page details over customer_invoice_number", () => {
|
|
expect(
|
|
readItemInvoiceNumber({
|
|
customer_invoice_number: "OLD-1",
|
|
order_item_details: qbDetails("INV10983"),
|
|
}),
|
|
).toBe("INV10983");
|
|
});
|
|
|
|
it("falls back to customer_invoice_number", () => {
|
|
expect(readItemInvoiceNumber({ customer_invoice_number: "INV1" })).toBe("INV1");
|
|
});
|
|
|
|
it("parses order_item_details stored as a JSON string", () => {
|
|
expect(
|
|
readItemInvoiceNumber({ order_item_details: JSON.stringify(qbDetails("INV7")) }),
|
|
).toBe("INV7");
|
|
});
|
|
|
|
it("ignores the supplier invoice collection-confirm writes before billing", () => {
|
|
// Same blob shape collection-confirm writes: no QuickBooks fields.
|
|
const supplierInvoice = {
|
|
invoice: { number: "IN-5018651", date: "2026-09-25", setBy: "u1", setByName: "Dave", setAt: "x" },
|
|
};
|
|
expect(readItemInvoiceNumber({ order_item_details: supplierInvoice })).toBeNull();
|
|
expect(summarizeOrderInvoices([{ order_item_details: supplierInvoice }])).toEqual([]);
|
|
// …but a reconciled customer_invoice_number still counts.
|
|
expect(
|
|
readItemInvoiceNumber({ order_item_details: supplierInvoice, customer_invoice_number: "INV1" }),
|
|
).toBe("INV1");
|
|
});
|
|
|
|
it("returns null for uninvoiced or malformed rows", () => {
|
|
expect(readItemInvoiceNumber({})).toBeNull();
|
|
expect(readItemInvoiceNumber({ order_item_details: "{not json" })).toBeNull();
|
|
expect(readItemInvoiceNumber({ customer_invoice_number: " " })).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("summarizeOrderInvoices", () => {
|
|
it("groups lines by invoice number and counts them", () => {
|
|
const result = summarizeOrderInvoices([
|
|
{ order_item_details: qbDetails("INV2", "2026-09-25") },
|
|
{ order_item_details: qbDetails("INV2", "2026-09-25") },
|
|
{ order_item_details: qbDetails("INV1", "2026-09-20") },
|
|
{ order_item_details: null },
|
|
]);
|
|
expect(result.map((r) => [r.number, r.lineCount])).toEqual([
|
|
["INV1", 1],
|
|
["INV2", 2],
|
|
]);
|
|
expect(result[1]).toMatchObject({
|
|
date: "2026-09-25",
|
|
billingCompany: "CNL",
|
|
setByName: "David Els",
|
|
});
|
|
});
|
|
|
|
it("uses invoiced_date when the details carry no date", () => {
|
|
const [only] = summarizeOrderInvoices([
|
|
{ customer_invoice_number: "INV9", invoiced_date: "2026-09-01" },
|
|
]);
|
|
expect(only).toMatchObject({ number: "INV9", date: "2026-09-01", qbInvoiceLink: null });
|
|
});
|
|
|
|
it("returns an empty list for an uninvoiced order", () => {
|
|
expect(summarizeOrderInvoices([{}, { customer_invoice_number: "" }])).toEqual([]);
|
|
});
|
|
});
|