mirror of
https://github.com/Sea-Haven-Industries/seahaven-ap.git
synced 2026-09-30 06:53:18 +00:00
* feat(shared): add payment ladder and CSV domain package Introduce @seahaven-ap/shared via npm workspaces so FE and future API share payments-dashboard-compatible status ladders, pay-date helpers, and CSV headers. * fix(web): build shared package before vite dev Ensure fresh npm ci && npm run dev (and Playwright webServer) can resolve @seahaven-ap/shared dist exports that are gitignored.
66 lines
2.7 KiB
TypeScript
66 lines
2.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
CANCEL_STATUSES,
|
|
PAYMENT_STATUS_RANK,
|
|
canTransitionPaymentStatus,
|
|
isCancelStatus,
|
|
parsePaymentStatus,
|
|
toPaymentDisplayStatus,
|
|
} from "./payment-status.js";
|
|
|
|
describe("payment status ladder", () => {
|
|
it("ranks the ladder in consumer order", () => {
|
|
expect(PAYMENT_STATUS_RANK.scheduled).toBe(1);
|
|
expect(PAYMENT_STATUS_RANK.payment_submitted).toBe(2);
|
|
expect(PAYMENT_STATUS_RANK.issued).toBe(3);
|
|
expect(PAYMENT_STATUS_RANK.outstanding).toBe(4);
|
|
expect(PAYMENT_STATUS_RANK.cleared).toBe(5);
|
|
});
|
|
|
|
it("maps internal statuses to CSV display strings", () => {
|
|
expect(toPaymentDisplayStatus("payment_submitted")).toBe("Payment Submitted");
|
|
expect(toPaymentDisplayStatus("cleared")).toBe("Cleared");
|
|
});
|
|
|
|
it("parses display and internal status strings", () => {
|
|
expect(parsePaymentStatus("Payment Submitted")).toBe("payment_submitted");
|
|
expect(parsePaymentStatus("OUTSTANDING")).toBe("outstanding");
|
|
expect(parsePaymentStatus("scheduled")).toBe("scheduled");
|
|
expect(parsePaymentStatus("voided")).toBeNull();
|
|
});
|
|
|
|
it("allows forward transitions and same-rank no-ops", () => {
|
|
expect(canTransitionPaymentStatus("scheduled", "payment_submitted")).toBe(true);
|
|
expect(canTransitionPaymentStatus("issued", "Outstanding")).toBe(true);
|
|
expect(canTransitionPaymentStatus("outstanding", "outstanding")).toBe(true);
|
|
expect(canTransitionPaymentStatus("outstanding", "cleared")).toBe(true);
|
|
});
|
|
|
|
it("blocks non-cancel rank regression", () => {
|
|
expect(canTransitionPaymentStatus("issued", "scheduled")).toBe(false);
|
|
expect(canTransitionPaymentStatus("cleared", "outstanding")).toBe(false);
|
|
expect(canTransitionPaymentStatus("payment_submitted", "Scheduled")).toBe(false);
|
|
});
|
|
|
|
it("allows void from ranks below cleared", () => {
|
|
for (const status of ["scheduled", "payment_submitted", "issued", "outstanding"] as const) {
|
|
expect(canTransitionPaymentStatus(status, "voided")).toBe(true);
|
|
expect(canTransitionPaymentStatus(status, "Cancelled")).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("blocks all transitions once cleared, including void", () => {
|
|
expect(canTransitionPaymentStatus("cleared", "voided")).toBe(false);
|
|
expect(canTransitionPaymentStatus("cleared", "cleared")).toBe(false);
|
|
expect(canTransitionPaymentStatus("cleared", "outstanding")).toBe(false);
|
|
});
|
|
|
|
it("recognizes cancel vocabulary case-insensitively", () => {
|
|
for (const status of CANCEL_STATUSES) {
|
|
expect(isCancelStatus(status)).toBe(true);
|
|
expect(isCancelStatus(status.toUpperCase())).toBe(true);
|
|
}
|
|
expect(isCancelStatus("Marked As Void")).toBe(true);
|
|
expect(isCancelStatus("Cleared")).toBe(false);
|
|
});
|
|
});
|