change ewit images

This commit is contained in:
Marshal
2026-08-04 08:42:15 +00:00
parent 2eb752e8c2
commit aac1175964
2 changed files with 67 additions and 7 deletions

View File

@@ -145,12 +145,38 @@ export function paymentStatusLabel(status?: string | null): string {
}
/**
* Payment status pill. Once the booking's own lifecycle status has moved past
* payment (PAID or later — stage ≥ 3 in STATUS_CONFIG), payment is a settled
* fact: show "Paid" even if a stale/lagging `paymentStatus` value says
* otherwise, rather than surface a contradictory "Paid booking, pending
* payment" row.
* Booking statuses that are only reachable at or after the payment gate.
* Settlement writes `status` and `paymentStatus` in one transaction
* (booking-invoice.service.ts `advanceBookingOnPayment`), so these are a
* backstop for a stale/lagging `paymentStatus` — not the primary signal.
*/
const PAID_OR_LATER_STATUSES = new Set([
"PAID",
"TRUCK_ASSIGNED",
"IN_TRANSIT",
"ARRIVED",
"COMPLETED",
]);
/**
* Payment status pill. `paymentStatus` is authoritative; the status set above
* only covers a lagging read, so a booking past the payment gate never shows a
* contradictory "Paid booking, pending payment" row.
*
* Note the set is explicit rather than derived from `STATUS_CONFIG.stage` —
* stage is a portal timeline grouping, and stage 3 lumps pre-payment clearance
* statuses (AWAITING_DOCUMENTS, CLEARANCE_READY, SIGNED_CUSTOMER, OPERATION_*)
* in with genuinely post-payment ones, which made every freshly initiated
* contract booking render as "Paid".
*/
export function effectivePaymentStatus(
status?: string | null,
bookingStatus?: string | null,
): string | null | undefined {
const settled = bookingStatus ? PAID_OR_LATER_STATUSES.has(bookingStatus) : false;
return settled ? "PAID" : status;
}
export function PaymentBadge({
status,
bookingStatus,
@@ -158,8 +184,7 @@ export function PaymentBadge({
status?: string | null;
bookingStatus?: string | null;
}) {
const settled = bookingStatus ? (STATUS_CONFIG[bookingStatus]?.stage ?? 0) >= 3 : false;
const effective = settled ? "PAID" : status;
const effective = effectivePaymentStatus(status, bookingStatus);
if (!effective) return <Text fz={13} c="dimmed"></Text>;
return (
<Badge

View File

@@ -0,0 +1,35 @@
import { describe, expect, it } from "vitest";
import { effectivePaymentStatus } from "./booking-display";
describe("effectivePaymentStatus", () => {
it("keeps PENDING for pre-payment statuses", () => {
// Regression: these all sit at STATUS_CONFIG stage 3, so the old
// `stage >= 3` heuristic rendered every freshly initiated contract
// booking as "Paid".
for (const s of [
"AWAITING_DOCUMENTS",
"DOCUMENTS_UNDER_REVIEW",
"CLEARANCE_READY",
"SIGNED_CUSTOMER",
"FULLY_EXECUTED",
"SELECTED_FOR_BATCH",
"OPERATION_REQUEST_PENDING",
"PNR_GENERATED",
]) {
expect(effectivePaymentStatus("PENDING", s)).toBe("PENDING");
}
});
it("shows PAID once the booking is at or past the payment gate", () => {
for (const s of ["PAID", "TRUCK_ASSIGNED", "IN_TRANSIT", "ARRIVED", "COMPLETED"]) {
expect(effectivePaymentStatus("PENDING", s)).toBe("PAID");
}
});
it("passes the real payment status through when the booking status is absent", () => {
expect(effectivePaymentStatus("PAID", null)).toBe("PAID");
expect(effectivePaymentStatus("FAILED", undefined)).toBe("FAILED");
expect(effectivePaymentStatus(null, null)).toBeNull();
});
});