import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import { manufacturingCostSummaryLifecycle } from "../db/manufacturingCostSummary.lifecycle.generated"; import type { Transaction } from "../generated/kysely-tailordb"; import { CostSummaryNotFoundError, CostSummaryNotSettlableError, AcknowledgmentMismatchError, AcknowledgmentRejectedOrSupersededError, AcknowledgmentSourceInvalidError, } from "../lib/errors.generated"; export interface RecordManufacturingCostSettlementAcknowledgmentInput { costSummaryId: string; productionOrderId: string; currencyCode: string; settlementReference: string; settlementDate: string; acknowledgedDate?: string | null; acknowledgmentStatus?: string | null; acknowledgmentSource?: string | null; } /** * Function: recordManufacturingCostSettlementAcknowledgment * * Persists the downstream accounting acknowledgment that a reviewed * manufacturing cost handoff has been consumed by settlement processing. * It is the only path that moves a reviewed summary to SETTLED. */ export async function run( db: Transaction, input: RecordManufacturingCostSettlementAcknowledgmentInput, _ctx: CommandContext, ) { const { costSummaryId, productionOrderId, currencyCode, settlementReference, settlementDate, acknowledgedDate, acknowledgmentStatus, acknowledgmentSource, } = input; // 1. Validate acknowledgment source if (!acknowledgmentSource) { return err(new AcknowledgmentSourceInvalidError(costSummaryId)); } // 2. Resolve cost summary const costSummary = await db .selectFrom("ManufacturingCostSummary") .selectAll() .where("id", "=", costSummaryId) .forUpdate() .executeTakeFirst(); if (!costSummary) { return err(new CostSummaryNotFoundError(costSummaryId)); } // 3. Summary must be VARIANCE_REVIEWED const nextStatus = manufacturingCostSummaryLifecycle.tryTransition(costSummary.status, "settle"); if (!nextStatus) { return err(new CostSummaryNotSettlableError(costSummaryId)); } // 4. Validate payload matches the reviewed summary's identity and currency if ( costSummary.productionOrderId !== productionOrderId || costSummary.currencyCode !== currencyCode ) { return err(new AcknowledgmentMismatchError(costSummaryId)); } // 5. Check that downstream accounting accepted (not rejected/reversed/superseded) if ( acknowledgmentStatus === "REJECTED" || acknowledgmentStatus === "REVERSED" || acknowledgmentStatus === "SUPERSEDED" ) { return err(new AcknowledgmentRejectedOrSupersededError(costSummaryId)); } // 6. Create settlement record await db .insertInto("ManufacturingCostSettlementRecord") .values({ costSummaryId: costSummary.id, settlementDate: new Date(settlementDate), settlementReference, acknowledgedDate: acknowledgedDate ? new Date(acknowledgedDate) : new Date(), }) .returningAll() .executeTakeFirst(); // 7. Update summary to SETTLED const updatedSummary = await db .updateTable("ManufacturingCostSummary") .set({ status: nextStatus, }) .where("id", "=", costSummary.id) .returningAll() .executeTakeFirstOrThrow(); return ok({ manufacturingCostSummary: updatedSummary }); }