WFDASH-WEBAPP/src/lib/server/stock-items-export.test.ts
Dave aed3f5c861 feat: implement discount functionality in POS system
Added support for discounts in the POS checkout process, allowing operators to apply either a fixed amount or a percentage off the gross total. Updated the state management to include discount details and modified the receipt and cart rendering to display pre- and post-discount values. Enhanced the checkout API to handle discount inputs and ensure proper calculations. Updated relevant tests to cover new discount logic.
2026-09-03 12:19:21 +02:00

153 lines
4.5 KiB
TypeScript

import { describe, it, expect } from "vitest";
import * as XLSX from "xlsx";
import {
buildStockExportWorkbook,
STOCK_EXPORT_COLUMNS,
stockItemToExportRow,
type StockExportRow,
} from "./stock-items-service";
function parseWorkbook(bytes: Uint8Array): { sheets: Record<string, XLSX.WorkSheet> } {
const wb = XLSX.read(bytes, { type: "buffer" });
return { sheets: wb.Sheets };
}
describe("stockItemToExportRow", () => {
it("flattens a StockItem to the canonical export row, resolving supplier to name", () => {
const row = stockItemToExportRow(
{
id: "si-1",
sku: "WID-1",
name: "Widget",
description: "A widget",
unit: "ea",
current_qty: 10,
min_qty: 2,
target_qty: 20,
cost_price: 100,
markup: 30,
selling_price: 130,
location: "A1",
notes: "shiny",
is_active: true,
supplier: "sup-1",
created: "2026-09-01T00:00:00Z",
updated: "2026-09-02T00:00:00Z",
collectionId: "pbc_xxx",
collectionName: "stock_items",
} as never,
"ACME",
);
expect(row.id).toBe("si-1");
expect(row.sku).toBe("WID-1");
expect(row.supplier).toBe("ACME");
expect(row.is_active).toBe(true);
expect(row.current_qty).toBe(10);
expect(row.cost_price).toBe(100);
});
it("treats missing fields as empty / zero / inactive=false (for is_active) sensibly", () => {
const row = stockItemToExportRow(
{
id: "si-2",
sku: "WID-2",
name: "Bare",
is_active: false,
} as never,
"",
);
expect(row.is_active).toBe(false);
expect(row.supplier).toBe("");
expect(row.current_qty).toBe(0);
expect(row.notes).toBe("");
});
});
describe("buildStockExportWorkbook", () => {
const baseRows: StockExportRow[] = [
{
id: "si-1",
sku: "WID-1",
name: "Widget",
description: "",
unit: "ea",
supplier: "ACME",
current_qty: 10,
min_qty: 2,
target_qty: 20,
cost_price: 100,
markup: 30,
selling_price: 130,
location: "A1",
notes: "",
is_active: true,
},
];
it("produces a non-empty xlsx that opens in SheetJS and contains the canonical column order", () => {
const bytes = buildStockExportWorkbook({
rows: baseRows,
generatedAt: "2026-09-02T12:00:00.000Z",
supplierNames: ["ACME", "Bosch"],
});
expect(bytes.byteLength).toBeGreaterThan(0);
const { sheets } = parseWorkbook(bytes);
const stock = sheets.Stock;
expect(stock).toBeDefined();
// Header row is the first row of AOA; columns come back in order.
const header = (XLSX.utils.sheet_to_json(stock, { header: 1 }) as unknown[][])[0];
expect(header).toEqual([...STOCK_EXPORT_COLUMNS]);
});
it("writes each data row with the right cell types (booleans → TRUE/FALSE strings, numbers stay numeric)", () => {
const { sheets } = parseWorkbook(
buildStockExportWorkbook({
rows: [
{
...baseRows[0]!,
is_active: false,
},
],
generatedAt: "2026-09-02T12:00:00.000Z",
supplierNames: ["ACME"],
}),
);
const stock = sheets.Stock!;
const data = XLSX.utils.sheet_to_json<Record<string, unknown>>(stock);
expect(data).toHaveLength(1);
expect(data[0]?.is_active).toBe("FALSE");
expect(data[0]?.current_qty).toBe(10);
expect(data[0]?.sku).toBe("WID-1");
});
it("includes a Help sheet that lists every column with a description", () => {
const { sheets } = parseWorkbook(
buildStockExportWorkbook({
rows: baseRows,
generatedAt: "2026-09-02T12:00:00.000Z",
supplierNames: ["ACME"],
}),
);
const help = sheets.Help;
expect(help).toBeDefined();
const helpData = XLSX.utils.sheet_to_json<{ Column: string; "What it is": string }>(help, {
header: ["Column", "What it is"],
});
// First row is the header itself; subsequent rows are the columns.
const columns = helpData.slice(1).map((r) => r.Column);
for (const col of STOCK_EXPORT_COLUMNS) {
expect(columns).toContain(col);
}
});
it("handles the zero-supplierNames case (no crash)", () => {
const bytes = buildStockExportWorkbook({
rows: baseRows,
generatedAt: "2026-09-02T12:00:00.000Z",
supplierNames: [],
});
const { sheets } = parseWorkbook(bytes);
const data = XLSX.utils.sheet_to_json<Record<string, unknown>>(sheets.Stock!);
expect(data).toHaveLength(baseRows.length);
});
});