@open-mercato/core 0.10.1-develop.7709.1.046124599c → 0.10.1-develop.7714.1.9dbb8200d8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/asn/index.js +19 -0
- package/dist/generated/entities/asn/index.js.map +7 -0
- package/dist/generated/entities/putaway_task/index.js +25 -0
- package/dist/generated/entities/putaway_task/index.js.map +7 -0
- package/dist/generated/entities/receiving_line/index.js +21 -0
- package/dist/generated/entities/receiving_line/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +4 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +34 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/communication_channels/lib/sanitize-channel-html.js +22 -3
- package/dist/modules/communication_channels/lib/sanitize-channel-html.js.map +2 -2
- package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.js +40 -11
- package/dist/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +13 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
- package/dist/modules/wms/acl.js +2 -0
- package/dist/modules/wms/acl.js.map +2 -2
- package/dist/modules/wms/api/asns/[id]/complete/route.js +61 -0
- package/dist/modules/wms/api/asns/[id]/complete/route.js.map +7 -0
- package/dist/modules/wms/api/asns/[id]/receive/route.js +68 -0
- package/dist/modules/wms/api/asns/[id]/receive/route.js.map +7 -0
- package/dist/modules/wms/api/asns/route.js +197 -0
- package/dist/modules/wms/api/asns/route.js.map +7 -0
- package/dist/modules/wms/api/inventory/helpers.js +42 -34
- package/dist/modules/wms/api/inventory/helpers.js.map +2 -2
- package/dist/modules/wms/api/inventory/receive/route.js +1 -1
- package/dist/modules/wms/api/inventory/receive/route.js.map +2 -2
- package/dist/modules/wms/api/listEnrichers.js +23 -0
- package/dist/modules/wms/api/listEnrichers.js.map +2 -2
- package/dist/modules/wms/api/putaway-tasks/[id]/assign/route.js +56 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/assign/route.js.map +7 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/cancel/route.js +56 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/cancel/route.js.map +7 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/complete/route.js +65 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/complete/route.js.map +7 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/start/route.js +56 -0
- package/dist/modules/wms/api/putaway-tasks/[id]/start/route.js.map +7 -0
- package/dist/modules/wms/api/putaway-tasks/create-from-balance/route.js +51 -0
- package/dist/modules/wms/api/putaway-tasks/create-from-balance/route.js.map +7 -0
- package/dist/modules/wms/api/putaway-tasks/route.js +192 -0
- package/dist/modules/wms/api/putaway-tasks/route.js.map +7 -0
- package/dist/modules/wms/api/receiving-lines/route.js +180 -0
- package/dist/modules/wms/api/receiving-lines/route.js.map +7 -0
- package/dist/modules/wms/api/scan/putaway/route.js +104 -0
- package/dist/modules/wms/api/scan/putaway/route.js.map +7 -0
- package/dist/modules/wms/api/scan/receive/route.js +109 -0
- package/dist/modules/wms/api/scan/receive/route.js.map +7 -0
- package/dist/modules/wms/api/scan/resolve-location/route.js +89 -0
- package/dist/modules/wms/api/scan/resolve-location/route.js.map +7 -0
- package/dist/modules/wms/api/scan/resolve-lot/route.js +89 -0
- package/dist/modules/wms/api/scan/resolve-lot/route.js.map +7 -0
- package/dist/modules/wms/backend/wms/asns/[id]/page.js +9 -0
- package/dist/modules/wms/backend/wms/asns/[id]/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/asns/[id]/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/asns/[id]/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/asns/page.js +9 -0
- package/dist/modules/wms/backend/wms/asns/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/asns/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/asns/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/putaway/page.js +9 -0
- package/dist/modules/wms/backend/wms/putaway/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/putaway/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/putaway/page.meta.js.map +7 -0
- package/dist/modules/wms/backend/wms/receiving/page.js +8 -0
- package/dist/modules/wms/backend/wms/receiving/page.js.map +7 -0
- package/dist/modules/wms/backend/wms/receiving/page.meta.js +18 -0
- package/dist/modules/wms/backend/wms/receiving/page.meta.js.map +7 -0
- package/dist/modules/wms/ce.js +27 -0
- package/dist/modules/wms/ce.js.map +2 -2
- package/dist/modules/wms/commands/asn.js +1746 -0
- package/dist/modules/wms/commands/asn.js.map +7 -0
- package/dist/modules/wms/commands/index.js +2 -0
- package/dist/modules/wms/commands/index.js.map +2 -2
- package/dist/modules/wms/commands/inventory-actions.js +347 -243
- package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
- package/dist/modules/wms/commands/putaway.js +945 -0
- package/dist/modules/wms/commands/putaway.js.map +7 -0
- package/dist/modules/wms/commands/shared.js +51 -0
- package/dist/modules/wms/commands/shared.js.map +2 -2
- package/dist/modules/wms/components/backend/AssignPutawayTaskDialog.js +278 -0
- package/dist/modules/wms/components/backend/AssignPutawayTaskDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/CompletePutawayTaskDialog.js +327 -0
- package/dist/modules/wms/components/backend/CompletePutawayTaskDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/CreateAsnDialog.js +404 -0
- package/dist/modules/wms/components/backend/CreateAsnDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/InventoryOperationsSection.js +16 -3
- package/dist/modules/wms/components/backend/InventoryOperationsSection.js.map +2 -2
- package/dist/modules/wms/components/backend/ReceiveAsnLineDialog.js +476 -0
- package/dist/modules/wms/components/backend/ReceiveAsnLineDialog.js.map +7 -0
- package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js +2 -2
- package/dist/modules/wms/components/backend/ReceiveInventoryDialog.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsAsnDetailPage.js +524 -0
- package/dist/modules/wms/components/backend/WmsAsnDetailPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsAsnsListPage.js +339 -0
- package/dist/modules/wms/components/backend/WmsAsnsListPage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +5 -6
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js +5 -6
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js +14 -10
- package/dist/modules/wms/components/backend/WmsOperationalDashboardPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsPutawayQueuePage.js +598 -0
- package/dist/modules/wms/components/backend/WmsPutawayQueuePage.js.map +7 -0
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +5 -6
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/asnCompleteOptimisticLock.js +32 -0
- package/dist/modules/wms/components/backend/asnCompleteOptimisticLock.js.map +7 -0
- package/dist/modules/wms/components/backend/asnReceivingLinesLoader.js +36 -0
- package/dist/modules/wms/components/backend/asnReceivingLinesLoader.js.map +7 -0
- package/dist/modules/wms/components/backend/inboundStatusUi.js +106 -0
- package/dist/modules/wms/components/backend/inboundStatusUi.js.map +7 -0
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +17 -0
- package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
- package/dist/modules/wms/components/backend/putawayQueueOptimisticLock.js +14 -0
- package/dist/modules/wms/components/backend/putawayQueueOptimisticLock.js.map +7 -0
- package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js +4 -0
- package/dist/modules/wms/components/backend/useWmsInventoryMutationAccess.js.map +2 -2
- package/dist/modules/wms/data/enrichers.js +117 -12
- package/dist/modules/wms/data/enrichers.js.map +2 -2
- package/dist/modules/wms/data/entities.js +150 -1
- package/dist/modules/wms/data/entities.js.map +2 -2
- package/dist/modules/wms/data/validators.js +214 -0
- package/dist/modules/wms/data/validators.js.map +2 -2
- package/dist/modules/wms/events.js +12 -1
- package/dist/modules/wms/events.js.map +2 -2
- package/dist/modules/wms/extension-points.js +3 -1
- package/dist/modules/wms/extension-points.js.map +2 -2
- package/dist/modules/wms/lib/asnReceiving.js +124 -0
- package/dist/modules/wms/lib/asnReceiving.js.map +7 -0
- package/dist/modules/wms/lib/asnVendor.js +52 -0
- package/dist/modules/wms/lib/asnVendor.js.map +7 -0
- package/dist/modules/wms/lib/flashMutationError.js +4 -0
- package/dist/modules/wms/lib/flashMutationError.js.map +2 -2
- package/dist/modules/wms/lib/inventoryDisplayUi.js +24 -0
- package/dist/modules/wms/lib/inventoryDisplayUi.js.map +2 -2
- package/dist/modules/wms/lib/inventoryPolicy.js +17 -0
- package/dist/modules/wms/lib/inventoryPolicy.js.map +2 -2
- package/dist/modules/wms/lib/loadOperationalDashboard.js +67 -1
- package/dist/modules/wms/lib/loadOperationalDashboard.js.map +2 -2
- package/dist/modules/wms/lib/putaway.js +141 -0
- package/dist/modules/wms/lib/putaway.js.map +7 -0
- package/dist/modules/wms/lib/roleFeatures.js +3 -1
- package/dist/modules/wms/lib/roleFeatures.js.map +2 -2
- package/dist/modules/wms/lib/salesOrderInventoryAutomation.js +99 -1
- package/dist/modules/wms/lib/salesOrderInventoryAutomation.js.map +2 -2
- package/dist/modules/wms/lib/scanResolve.js +147 -0
- package/dist/modules/wms/lib/scanResolve.js.map +7 -0
- package/dist/modules/wms/lib/wmsIntegrationToggles.js +1 -1
- package/dist/modules/wms/lib/wmsIntegrationToggles.js.map +2 -2
- package/dist/modules/wms/migrations/Migration20260812120000.js +43 -0
- package/dist/modules/wms/migrations/Migration20260812120000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260812130000.js +30 -0
- package/dist/modules/wms/migrations/Migration20260812130000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260822120000.js +17 -0
- package/dist/modules/wms/migrations/Migration20260822120000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20260822130000.js +17 -0
- package/dist/modules/wms/migrations/Migration20260822130000.js.map +7 -0
- package/dist/modules/wms/migrations/Migration20261029120000.js +13 -0
- package/dist/modules/wms/migrations/Migration20261029120000.js.map +7 -0
- package/dist/modules/wms/search.js +85 -0
- package/dist/modules/wms/search.js.map +2 -2
- package/dist/modules/wms/subscribers/asn-line-received-reevaluate-reservations.js +14 -0
- package/dist/modules/wms/subscribers/asn-line-received-reevaluate-reservations.js.map +7 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-asn.js +12 -0
- package/dist/modules/wms/subscribers/invalidate-enricher-cache-asn.js.map +7 -0
- package/dist/modules/wms/subscribers/procurement-goods-receipt-created.js +163 -0
- package/dist/modules/wms/subscribers/procurement-goods-receipt-created.js.map +7 -0
- package/dist/modules/wms/subscribers/putaway-completed-reevaluate-reservations.js +14 -0
- package/dist/modules/wms/subscribers/putaway-completed-reevaluate-reservations.js.map +7 -0
- package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js +37 -8
- package/dist/modules/wms/widgets/injection/sales-order-stock-context/widget.client.js.map +2 -2
- package/generated/entities/asn/index.ts +8 -0
- package/generated/entities/putaway_task/index.ts +11 -0
- package/generated/entities/receiving_line/index.ts +9 -0
- package/generated/entities.ids.generated.ts +4 -1
- package/generated/entity-fields-registry.ts +34 -0
- package/package.json +7 -7
- package/src/modules/auth/i18n/de.json +2 -0
- package/src/modules/auth/i18n/en.json +2 -0
- package/src/modules/auth/i18n/es.json +2 -0
- package/src/modules/auth/i18n/ko.json +2 -0
- package/src/modules/auth/i18n/pl.json +2 -0
- package/src/modules/communication_channels/i18n/de.json +2 -0
- package/src/modules/communication_channels/i18n/en.json +2 -0
- package/src/modules/communication_channels/i18n/es.json +2 -0
- package/src/modules/communication_channels/i18n/ko.json +2 -0
- package/src/modules/communication_channels/i18n/pl.json +2 -0
- package/src/modules/communication_channels/lib/sanitize-channel-html.ts +23 -3
- package/src/modules/communication_channels/widgets/injection/channel-payload-renderer/widget.client.tsx +44 -12
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +16 -2
- package/src/modules/wms/acl.ts +2 -0
- package/src/modules/wms/api/asns/[id]/complete/route.ts +62 -0
- package/src/modules/wms/api/asns/[id]/receive/route.ts +74 -0
- package/src/modules/wms/api/asns/route.ts +200 -0
- package/src/modules/wms/api/inventory/helpers.ts +57 -34
- package/src/modules/wms/api/inventory/receive/route.ts +2 -1
- package/src/modules/wms/api/listEnrichers.ts +38 -0
- package/src/modules/wms/api/putaway-tasks/[id]/assign/route.ts +56 -0
- package/src/modules/wms/api/putaway-tasks/[id]/cancel/route.ts +56 -0
- package/src/modules/wms/api/putaway-tasks/[id]/complete/route.ts +66 -0
- package/src/modules/wms/api/putaway-tasks/[id]/start/route.ts +56 -0
- package/src/modules/wms/api/putaway-tasks/create-from-balance/route.ts +50 -0
- package/src/modules/wms/api/putaway-tasks/route.ts +199 -0
- package/src/modules/wms/api/receiving-lines/route.ts +180 -0
- package/src/modules/wms/api/scan/putaway/route.ts +108 -0
- package/src/modules/wms/api/scan/receive/route.ts +118 -0
- package/src/modules/wms/api/scan/resolve-location/route.ts +92 -0
- package/src/modules/wms/api/scan/resolve-lot/route.ts +92 -0
- package/src/modules/wms/backend/wms/asns/[id]/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/asns/[id]/page.tsx +5 -0
- package/src/modules/wms/backend/wms/asns/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/asns/page.tsx +5 -0
- package/src/modules/wms/backend/wms/putaway/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/putaway/page.tsx +5 -0
- package/src/modules/wms/backend/wms/receiving/page.meta.ts +14 -0
- package/src/modules/wms/backend/wms/receiving/page.tsx +5 -0
- package/src/modules/wms/ce.ts +27 -0
- package/src/modules/wms/commands/asn.ts +2122 -0
- package/src/modules/wms/commands/index.ts +2 -0
- package/src/modules/wms/commands/inventory-actions.ts +413 -243
- package/src/modules/wms/commands/putaway.ts +1169 -0
- package/src/modules/wms/commands/shared.ts +51 -0
- package/src/modules/wms/components/backend/AssignPutawayTaskDialog.tsx +328 -0
- package/src/modules/wms/components/backend/CompletePutawayTaskDialog.tsx +366 -0
- package/src/modules/wms/components/backend/CreateAsnDialog.tsx +427 -0
- package/src/modules/wms/components/backend/InventoryOperationsSection.tsx +20 -2
- package/src/modules/wms/components/backend/ReceiveAsnLineDialog.tsx +535 -0
- package/src/modules/wms/components/backend/ReceiveInventoryDialog.tsx +2 -2
- package/src/modules/wms/components/backend/WmsAsnDetailPage.tsx +647 -0
- package/src/modules/wms/components/backend/WmsAsnsListPage.tsx +407 -0
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +4 -5
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +4 -5
- package/src/modules/wms/components/backend/WmsOperationalDashboardPage.tsx +12 -8
- package/src/modules/wms/components/backend/WmsPutawayQueuePage.tsx +677 -0
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +4 -5
- package/src/modules/wms/components/backend/asnCompleteOptimisticLock.ts +52 -0
- package/src/modules/wms/components/backend/asnReceivingLinesLoader.ts +83 -0
- package/src/modules/wms/components/backend/inboundStatusUi.ts +154 -0
- package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +20 -0
- package/src/modules/wms/components/backend/putawayQueueOptimisticLock.ts +20 -0
- package/src/modules/wms/components/backend/useWmsInventoryMutationAccess.ts +4 -0
- package/src/modules/wms/data/enrichers.ts +175 -13
- package/src/modules/wms/data/entities.ts +155 -0
- package/src/modules/wms/data/validators.ts +256 -0
- package/src/modules/wms/events.ts +11 -0
- package/src/modules/wms/extension-points.ts +2 -0
- package/src/modules/wms/i18n/de.json +205 -3
- package/src/modules/wms/i18n/en.json +205 -3
- package/src/modules/wms/i18n/es.json +205 -3
- package/src/modules/wms/i18n/ko.json +205 -3
- package/src/modules/wms/i18n/pl.json +205 -3
- package/src/modules/wms/lib/asnReceiving.ts +226 -0
- package/src/modules/wms/lib/asnVendor.ts +80 -0
- package/src/modules/wms/lib/flashMutationError.ts +4 -0
- package/src/modules/wms/lib/inventoryDisplayUi.ts +46 -0
- package/src/modules/wms/lib/inventoryPolicy.ts +31 -1
- package/src/modules/wms/lib/loadOperationalDashboard.ts +89 -1
- package/src/modules/wms/lib/putaway.ts +210 -0
- package/src/modules/wms/lib/roleFeatures.ts +2 -0
- package/src/modules/wms/lib/salesOrderInventoryAutomation.ts +150 -1
- package/src/modules/wms/lib/scanResolve.ts +185 -0
- package/src/modules/wms/lib/wmsIntegrationToggles.ts +2 -1
- package/src/modules/wms/migrations/.snapshot-open-mercato.json +1000 -0
- package/src/modules/wms/migrations/Migration20260812120000.ts +43 -0
- package/src/modules/wms/migrations/Migration20260812130000.ts +28 -0
- package/src/modules/wms/migrations/Migration20260822120000.ts +17 -0
- package/src/modules/wms/migrations/Migration20260822130000.ts +15 -0
- package/src/modules/wms/migrations/Migration20261029120000.ts +11 -0
- package/src/modules/wms/search.ts +95 -0
- package/src/modules/wms/subscribers/asn-line-received-reevaluate-reservations.ts +21 -0
- package/src/modules/wms/subscribers/invalidate-enricher-cache-asn.ts +12 -0
- package/src/modules/wms/subscribers/procurement-goods-receipt-created.ts +238 -0
- package/src/modules/wms/subscribers/putaway-completed-reevaluate-reservations.ts +21 -0
- package/src/modules/wms/widgets/injection/sales-order-stock-context/widget.client.tsx +63 -13
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/wms/api/putaway-tasks/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '@open-mercato/shared/lib/api/scoped'\nimport { E } from '#generated/entities.ids.generated'\nimport { PutawayTask } from '../../data/entities'\nimport { putawayTaskCreateSchema, putawayTaskUpdateSchema } from '../../data/validators'\nimport {\n assertPutawayLifecycleFieldsForbidden,\n buildPutawayTaskStatusFilter,\n} from '../../lib/putaway'\nimport { createPagedListResponseSchema, createWmsCrudOpenApi, defaultOkResponseSchema } from '../openapi'\n\nconst F = {\n id: 'id',\n organization_id: 'organization_id',\n tenant_id: 'tenant_id',\n warehouse_id: 'warehouse_id',\n source_location_id: 'source_location_id',\n target_location_id: 'target_location_id',\n catalog_variant_id: 'catalog_variant_id',\n lot_id: 'lot_id',\n serial_number: 'serial_number',\n quantity: 'quantity',\n status: 'status',\n assigned_to: 'assigned_to',\n priority: 'priority',\n created_at: 'created_at',\n updated_at: 'updated_at',\n} as const\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['wms.view'] },\n POST: { requireAuth: true, requireFeatures: ['wms.manage_putaway'] },\n PUT: { requireAuth: true, requireFeatures: ['wms.manage_putaway'] },\n DELETE: { requireAuth: true, requireFeatures: ['wms.manage_putaway'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(25),\n ids: z.string().optional(),\n warehouseId: z.string().uuid().optional(),\n // Single status or comma-separated (e.g. open,in_progress for the active queue).\n status: z.string().optional(),\n assignedTo: z.string().uuid().optional(),\n catalogVariantId: z.string().uuid().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: PutawayTask,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.wms.putaway_task },\n list: {\n schema: listSchema,\n disableListCache: true,\n entityId: E.wms.putaway_task,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.warehouse_id,\n F.source_location_id,\n F.target_location_id,\n F.catalog_variant_id,\n F.lot_id,\n F.serial_number,\n F.quantity,\n F.status,\n F.assigned_to,\n F.priority,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n status: F.status,\n priority: F.priority,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n quantity: F.quantity,\n },\n buildFilters: async (query) => {\n const filters: Record<string, unknown> = {}\n if (typeof query.ids === 'string' && query.ids.trim().length > 0) {\n filters[F.id] = {\n $in: query.ids\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0),\n }\n }\n if (typeof query.warehouseId === 'string' && query.warehouseId.length > 0) {\n filters[F.warehouse_id] = { $eq: query.warehouseId }\n }\n if (typeof query.status === 'string' && query.status.length > 0) {\n const statusFilter = buildPutawayTaskStatusFilter(query.status)\n if (statusFilter) filters[F.status] = statusFilter\n }\n if (typeof query.assignedTo === 'string' && query.assignedTo.length > 0) {\n filters[F.assigned_to] = { $eq: query.assignedTo }\n }\n if (typeof query.catalogVariantId === 'string' && query.catalogVariantId.length > 0) {\n filters[F.catalog_variant_id] = { $eq: query.catalogVariantId }\n }\n return filters\n },\n },\n actions: {\n create: {\n commandId: 'wms.putaway-tasks.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(putawayTaskCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.taskId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'wms.putaway-tasks.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n assertPutawayLifecycleFieldsForbidden(raw)\n return parseScopedCommandInput(putawayTaskUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'wms.putaway-tasks.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n return { id: resolveCrudRecordId(parsed, ctx, translate) }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst putawayTaskListItemSchema = z.object({\n id: z.string().uuid().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n warehouse_id: z.string().uuid().nullable().optional(),\n source_location_id: z.string().uuid().nullable().optional(),\n target_location_id: z.string().uuid().nullable().optional(),\n catalog_variant_id: z.string().uuid().nullable().optional(),\n lot_id: z.string().uuid().nullable().optional(),\n serial_number: z.string().nullable().optional(),\n quantity: z.union([z.string(), z.number()]).nullable().optional(),\n status: z.string().nullable().optional(),\n assigned_to: z.string().uuid().nullable().optional(),\n priority: z.union([z.string(), z.number()]).nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createWmsCrudOpenApi({\n resourceName: 'PutawayTask',\n pluralName: 'Putaway tasks',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(putawayTaskListItemSchema),\n create: {\n schema: putawayTaskCreateSchema,\n description:\n 'Creates an open putaway task after verifying available staging balance (on-hand minus reserved/allocated minus open/in-progress putaway commitments). Target location may be null until completion. Assignee changes use POST .../assign.',\n },\n update: {\n schema: putawayTaskUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description:\n 'Updates putaway task fields (locations, quantity, priority, metadata). Status and assignedTo are lifecycle-only \u2014 use POST .../{assign,start,complete,cancel}.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Soft-deletes a putaway task by id.',\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
|
|
3
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
4
|
+
import { parseScopedCommandInput, resolveCrudRecordId } from "@open-mercato/shared/lib/api/scoped";
|
|
5
|
+
import { E } from "../../../../generated/entities.ids.generated.js";
|
|
6
|
+
import { ReceivingLine } from "../../data/entities.js";
|
|
7
|
+
import { receivingLineCreateSchema, receivingLineUpdateSchema } from "../../data/validators.js";
|
|
8
|
+
import { assertReceivingLineLifecycleFieldsForbidden } from "../../lib/asnReceiving.js";
|
|
9
|
+
import { createPagedListResponseSchema, createWmsCrudOpenApi, defaultOkResponseSchema } from "../openapi.js";
|
|
10
|
+
const F = {
|
|
11
|
+
id: "id",
|
|
12
|
+
organization_id: "organization_id",
|
|
13
|
+
tenant_id: "tenant_id",
|
|
14
|
+
asn_id: "asn_id",
|
|
15
|
+
catalog_variant_id: "catalog_variant_id",
|
|
16
|
+
expected_qty: "expected_qty",
|
|
17
|
+
received_qty: "received_qty",
|
|
18
|
+
lot_number: "lot_number",
|
|
19
|
+
serial_numbers: "serial_numbers",
|
|
20
|
+
qc_status: "qc_status",
|
|
21
|
+
target_staging_location_id: "target_staging_location_id",
|
|
22
|
+
rejection_reason: "rejection_reason",
|
|
23
|
+
created_at: "created_at",
|
|
24
|
+
updated_at: "updated_at"
|
|
25
|
+
};
|
|
26
|
+
const routeMetadata = {
|
|
27
|
+
GET: { requireAuth: true, requireFeatures: ["wms.view"] },
|
|
28
|
+
POST: { requireAuth: true, requireFeatures: ["wms.manage_asn"] },
|
|
29
|
+
PUT: { requireAuth: true, requireFeatures: ["wms.manage_asn"] },
|
|
30
|
+
DELETE: { requireAuth: true, requireFeatures: ["wms.manage_asn"] }
|
|
31
|
+
};
|
|
32
|
+
const metadata = routeMetadata;
|
|
33
|
+
const rawBodySchema = z.object({}).passthrough();
|
|
34
|
+
const listSchema = z.object({
|
|
35
|
+
page: z.coerce.number().min(1).default(1),
|
|
36
|
+
pageSize: z.coerce.number().min(1).max(100).default(25),
|
|
37
|
+
ids: z.string().optional(),
|
|
38
|
+
asnId: z.string().uuid().optional(),
|
|
39
|
+
catalogVariantId: z.string().uuid().optional(),
|
|
40
|
+
qcStatus: z.enum(["pending", "passed", "failed"]).optional(),
|
|
41
|
+
sortField: z.string().optional(),
|
|
42
|
+
sortDir: z.enum(["asc", "desc"]).optional()
|
|
43
|
+
}).passthrough();
|
|
44
|
+
const crud = makeCrudRoute({
|
|
45
|
+
metadata: routeMetadata,
|
|
46
|
+
orm: {
|
|
47
|
+
entity: ReceivingLine,
|
|
48
|
+
idField: "id",
|
|
49
|
+
orgField: "organizationId",
|
|
50
|
+
tenantField: "tenantId",
|
|
51
|
+
softDeleteField: "deletedAt"
|
|
52
|
+
},
|
|
53
|
+
indexer: { entityType: E.wms.receiving_line },
|
|
54
|
+
list: {
|
|
55
|
+
schema: listSchema,
|
|
56
|
+
disableListCache: true,
|
|
57
|
+
entityId: E.wms.receiving_line,
|
|
58
|
+
fields: [
|
|
59
|
+
F.id,
|
|
60
|
+
F.organization_id,
|
|
61
|
+
F.tenant_id,
|
|
62
|
+
F.asn_id,
|
|
63
|
+
F.catalog_variant_id,
|
|
64
|
+
F.expected_qty,
|
|
65
|
+
F.received_qty,
|
|
66
|
+
F.lot_number,
|
|
67
|
+
F.serial_numbers,
|
|
68
|
+
F.qc_status,
|
|
69
|
+
F.target_staging_location_id,
|
|
70
|
+
F.rejection_reason,
|
|
71
|
+
F.created_at,
|
|
72
|
+
F.updated_at
|
|
73
|
+
],
|
|
74
|
+
sortFieldMap: {
|
|
75
|
+
expectedQty: F.expected_qty,
|
|
76
|
+
receivedQty: F.received_qty,
|
|
77
|
+
qcStatus: F.qc_status,
|
|
78
|
+
createdAt: F.created_at,
|
|
79
|
+
updatedAt: F.updated_at
|
|
80
|
+
},
|
|
81
|
+
buildFilters: async (query) => {
|
|
82
|
+
const filters = {};
|
|
83
|
+
if (typeof query.ids === "string" && query.ids.trim().length > 0) {
|
|
84
|
+
filters[F.id] = {
|
|
85
|
+
$in: query.ids.split(",").map((value) => value.trim()).filter((value) => value.length > 0)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (typeof query.asnId === "string" && query.asnId.length > 0) {
|
|
89
|
+
filters[F.asn_id] = { $eq: query.asnId };
|
|
90
|
+
}
|
|
91
|
+
if (typeof query.catalogVariantId === "string" && query.catalogVariantId.length > 0) {
|
|
92
|
+
filters[F.catalog_variant_id] = { $eq: query.catalogVariantId };
|
|
93
|
+
}
|
|
94
|
+
if (typeof query.qcStatus === "string" && query.qcStatus.length > 0) {
|
|
95
|
+
filters[F.qc_status] = { $eq: query.qcStatus };
|
|
96
|
+
}
|
|
97
|
+
return filters;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
actions: {
|
|
101
|
+
create: {
|
|
102
|
+
commandId: "wms.receiving-lines.create",
|
|
103
|
+
schema: rawBodySchema,
|
|
104
|
+
mapInput: async ({ raw, ctx }) => {
|
|
105
|
+
const { translate } = await resolveTranslations();
|
|
106
|
+
return parseScopedCommandInput(receivingLineCreateSchema, raw ?? {}, ctx, translate);
|
|
107
|
+
},
|
|
108
|
+
response: ({ result }) => ({ id: result?.lineId ?? null }),
|
|
109
|
+
status: 201
|
|
110
|
+
},
|
|
111
|
+
update: {
|
|
112
|
+
commandId: "wms.receiving-lines.update",
|
|
113
|
+
schema: rawBodySchema,
|
|
114
|
+
mapInput: async ({ raw, ctx }) => {
|
|
115
|
+
const { translate } = await resolveTranslations();
|
|
116
|
+
assertReceivingLineLifecycleFieldsForbidden(raw);
|
|
117
|
+
return parseScopedCommandInput(receivingLineUpdateSchema, raw ?? {}, ctx, translate);
|
|
118
|
+
},
|
|
119
|
+
response: () => ({ ok: true })
|
|
120
|
+
},
|
|
121
|
+
delete: {
|
|
122
|
+
commandId: "wms.receiving-lines.delete",
|
|
123
|
+
schema: rawBodySchema,
|
|
124
|
+
mapInput: async ({ parsed, ctx }) => {
|
|
125
|
+
const { translate } = await resolveTranslations();
|
|
126
|
+
return { id: resolveCrudRecordId(parsed, ctx, translate) };
|
|
127
|
+
},
|
|
128
|
+
response: () => ({ ok: true })
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
const GET = crud.GET;
|
|
133
|
+
const POST = crud.POST;
|
|
134
|
+
const PUT = crud.PUT;
|
|
135
|
+
const DELETE = crud.DELETE;
|
|
136
|
+
const receivingLineListItemSchema = z.object({
|
|
137
|
+
id: z.string().uuid().nullable().optional(),
|
|
138
|
+
organization_id: z.string().uuid().nullable().optional(),
|
|
139
|
+
tenant_id: z.string().uuid().nullable().optional(),
|
|
140
|
+
asn_id: z.string().uuid().nullable().optional(),
|
|
141
|
+
catalog_variant_id: z.string().uuid().nullable().optional(),
|
|
142
|
+
expected_qty: z.union([z.string(), z.number()]).nullable().optional(),
|
|
143
|
+
received_qty: z.union([z.string(), z.number()]).nullable().optional(),
|
|
144
|
+
lot_number: z.string().nullable().optional(),
|
|
145
|
+
serial_numbers: z.array(z.string()).nullable().optional(),
|
|
146
|
+
qc_status: z.string().nullable().optional(),
|
|
147
|
+
target_staging_location_id: z.string().uuid().nullable().optional(),
|
|
148
|
+
rejection_reason: z.string().nullable().optional(),
|
|
149
|
+
created_at: z.string().nullable().optional(),
|
|
150
|
+
updated_at: z.string().nullable().optional()
|
|
151
|
+
});
|
|
152
|
+
const openApi = createWmsCrudOpenApi({
|
|
153
|
+
resourceName: "ReceivingLine",
|
|
154
|
+
pluralName: "Receiving lines",
|
|
155
|
+
querySchema: listSchema,
|
|
156
|
+
listResponseSchema: createPagedListResponseSchema(receivingLineListItemSchema),
|
|
157
|
+
create: {
|
|
158
|
+
schema: receivingLineCreateSchema,
|
|
159
|
+
description: "Creates a receiving line against an ASN."
|
|
160
|
+
},
|
|
161
|
+
update: {
|
|
162
|
+
schema: receivingLineUpdateSchema,
|
|
163
|
+
responseSchema: defaultOkResponseSchema,
|
|
164
|
+
description: "Updates a receiving line by id."
|
|
165
|
+
},
|
|
166
|
+
del: {
|
|
167
|
+
schema: z.object({ id: z.string().uuid() }),
|
|
168
|
+
responseSchema: defaultOkResponseSchema,
|
|
169
|
+
description: "Soft-deletes a receiving line by id."
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
export {
|
|
173
|
+
DELETE,
|
|
174
|
+
GET,
|
|
175
|
+
POST,
|
|
176
|
+
PUT,
|
|
177
|
+
metadata,
|
|
178
|
+
openApi
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/wms/api/receiving-lines/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '@open-mercato/shared/lib/api/scoped'\nimport { E } from '#generated/entities.ids.generated'\nimport { ReceivingLine } from '../../data/entities'\nimport { receivingLineCreateSchema, receivingLineUpdateSchema } from '../../data/validators'\nimport { assertReceivingLineLifecycleFieldsForbidden } from '../../lib/asnReceiving'\nimport { createPagedListResponseSchema, createWmsCrudOpenApi, defaultOkResponseSchema } from '../openapi'\n\nconst F = {\n id: 'id',\n organization_id: 'organization_id',\n tenant_id: 'tenant_id',\n asn_id: 'asn_id',\n catalog_variant_id: 'catalog_variant_id',\n expected_qty: 'expected_qty',\n received_qty: 'received_qty',\n lot_number: 'lot_number',\n serial_numbers: 'serial_numbers',\n qc_status: 'qc_status',\n target_staging_location_id: 'target_staging_location_id',\n rejection_reason: 'rejection_reason',\n created_at: 'created_at',\n updated_at: 'updated_at',\n} as const\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['wms.view'] },\n POST: { requireAuth: true, requireFeatures: ['wms.manage_asn'] },\n PUT: { requireAuth: true, requireFeatures: ['wms.manage_asn'] },\n DELETE: { requireAuth: true, requireFeatures: ['wms.manage_asn'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(25),\n ids: z.string().optional(),\n asnId: z.string().uuid().optional(),\n catalogVariantId: z.string().uuid().optional(),\n qcStatus: z.enum(['pending', 'passed', 'failed']).optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: ReceivingLine,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.wms.receiving_line },\n list: {\n schema: listSchema,\n disableListCache: true,\n entityId: E.wms.receiving_line,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.asn_id,\n F.catalog_variant_id,\n F.expected_qty,\n F.received_qty,\n F.lot_number,\n F.serial_numbers,\n F.qc_status,\n F.target_staging_location_id,\n F.rejection_reason,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n expectedQty: F.expected_qty,\n receivedQty: F.received_qty,\n qcStatus: F.qc_status,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => {\n const filters: Record<string, unknown> = {}\n if (typeof query.ids === 'string' && query.ids.trim().length > 0) {\n filters[F.id] = {\n $in: query.ids.split(',').map((value) => value.trim()).filter((value) => value.length > 0),\n }\n }\n if (typeof query.asnId === 'string' && query.asnId.length > 0) {\n filters[F.asn_id] = { $eq: query.asnId }\n }\n if (typeof query.catalogVariantId === 'string' && query.catalogVariantId.length > 0) {\n filters[F.catalog_variant_id] = { $eq: query.catalogVariantId }\n }\n if (typeof query.qcStatus === 'string' && query.qcStatus.length > 0) {\n filters[F.qc_status] = { $eq: query.qcStatus }\n }\n return filters\n },\n },\n actions: {\n create: {\n commandId: 'wms.receiving-lines.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(receivingLineCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.lineId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'wms.receiving-lines.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n assertReceivingLineLifecycleFieldsForbidden(raw)\n return parseScopedCommandInput(receivingLineUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'wms.receiving-lines.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n return { id: resolveCrudRecordId(parsed, ctx, translate) }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst receivingLineListItemSchema = z.object({\n id: z.string().uuid().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n asn_id: z.string().uuid().nullable().optional(),\n catalog_variant_id: z.string().uuid().nullable().optional(),\n expected_qty: z.union([z.string(), z.number()]).nullable().optional(),\n received_qty: z.union([z.string(), z.number()]).nullable().optional(),\n lot_number: z.string().nullable().optional(),\n serial_numbers: z.array(z.string()).nullable().optional(),\n qc_status: z.string().nullable().optional(),\n target_staging_location_id: z.string().uuid().nullable().optional(),\n rejection_reason: z.string().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createWmsCrudOpenApi({\n resourceName: 'ReceivingLine',\n pluralName: 'Receiving lines',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(receivingLineListItemSchema),\n create: {\n schema: receivingLineCreateSchema,\n description: 'Creates a receiving line against an ASN.',\n },\n update: {\n schema: receivingLineUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates a receiving line by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Soft-deletes a receiving line by id.',\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
5
|
+
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
|
+
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
7
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
8
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
9
|
+
import { putawayTaskCompleteSchema, scanPutawaySchema } from "../../../data/validators.js";
|
|
10
|
+
import { resolveScanPutawayCommandInput } from "../../../lib/scanResolve.js";
|
|
11
|
+
import { executeWmsCustomPostRoute } from "../../inventory/helpers.js";
|
|
12
|
+
const logger = createLogger("wms");
|
|
13
|
+
const metadata = {
|
|
14
|
+
// Same floor ACL as putaway-tasks/:id/complete (command enforces manage vs assignee).
|
|
15
|
+
POST: { requireAuth: true, requireFeatures: ["wms.adjust_inventory"] }
|
|
16
|
+
};
|
|
17
|
+
const successSchema = z.object({
|
|
18
|
+
ok: z.literal(true),
|
|
19
|
+
movementId: z.string().uuid()
|
|
20
|
+
});
|
|
21
|
+
const errorSchema = z.object({ error: z.string() });
|
|
22
|
+
async function POST(request) {
|
|
23
|
+
try {
|
|
24
|
+
const container = await createRequestContainer();
|
|
25
|
+
const auth = await getAuthFromRequest(request);
|
|
26
|
+
if (!auth?.tenantId) {
|
|
27
|
+
throw new CrudHttpError(401, { error: "Unauthorized" });
|
|
28
|
+
}
|
|
29
|
+
const organizationScope = await resolveOrganizationScopeForRequest({
|
|
30
|
+
container,
|
|
31
|
+
auth,
|
|
32
|
+
request
|
|
33
|
+
});
|
|
34
|
+
const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null;
|
|
35
|
+
if (!organizationId) {
|
|
36
|
+
throw new CrudHttpError(400, { error: "organization_scope_required" });
|
|
37
|
+
}
|
|
38
|
+
const body = await readJsonSafe(request, {});
|
|
39
|
+
const parsed = scanPutawaySchema.parse(body);
|
|
40
|
+
if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {
|
|
41
|
+
throw new CrudHttpError(403, { error: "Forbidden" });
|
|
42
|
+
}
|
|
43
|
+
const scoped = {
|
|
44
|
+
...parsed,
|
|
45
|
+
tenantId: auth.tenantId,
|
|
46
|
+
organizationId
|
|
47
|
+
};
|
|
48
|
+
const em = container.resolve("em").fork();
|
|
49
|
+
const commandInput = await resolveScanPutawayCommandInput(em, scoped);
|
|
50
|
+
const scopedRequest = new Request(request.url, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: request.headers,
|
|
53
|
+
body: JSON.stringify(commandInput)
|
|
54
|
+
});
|
|
55
|
+
return executeWmsCustomPostRoute({
|
|
56
|
+
request: scopedRequest,
|
|
57
|
+
routePath: "wms/scan/putaway",
|
|
58
|
+
inputSchema: putawayTaskCompleteSchema,
|
|
59
|
+
commandId: "wms.putaway-tasks.complete",
|
|
60
|
+
describeResource: (input) => ({
|
|
61
|
+
resourceKind: "wms.putawayTask",
|
|
62
|
+
resourceId: input.id
|
|
63
|
+
}),
|
|
64
|
+
mapSuccess: (result) => ({
|
|
65
|
+
ok: true,
|
|
66
|
+
movementId: result.movementId
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (error instanceof CrudHttpError) {
|
|
71
|
+
return NextResponse.json(error.body, { status: error.status });
|
|
72
|
+
}
|
|
73
|
+
if (error instanceof z.ZodError) {
|
|
74
|
+
return NextResponse.json({ error: "Validation failed", details: error.issues }, { status: 400 });
|
|
75
|
+
}
|
|
76
|
+
logger.error("scan putaway failed", { err: error });
|
|
77
|
+
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const openApi = {
|
|
81
|
+
tag: "WMS",
|
|
82
|
+
summary: "Scan-assisted putaway complete",
|
|
83
|
+
methods: {
|
|
84
|
+
POST: {
|
|
85
|
+
summary: "Complete putaway from scanned target location code",
|
|
86
|
+
description: "Resolves the scanned target location code, then executes the same command path as POST /api/wms/putaway-tasks/:id/complete. Organization is taken from the authenticated session scope, not the request body. Requires `wms.adjust_inventory`; managers with `wms.manage_putaway` may complete any task, operators only when assigned.",
|
|
87
|
+
requestBody: { contentType: "application/json", schema: scanPutawaySchema },
|
|
88
|
+
responses: [{ status: 200, description: "Putaway completed", schema: successSchema }],
|
|
89
|
+
errors: [
|
|
90
|
+
{ status: 400, description: "Validation failed", schema: errorSchema },
|
|
91
|
+
{ status: 401, description: "Unauthorized", schema: errorSchema },
|
|
92
|
+
{ status: 404, description: "Task or location not found", schema: errorSchema },
|
|
93
|
+
{ status: 409, description: "Invalid putaway state or insufficient stock", schema: errorSchema },
|
|
94
|
+
{ status: 422, description: "Invalid or inactive location", schema: errorSchema }
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
export {
|
|
100
|
+
POST,
|
|
101
|
+
metadata,
|
|
102
|
+
openApi
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/wms/api/scan/putaway/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { putawayTaskCompleteSchema, scanPutawaySchema } from '../../../data/validators'\nimport { resolveScanPutawayCommandInput } from '../../../lib/scanResolve'\nimport { executeWmsCustomPostRoute } from '../../inventory/helpers'\n\nconst logger = createLogger('wms')\n\nexport const metadata = {\n // Same floor ACL as putaway-tasks/:id/complete (command enforces manage vs assignee).\n POST: { requireAuth: true, requireFeatures: ['wms.adjust_inventory'] },\n}\n\nconst successSchema = z.object({\n ok: z.literal(true),\n movementId: z.string().uuid(),\n})\nconst errorSchema = z.object({ error: z.string() })\n\nexport async function POST(request: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(request)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const organizationScope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n })\n const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: 'organization_scope_required' })\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = scanPutawaySchema.parse(body)\n if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {\n throw new CrudHttpError(403, { error: 'Forbidden' })\n }\n // Scope organization from auth/session \u2014 never trust body organizationId for\n // task/location resolve (same contract as scan/receive and resolve-location/lot).\n const scoped = {\n ...parsed,\n tenantId: auth.tenantId,\n organizationId,\n }\n const em = (container.resolve('em') as EntityManager).fork()\n const commandInput = await resolveScanPutawayCommandInput(em, scoped)\n const scopedRequest = new Request(request.url, {\n method: 'POST',\n headers: request.headers,\n body: JSON.stringify(commandInput),\n })\n return executeWmsCustomPostRoute({\n request: scopedRequest,\n routePath: 'wms/scan/putaway',\n inputSchema: putawayTaskCompleteSchema,\n commandId: 'wms.putaway-tasks.complete',\n describeResource: (input) => ({\n resourceKind: 'wms.putawayTask',\n resourceId: input.id,\n }),\n mapSuccess: (result: { movementId: string }) => ({\n ok: true,\n movementId: result.movementId,\n }),\n })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('scan putaway failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'WMS',\n summary: 'Scan-assisted putaway complete',\n methods: {\n POST: {\n summary: 'Complete putaway from scanned target location code',\n description:\n 'Resolves the scanned target location code, then executes the same command path as POST /api/wms/putaway-tasks/:id/complete. Organization is taken from the authenticated session scope, not the request body. Requires `wms.adjust_inventory`; managers with `wms.manage_putaway` may complete any task, operators only when assigned.',\n requestBody: { contentType: 'application/json', schema: scanPutawaySchema },\n responses: [{ status: 200, description: 'Putaway completed', schema: successSchema }],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Task or location not found', schema: errorSchema },\n { status: 409, description: 'Invalid putaway state or insufficient stock', schema: errorSchema },\n { status: 422, description: 'Invalid or inactive location', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
5
|
+
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
|
+
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
7
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
8
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
9
|
+
import { asnReceiveLineSchema, scanReceiveSchema } from "../../../data/validators.js";
|
|
10
|
+
import { resolveScanReceiveCommandInput } from "../../../lib/scanResolve.js";
|
|
11
|
+
import { executeWmsCustomPostRoute } from "../../inventory/helpers.js";
|
|
12
|
+
const logger = createLogger("wms");
|
|
13
|
+
const metadata = {
|
|
14
|
+
POST: { requireAuth: true, requireFeatures: ["wms.receive_inventory"] }
|
|
15
|
+
};
|
|
16
|
+
const successSchema = z.object({
|
|
17
|
+
ok: z.literal(true),
|
|
18
|
+
movementIds: z.array(z.string().uuid()),
|
|
19
|
+
putawayTaskIds: z.array(z.string().uuid()),
|
|
20
|
+
receivedQty: z.number().optional(),
|
|
21
|
+
asnUpdatedAt: z.string().datetime().optional()
|
|
22
|
+
});
|
|
23
|
+
const errorSchema = z.object({ error: z.string() });
|
|
24
|
+
async function POST(request) {
|
|
25
|
+
try {
|
|
26
|
+
const container = await createRequestContainer();
|
|
27
|
+
const auth = await getAuthFromRequest(request);
|
|
28
|
+
if (!auth?.tenantId) {
|
|
29
|
+
throw new CrudHttpError(401, { error: "Unauthorized" });
|
|
30
|
+
}
|
|
31
|
+
const organizationScope = await resolveOrganizationScopeForRequest({
|
|
32
|
+
container,
|
|
33
|
+
auth,
|
|
34
|
+
request
|
|
35
|
+
});
|
|
36
|
+
const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null;
|
|
37
|
+
if (!organizationId) {
|
|
38
|
+
throw new CrudHttpError(400, { error: "organization_scope_required" });
|
|
39
|
+
}
|
|
40
|
+
const body = await readJsonSafe(request, {});
|
|
41
|
+
const parsed = scanReceiveSchema.parse(body);
|
|
42
|
+
if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {
|
|
43
|
+
throw new CrudHttpError(403, { error: "Forbidden" });
|
|
44
|
+
}
|
|
45
|
+
const scoped = {
|
|
46
|
+
...parsed,
|
|
47
|
+
tenantId: auth.tenantId,
|
|
48
|
+
organizationId
|
|
49
|
+
};
|
|
50
|
+
const em = container.resolve("em").fork();
|
|
51
|
+
const commandInput = await resolveScanReceiveCommandInput(em, scoped);
|
|
52
|
+
const scopedRequest = new Request(request.url, {
|
|
53
|
+
method: "POST",
|
|
54
|
+
headers: request.headers,
|
|
55
|
+
body: JSON.stringify(commandInput)
|
|
56
|
+
});
|
|
57
|
+
return executeWmsCustomPostRoute({
|
|
58
|
+
request: scopedRequest,
|
|
59
|
+
routePath: "wms/scan/receive",
|
|
60
|
+
inputSchema: asnReceiveLineSchema,
|
|
61
|
+
commandId: "wms.asns.receive-line",
|
|
62
|
+
describeResource: (input) => ({
|
|
63
|
+
resourceKind: "wms.asn",
|
|
64
|
+
resourceId: input.asnId
|
|
65
|
+
}),
|
|
66
|
+
mapSuccess: (result) => ({
|
|
67
|
+
ok: true,
|
|
68
|
+
movementIds: result.movementIds,
|
|
69
|
+
putawayTaskIds: result.putawayTaskIds,
|
|
70
|
+
receivedQty: result.receivedQty,
|
|
71
|
+
asnUpdatedAt: result.asnUpdatedAt
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (error instanceof CrudHttpError) {
|
|
76
|
+
return NextResponse.json(error.body, { status: error.status });
|
|
77
|
+
}
|
|
78
|
+
if (error instanceof z.ZodError) {
|
|
79
|
+
return NextResponse.json({ error: "Validation failed", details: error.issues }, { status: 400 });
|
|
80
|
+
}
|
|
81
|
+
logger.error("scan receive failed", { err: error });
|
|
82
|
+
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const openApi = {
|
|
86
|
+
tag: "WMS",
|
|
87
|
+
summary: "Scan-assisted ASN receive",
|
|
88
|
+
methods: {
|
|
89
|
+
POST: {
|
|
90
|
+
summary: "Receive ASN line from scanned location/lot codes",
|
|
91
|
+
description: "Resolves scanned location (and optional lot) codes, then executes the same command path as POST /api/wms/asns/:id/receive. Organization is taken from the authenticated session scope, not the request body. Both QC-pass and QC-fail require absolute targetReceivedQty for retry-safe attempts (optional idempotencyKey is an extra stabilizer only).",
|
|
92
|
+
requestBody: { contentType: "application/json", schema: scanReceiveSchema },
|
|
93
|
+
responses: [{ status: 200, description: "ASN line received", schema: successSchema }],
|
|
94
|
+
errors: [
|
|
95
|
+
{ status: 400, description: "Validation failed", schema: errorSchema },
|
|
96
|
+
{ status: 401, description: "Unauthorized", schema: errorSchema },
|
|
97
|
+
{ status: 404, description: "ASN or location not found", schema: errorSchema },
|
|
98
|
+
{ status: 409, description: "Invalid receipt state", schema: errorSchema },
|
|
99
|
+
{ status: 422, description: "Tracking or QC transition invalid", schema: errorSchema }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
export {
|
|
105
|
+
POST,
|
|
106
|
+
metadata,
|
|
107
|
+
openApi
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/wms/api/scan/receive/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { asnReceiveLineSchema, scanReceiveSchema } from '../../../data/validators'\nimport { resolveScanReceiveCommandInput } from '../../../lib/scanResolve'\nimport { executeWmsCustomPostRoute } from '../../inventory/helpers'\n\nconst logger = createLogger('wms')\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['wms.receive_inventory'] },\n}\n\nconst successSchema = z.object({\n ok: z.literal(true),\n movementIds: z.array(z.string().uuid()),\n putawayTaskIds: z.array(z.string().uuid()),\n receivedQty: z.number().optional(),\n asnUpdatedAt: z.string().datetime().optional(),\n})\nconst errorSchema = z.object({ error: z.string() })\n\nexport async function POST(request: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(request)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const organizationScope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n })\n const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: 'organization_scope_required' })\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = scanReceiveSchema.parse(body)\n if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {\n throw new CrudHttpError(403, { error: 'Forbidden' })\n }\n // Scope organization from auth/session \u2014 never trust body organizationId for\n // ASN/location resolve (same contract as resolve-location / resolve-lot).\n const scoped = {\n ...parsed,\n tenantId: auth.tenantId,\n organizationId,\n }\n const em = (container.resolve('em') as EntityManager).fork()\n const commandInput = await resolveScanReceiveCommandInput(em, scoped)\n const scopedRequest = new Request(request.url, {\n method: 'POST',\n headers: request.headers,\n body: JSON.stringify(commandInput),\n })\n return executeWmsCustomPostRoute({\n request: scopedRequest,\n routePath: 'wms/scan/receive',\n inputSchema: asnReceiveLineSchema,\n commandId: 'wms.asns.receive-line',\n describeResource: (input) => ({\n resourceKind: 'wms.asn',\n resourceId: input.asnId,\n }),\n mapSuccess: (result: {\n movementIds: string[]\n putawayTaskIds: string[]\n receivedQty?: number\n asnUpdatedAt?: string\n }) => ({\n ok: true,\n movementIds: result.movementIds,\n putawayTaskIds: result.putawayTaskIds,\n receivedQty: result.receivedQty,\n asnUpdatedAt: result.asnUpdatedAt,\n }),\n })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('scan receive failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'WMS',\n summary: 'Scan-assisted ASN receive',\n methods: {\n POST: {\n summary: 'Receive ASN line from scanned location/lot codes',\n description:\n 'Resolves scanned location (and optional lot) codes, then executes the same command path as POST /api/wms/asns/:id/receive. Organization is taken from the authenticated session scope, not the request body. Both QC-pass and QC-fail require absolute targetReceivedQty for retry-safe attempts (optional idempotencyKey is an extra stabilizer only).',\n requestBody: { contentType: 'application/json', schema: scanReceiveSchema },\n responses: [{ status: 200, description: 'ASN line received', schema: successSchema }],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'ASN or location not found', schema: errorSchema },\n { status: 409, description: 'Invalid receipt state', schema: errorSchema },\n { status: 422, description: 'Tracking or QC transition invalid', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
5
|
+
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
|
+
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
7
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
8
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
9
|
+
import { scanResolveLocationSchema } from "../../../data/validators.js";
|
|
10
|
+
import { resolveLocationByCode } from "../../../lib/scanResolve.js";
|
|
11
|
+
const logger = createLogger("wms");
|
|
12
|
+
const metadata = {
|
|
13
|
+
POST: { requireAuth: true, requireFeatures: ["wms.view"] }
|
|
14
|
+
};
|
|
15
|
+
const successSchema = z.object({
|
|
16
|
+
ok: z.literal(true),
|
|
17
|
+
locationId: z.string().uuid(),
|
|
18
|
+
code: z.string(),
|
|
19
|
+
type: z.string()
|
|
20
|
+
});
|
|
21
|
+
const errorSchema = z.object({ error: z.string() });
|
|
22
|
+
async function POST(request) {
|
|
23
|
+
try {
|
|
24
|
+
const container = await createRequestContainer();
|
|
25
|
+
const auth = await getAuthFromRequest(request);
|
|
26
|
+
if (!auth?.tenantId) {
|
|
27
|
+
throw new CrudHttpError(401, { error: "Unauthorized" });
|
|
28
|
+
}
|
|
29
|
+
const organizationScope = await resolveOrganizationScopeForRequest({
|
|
30
|
+
container,
|
|
31
|
+
auth,
|
|
32
|
+
request
|
|
33
|
+
});
|
|
34
|
+
const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null;
|
|
35
|
+
if (!organizationId) {
|
|
36
|
+
throw new CrudHttpError(400, { error: "organization_scope_required" });
|
|
37
|
+
}
|
|
38
|
+
const body = await readJsonSafe(request, {});
|
|
39
|
+
const parsed = scanResolveLocationSchema.parse(body);
|
|
40
|
+
if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {
|
|
41
|
+
throw new CrudHttpError(403, { error: "Forbidden" });
|
|
42
|
+
}
|
|
43
|
+
const scoped = {
|
|
44
|
+
...parsed,
|
|
45
|
+
tenantId: auth.tenantId,
|
|
46
|
+
organizationId
|
|
47
|
+
};
|
|
48
|
+
const em = container.resolve("em").fork();
|
|
49
|
+
const resolved = await resolveLocationByCode(em, scoped);
|
|
50
|
+
return NextResponse.json({
|
|
51
|
+
ok: true,
|
|
52
|
+
locationId: resolved.locationId,
|
|
53
|
+
code: resolved.code,
|
|
54
|
+
type: resolved.type
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error instanceof CrudHttpError) {
|
|
58
|
+
return NextResponse.json(error.body, { status: error.status });
|
|
59
|
+
}
|
|
60
|
+
if (error instanceof z.ZodError) {
|
|
61
|
+
return NextResponse.json({ error: "Validation failed", details: error.issues }, { status: 400 });
|
|
62
|
+
}
|
|
63
|
+
logger.error("scan resolve-location failed", { err: error });
|
|
64
|
+
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const openApi = {
|
|
68
|
+
tag: "WMS",
|
|
69
|
+
summary: "Resolve scanned location code",
|
|
70
|
+
methods: {
|
|
71
|
+
POST: {
|
|
72
|
+
summary: "Resolve location by warehouse + barcode/code",
|
|
73
|
+
description: "Returns the canonical location id and type for a scanned warehouse location code. Organization is taken from the authenticated session scope, not the request body.",
|
|
74
|
+
requestBody: { contentType: "application/json", schema: scanResolveLocationSchema },
|
|
75
|
+
responses: [{ status: 200, description: "Location resolved", schema: successSchema }],
|
|
76
|
+
errors: [
|
|
77
|
+
{ status: 400, description: "Validation failed", schema: errorSchema },
|
|
78
|
+
{ status: 401, description: "Unauthorized", schema: errorSchema },
|
|
79
|
+
{ status: 404, description: "Location not found", schema: errorSchema }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
export {
|
|
85
|
+
POST,
|
|
86
|
+
metadata,
|
|
87
|
+
openApi
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/wms/api/scan/resolve-location/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { scanResolveLocationSchema } from '../../../data/validators'\nimport { resolveLocationByCode } from '../../../lib/scanResolve'\n\nconst logger = createLogger('wms')\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['wms.view'] },\n}\n\nconst successSchema = z.object({\n ok: z.literal(true),\n locationId: z.string().uuid(),\n code: z.string(),\n type: z.string(),\n})\nconst errorSchema = z.object({ error: z.string() })\n\nexport async function POST(request: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(request)\n if (!auth?.tenantId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const organizationScope = await resolveOrganizationScopeForRequest({\n container,\n auth,\n request,\n })\n const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, { error: 'organization_scope_required' })\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = scanResolveLocationSchema.parse(body)\n if (parsed.tenantId !== auth.tenantId && !auth.isSuperAdmin) {\n throw new CrudHttpError(403, { error: 'Forbidden' })\n }\n // Scope organization from auth/session \u2014 never trust body organizationId for cross-org reads.\n const scoped = {\n ...parsed,\n tenantId: auth.tenantId,\n organizationId,\n }\n const em = (container.resolve('em') as EntityManager).fork()\n const resolved = await resolveLocationByCode(em, scoped)\n return NextResponse.json({\n ok: true as const,\n locationId: resolved.locationId,\n code: resolved.code,\n type: resolved.type,\n })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: 'Validation failed', details: error.issues }, { status: 400 })\n }\n logger.error('scan resolve-location failed', { err: error })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'WMS',\n summary: 'Resolve scanned location code',\n methods: {\n POST: {\n summary: 'Resolve location by warehouse + barcode/code',\n description:\n 'Returns the canonical location id and type for a scanned warehouse location code. Organization is taken from the authenticated session scope, not the request body.',\n requestBody: { contentType: 'application/json', schema: scanResolveLocationSchema },\n responses: [{ status: 200, description: 'Location resolved', schema: successSchema }],\n errors: [\n { status: 400, description: 'Validation failed', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 404, description: 'Location not found', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|