Files
0pt/lib/order-flow.ts
T
admin a2377215e7
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (pull_request) Successful in 7s
masterplan-lock / check (push) Successful in 8s
CI (SIAX Cloud) / security (pull_request) Successful in 19s
Security Scan (SIAX Cloud) / security (push) Successful in 20s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 23s
CI (SIAX Cloud) / security (push) Successful in 24s
CI (SIAX Cloud) / integration (pull_request) Successful in 31s
CI (SIAX Cloud) / quality (push) Successful in 44s
CI (SIAX Cloud) / quality (pull_request) Successful in 2m13s
feat(admin): InboxList — orderkön som universal inkorg (våg 3.3-adoption)
Servern projicerar öppna ordrar (draft/quoted/in_production/review) på
universal-inbox-konvolverna via createInboxItem (buildOrderInboxItem i
lib/order-flow, ADR-0001-mönstret: policy/resolution i serverlagret).
Admin renderar InboxList (@siax/ui 0.11.1) ovanpå orderkön — resolve-
aktionen gateras genom advance_action-state (available krävs). Terminala
statusar ger ingen post. tests/order-flow 6/6; full svit 1144/1144; build ✓.
2026-09-29 16:10:10 +02:00

61 lines
2.4 KiB
TypeScript

import { createInboxItem, type InboxItem } from "@siax/contracts/inbox";
import { resolveAction, type ResolvedAction } from "@siax/contracts/authz-ux";
/** Kanonisk orderflöde — servern äger resolutionen (ADR-0001), UI renderar. */
export const NEXT_STATUS: Record<string, string> = {
draft: "quoted",
quoted: "in_production",
in_production: "review",
review: "accepted",
accepted: "delivered",
};
/**
* Server-renderad action-resolution för advance-steget (ADR-0001):
* ägarskapenforces redan av requireOrderOwner på GET/PATCH; tillståndet
* avgör read_only. Innan Session/roller finns i 0pt är permission alltid
* granted för autentiserade ägare — hårdkoda aldrig denna resolve i klienten.
*/
export function resolveAdvanceAction(status: string): ResolvedAction {
if (NEXT_STATUS[status]) {
return resolveAction({ permission: "granted", entitlement: "active", approval: "not_required", readOnly: false });
}
return resolveAction({ permission: "granted", entitlement: "active", approval: "not_required", readOnly: true });
}
/** Orderstatus som utgör en inkorgspost (våg 3.3: orders kö = inbox). */
const INBOX_ELIGIBLE: Record<string, { kind: "task" | "approval"; priority: "normal" | "high" }> = {
draft: { kind: "task", priority: "normal" },
quoted: { kind: "task", priority: "normal" },
in_production: { kind: "task", priority: "normal" },
review: { kind: "approval", priority: "high" },
};
/**
* Server-renderad inkorgspost (ADR-0001-mönstret): en order som väntar på
* nästa steg projiceras på universal-inbox-konvolverna. Terminala statusar
* (delivered m.fl.) ger ingen post — inboxen är öppna arbetsobjekt.
*/
export function buildOrderInboxItem(order: {
order_id: string;
status: string;
flow: string;
total_ore?: number | null;
}): InboxItem | null {
const eligible = INBOX_ELIGIBLE[order.status];
if (!eligible) return null;
return createInboxItem({
id: `order:${order.order_id}`,
kind: eligible.kind,
tenantId: "0pt",
subject: `Order ${order.order_id.slice(0, 8)} — ${order.status} → ${NEXT_STATUS[order.status] ?? "nästa steg"}`,
priority: eligible.priority,
createdAt: new Date().toISOString(),
source: { system: "0pt", channel: "order-queue" },
entity: { type: "order", id: order.order_id },
actions: NEXT_STATUS[order.status]
? [{ id: "advance", label: `→ ${NEXT_STATUS[order.status]}` }]
: undefined,
});
}