import { createContext, DomainError } from "@tailor-platform/erp-kit/app"; import { createResolver, t } from "@tailor-platform/sdk"; import { getDB } from "@/generated/kysely-tailordb"; import { inboundShipmentModulesExport } from "@/modules"; /** * Cancel a draft Inbound Shipment (DRAFT → CANCELLED). * * In erp-kit 0.45 the receipt is an InboundShipment; cancellation goes through * the inbound-shipment lifecycle's `cancel` transition, which only DRAFT * allows — POSTED is terminal. A missing row and a non-DRAFT receipt both * surface as INBOUND_SHIPMENT_INVALID_STATUS. The resolver name stays * `cancelInboundShipment` for frontend compatibility. */ export default createResolver({ name: "cancelInboundShipment", operation: "mutation", input: { id: t.string().description("Inbound shipment (InboundShipment) ID"), }, body: async (context) => { const ctx = createContext(context); const db = getDB("main-db"); return db .transaction() .execute(async (trx) => { const result = await inboundShipmentModulesExport.commands.cancelInboundShipment( trx, { id: context.input.id }, ctx, ); if (!result.ok) { switch (result.error.code) { case "INBOUND_SHIPMENT_INVALID_STATUS": throw new DomainError( `Inbound shipment cannot be cancelled — it does not exist or is not in DRAFT status: ${context.input.id}`, ); case "UNAUTHENTICATED": throw new DomainError("Authentication is required"); case "INSUFFICIENT_PERMISSION": throw new DomainError("You do not have permission to perform this action"); default: throw result.error satisfies never; } } return { id: result.value.inboundShipmentId, // A successful transition implies the target status. status: "CANCELLED", }; }) .catch((err: unknown) => { if (err instanceof DomainError) throw err; throw new Error("Failed to cancel the inbound shipment", { cause: err }); }); }, output: t .object({ id: t.string().description("Inbound shipment (InboundShipment) ID"), status: t.string().description("New inbound shipment status"), }) .description("CancelInboundShipment response"), });