diff --git a/api/src/routes/checkout.ts b/api/src/routes/checkout.ts index 8f8c2ea..69e9693 100644 --- a/api/src/routes/checkout.ts +++ b/api/src/routes/checkout.ts @@ -348,6 +348,27 @@ export async function ensureComplianceSalesOrder( custom_surcharge_pct: surchargePct, workflow_state: "Received", items: lineItems, + }).catch(async (e: unknown) => { + // Resilience: if a service's ERPNext Item is missing, the SO would 404. + // Retry once with every line item remapped to the generic COMPLIANCE-SERVICE + // item so a missing catalog Item never strands a paid order's SO. (The + // catalog Item should still be created; this is a safety net.) + const msg = String((e as { body?: { _server_messages?: string } })?.body?._server_messages || e); + if (/not found/i.test(msg)) { + console.warn(`[checkout] SO item missing for ${orderId}, retrying with generic item:`, msg.slice(0, 120)); + const fallback = lineItems.map(li => ({ ...li, item_code: "COMPLIANCE-SERVICE" })); + return createResource("Sales Order", { + customer: erpnextCustomer, + delivery_date: new Date(Date.now() + 30 * 86400000).toISOString().split("T")[0], + custom_external_order_id: orderId, + custom_order_type: "compliance", + custom_payment_gateway: GATEWAY_LABELS[paymentMethod] || paymentMethod, + custom_surcharge_pct: surchargePct, + workflow_state: "Received", + items: fallback, + }); + } + throw e; })) as { name: string }; try {