import { ok, type CommandContext } from "@tailor-platform/erp-kit/core"; import { createDraft } from "../domain/outboundShipment"; import type { OutboundShipmentLineSourceDocumentType, OutboundShipmentLineStockType, } from "../generated/enums"; import type { Transaction } from "../generated/kysely-tailordb"; import type { InventoryQueries, ItemManagementQueries } from "../module"; import { createOutboundShipmentRepository, type OutboundShipmentRepository, } from "../repository/outboundShipmentRepository"; export interface OutboundShipmentLineInput { itemId: string; storageLocationId: string; quantity: string; unitId: string; primaryQuantity: string; primaryUnitId: string; unitConversionRate: string; stockType?: OutboundShipmentLineStockType; sourceDocumentType: OutboundShipmentLineSourceDocumentType; sourceDocumentId: string; sourceLineId: string; } export interface OutboundShipmentHeaderInput { effectiveDate: Date; } export interface CreateOutboundShipmentInput { header: OutboundShipmentHeaderInput; lines: OutboundShipmentLineInput[]; } export async function run, LCF extends Record>( db: Transaction, input: { header: OutboundShipmentHeaderInput & CF; lines: (OutboundShipmentLineInput & LCF)[]; }, ctx: CommandContext, itemManagementQueries: Pick, inventoryQueries: Pick, repositoryFactory: ( db: Transaction, ) => OutboundShipmentRepository = createOutboundShipmentRepository, ) { const { effectiveDate, ...headerCustomFields } = input.header; // Whether a referenced record satisfies the rules is judged by the domain, // which treats a missing entry as a nonexistent reference. const itemById = new Map(); for (const itemId of new Set(input.lines.map((line) => line.itemId))) { const { item } = (await itemManagementQueries.getItem(db, { id: itemId }, ctx)).value; if (item) { itemById.set(itemId, item); } } const storageLocationById = new Map(); for (const locationId of new Set(input.lines.map((line) => line.storageLocationId))) { const { storageLocation } = ( await inventoryQueries.getStorageLocation(db, { id: locationId }, ctx) ).value; if (storageLocation) { storageLocationById.set(locationId, storageLocation); } } const shipment = createDraft( { effectiveDate, customFields: headerCustomFields, lines: input.lines.map((line) => { const { itemId, storageLocationId, quantity, unitId, primaryQuantity, primaryUnitId, unitConversionRate, stockType, sourceDocumentType, sourceDocumentId, sourceLineId, ...lineCustomFields } = line; return { itemId, storageLocationId, quantity, unitId, primaryQuantity, primaryUnitId, unitConversionRate, stockType, sourceDocumentType, sourceDocumentId, sourceLineId, customFields: lineCustomFields, }; }), }, { itemById, storageLocationById }, ); if (!shipment.ok) { return shipment; } await repositoryFactory(db).save(shipment.value); return ok({ outboundShipmentId: shipment.value.id }); }