Files
Wabenhain/src/lib/inventory.test.ts
T
Nick SzaunigandClaude Opus 5.5 e0b47faf45
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 2m24s
feat(orders): reopen cancelled orders only after confirmation; accurate sales
Cancelled orders:
- Moving an order out of STORNIERT is possible again, but only after a
  warning is confirmed in the status form (OrderStatusForm); without
  the confirmation the server changes nothing.
- Reopening books the counter-entry to the cancellation: goods that the
  cancellation restocked are deducted again (atomically, only if enough
  stock is left, otherwise the order stays cancelled). A later second
  cancellation therefore restocks +1 again instead of leaving +2.
- The warning states that no new payment is collected.

Dashboard figures:
- One definition of a counted sale (lib/sales.ts): not unpaid (NEU),
  not cancelled, no refunded return. Used for revenue today/month, sold
  glasses, average cart, top products/categories, revenue trend and
  repeat customers.
- "Verkaufte Gläser" previously summed every order item, including
  cancelled orders and refunded returns.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-27 01:14:12 +02:00

73 lines
3.2 KiB
TypeScript

import { describe, test, expect } from "vitest";
import { needsConfirmToChangeStatus, needsReserveOnReopen, needsRestockOnCancel, planInventoryEdit } from "./inventory";
describe("planInventoryEdit", () => {
test("laesst den Bestand unberuehrt, wenn das Feld nicht geaendert wurde", () => {
// Zwischen Oeffnen und Speichern verkaufte Glaeser duerfen nicht
// mit dem alten Formularwert ueberschrieben werden.
expect(planInventoryEdit({ loaded: "105", submitted: 105 })).toEqual({ kind: "keep" });
});
test("setzt den Bestand nur unter der Bedingung, dass er noch dem geladenen Wert entspricht", () => {
expect(planInventoryEdit({ loaded: "105", submitted: 120 })).toEqual({
kind: "set",
expected: 105,
quantity: 120,
});
});
test("verlangt ein Neuladen, wenn der geladene Wert fehlt", () => {
// Formular aus einem Tab, der vor dem Deployment geoeffnet wurde.
expect(planInventoryEdit({ loaded: "", submitted: 105 })).toEqual({ kind: "reload" });
});
test("verlangt ein Neuladen bei einem manipulierten geladenen Wert", () => {
expect(planInventoryEdit({ loaded: "-1", submitted: 105 })).toEqual({ kind: "reload" });
expect(planInventoryEdit({ loaded: "1.5", submitted: 105 })).toEqual({ kind: "reload" });
expect(planInventoryEdit({ loaded: "abc", submitted: 105 })).toEqual({ kind: "reload" });
});
});
describe("needsRestockOnCancel", () => {
test("bucht zurueck, wenn es keine Retoure gibt", () => {
expect(needsRestockOnCancel(null)).toBe(true);
});
test("bucht zurueck, solange die Retoure noch nicht erstattet ist", () => {
expect(needsRestockOnCancel("ANGEFRAGT")).toBe(true);
expect(needsRestockOnCancel("ANGENOMMEN")).toBe(true);
expect(needsRestockOnCancel("ABGELEHNT")).toBe(true);
});
test("bucht nicht noch einmal zurueck, wenn die Retoure die Ware schon zurueckgebucht hat", () => {
expect(needsRestockOnCancel("ERSTATTET")).toBe(false);
});
});
describe("needsConfirmToChangeStatus", () => {
test("leaving a cancelled order requires an explicit confirmation", () => {
expect(needsConfirmToChangeStatus("STORNIERT", "BEZAHLT")).toBe(true);
expect(needsConfirmToChangeStatus("STORNIERT", "NEU")).toBe(true);
expect(needsConfirmToChangeStatus("STORNIERT", "VERSENDET")).toBe(true);
});
test("re-selecting the cancelled status or moving active orders needs no confirmation", () => {
expect(needsConfirmToChangeStatus("STORNIERT", "STORNIERT")).toBe(false);
expect(needsConfirmToChangeStatus("BEZAHLT", "VERSENDET")).toBe(false);
expect(needsConfirmToChangeStatus("VERSENDET", "STORNIERT")).toBe(false);
});
});
describe("needsReserveOnReopen", () => {
test("reopening takes back exactly what the cancellation restocked (no +2 on the next cancel)", () => {
for (const status of [null, "ANGEFRAGT", "ANGENOMMEN", "ABGELEHNT", "ERSTATTET"] as const) {
expect(needsReserveOnReopen(status)).toBe(needsRestockOnCancel(status));
}
});
test("an order whose return was refunded was not restocked on cancel, so nothing is deducted", () => {
expect(needsReserveOnReopen("ERSTATTET")).toBe(false);
expect(needsReserveOnReopen(null)).toBe(true);
});
});