@open-mercato/core 0.7.1-develop.7154.1.981330c924 → 0.7.1-develop.7171.1.9b31dbba45

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.
Files changed (155) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +2 -2
  3. package/dist/modules/auth/commands/users.js +14 -1
  4. package/dist/modules/auth/commands/users.js.map +2 -2
  5. package/dist/modules/auth/data/entities.js +2 -2
  6. package/dist/modules/auth/data/entities.js.map +2 -2
  7. package/dist/modules/auth/lib/backendChrome.js +26 -3
  8. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  9. package/dist/modules/auth/lib/profile-sections.js +1 -1
  10. package/dist/modules/auth/lib/profile-sections.js.map +2 -2
  11. package/dist/modules/auth/migrations/Migration20260907120000_auth.js +19 -0
  12. package/dist/modules/auth/migrations/Migration20260907120000_auth.js.map +7 -0
  13. package/dist/modules/communication_channels/backend/profile/communication-channels/page.meta.js +2 -2
  14. package/dist/modules/communication_channels/backend/profile/communication-channels/page.meta.js.map +1 -1
  15. package/dist/modules/customer_accounts/api/admin/demo-accounts.js +118 -0
  16. package/dist/modules/customer_accounts/api/admin/demo-accounts.js.map +7 -0
  17. package/dist/modules/customer_accounts/api/invitations/accept.js +23 -6
  18. package/dist/modules/customer_accounts/api/invitations/accept.js.map +2 -2
  19. package/dist/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.js +10 -13
  20. package/dist/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.js.map +2 -2
  21. package/dist/modules/customer_accounts/backend/customer_accounts/useDemoPortalAccounts.js +28 -0
  22. package/dist/modules/customer_accounts/backend/customer_accounts/useDemoPortalAccounts.js.map +7 -0
  23. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js +6 -1
  24. package/dist/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.js.map +2 -2
  25. package/dist/modules/customer_accounts/data/entities.js +4 -1
  26. package/dist/modules/customer_accounts/data/entities.js.map +2 -2
  27. package/dist/modules/customer_accounts/lib/exampleAccounts.js +9 -0
  28. package/dist/modules/customer_accounts/lib/exampleAccounts.js.map +7 -0
  29. package/dist/modules/customer_accounts/migrations/Migration20260827160000_customer_accounts.js +16 -0
  30. package/dist/modules/customer_accounts/migrations/Migration20260827160000_customer_accounts.js.map +7 -0
  31. package/dist/modules/customer_accounts/services/customerInvitationService.js +53 -6
  32. package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
  33. package/dist/modules/customer_accounts/setup.js +2 -6
  34. package/dist/modules/customer_accounts/setup.js.map +2 -2
  35. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +55 -40
  36. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  37. package/dist/modules/customers/commands/people.js +16 -1
  38. package/dist/modules/customers/commands/people.js.map +2 -2
  39. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +18 -36
  40. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  41. package/dist/modules/entities/api/records.js +18 -15
  42. package/dist/modules/entities/api/records.js.map +3 -3
  43. package/dist/modules/entities/lib/scoped-field-defs.js +52 -0
  44. package/dist/modules/entities/lib/scoped-field-defs.js.map +7 -0
  45. package/dist/modules/entities/lib/validation.js +4 -35
  46. package/dist/modules/entities/lib/validation.js.map +2 -2
  47. package/dist/modules/integrations/backend/integrations/[id]/page.js +32 -54
  48. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  49. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +12 -29
  50. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  51. package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js +2 -2
  52. package/dist/modules/notifications/backend/profile/notification-preferences/page.meta.js.map +1 -1
  53. package/dist/modules/progress/lib/progressServiceImpl.js +14 -3
  54. package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
  55. package/dist/modules/sales/backend/sales/documents/[id]/page.js +9 -9
  56. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  57. package/dist/modules/sales/components/documents/LineItemDialog.js +50 -10
  58. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  59. package/dist/modules/sales/components/documents/PaymentsSection.js +8 -3
  60. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  61. package/dist/modules/sales/components/documents/ReturnEditDialog.js +2 -7
  62. package/dist/modules/sales/components/documents/ReturnEditDialog.js.map +2 -2
  63. package/dist/modules/sales/components/documents/ReturnsSection.js +2 -7
  64. package/dist/modules/sales/components/documents/ReturnsSection.js.map +2 -2
  65. package/dist/modules/sales/components/documents/ShipmentsSection.js +3 -8
  66. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  67. package/dist/modules/wms/commands/sales-order-assignment.js +12 -0
  68. package/dist/modules/wms/commands/sales-order-assignment.js.map +2 -2
  69. package/dist/modules/wms/data/enrichers.js +25 -0
  70. package/dist/modules/wms/data/enrichers.js.map +2 -2
  71. package/dist/modules/wms/lib/enricherCacheTags.js +9 -0
  72. package/dist/modules/wms/lib/enricherCacheTags.js.map +7 -0
  73. package/dist/modules/wms/lib/invalidateInventoryEnricherCache.js +37 -0
  74. package/dist/modules/wms/lib/invalidateInventoryEnricherCache.js.map +7 -0
  75. package/dist/modules/wms/lib/inventoryEnricherCacheSubscriber.js +14 -0
  76. package/dist/modules/wms/lib/inventoryEnricherCacheSubscriber.js.map +7 -0
  77. package/dist/modules/wms/subscribers/invalidate-enricher-cache-balance.js +12 -0
  78. package/dist/modules/wms/subscribers/invalidate-enricher-cache-balance.js.map +7 -0
  79. package/dist/modules/wms/subscribers/invalidate-enricher-cache-inventory.js +12 -0
  80. package/dist/modules/wms/subscribers/invalidate-enricher-cache-inventory.js.map +7 -0
  81. package/dist/modules/wms/subscribers/invalidate-enricher-cache-movement.js +12 -0
  82. package/dist/modules/wms/subscribers/invalidate-enricher-cache-movement.js.map +7 -0
  83. package/dist/modules/wms/subscribers/invalidate-enricher-cache-profile.js +12 -0
  84. package/dist/modules/wms/subscribers/invalidate-enricher-cache-profile.js.map +7 -0
  85. package/dist/modules/wms/subscribers/invalidate-enricher-cache-reservation.js +12 -0
  86. package/dist/modules/wms/subscribers/invalidate-enricher-cache-reservation.js.map +7 -0
  87. package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-line.js +12 -0
  88. package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-line.js.map +7 -0
  89. package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-order.js +12 -0
  90. package/dist/modules/wms/subscribers/invalidate-enricher-cache-sales-order.js.map +7 -0
  91. package/dist/modules/wms/subscribers/invalidate-enricher-cache-variant.js +12 -0
  92. package/dist/modules/wms/subscribers/invalidate-enricher-cache-variant.js.map +7 -0
  93. package/dist/modules/wms/subscribers/invalidate-enricher-cache-warehouse.js +12 -0
  94. package/dist/modules/wms/subscribers/invalidate-enricher-cache-warehouse.js.map +7 -0
  95. package/package.json +7 -7
  96. package/src/modules/auth/commands/users.ts +14 -1
  97. package/src/modules/auth/data/entities.ts +2 -2
  98. package/src/modules/auth/lib/backendChrome.tsx +46 -2
  99. package/src/modules/auth/lib/profile-sections.tsx +14 -3
  100. package/src/modules/auth/migrations/.snapshot-open-mercato.json +4 -2
  101. package/src/modules/auth/migrations/Migration20260907120000_auth.ts +21 -0
  102. package/src/modules/communication_channels/backend/profile/communication-channels/page.meta.ts +2 -2
  103. package/src/modules/customer_accounts/AGENTS.md +3 -1
  104. package/src/modules/customer_accounts/api/admin/demo-accounts.ts +149 -0
  105. package/src/modules/customer_accounts/api/invitations/accept.ts +23 -6
  106. package/src/modules/customer_accounts/backend/customer_accounts/settings/CustomerAccountsSettingsPageClient.tsx +43 -41
  107. package/src/modules/customer_accounts/backend/customer_accounts/useDemoPortalAccounts.ts +42 -0
  108. package/src/modules/customer_accounts/backend/customer_accounts/users/PortalUsersPageClient.tsx +10 -3
  109. package/src/modules/customer_accounts/data/entities.ts +5 -1
  110. package/src/modules/customer_accounts/i18n/de.json +4 -2
  111. package/src/modules/customer_accounts/i18n/en.json +4 -2
  112. package/src/modules/customer_accounts/i18n/es.json +4 -2
  113. package/src/modules/customer_accounts/i18n/ko.json +4 -2
  114. package/src/modules/customer_accounts/i18n/pl.json +4 -2
  115. package/src/modules/customer_accounts/lib/exampleAccounts.ts +18 -0
  116. package/src/modules/customer_accounts/migrations/.snapshot-open-mercato.json +5 -7
  117. package/src/modules/customer_accounts/migrations/Migration20260827160000_customer_accounts.ts +23 -0
  118. package/src/modules/customer_accounts/services/customerInvitationService.ts +89 -5
  119. package/src/modules/customer_accounts/setup.ts +2 -6
  120. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +74 -41
  121. package/src/modules/customers/commands/people.ts +15 -0
  122. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +19 -44
  123. package/src/modules/entities/api/records.ts +24 -15
  124. package/src/modules/entities/lib/scoped-field-defs.ts +76 -0
  125. package/src/modules/entities/lib/validation.ts +5 -45
  126. package/src/modules/integrations/backend/integrations/[id]/page.tsx +33 -62
  127. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +13 -37
  128. package/src/modules/notifications/backend/profile/notification-preferences/page.meta.ts +2 -2
  129. package/src/modules/progress/AGENTS.md +1 -1
  130. package/src/modules/progress/lib/progressServiceImpl.ts +26 -3
  131. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +19 -25
  132. package/src/modules/sales/components/documents/LineItemDialog.tsx +53 -9
  133. package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -8
  134. package/src/modules/sales/components/documents/ReturnEditDialog.tsx +2 -8
  135. package/src/modules/sales/components/documents/ReturnsSection.tsx +8 -7
  136. package/src/modules/sales/components/documents/ShipmentsSection.tsx +9 -8
  137. package/src/modules/sales/i18n/de.json +2 -0
  138. package/src/modules/sales/i18n/en.json +2 -0
  139. package/src/modules/sales/i18n/es.json +2 -0
  140. package/src/modules/sales/i18n/ko.json +2 -0
  141. package/src/modules/sales/i18n/pl.json +2 -0
  142. package/src/modules/wms/commands/sales-order-assignment.ts +20 -0
  143. package/src/modules/wms/data/enrichers.ts +25 -0
  144. package/src/modules/wms/lib/enricherCacheTags.ts +29 -0
  145. package/src/modules/wms/lib/invalidateInventoryEnricherCache.ts +71 -0
  146. package/src/modules/wms/lib/inventoryEnricherCacheSubscriber.ts +30 -0
  147. package/src/modules/wms/subscribers/invalidate-enricher-cache-balance.ts +9 -0
  148. package/src/modules/wms/subscribers/invalidate-enricher-cache-inventory.ts +9 -0
  149. package/src/modules/wms/subscribers/invalidate-enricher-cache-movement.ts +9 -0
  150. package/src/modules/wms/subscribers/invalidate-enricher-cache-profile.ts +9 -0
  151. package/src/modules/wms/subscribers/invalidate-enricher-cache-reservation.ts +9 -0
  152. package/src/modules/wms/subscribers/invalidate-enricher-cache-sales-line.ts +14 -0
  153. package/src/modules/wms/subscribers/invalidate-enricher-cache-sales-order.ts +18 -0
  154. package/src/modules/wms/subscribers/invalidate-enricher-cache-variant.ts +9 -0
  155. package/src/modules/wms/subscribers/invalidate-enricher-cache-warehouse.ts +9 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/sales/components/documents/ShipmentsSection.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Pencil, Plus, Trash2, Truck } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { ErrorMessage, LoadingMessage, TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n emitSalesDocumentTotalsRefresh,\n subscribeSalesDocumentTotalsRefresh,\n} from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'\nimport type { SectionAction } from '@open-mercato/core/modules/customers/components/detail/types'\nimport { generateTempId } from '@open-mercato/core/modules/customers/lib/detailHelpers'\nimport { formatAddressString, type AddressValue } from '@open-mercato/core/modules/customers/utils/addressFormat'\nimport { ShipmentDialog } from './ShipmentDialog'\nimport { handleSectionMutationError, readRowUpdatedAt } from './optimisticLock'\nimport { extractCustomFieldValues } from './customFieldHelpers'\nimport type { OrderLine, ShipmentRow, ShipmentItem } from './shipmentTypes'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nconst ADDRESS_SNAPSHOT_KEY = 'shipmentAddressSnapshot'\nconst ADDRESS_FORMAT: 'line_first' = 'line_first'\n\ntype SalesShipmentsSectionProps = {\n orderId: string\n currencyCode?: string | null\n shippingAddressSnapshot?: Record<string, unknown> | null\n organizationId?: string | null\n tenantId?: string | null\n documentUpdatedAt?: string | null\n onActionChange?: (action: SectionAction | null) => void\n onAddComment?: (body: string) => Promise<void>\n}\n\nexport function formatDisplayDate(value: string | null | undefined, locale?: string): string | null {\n if (!value) return null\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return null\n return new Intl.DateTimeFormat(locale, { dateStyle: 'medium' }).format(date)\n}\n\nconst formatShipmentAddress = (metadata?: Record<string, unknown> | null): string | null => {\n if (!metadata || typeof metadata !== 'object') return null\n const snapshot = (metadata as any)[ADDRESS_SNAPSHOT_KEY]\n if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) return null\n const read = (key: string): string | null => {\n const value = (snapshot as any)[key]\n return typeof value === 'string' && value.trim().length ? value.trim() : null\n }\n const addressValue: AddressValue = {\n addressLine1: read('addressLine1') ?? read('address_line1'),\n addressLine2: read('addressLine2') ?? read('address_line2'),\n buildingNumber: read('buildingNumber') ?? read('building_number'),\n flatNumber: read('flatNumber') ?? read('flat_number'),\n city: read('city'),\n region: read('region'),\n postalCode: read('postalCode') ?? read('postal_code'),\n country: read('country'),\n companyName: read('companyName') ?? read('company_name'),\n }\n const summary = formatAddressString(addressValue, ADDRESS_FORMAT)\n return summary && summary.trim().length ? summary : null\n}\n\nconst resolveLineThumbnail = (item: Record<string, unknown>): string | null => {\n const pickThumbnail = (...candidates: Array<unknown>): string | null => {\n const found = candidates.find(\n (candidate): candidate is string =>\n typeof candidate === 'string' && candidate.trim().length > 0,\n )\n return found ?? null\n }\n\n const metadata =\n typeof (item as any).metadata === 'object' && (item as any).metadata !== null\n ? ((item as any).metadata as Record<string, unknown>)\n : null\n const snapshot =\n typeof (item as any).catalog_snapshot === 'object' && (item as any).catalog_snapshot !== null\n ? ((item as any).catalog_snapshot as Record<string, unknown>)\n : null\n const productSnapshot =\n snapshot && typeof (snapshot as any).product === 'object' ? ((snapshot as any).product as Record<string, unknown>) : null\n const variantSnapshot =\n snapshot && typeof (snapshot as any).variant === 'object' ? ((snapshot as any).variant as Record<string, unknown>) : null\n\n const productThumb = pickThumbnail(\n metadata ? (metadata as any).productThumbnail : null,\n productSnapshot ? (productSnapshot as any).thumbnailUrl : null,\n productSnapshot ? (productSnapshot as any).thumbnail_url : null,\n )\n const variantThumb = pickThumbnail(\n metadata ? (metadata as any).variantThumbnail : null,\n variantSnapshot ? (variantSnapshot as any).thumbnailUrl : null,\n variantSnapshot ? (variantSnapshot as any).thumbnail_url : null,\n )\n\n const snapshotThumb = pickThumbnail(\n snapshot ? (snapshot as any).thumbnailUrl : null,\n snapshot ? (snapshot as any).thumbnail_url : null,\n )\n\n return variantThumb ?? productThumb ?? snapshotThumb ?? null\n}\n\nexport function SalesShipmentsSection({\n orderId,\n currencyCode,\n shippingAddressSnapshot,\n organizationId: organizationIdProp,\n tenantId: tenantIdProp,\n documentUpdatedAt,\n onActionChange,\n onAddComment,\n}: SalesShipmentsSectionProps) {\n const t = useT()\n const locale = useLocale()\n const { organizationId, tenantId } = useOrganizationScopeDetail()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const resolvedOrganizationId = organizationIdProp ?? organizationId ?? null\n const resolvedTenantId = tenantIdProp ?? tenantId ?? null\n const addShipmentLabel = React.useMemo(\n () => t('sales.documents.shipments.add', 'Add shipment'),\n [t]\n )\n const [shipments, setShipments] = React.useState<ShipmentRow[]>([])\n const [lines, setLines] = React.useState<OrderLine[]>([])\n const [loading, setLoading] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [dialogState, setDialogState] = React.useState<{ mode: 'create' | 'edit'; shipment: ShipmentRow | null } | null>(null)\n\n const lineMap = React.useMemo(() => new Map(lines.map((line) => [line.id, line])), [lines])\n\n const shippedTotals = React.useMemo(() => {\n const totals = new Map<string, number>()\n shipments.forEach((shipment) => {\n shipment.items.forEach((item) => {\n const current = totals.get(item.orderLineId) ?? 0\n totals.set(item.orderLineId, current + (Number.isFinite(item.quantity) ? item.quantity : 0))\n })\n })\n return totals\n }, [shipments])\n\n const computeAvailable = React.useCallback(\n (lineId: string, excludeShipmentId?: string | null) => {\n const line = lineMap.get(lineId)\n if (!line) return 0\n const shipped = shippedTotals.get(lineId) ?? 0\n const editingShipment = excludeShipmentId ? shipments.find((entry) => entry.id === excludeShipmentId) : null\n const editingQty =\n editingShipment?.items\n .filter((item) => item.orderLineId === lineId)\n .reduce((acc, item) => acc + (Number.isFinite(item.quantity) ? item.quantity : 0), 0) ?? 0\n const remaining = line.quantity - (shipped - editingQty)\n return remaining < 0 ? 0 : remaining\n },\n [lineMap, shipments, shippedTotals]\n )\n\n const loadLines = React.useCallback(async () => {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-lines?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []\n const mapped: OrderLine[] = items\n .map((item) => {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const name =\n typeof item.name === 'string'\n ? item.name\n : typeof (item as any).catalog_snapshot === 'object' &&\n (item as any).catalog_snapshot &&\n typeof (item as any).catalog_snapshot.name === 'string'\n ? (item as any).catalog_snapshot.name\n : null\n const lineNumber =\n typeof (item as any).line_number === 'number'\n ? (item as any).line_number\n : typeof (item as any).lineNumber === 'number'\n ? (item as any).lineNumber\n : null\n const quantity =\n typeof item.quantity === 'number'\n ? item.quantity\n : typeof (item as any).quantity === 'string'\n ? Number((item as any).quantity)\n : 0\n return {\n id,\n title: name ?? id,\n lineNumber,\n quantity: Number.isFinite(quantity) ? quantity : 0,\n thumbnail: resolveLineThumbnail(item as Record<string, unknown>),\n }\n })\n .filter((entry): entry is OrderLine => Boolean(entry?.id))\n setLines(mapped)\n }, [orderId])\n\n const loadShipments = React.useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/shipments?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []\n const mapped: ShipmentRow[] = items\n .map((item) => {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const snapshotItemsRaw = Array.isArray((item as any).items_snapshot)\n ? ((item as any).items_snapshot as Array<Record<string, unknown>>)\n : []\n const responseItems = Array.isArray((item as any).items)\n ? ((item as any).items as Array<Record<string, unknown>>)\n : []\n const itemsRaw = responseItems.length ? responseItems : snapshotItemsRaw\n const shipmentItems: ShipmentItem[] = itemsRaw\n .map((entry) => {\n const lineId =\n typeof entry.orderLineId === 'string'\n ? entry.orderLineId\n : typeof (entry as any).order_line_id === 'string'\n ? (entry as any).order_line_id\n : null\n if (!lineId) return null\n const quantity =\n typeof entry.quantity === 'number'\n ? entry.quantity\n : typeof (entry as any).quantity === 'string'\n ? Number((entry as any).quantity)\n : 0\n return {\n id: typeof entry.id === 'string' ? entry.id : generateTempId(),\n orderLineId: lineId,\n orderLineName:\n typeof entry.orderLineName === 'string'\n ? entry.orderLineName\n : typeof (entry as any).order_line_name === 'string'\n ? (entry as any).order_line_name\n : null,\n orderLineNumber:\n typeof entry.orderLineNumber === 'number'\n ? entry.orderLineNumber\n : typeof (entry as any).order_line_number === 'number'\n ? (entry as any).order_line_number\n : null,\n quantity: Number.isFinite(quantity) ? quantity : 0,\n metadata: (entry.metadata as Record<string, unknown> | undefined | null) ?? null,\n }\n })\n .filter((entry): entry is ShipmentItem => Boolean(entry))\n const tracking =\n Array.isArray((item as any).tracking_numbers) && (item as any).tracking_numbers.length\n ? ((item as any).tracking_numbers as string[])\n : []\n const customValues = extractCustomFieldValues(item as Record<string, unknown>)\n return {\n id,\n updatedAt: readRowUpdatedAt(item),\n shipmentNumber:\n typeof (item as any).shipment_number === 'string'\n ? (item as any).shipment_number\n : typeof (item as any).shipmentNumber === 'string'\n ? (item as any).shipmentNumber\n : null,\n shippingMethodId:\n typeof (item as any).shipping_method_id === 'string'\n ? (item as any).shipping_method_id\n : typeof (item as any).shippingMethodId === 'string'\n ? (item as any).shippingMethodId\n : null,\n shippingMethodCode:\n typeof (item as any).shipping_method_code === 'string'\n ? (item as any).shipping_method_code\n : typeof (item as any).shippingMethodCode === 'string'\n ? (item as any).shippingMethodCode\n : null,\n shippingMethodName:\n typeof (item as any).shipping_method_name === 'string'\n ? (item as any).shipping_method_name\n : typeof (item as any).shippingMethodName === 'string'\n ? (item as any).shippingMethodName\n : null,\n status:\n typeof item.status === 'string'\n ? item.status\n : typeof (item as any).status === 'string'\n ? (item as any).status\n : null,\n statusLabel:\n typeof (item as any).status_label === 'string'\n ? (item as any).status_label\n : typeof (item as any).statusLabel === 'string'\n ? (item as any).statusLabel\n : null,\n statusEntryId:\n typeof (item as any).status_entry_id === 'string'\n ? (item as any).status_entry_id\n : typeof (item as any).statusEntryId === 'string'\n ? (item as any).statusEntryId\n : null,\n carrierName:\n typeof (item as any).carrier_name === 'string'\n ? (item as any).carrier_name\n : typeof (item as any).carrierName === 'string'\n ? (item as any).carrierName\n : null,\n trackingNumbers: tracking,\n shippedAt:\n typeof (item as any).shipped_at === 'string'\n ? (item as any).shipped_at\n : typeof (item as any).shippedAt === 'string'\n ? (item as any).shippedAt\n : null,\n deliveredAt:\n typeof (item as any).delivered_at === 'string'\n ? (item as any).delivered_at\n : typeof (item as any).deliveredAt === 'string'\n ? (item as any).deliveredAt\n : null,\n notes:\n typeof (item as any).notes === 'string'\n ? (item as any).notes\n : typeof (item as any).notesText === 'string'\n ? (item as any).notesText\n : null,\n metadata: (item as Record<string, unknown> | null | undefined)?.metadata ?? null,\n customValues: Object.keys(customValues).length ? customValues : null,\n items: shipmentItems,\n createdAt:\n typeof (item as any).created_at === 'string'\n ? (item as any).created_at\n : typeof (item as any).createdAt === 'string'\n ? (item as any).createdAt\n : null,\n }\n })\n .filter((entry): entry is ShipmentRow => Boolean(entry))\n setShipments(mapped)\n } catch (err) {\n logger.error('sales.shipments.load', { err })\n setError(t('sales.documents.shipments.errorLoad', 'Failed to load shipments.'))\n } finally {\n setLoading(false)\n }\n }, [orderId, t])\n\n React.useEffect(() => {\n void loadLines()\n void loadShipments()\n }, [loadLines, loadShipments])\n\n React.useEffect(\n () =>\n subscribeSalesDocumentTotalsRefresh((detail) => {\n if (detail.documentId !== orderId) return\n if (detail.kind && detail.kind !== 'order') return\n void loadLines()\n void loadShipments()\n }),\n [loadLines, loadShipments, orderId],\n )\n\n const handleOpenCreate = React.useCallback(() => {\n setDialogState({ mode: 'create', shipment: null })\n }, [])\n\n React.useEffect(() => {\n if (!onActionChange) return\n onActionChange({\n label: addShipmentLabel,\n onClick: handleOpenCreate,\n disabled: false,\n })\n return () => onActionChange(null)\n }, [addShipmentLabel, handleOpenCreate, onActionChange])\n\n const handleEdit = React.useCallback((shipment: ShipmentRow) => {\n setDialogState({ mode: 'edit', shipment })\n }, [])\n\n const handleDelete = React.useCallback(\n async (shipment: ShipmentRow) => {\n const confirmed = await confirm({\n title: t('sales.documents.shipments.confirmDelete', 'Delete this shipment?'),\n variant: 'default',\n })\n if (!confirmed) return\n try {\n const result = await withScopedApiRequestHeaders(\n // The server guards the PARENT order's aggregate version (Gap B), so\n // send the order's `updated_at`, not the shipment row's.\n buildOptimisticLockHeader(documentUpdatedAt ?? undefined),\n () =>\n deleteCrud('sales/shipments', {\n body: {\n id: shipment.id,\n orderId,\n organizationId: resolvedOrganizationId,\n tenantId: resolvedTenantId,\n },\n errorMessage: t('sales.documents.shipments.errorDelete', 'Failed to delete shipment.'),\n })\n )\n if (result.ok) {\n await loadShipments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadShipments())) {\n return\n }\n logger.error('sales.shipments.delete', { err })\n flash(t('sales.documents.shipments.errorDelete', 'Failed to delete shipment.'), 'error')\n }\n },\n [confirm, documentUpdatedAt, loadShipments, orderId, resolvedOrganizationId, resolvedTenantId, t]\n )\n\n const renderItemList = (items: ShipmentItem[]) => (\n <ul className=\"space-y-1 text-sm text-muted-foreground\">\n {items.map((item) => {\n const label = item.orderLineNumber ? `#${item.orderLineNumber}` : ''\n return (\n <li key={item.id} className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate\">\n {label ? `${label} \u00B7 ` : null}\n {item.orderLineName ?? item.orderLineId}\n </span>\n <Badge variant=\"secondary\">{item.quantity}</Badge>\n </li>\n )\n })}\n </ul>\n )\n\n if (loading) {\n return (\n <LoadingMessage\n label={t('sales.documents.shipments.loading', 'Loading shipments\u2026')}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n )\n }\n\n if (error) {\n return <ErrorMessage label={error} />\n }\n\n const empty = !shipments.length\n\n return (\n <div className=\"space-y-4\">\n {empty ? (\n <TabEmptyState\n title={t('sales.documents.shipments.empty.title', 'No shipments yet.')}\n description={t(\n 'sales.documents.shipments.empty.description',\n 'Add shipments for this document to let the user track the order.'\n )}\n action={{\n label: addShipmentLabel,\n onClick: handleOpenCreate,\n icon: <Plus className=\"h-4 w-4\" aria-hidden />,\n disabled: loading,\n }}\n />\n ) : (\n <div className=\"grid gap-3 md:grid-cols-2\">\n {shipments.map((shipment) => {\n const shippedAt = formatDisplayDate(shipment.shippedAt, locale)\n const deliveredAt = formatDisplayDate(shipment.deliveredAt, locale)\n const addressSummary = formatShipmentAddress(shipment.metadata)\n const statusLabel =\n shipment.statusLabel ??\n shipment.status ??\n t('sales.documents.shipments.statusMissing', 'Status pending')\n return (\n <div key={shipment.id} className=\"rounded-lg border bg-card p-4 shadow-sm\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex h-9 w-9 items-center justify-center rounded-full bg-primary/10 text-primary\">\n <Truck className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"text-sm font-semibold\">\n {shipment.shipmentNumber\n ? t('sales.documents.shipments.numberLabel', 'Shipment {{number}}', {\n number: shipment.shipmentNumber,\n })\n : t('sales.documents.shipments.fallbackNumber', 'Shipment {{id}}', {\n id: shipment.id.slice(0, 6),\n })}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {statusLabel}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => handleEdit(shipment)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-destructive\"\n onClick={() => void handleDelete(shipment)}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n <div className=\"mt-3 space-y-2 text-sm\">\n <div className=\"flex flex-wrap items-center gap-2 text-muted-foreground\">\n {shipment.carrierName ? (\n <Badge variant=\"outline\">{shipment.carrierName}</Badge>\n ) : null}\n {shipment.trackingNumbers.length ? (\n <span className=\"truncate\">\n {t('sales.documents.shipments.tracking', 'Tracking')}: {shipment.trackingNumbers.join(', ')}\n </span>\n ) : null}\n </div>\n {shippedAt ? (\n <p className=\"text-muted-foreground\">\n {t('sales.documents.shipments.shippedOn', 'Shipped on {{date}}', { date: shippedAt })}\n </p>\n ) : null}\n {deliveredAt ? (\n <p className=\"text-muted-foreground\">\n {t('sales.documents.shipments.deliveredOn', 'Delivered on {{date}}', { date: deliveredAt })}\n </p>\n ) : null}\n {addressSummary ? (\n <p className=\"text-xs text-muted-foreground\">{addressSummary}</p>\n ) : null}\n {shipment.notes ? (\n <p className=\"rounded-md bg-muted px-3 py-2 text-muted-foreground\">\n {shipment.notes}\n </p>\n ) : null}\n {renderItemList(shipment.items)}\n </div>\n </div>\n )\n })}\n </div>\n )}\n\n <ShipmentDialog\n open={dialogState !== null}\n mode={dialogState?.mode ?? 'create'}\n shipment={dialogState?.shipment ?? null}\n lines={lines}\n orderId={orderId}\n currencyCode={currencyCode}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n documentUpdatedAt={documentUpdatedAt ?? null}\n computeAvailable={computeAvailable}\n shippingAddressSnapshot={shippingAddressSnapshot}\n onClose={() => setDialogState(null)}\n onSaved={async () => {\n setDialogState(null)\n await loadShipments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n }}\n onAddComment={onAddComment}\n />\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { formatDisplayDate, toUtcDateInputValue } from '@open-mercato/ui/primitives/date-format'\nimport { Pencil, Plus, Trash2, Truck } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { ErrorMessage, LoadingMessage, TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport {\n emitSalesDocumentTotalsRefresh,\n subscribeSalesDocumentTotalsRefresh,\n} from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'\nimport type { SectionAction } from '@open-mercato/core/modules/customers/components/detail/types'\nimport { generateTempId } from '@open-mercato/core/modules/customers/lib/detailHelpers'\nimport { formatAddressString, type AddressValue } from '@open-mercato/core/modules/customers/utils/addressFormat'\nimport { ShipmentDialog } from './ShipmentDialog'\nimport { handleSectionMutationError, readRowUpdatedAt } from './optimisticLock'\nimport { extractCustomFieldValues } from './customFieldHelpers'\nimport type { OrderLine, ShipmentRow, ShipmentItem } from './shipmentTypes'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nconst ADDRESS_SNAPSHOT_KEY = 'shipmentAddressSnapshot'\nconst ADDRESS_FORMAT: 'line_first' = 'line_first'\n\ntype SalesShipmentsSectionProps = {\n orderId: string\n currencyCode?: string | null\n shippingAddressSnapshot?: Record<string, unknown> | null\n organizationId?: string | null\n tenantId?: string | null\n documentUpdatedAt?: string | null\n onActionChange?: (action: SectionAction | null) => void\n onAddComment?: (body: string) => Promise<void>\n}\n\n// One date formatter for this page rather than three with incompatible semantics.\nexport { formatDisplayDate }\n\nconst formatShipmentAddress = (metadata?: Record<string, unknown> | null): string | null => {\n if (!metadata || typeof metadata !== 'object') return null\n const snapshot = (metadata as any)[ADDRESS_SNAPSHOT_KEY]\n if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) return null\n const read = (key: string): string | null => {\n const value = (snapshot as any)[key]\n return typeof value === 'string' && value.trim().length ? value.trim() : null\n }\n const addressValue: AddressValue = {\n addressLine1: read('addressLine1') ?? read('address_line1'),\n addressLine2: read('addressLine2') ?? read('address_line2'),\n buildingNumber: read('buildingNumber') ?? read('building_number'),\n flatNumber: read('flatNumber') ?? read('flat_number'),\n city: read('city'),\n region: read('region'),\n postalCode: read('postalCode') ?? read('postal_code'),\n country: read('country'),\n companyName: read('companyName') ?? read('company_name'),\n }\n const summary = formatAddressString(addressValue, ADDRESS_FORMAT)\n return summary && summary.trim().length ? summary : null\n}\n\nconst resolveLineThumbnail = (item: Record<string, unknown>): string | null => {\n const pickThumbnail = (...candidates: Array<unknown>): string | null => {\n const found = candidates.find(\n (candidate): candidate is string =>\n typeof candidate === 'string' && candidate.trim().length > 0,\n )\n return found ?? null\n }\n\n const metadata =\n typeof (item as any).metadata === 'object' && (item as any).metadata !== null\n ? ((item as any).metadata as Record<string, unknown>)\n : null\n const snapshot =\n typeof (item as any).catalog_snapshot === 'object' && (item as any).catalog_snapshot !== null\n ? ((item as any).catalog_snapshot as Record<string, unknown>)\n : null\n const productSnapshot =\n snapshot && typeof (snapshot as any).product === 'object' ? ((snapshot as any).product as Record<string, unknown>) : null\n const variantSnapshot =\n snapshot && typeof (snapshot as any).variant === 'object' ? ((snapshot as any).variant as Record<string, unknown>) : null\n\n const productThumb = pickThumbnail(\n metadata ? (metadata as any).productThumbnail : null,\n productSnapshot ? (productSnapshot as any).thumbnailUrl : null,\n productSnapshot ? (productSnapshot as any).thumbnail_url : null,\n )\n const variantThumb = pickThumbnail(\n metadata ? (metadata as any).variantThumbnail : null,\n variantSnapshot ? (variantSnapshot as any).thumbnailUrl : null,\n variantSnapshot ? (variantSnapshot as any).thumbnail_url : null,\n )\n\n const snapshotThumb = pickThumbnail(\n snapshot ? (snapshot as any).thumbnailUrl : null,\n snapshot ? (snapshot as any).thumbnail_url : null,\n )\n\n return variantThumb ?? productThumb ?? snapshotThumb ?? null\n}\n\nexport function SalesShipmentsSection({\n orderId,\n currencyCode,\n shippingAddressSnapshot,\n organizationId: organizationIdProp,\n tenantId: tenantIdProp,\n documentUpdatedAt,\n onActionChange,\n onAddComment,\n}: SalesShipmentsSectionProps) {\n const t = useT()\n const locale = useLocale()\n const { organizationId, tenantId } = useOrganizationScopeDetail()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const resolvedOrganizationId = organizationIdProp ?? organizationId ?? null\n const resolvedTenantId = tenantIdProp ?? tenantId ?? null\n const addShipmentLabel = React.useMemo(\n () => t('sales.documents.shipments.add', 'Add shipment'),\n [t]\n )\n const [shipments, setShipments] = React.useState<ShipmentRow[]>([])\n const [lines, setLines] = React.useState<OrderLine[]>([])\n const [loading, setLoading] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [dialogState, setDialogState] = React.useState<{ mode: 'create' | 'edit'; shipment: ShipmentRow | null } | null>(null)\n\n const lineMap = React.useMemo(() => new Map(lines.map((line) => [line.id, line])), [lines])\n\n const shippedTotals = React.useMemo(() => {\n const totals = new Map<string, number>()\n shipments.forEach((shipment) => {\n shipment.items.forEach((item) => {\n const current = totals.get(item.orderLineId) ?? 0\n totals.set(item.orderLineId, current + (Number.isFinite(item.quantity) ? item.quantity : 0))\n })\n })\n return totals\n }, [shipments])\n\n const computeAvailable = React.useCallback(\n (lineId: string, excludeShipmentId?: string | null) => {\n const line = lineMap.get(lineId)\n if (!line) return 0\n const shipped = shippedTotals.get(lineId) ?? 0\n const editingShipment = excludeShipmentId ? shipments.find((entry) => entry.id === excludeShipmentId) : null\n const editingQty =\n editingShipment?.items\n .filter((item) => item.orderLineId === lineId)\n .reduce((acc, item) => acc + (Number.isFinite(item.quantity) ? item.quantity : 0), 0) ?? 0\n const remaining = line.quantity - (shipped - editingQty)\n return remaining < 0 ? 0 : remaining\n },\n [lineMap, shipments, shippedTotals]\n )\n\n const loadLines = React.useCallback(async () => {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-lines?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []\n const mapped: OrderLine[] = items\n .map((item) => {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const name =\n typeof item.name === 'string'\n ? item.name\n : typeof (item as any).catalog_snapshot === 'object' &&\n (item as any).catalog_snapshot &&\n typeof (item as any).catalog_snapshot.name === 'string'\n ? (item as any).catalog_snapshot.name\n : null\n const lineNumber =\n typeof (item as any).line_number === 'number'\n ? (item as any).line_number\n : typeof (item as any).lineNumber === 'number'\n ? (item as any).lineNumber\n : null\n const quantity =\n typeof item.quantity === 'number'\n ? item.quantity\n : typeof (item as any).quantity === 'string'\n ? Number((item as any).quantity)\n : 0\n return {\n id,\n title: name ?? id,\n lineNumber,\n quantity: Number.isFinite(quantity) ? quantity : 0,\n thumbnail: resolveLineThumbnail(item as Record<string, unknown>),\n }\n })\n .filter((entry): entry is OrderLine => Boolean(entry?.id))\n setLines(mapped)\n }, [orderId])\n\n const loadShipments = React.useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/shipments?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n const items = Array.isArray(response.result?.items) ? response.result?.items ?? [] : []\n const mapped: ShipmentRow[] = items\n .map((item) => {\n const id = typeof item.id === 'string' ? item.id : null\n if (!id) return null\n const snapshotItemsRaw = Array.isArray((item as any).items_snapshot)\n ? ((item as any).items_snapshot as Array<Record<string, unknown>>)\n : []\n const responseItems = Array.isArray((item as any).items)\n ? ((item as any).items as Array<Record<string, unknown>>)\n : []\n const itemsRaw = responseItems.length ? responseItems : snapshotItemsRaw\n const shipmentItems: ShipmentItem[] = itemsRaw\n .map((entry) => {\n const lineId =\n typeof entry.orderLineId === 'string'\n ? entry.orderLineId\n : typeof (entry as any).order_line_id === 'string'\n ? (entry as any).order_line_id\n : null\n if (!lineId) return null\n const quantity =\n typeof entry.quantity === 'number'\n ? entry.quantity\n : typeof (entry as any).quantity === 'string'\n ? Number((entry as any).quantity)\n : 0\n return {\n id: typeof entry.id === 'string' ? entry.id : generateTempId(),\n orderLineId: lineId,\n orderLineName:\n typeof entry.orderLineName === 'string'\n ? entry.orderLineName\n : typeof (entry as any).order_line_name === 'string'\n ? (entry as any).order_line_name\n : null,\n orderLineNumber:\n typeof entry.orderLineNumber === 'number'\n ? entry.orderLineNumber\n : typeof (entry as any).order_line_number === 'number'\n ? (entry as any).order_line_number\n : null,\n quantity: Number.isFinite(quantity) ? quantity : 0,\n metadata: (entry.metadata as Record<string, unknown> | undefined | null) ?? null,\n }\n })\n .filter((entry): entry is ShipmentItem => Boolean(entry))\n const tracking =\n Array.isArray((item as any).tracking_numbers) && (item as any).tracking_numbers.length\n ? ((item as any).tracking_numbers as string[])\n : []\n const customValues = extractCustomFieldValues(item as Record<string, unknown>)\n return {\n id,\n updatedAt: readRowUpdatedAt(item),\n shipmentNumber:\n typeof (item as any).shipment_number === 'string'\n ? (item as any).shipment_number\n : typeof (item as any).shipmentNumber === 'string'\n ? (item as any).shipmentNumber\n : null,\n shippingMethodId:\n typeof (item as any).shipping_method_id === 'string'\n ? (item as any).shipping_method_id\n : typeof (item as any).shippingMethodId === 'string'\n ? (item as any).shippingMethodId\n : null,\n shippingMethodCode:\n typeof (item as any).shipping_method_code === 'string'\n ? (item as any).shipping_method_code\n : typeof (item as any).shippingMethodCode === 'string'\n ? (item as any).shippingMethodCode\n : null,\n shippingMethodName:\n typeof (item as any).shipping_method_name === 'string'\n ? (item as any).shipping_method_name\n : typeof (item as any).shippingMethodName === 'string'\n ? (item as any).shippingMethodName\n : null,\n status:\n typeof item.status === 'string'\n ? item.status\n : typeof (item as any).status === 'string'\n ? (item as any).status\n : null,\n statusLabel:\n typeof (item as any).status_label === 'string'\n ? (item as any).status_label\n : typeof (item as any).statusLabel === 'string'\n ? (item as any).statusLabel\n : null,\n statusEntryId:\n typeof (item as any).status_entry_id === 'string'\n ? (item as any).status_entry_id\n : typeof (item as any).statusEntryId === 'string'\n ? (item as any).statusEntryId\n : null,\n carrierName:\n typeof (item as any).carrier_name === 'string'\n ? (item as any).carrier_name\n : typeof (item as any).carrierName === 'string'\n ? (item as any).carrierName\n : null,\n trackingNumbers: tracking,\n shippedAt:\n typeof (item as any).shipped_at === 'string'\n ? (item as any).shipped_at\n : typeof (item as any).shippedAt === 'string'\n ? (item as any).shippedAt\n : null,\n deliveredAt:\n typeof (item as any).delivered_at === 'string'\n ? (item as any).delivered_at\n : typeof (item as any).deliveredAt === 'string'\n ? (item as any).deliveredAt\n : null,\n notes:\n typeof (item as any).notes === 'string'\n ? (item as any).notes\n : typeof (item as any).notesText === 'string'\n ? (item as any).notesText\n : null,\n metadata: (item as Record<string, unknown> | null | undefined)?.metadata ?? null,\n customValues: Object.keys(customValues).length ? customValues : null,\n items: shipmentItems,\n createdAt:\n typeof (item as any).created_at === 'string'\n ? (item as any).created_at\n : typeof (item as any).createdAt === 'string'\n ? (item as any).createdAt\n : null,\n }\n })\n .filter((entry): entry is ShipmentRow => Boolean(entry))\n setShipments(mapped)\n } catch (err) {\n logger.error('sales.shipments.load', { err })\n setError(t('sales.documents.shipments.errorLoad', 'Failed to load shipments.'))\n } finally {\n setLoading(false)\n }\n }, [orderId, t])\n\n React.useEffect(() => {\n void loadLines()\n void loadShipments()\n }, [loadLines, loadShipments])\n\n React.useEffect(\n () =>\n subscribeSalesDocumentTotalsRefresh((detail) => {\n if (detail.documentId !== orderId) return\n if (detail.kind && detail.kind !== 'order') return\n void loadLines()\n void loadShipments()\n }),\n [loadLines, loadShipments, orderId],\n )\n\n const handleOpenCreate = React.useCallback(() => {\n setDialogState({ mode: 'create', shipment: null })\n }, [])\n\n React.useEffect(() => {\n if (!onActionChange) return\n onActionChange({\n label: addShipmentLabel,\n onClick: handleOpenCreate,\n disabled: false,\n })\n return () => onActionChange(null)\n }, [addShipmentLabel, handleOpenCreate, onActionChange])\n\n const handleEdit = React.useCallback((shipment: ShipmentRow) => {\n setDialogState({ mode: 'edit', shipment })\n }, [])\n\n const handleDelete = React.useCallback(\n async (shipment: ShipmentRow) => {\n const confirmed = await confirm({\n title: t('sales.documents.shipments.confirmDelete', 'Delete this shipment?'),\n variant: 'default',\n })\n if (!confirmed) return\n try {\n const result = await withScopedApiRequestHeaders(\n // The server guards the PARENT order's aggregate version (Gap B), so\n // send the order's `updated_at`, not the shipment row's.\n buildOptimisticLockHeader(documentUpdatedAt ?? undefined),\n () =>\n deleteCrud('sales/shipments', {\n body: {\n id: shipment.id,\n orderId,\n organizationId: resolvedOrganizationId,\n tenantId: resolvedTenantId,\n },\n errorMessage: t('sales.documents.shipments.errorDelete', 'Failed to delete shipment.'),\n })\n )\n if (result.ok) {\n await loadShipments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadShipments())) {\n return\n }\n logger.error('sales.shipments.delete', { err })\n flash(t('sales.documents.shipments.errorDelete', 'Failed to delete shipment.'), 'error')\n }\n },\n [confirm, documentUpdatedAt, loadShipments, orderId, resolvedOrganizationId, resolvedTenantId, t]\n )\n\n const renderItemList = (items: ShipmentItem[]) => (\n <ul className=\"space-y-1 text-sm text-muted-foreground\">\n {items.map((item) => {\n const label = item.orderLineNumber ? `#${item.orderLineNumber}` : ''\n return (\n <li key={item.id} className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate\">\n {label ? `${label} \u00B7 ` : null}\n {item.orderLineName ?? item.orderLineId}\n </span>\n <Badge variant=\"secondary\">{item.quantity}</Badge>\n </li>\n )\n })}\n </ul>\n )\n\n if (loading) {\n return (\n <LoadingMessage\n label={t('sales.documents.shipments.loading', 'Loading shipments\u2026')}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n )\n }\n\n if (error) {\n return <ErrorMessage label={error} />\n }\n\n const empty = !shipments.length\n\n return (\n <div className=\"space-y-4\">\n {empty ? (\n <TabEmptyState\n title={t('sales.documents.shipments.empty.title', 'No shipments yet.')}\n description={t(\n 'sales.documents.shipments.empty.description',\n 'Add shipments for this document to let the user track the order.'\n )}\n action={{\n label: addShipmentLabel,\n onClick: handleOpenCreate,\n icon: <Plus className=\"h-4 w-4\" aria-hidden />,\n disabled: loading,\n }}\n />\n ) : (\n <div className=\"grid gap-3 md:grid-cols-2\">\n {shipments.map((shipment) => {\n // `shippedAt` / `deliveredAt` are written from date inputs (`ShipmentDialog`), coerced\n // by `z.coerce.date()` and stored as UTC midnight, and the dialog seeds itself back from\n // `.slice(0, 10)` \u2014 the UTC day. Reading them locally names the previous day west of UTC\n // and disagrees with that dialog on the same row.\n const shippedAt = formatDisplayDate(toUtcDateInputValue(shipment.shippedAt), locale)\n const deliveredAt = formatDisplayDate(toUtcDateInputValue(shipment.deliveredAt), locale)\n const addressSummary = formatShipmentAddress(shipment.metadata)\n const statusLabel =\n shipment.statusLabel ??\n shipment.status ??\n t('sales.documents.shipments.statusMissing', 'Status pending')\n return (\n <div key={shipment.id} className=\"rounded-lg border bg-card p-4 shadow-sm\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex h-9 w-9 items-center justify-center rounded-full bg-primary/10 text-primary\">\n <Truck className=\"h-5 w-5\" />\n </div>\n <div>\n <p className=\"text-sm font-semibold\">\n {shipment.shipmentNumber\n ? t('sales.documents.shipments.numberLabel', 'Shipment {{number}}', {\n number: shipment.shipmentNumber,\n })\n : t('sales.documents.shipments.fallbackNumber', 'Shipment {{id}}', {\n id: shipment.id.slice(0, 6),\n })}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {statusLabel}\n </p>\n </div>\n </div>\n <div className=\"flex items-center gap-1\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => handleEdit(shipment)}\n >\n <Pencil className=\"h-4 w-4\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 text-destructive\"\n onClick={() => void handleDelete(shipment)}\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n <div className=\"mt-3 space-y-2 text-sm\">\n <div className=\"flex flex-wrap items-center gap-2 text-muted-foreground\">\n {shipment.carrierName ? (\n <Badge variant=\"outline\">{shipment.carrierName}</Badge>\n ) : null}\n {shipment.trackingNumbers.length ? (\n <span className=\"truncate\">\n {t('sales.documents.shipments.tracking', 'Tracking')}: {shipment.trackingNumbers.join(', ')}\n </span>\n ) : null}\n </div>\n {shippedAt ? (\n <p className=\"text-muted-foreground\">\n {t('sales.documents.shipments.shippedOn', 'Shipped on {{date}}', { date: shippedAt })}\n </p>\n ) : null}\n {deliveredAt ? (\n <p className=\"text-muted-foreground\">\n {t('sales.documents.shipments.deliveredOn', 'Delivered on {{date}}', { date: deliveredAt })}\n </p>\n ) : null}\n {addressSummary ? (\n <p className=\"text-xs text-muted-foreground\">{addressSummary}</p>\n ) : null}\n {shipment.notes ? (\n <p className=\"rounded-md bg-muted px-3 py-2 text-muted-foreground\">\n {shipment.notes}\n </p>\n ) : null}\n {renderItemList(shipment.items)}\n </div>\n </div>\n )\n })}\n </div>\n )}\n\n <ShipmentDialog\n open={dialogState !== null}\n mode={dialogState?.mode ?? 'create'}\n shipment={dialogState?.shipment ?? null}\n lines={lines}\n orderId={orderId}\n currencyCode={currencyCode}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n documentUpdatedAt={documentUpdatedAt ?? null}\n computeAvailable={computeAvailable}\n shippingAddressSnapshot={shippingAddressSnapshot}\n onClose={() => setDialogState(null)}\n onSaved={async () => {\n setDialogState(null)\n await loadShipments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n }}\n onAddComment={onAddComment}\n />\n {ConfirmDialogElement}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAybY,SAIA,KAJA;AAvbZ,YAAY,WAAW;AACvB,SAAS,mBAAmB,2BAA2B;AACvD,SAAS,QAAQ,MAAM,QAAQ,aAAa;AAC5C,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,cAAc,gBAAgB,qBAAqB;AAC5D,SAAS,aAAa;AACtB,SAAS,SAAS,mCAAmC;AACrD,SAAS,iCAAiC;AAC1C,SAAS,kBAAkB;AAC3B,SAAS,kCAAkC;AAC3C,SAAS,MAAM,iBAAiB;AAChC,SAAS,wBAAwB;AACjC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,SAAS,sBAAsB;AAC/B,SAAS,2BAA8C;AACvD,SAAS,sBAAsB;AAC/B,SAAS,4BAA4B,wBAAwB;AAC7D,SAAS,gCAAgC;AAEzC,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,OAAO;AAEnC,MAAM,uBAAuB;AAC7B,MAAM,iBAA+B;AAgBrC,MAAM,wBAAwB,CAAC,aAA6D;AAC1F,MAAI,CAAC,YAAY,OAAO,aAAa,SAAU,QAAO;AACtD,QAAM,WAAY,SAAiB,oBAAoB;AACvD,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,MAAM,QAAQ,QAAQ,EAAG,QAAO;AACjF,QAAM,OAAO,CAAC,QAA+B;AAC3C,UAAM,QAAS,SAAiB,GAAG;AACnC,WAAO,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,MAAM,KAAK,IAAI;AAAA,EAC3E;AACA,QAAM,eAA6B;AAAA,IACjC,cAAc,KAAK,cAAc,KAAK,KAAK,eAAe;AAAA,IAC1D,cAAc,KAAK,cAAc,KAAK,KAAK,eAAe;AAAA,IAC1D,gBAAgB,KAAK,gBAAgB,KAAK,KAAK,iBAAiB;AAAA,IAChE,YAAY,KAAK,YAAY,KAAK,KAAK,aAAa;AAAA,IACpD,MAAM,KAAK,MAAM;AAAA,IACjB,QAAQ,KAAK,QAAQ;AAAA,IACrB,YAAY,KAAK,YAAY,KAAK,KAAK,aAAa;AAAA,IACpD,SAAS,KAAK,SAAS;AAAA,IACvB,aAAa,KAAK,aAAa,KAAK,KAAK,cAAc;AAAA,EACzD;AACA,QAAM,UAAU,oBAAoB,cAAc,cAAc;AAChE,SAAO,WAAW,QAAQ,KAAK,EAAE,SAAS,UAAU;AACtD;AAEA,MAAM,uBAAuB,CAAC,SAAiD;AAC7E,QAAM,gBAAgB,IAAI,eAA8C;AACtE,UAAM,QAAQ,WAAW;AAAA,MACvB,CAAC,cACC,OAAO,cAAc,YAAY,UAAU,KAAK,EAAE,SAAS;AAAA,IAC/D;AACA,WAAO,SAAS;AAAA,EAClB;AAEA,QAAM,WACJ,OAAQ,KAAa,aAAa,YAAa,KAAa,aAAa,OACnE,KAAa,WACf;AACN,QAAM,WACJ,OAAQ,KAAa,qBAAqB,YAAa,KAAa,qBAAqB,OACnF,KAAa,mBACf;AACN,QAAM,kBACJ,YAAY,OAAQ,SAAiB,YAAY,WAAa,SAAiB,UAAsC;AACvH,QAAM,kBACJ,YAAY,OAAQ,SAAiB,YAAY,WAAa,SAAiB,UAAsC;AAEvH,QAAM,eAAe;AAAA,IACnB,WAAY,SAAiB,mBAAmB;AAAA,IAChD,kBAAmB,gBAAwB,eAAe;AAAA,IAC1D,kBAAmB,gBAAwB,gBAAgB;AAAA,EAC7D;AACA,QAAM,eAAe;AAAA,IACnB,WAAY,SAAiB,mBAAmB;AAAA,IAChD,kBAAmB,gBAAwB,eAAe;AAAA,IAC1D,kBAAmB,gBAAwB,gBAAgB;AAAA,EAC7D;AAEA,QAAM,gBAAgB;AAAA,IACpB,WAAY,SAAiB,eAAe;AAAA,IAC5C,WAAY,SAAiB,gBAAgB;AAAA,EAC/C;AAEA,SAAO,gBAAgB,gBAAgB,iBAAiB;AAC1D;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,gBAAgB,SAAS,IAAI,2BAA2B;AAChE,QAAM,EAAE,SAAS,qBAAqB,IAAI,iBAAiB;AAC3D,QAAM,yBAAyB,sBAAsB,kBAAkB;AACvE,QAAM,mBAAmB,gBAAgB,YAAY;AACrD,QAAM,mBAAmB,MAAM;AAAA,IAC7B,MAAM,EAAE,iCAAiC,cAAc;AAAA,IACvD,CAAC,CAAC;AAAA,EACJ;AACA,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAwB,CAAC,CAAC;AAClE,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAsB,CAAC,CAAC;AACxD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAA2E,IAAI;AAE3H,QAAM,UAAU,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;AAE1F,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,UAAM,SAAS,oBAAI,IAAoB;AACvC,cAAU,QAAQ,CAAC,aAAa;AAC9B,eAAS,MAAM,QAAQ,CAAC,SAAS;AAC/B,cAAM,UAAU,OAAO,IAAI,KAAK,WAAW,KAAK;AAChD,eAAO,IAAI,KAAK,aAAa,WAAW,OAAO,SAAS,KAAK,QAAQ,IAAI,KAAK,WAAW,EAAE;AAAA,MAC7F,CAAC;AAAA,IACH,CAAC;AACD,WAAO;AAAA,EACT,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,mBAAmB,MAAM;AAAA,IAC7B,CAAC,QAAgB,sBAAsC;AACrD,YAAM,OAAO,QAAQ,IAAI,MAAM;AAC/B,UAAI,CAAC,KAAM,QAAO;AAClB,YAAM,UAAU,cAAc,IAAI,MAAM,KAAK;AAC7C,YAAM,kBAAkB,oBAAoB,UAAU,KAAK,CAAC,UAAU,MAAM,OAAO,iBAAiB,IAAI;AACxG,YAAM,aACJ,iBAAiB,MACd,OAAO,CAAC,SAAS,KAAK,gBAAgB,MAAM,EAC5C,OAAO,CAAC,KAAK,SAAS,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,KAAK,WAAW,IAAI,CAAC,KAAK;AAC7F,YAAM,YAAY,KAAK,YAAY,UAAU;AAC7C,aAAO,YAAY,IAAI,IAAI;AAAA,IAC7B;AAAA,IACA,CAAC,SAAS,WAAW,aAAa;AAAA,EACpC;AAEA,QAAM,YAAY,MAAM,YAAY,YAAY;AAC9C,UAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,KAAK,UAAU,OAAO,QAAQ,CAAC;AAC1E,UAAM,WAAW,MAAM;AAAA,MACrB,0BAA0B,OAAO,SAAS,CAAC;AAAA,MAC3C;AAAA,MACA,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,IAC5B;AACA,UAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ,KAAK,IAAI,SAAS,QAAQ,SAAS,CAAC,IAAI,CAAC;AACtF,UAAM,SAAsB,MACzB,IAAI,CAAC,SAAS;AACb,YAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACnD,UAAI,CAAC,GAAI,QAAO;AAChB,YAAM,OACJ,OAAO,KAAK,SAAS,WACjB,KAAK,OACL,OAAQ,KAAa,qBAAqB,YACvC,KAAa,oBACd,OAAQ,KAAa,iBAAiB,SAAS,WAC9C,KAAa,iBAAiB,OAC/B;AACR,YAAM,aACJ,OAAQ,KAAa,gBAAgB,WAChC,KAAa,cACd,OAAQ,KAAa,eAAe,WACjC,KAAa,aACd;AACR,YAAM,WACJ,OAAO,KAAK,aAAa,WACrB,KAAK,WACL,OAAQ,KAAa,aAAa,WAChC,OAAQ,KAAa,QAAQ,IAC7B;AACR,aAAO;AAAA,QACL;AAAA,QACA,OAAO,QAAQ;AAAA,QACf;AAAA,QACA,UAAU,OAAO,SAAS,QAAQ,IAAI,WAAW;AAAA,QACjD,WAAW,qBAAqB,IAA+B;AAAA,MACjE;AAAA,IACF,CAAC,EACA,OAAO,CAAC,UAA8B,QAAQ,OAAO,EAAE,CAAC;AAC3D,aAAS,MAAM;AAAA,EACjB,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,gBAAgB,MAAM,YAAY,YAAY;AAClD,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,KAAK,UAAU,OAAO,QAAQ,CAAC;AAC1E,YAAM,WAAW,MAAM;AAAA,QACrB,wBAAwB,OAAO,SAAS,CAAC;AAAA,QACzC;AAAA,QACA,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,MAC5B;AACA,YAAM,QAAQ,MAAM,QAAQ,SAAS,QAAQ,KAAK,IAAI,SAAS,QAAQ,SAAS,CAAC,IAAI,CAAC;AACtF,YAAM,SAAwB,MAC3B,IAAI,CAAC,SAAS;AACb,cAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACnD,YAAI,CAAC,GAAI,QAAO;AAChB,cAAM,mBAAmB,MAAM,QAAS,KAAa,cAAc,IAC7D,KAAa,iBACf,CAAC;AACL,cAAM,gBAAgB,MAAM,QAAS,KAAa,KAAK,IACjD,KAAa,QACf,CAAC;AACL,cAAM,WAAW,cAAc,SAAS,gBAAgB;AACxD,cAAM,gBAAgC,SACnC,IAAI,CAAC,UAAU;AACd,gBAAM,SACJ,OAAO,MAAM,gBAAgB,WACzB,MAAM,cACN,OAAQ,MAAc,kBAAkB,WACrC,MAAc,gBACf;AACR,cAAI,CAAC,OAAQ,QAAO;AACpB,gBAAM,WACJ,OAAO,MAAM,aAAa,WACtB,MAAM,WACN,OAAQ,MAAc,aAAa,WACjC,OAAQ,MAAc,QAAQ,IAC9B;AACR,iBAAO;AAAA,YACL,IAAI,OAAO,MAAM,OAAO,WAAW,MAAM,KAAK,eAAe;AAAA,YAC7D,aAAa;AAAA,YACb,eACE,OAAO,MAAM,kBAAkB,WAC3B,MAAM,gBACN,OAAQ,MAAc,oBAAoB,WACvC,MAAc,kBACf;AAAA,YACR,iBACE,OAAO,MAAM,oBAAoB,WAC7B,MAAM,kBACN,OAAQ,MAAc,sBAAsB,WACzC,MAAc,oBACf;AAAA,YACR,UAAU,OAAO,SAAS,QAAQ,IAAI,WAAW;AAAA,YACjD,UAAW,MAAM,YAA2D;AAAA,UAC9E;AAAA,QACF,CAAC,EACA,OAAO,CAAC,UAAiC,QAAQ,KAAK,CAAC;AAC1D,cAAM,WACJ,MAAM,QAAS,KAAa,gBAAgB,KAAM,KAAa,iBAAiB,SAC1E,KAAa,mBACf,CAAC;AACP,cAAM,eAAe,yBAAyB,IAA+B;AAC7E,eAAO;AAAA,UACL;AAAA,UACA,WAAW,iBAAiB,IAAI;AAAA,UAChC,gBACE,OAAQ,KAAa,oBAAoB,WACpC,KAAa,kBACd,OAAQ,KAAa,mBAAmB,WACrC,KAAa,iBACd;AAAA,UACR,kBACE,OAAQ,KAAa,uBAAuB,WACvC,KAAa,qBACd,OAAQ,KAAa,qBAAqB,WACvC,KAAa,mBACd;AAAA,UACR,oBACE,OAAQ,KAAa,yBAAyB,WACzC,KAAa,uBACd,OAAQ,KAAa,uBAAuB,WACzC,KAAa,qBACd;AAAA,UACR,oBACE,OAAQ,KAAa,yBAAyB,WACzC,KAAa,uBACd,OAAQ,KAAa,uBAAuB,WACzC,KAAa,qBACd;AAAA,UACR,QACE,OAAO,KAAK,WAAW,WACnB,KAAK,SACL,OAAQ,KAAa,WAAW,WAC7B,KAAa,SACd;AAAA,UACR,aACE,OAAQ,KAAa,iBAAiB,WACjC,KAAa,eACd,OAAQ,KAAa,gBAAgB,WAClC,KAAa,cACd;AAAA,UACR,eACE,OAAQ,KAAa,oBAAoB,WACpC,KAAa,kBACd,OAAQ,KAAa,kBAAkB,WACpC,KAAa,gBACd;AAAA,UACR,aACE,OAAQ,KAAa,iBAAiB,WACjC,KAAa,eACd,OAAQ,KAAa,gBAAgB,WAClC,KAAa,cACd;AAAA,UACR,iBAAiB;AAAA,UACjB,WACE,OAAQ,KAAa,eAAe,WAC/B,KAAa,aACd,OAAQ,KAAa,cAAc,WAChC,KAAa,YACd;AAAA,UACR,aACE,OAAQ,KAAa,iBAAiB,WACjC,KAAa,eACd,OAAQ,KAAa,gBAAgB,WAClC,KAAa,cACd;AAAA,UACR,OACE,OAAQ,KAAa,UAAU,WAC1B,KAAa,QACd,OAAQ,KAAa,cAAc,WAChC,KAAa,YACd;AAAA,UACR,UAAW,MAAqD,YAAY;AAAA,UAC5E,cAAc,OAAO,KAAK,YAAY,EAAE,SAAS,eAAe;AAAA,UAChE,OAAO;AAAA,UACP,WACE,OAAQ,KAAa,eAAe,WAC/B,KAAa,aACd,OAAQ,KAAa,cAAc,WAChC,KAAa,YACd;AAAA,QACV;AAAA,MACF,CAAC,EACA,OAAO,CAAC,UAAgC,QAAQ,KAAK,CAAC;AACzD,mBAAa,MAAM;AAAA,IACrB,SAAS,KAAK;AACZ,aAAO,MAAM,wBAAwB,EAAE,IAAI,CAAC;AAC5C,eAAS,EAAE,uCAAuC,2BAA2B,CAAC;AAAA,IAChF,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,SAAS,CAAC,CAAC;AAEf,QAAM,UAAU,MAAM;AACpB,SAAK,UAAU;AACf,SAAK,cAAc;AAAA,EACrB,GAAG,CAAC,WAAW,aAAa,CAAC;AAE7B,QAAM;AAAA,IACJ,MACE,oCAAoC,CAAC,WAAW;AAC9C,UAAI,OAAO,eAAe,QAAS;AACnC,UAAI,OAAO,QAAQ,OAAO,SAAS,QAAS;AAC5C,WAAK,UAAU;AACf,WAAK,cAAc;AAAA,IACrB,CAAC;AAAA,IACH,CAAC,WAAW,eAAe,OAAO;AAAA,EACpC;AAEA,QAAM,mBAAmB,MAAM,YAAY,MAAM;AAC/C,mBAAe,EAAE,MAAM,UAAU,UAAU,KAAK,CAAC;AAAA,EACnD,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,eAAgB;AACrB,mBAAe;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AACD,WAAO,MAAM,eAAe,IAAI;AAAA,EAClC,GAAG,CAAC,kBAAkB,kBAAkB,cAAc,CAAC;AAEvD,QAAM,aAAa,MAAM,YAAY,CAAC,aAA0B;AAC9D,mBAAe,EAAE,MAAM,QAAQ,SAAS,CAAC;AAAA,EAC3C,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,aAA0B;AAC/B,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC9B,OAAO,EAAE,2CAA2C,uBAAuB;AAAA,QAC3E,SAAS;AAAA,MACX,CAAC;AACD,UAAI,CAAC,UAAW;AAChB,UAAI;AACF,cAAM,SAAS,MAAM;AAAA;AAAA;AAAA,UAGnB,0BAA0B,qBAAqB,MAAS;AAAA,UACxD,MACE,WAAW,mBAAmB;AAAA,YAC5B,MAAM;AAAA,cACJ,IAAI,SAAS;AAAA,cACb;AAAA,cACA,gBAAgB;AAAA,cAChB,UAAU;AAAA,YACZ;AAAA,YACA,cAAc,EAAE,yCAAyC,4BAA4B;AAAA,UACvF,CAAC;AAAA,QACL;AACA,YAAI,OAAO,IAAI;AACb,gBAAM,cAAc;AACpB,yCAA+B,EAAE,YAAY,SAAS,MAAM,QAAQ,CAAC;AAAA,QACvE;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,2BAA2B,KAAK,GAAG,MAAM,KAAK,cAAc,CAAC,GAAG;AAClE;AAAA,QACF;AACA,eAAO,MAAM,0BAA0B,EAAE,IAAI,CAAC;AAC9C,cAAM,EAAE,yCAAyC,4BAA4B,GAAG,OAAO;AAAA,MACzF;AAAA,IACF;AAAA,IACA,CAAC,SAAS,mBAAmB,eAAe,SAAS,wBAAwB,kBAAkB,CAAC;AAAA,EAClG;AAEA,QAAM,iBAAiB,CAAC,UACtB,oBAAC,QAAG,WAAU,2CACX,gBAAM,IAAI,CAAC,SAAS;AACnB,UAAM,QAAQ,KAAK,kBAAkB,IAAI,KAAK,eAAe,KAAK;AAClE,WACE,qBAAC,QAAiB,WAAU,2CAC1B;AAAA,2BAAC,UAAK,WAAU,YACb;AAAA,gBAAQ,GAAG,KAAK,WAAQ;AAAA,QACxB,KAAK,iBAAiB,KAAK;AAAA,SAC9B;AAAA,MACA,oBAAC,SAAM,SAAQ,aAAa,eAAK,UAAS;AAAA,SALnC,KAAK,EAMd;AAAA,EAEJ,CAAC,GACH;AAGF,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,qCAAqC,yBAAoB;AAAA,QAClE,WAAU;AAAA;AAAA,IACZ;AAAA,EAEJ;AAEA,MAAI,OAAO;AACT,WAAO,oBAAC,gBAAa,OAAO,OAAO;AAAA,EACrC;AAEA,QAAM,QAAQ,CAAC,UAAU;AAEzB,SACE,qBAAC,SAAI,WAAU,aACZ;AAAA,YACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,yCAAyC,mBAAmB;AAAA,QACrE,aAAa;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA,QACA,QAAQ;AAAA,UACN,OAAO;AAAA,UACP,SAAS;AAAA,UACT,MAAM,oBAAC,QAAK,WAAU,WAAU,eAAW,MAAC;AAAA,UAC5C,UAAU;AAAA,QACZ;AAAA;AAAA,IACF,IAEA,oBAAC,SAAI,WAAU,6BACZ,oBAAU,IAAI,CAAC,aAAa;AAK3B,YAAM,YAAY,kBAAkB,oBAAoB,SAAS,SAAS,GAAG,MAAM;AACnF,YAAM,cAAc,kBAAkB,oBAAoB,SAAS,WAAW,GAAG,MAAM;AACvF,YAAM,iBAAiB,sBAAsB,SAAS,QAAQ;AAC9D,YAAM,cACJ,SAAS,eACT,SAAS,UACT,EAAE,2CAA2C,gBAAgB;AAC/D,aACE,qBAAC,SAAsB,WAAU,2CAC/B;AAAA,6BAAC,SAAI,WAAU,0CACb;AAAA,+BAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,SAAI,WAAU,oFACb,8BAAC,SAAM,WAAU,WAAU,GAC7B;AAAA,YACA,qBAAC,SACC;AAAA,kCAAC,OAAE,WAAU,yBACV,mBAAS,iBACN,EAAE,yCAAyC,uBAAuB;AAAA,gBAChE,QAAQ,SAAS;AAAA,cACnB,CAAC,IACD,EAAE,4CAA4C,mBAAmB;AAAA,gBAC/D,IAAI,SAAS,GAAG,MAAM,GAAG,CAAC;AAAA,cAC5B,CAAC,GACP;AAAA,cACA,oBAAC,OAAE,WAAU,iCACV,uBACH;AAAA,eACF;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,2BACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,MAAM,WAAW,QAAQ;AAAA,gBAElC,8BAAC,UAAO,WAAU,WAAU;AAAA;AAAA,YAC9B;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,WAAU;AAAA,gBACV,SAAS,MAAM,KAAK,aAAa,QAAQ;AAAA,gBAEzC,8BAAC,UAAO,WAAU,WAAU;AAAA;AAAA,YAC9B;AAAA,aACF;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,0BACb;AAAA,+BAAC,SAAI,WAAU,2DACZ;AAAA,qBAAS,cACR,oBAAC,SAAM,SAAQ,WAAW,mBAAS,aAAY,IAC7C;AAAA,YACH,SAAS,gBAAgB,SACxB,qBAAC,UAAK,WAAU,YACb;AAAA,gBAAE,sCAAsC,UAAU;AAAA,cAAE;AAAA,cAAG,SAAS,gBAAgB,KAAK,IAAI;AAAA,eAC5F,IACE;AAAA,aACN;AAAA,UACC,YACC,oBAAC,OAAE,WAAU,yBACV,YAAE,uCAAuC,uBAAuB,EAAE,MAAM,UAAU,CAAC,GACtF,IACE;AAAA,UACH,cACC,oBAAC,OAAE,WAAU,yBACV,YAAE,yCAAyC,yBAAyB,EAAE,MAAM,YAAY,CAAC,GAC5F,IACE;AAAA,UACH,iBACC,oBAAC,OAAE,WAAU,iCAAiC,0BAAe,IAC3D;AAAA,UACH,SAAS,QACR,oBAAC,OAAE,WAAU,uDACV,mBAAS,OACZ,IACE;AAAA,UACH,eAAe,SAAS,KAAK;AAAA,WAChC;AAAA,WAtEQ,SAAS,EAuEnB;AAAA,IAEJ,CAAC,GACH;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAgB;AAAA,QACtB,MAAM,aAAa,QAAQ;AAAA,QAC3B,UAAU,aAAa,YAAY;AAAA,QACnC;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,mBAAmB,qBAAqB;AAAA,QACxC;AAAA,QACA;AAAA,QACA,SAAS,MAAM,eAAe,IAAI;AAAA,QAClC,SAAS,YAAY;AACnB,yBAAe,IAAI;AACnB,gBAAM,cAAc;AACpB,yCAA+B,EAAE,YAAY,SAAS,MAAM,QAAQ,CAAC;AAAA,QACvE;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IACC;AAAA,KACH;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -6,7 +6,11 @@ import { extractUndoPayload } from "@open-mercato/shared/lib/commands/undo";
6
6
  import { SalesOrderWarehouseAssignment, Warehouse } from "../data/entities.js";
7
7
  import { z } from "zod";
8
8
  import { reserveInventoryForConfirmedOrder } from "../lib/salesOrderInventoryAutomation.js";
9
+ import { invalidateWmsInventoryEnricherCache } from "../lib/invalidateInventoryEnricherCache.js";
9
10
  import { ensureOrganizationScope, ensureTenantScope } from "./shared.js";
11
+ async function invalidateAssignmentEnricherCache(ctx, tenantId) {
12
+ await invalidateWmsInventoryEnricherCache(ctx.container, tenantId, "warehouse");
13
+ }
10
14
  function resolveScope(ctx, fallback) {
11
15
  return {
12
16
  tenantId: fallback?.tenantId ?? ctx.auth?.tenantId ?? null,
@@ -81,6 +85,7 @@ const assignWarehouseHandler = {
81
85
  existing.assignedBy = ctx.auth?.sub ?? null;
82
86
  existing.updatedAt = /* @__PURE__ */ new Date();
83
87
  await em.flush();
88
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
84
89
  return { assignmentId: existing.id, warehouseId: warehouse.id };
85
90
  }
86
91
  const assignment = em.create(SalesOrderWarehouseAssignment, {
@@ -93,6 +98,7 @@ const assignWarehouseHandler = {
93
98
  });
94
99
  em.persist(assignment);
95
100
  await em.flush();
101
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
96
102
  return { assignmentId: assignment.id, warehouseId: warehouse.id };
97
103
  },
98
104
  captureAfter: async (input, _result, ctx) => {
@@ -136,6 +142,7 @@ const assignWarehouseHandler = {
136
142
  if (!before) {
137
143
  assignment.deletedAt = /* @__PURE__ */ new Date();
138
144
  await em.flush();
145
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
139
146
  return;
140
147
  }
141
148
  const previousWarehouse = await findOneWithDecryption(
@@ -153,11 +160,13 @@ const assignWarehouseHandler = {
153
160
  if (!previousWarehouse) {
154
161
  assignment.deletedAt = /* @__PURE__ */ new Date();
155
162
  await em.flush();
163
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
156
164
  return;
157
165
  }
158
166
  assignment.warehouse = previousWarehouse;
159
167
  assignment.notes = before.notes ?? null;
160
168
  await em.flush();
169
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
161
170
  }
162
171
  }
163
172
  };
@@ -179,6 +188,7 @@ const unassignWarehouseHandler = {
179
188
  if (existing) {
180
189
  existing.deletedAt = /* @__PURE__ */ new Date();
181
190
  await em.flush();
191
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
182
192
  }
183
193
  return { ok: true };
184
194
  },
@@ -212,6 +222,7 @@ const unassignWarehouseHandler = {
212
222
  if (existingDeleted) {
213
223
  existingDeleted.deletedAt = null;
214
224
  await em.flush();
225
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
215
226
  return;
216
227
  }
217
228
  const warehouse = await findOneWithDecryption(
@@ -236,6 +247,7 @@ const unassignWarehouseHandler = {
236
247
  });
237
248
  em.persist(restored);
238
249
  await em.flush();
250
+ await invalidateAssignmentEnricherCache(ctx, scope.tenantId);
239
251
  }
240
252
  };
241
253
  registerCommand(assignWarehouseHandler);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/wms/commands/sales-order-assignment.ts"],
4
- "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { SalesOrderWarehouseAssignment, Warehouse } from '../data/entities'\nimport type { SalesOrderWarehouseAssignInput, SalesOrderWarehouseUnassignInput } from '../data/validators'\nimport { z } from 'zod'\nimport { reserveInventoryForConfirmedOrder } from '../lib/salesOrderInventoryAutomation'\nimport { ensureOrganizationScope, ensureTenantScope } from './shared'\n\ntype AssignmentSnapshot = {\n id: string\n salesOrderId: string\n warehouseId: string\n notes: string | null\n organizationId: string\n tenantId: string\n}\n\ntype AssignWarehouseUndoPayload = {\n before: AssignmentSnapshot | null\n after: AssignmentSnapshot | null\n}\n\ntype UnassignWarehouseUndoPayload = {\n before: AssignmentSnapshot | null\n}\n\nfunction resolveScope(\n ctx: CommandRuntimeContext,\n fallback?: { tenantId?: string | null; organizationId?: string | null },\n) {\n return {\n tenantId: fallback?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: fallback?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n}\n\nfunction resolveEm(ctx: CommandRuntimeContext): EntityManager {\n return (ctx.container.resolve('em') as EntityManager).fork()\n}\n\nasync function loadAssignment(\n em: EntityManager,\n salesOrderId: string,\n scope: ReturnType<typeof resolveScope>,\n): Promise<SalesOrderWarehouseAssignment | null> {\n if (!scope.organizationId || !scope.tenantId) return null\n return findOneWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n {\n salesOrderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope as { organizationId: string; tenantId: string },\n )\n}\n\nfunction snapshotAssignment(\n assignment: SalesOrderWarehouseAssignment | null,\n): AssignmentSnapshot | null {\n if (!assignment) return null\n const warehouseRel = assignment.warehouse as { id?: string } | undefined\n const warehouseId = warehouseRel?.id ?? ''\n return {\n id: assignment.id,\n salesOrderId: assignment.salesOrderId,\n warehouseId,\n notes: assignment.notes ?? null,\n organizationId: assignment.organizationId,\n tenantId: assignment.tenantId,\n }\n}\n\nconst assignWarehouseHandler: CommandHandler<\n SalesOrderWarehouseAssignInput,\n { assignmentId: string; warehouseId: string }\n> = {\n id: 'wms.sales-order.assign-warehouse',\n\n prepare: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n const em = resolveEm(ctx)\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n return { before: snapshotAssignment(existing) }\n },\n\n execute: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n if (!scope.tenantId || !scope.organizationId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const em = resolveEm(ctx)\n\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n {\n id: input.warehouseId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope as { organizationId: string; tenantId: string },\n )\n if (!warehouse) throw new CrudHttpError(404, { error: 'Warehouse not found.' })\n ensureTenantScope(ctx, warehouse.tenantId)\n ensureOrganizationScope(ctx, warehouse.organizationId)\n if (!warehouse.isActive) throw new CrudHttpError(422, { error: 'Warehouse is inactive.' })\n\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n\n if (existing) {\n existing.warehouse = warehouse\n existing.notes = input.notes ?? null\n existing.assignedBy = ctx.auth?.sub ?? null\n existing.updatedAt = new Date()\n await em.flush()\n return { assignmentId: existing.id, warehouseId: warehouse.id }\n }\n\n const assignment = em.create(SalesOrderWarehouseAssignment, {\n salesOrderId: input.salesOrderId,\n warehouse,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n assignedBy: ctx.auth?.sub ?? null,\n notes: input.notes ?? null,\n })\n em.persist(assignment)\n await em.flush()\n return { assignmentId: assignment.id, warehouseId: warehouse.id }\n },\n\n captureAfter: async (input, _result, ctx) => {\n const scope = resolveScope(ctx, input)\n const em = resolveEm(ctx)\n const updated = await loadAssignment(em, input.salesOrderId, scope)\n return { after: snapshotAssignment(updated) }\n },\n\n buildLog: async ({ input, result, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('wms.audit.salesOrder.assignWarehouse', 'Assign warehouse to order'),\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: result?.assignmentId ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n payload: {\n undo: {\n before: (snapshots as { before?: AssignmentSnapshot | null })?.before ?? null,\n after: (snapshots as { after?: AssignmentSnapshot | null })?.after ?? null,\n } satisfies AssignWarehouseUndoPayload,\n },\n }\n },\n\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<AssignWarehouseUndoPayload>(logEntry)\n if (!payload) return\n const em = resolveEm(ctx)\n\n const after = payload.after\n const before = payload.before\n\n if (after) {\n const scope = { tenantId: after.tenantId, organizationId: after.organizationId }\n const assignment = await findOneWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n { id: after.id, organizationId: after.organizationId, tenantId: after.tenantId },\n undefined,\n scope,\n )\n if (!assignment) return\n\n if (!before) {\n assignment.deletedAt = new Date()\n await em.flush()\n return\n }\n\n const previousWarehouse = await findOneWithDecryption(\n em,\n Warehouse,\n {\n id: before.warehouseId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!previousWarehouse) {\n assignment.deletedAt = new Date()\n await em.flush()\n return\n }\n\n assignment.warehouse = previousWarehouse\n assignment.notes = before.notes ?? null\n await em.flush()\n }\n },\n}\n\nconst unassignWarehouseHandler: CommandHandler<\n SalesOrderWarehouseUnassignInput,\n { ok: true }\n> = {\n id: 'wms.sales-order.unassign-warehouse',\n\n prepare: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n const em = resolveEm(ctx)\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n return { before: snapshotAssignment(existing) }\n },\n\n execute: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n if (!scope.tenantId || !scope.organizationId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const em = resolveEm(ctx)\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n\n if (existing) {\n existing.deletedAt = new Date()\n await em.flush()\n }\n\n return { ok: true as const }\n },\n\n buildLog: async ({ input, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = (snapshots as { before?: AssignmentSnapshot | null })?.before ?? null\n return {\n actionLabel: translate('wms.audit.salesOrder.unassignWarehouse', 'Remove warehouse assignment from order'),\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: before?.id ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n payload: {\n undo: { before } satisfies UnassignWarehouseUndoPayload,\n },\n }\n },\n\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<UnassignWarehouseUndoPayload>(logEntry)\n const before = payload?.before\n if (!before?.salesOrderId || !before.warehouseId) return\n\n const scope = { tenantId: before.tenantId, organizationId: before.organizationId }\n const em = resolveEm(ctx)\n\n const existingDeleted = await findOneWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n { id: before.id, organizationId: before.organizationId, tenantId: before.tenantId },\n undefined,\n scope,\n )\n\n if (existingDeleted) {\n existingDeleted.deletedAt = null\n await em.flush()\n return\n }\n\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n {\n id: before.warehouseId,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!warehouse) return\n\n const restored = em.create(SalesOrderWarehouseAssignment, {\n salesOrderId: before.salesOrderId,\n warehouse,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n notes: before.notes ?? null,\n })\n em.persist(restored)\n await em.flush()\n },\n}\n\nregisterCommand(assignWarehouseHandler)\nregisterCommand(unassignWarehouseHandler)\n\nexport const reRunReservationInputSchema = z.object({\n salesOrderId: z.string().uuid(),\n organizationId: z.string().uuid(),\n tenantId: z.string().uuid(),\n})\nexport type ReRunReservationInput = z.infer<typeof reRunReservationInputSchema>\n\nconst reRunReservationHandler: CommandHandler<ReRunReservationInput, { ok: boolean }> = {\n id: 'wms.sales-order.re-run-reservation',\n isUndoable: false,\n async execute(rawInput, ctx) {\n const input = reRunReservationInputSchema.parse(rawInput)\n const eventCtx = {\n resolve: <T>(name: string) => ctx.container.resolve<T>(name),\n }\n await reserveInventoryForConfirmedOrder(\n { orderId: input.salesOrderId, tenantId: input.tenantId, organizationId: input.organizationId },\n eventCtx,\n )\n return { ok: true }\n },\n async buildLog({ input, ctx }) {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('wms.audit.salesOrder.reRunReservation', 'Re-run reservation for order'),\n resourceKind: 'wms.sales_order_reservation',\n resourceId: input?.salesOrderId ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nregisterCommand(reRunReservationHandler)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { SalesOrderWarehouseAssignment, Warehouse } from '../data/entities'\nimport type { SalesOrderWarehouseAssignInput, SalesOrderWarehouseUnassignInput } from '../data/validators'\nimport { z } from 'zod'\nimport { reserveInventoryForConfirmedOrder } from '../lib/salesOrderInventoryAutomation'\nimport { invalidateWmsInventoryEnricherCache } from '../lib/invalidateInventoryEnricherCache'\nimport { ensureOrganizationScope, ensureTenantScope } from './shared'\n\ntype AssignmentSnapshot = {\n id: string\n salesOrderId: string\n warehouseId: string\n notes: string | null\n organizationId: string\n tenantId: string\n}\n\ntype AssignWarehouseUndoPayload = {\n before: AssignmentSnapshot | null\n after: AssignmentSnapshot | null\n}\n\ntype UnassignWarehouseUndoPayload = {\n before: AssignmentSnapshot | null\n}\n\n// These commands emit no WMS event, so the enricher-cache subscribers never see\n// them. `wms.sales-order-inventory` surfaces the assigned warehouse, so every\n// path here that writes an assignment \u2014 including the undo handlers \u2014 drops the\n// warehouse tag itself.\nasync function invalidateAssignmentEnricherCache(\n ctx: CommandRuntimeContext,\n tenantId: string | null | undefined,\n): Promise<void> {\n await invalidateWmsInventoryEnricherCache(ctx.container, tenantId, 'warehouse')\n}\n\nfunction resolveScope(\n ctx: CommandRuntimeContext,\n fallback?: { tenantId?: string | null; organizationId?: string | null },\n) {\n return {\n tenantId: fallback?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: fallback?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n}\n\nfunction resolveEm(ctx: CommandRuntimeContext): EntityManager {\n return (ctx.container.resolve('em') as EntityManager).fork()\n}\n\nasync function loadAssignment(\n em: EntityManager,\n salesOrderId: string,\n scope: ReturnType<typeof resolveScope>,\n): Promise<SalesOrderWarehouseAssignment | null> {\n if (!scope.organizationId || !scope.tenantId) return null\n return findOneWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n {\n salesOrderId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope as { organizationId: string; tenantId: string },\n )\n}\n\nfunction snapshotAssignment(\n assignment: SalesOrderWarehouseAssignment | null,\n): AssignmentSnapshot | null {\n if (!assignment) return null\n const warehouseRel = assignment.warehouse as { id?: string } | undefined\n const warehouseId = warehouseRel?.id ?? ''\n return {\n id: assignment.id,\n salesOrderId: assignment.salesOrderId,\n warehouseId,\n notes: assignment.notes ?? null,\n organizationId: assignment.organizationId,\n tenantId: assignment.tenantId,\n }\n}\n\nconst assignWarehouseHandler: CommandHandler<\n SalesOrderWarehouseAssignInput,\n { assignmentId: string; warehouseId: string }\n> = {\n id: 'wms.sales-order.assign-warehouse',\n\n prepare: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n const em = resolveEm(ctx)\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n return { before: snapshotAssignment(existing) }\n },\n\n execute: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n if (!scope.tenantId || !scope.organizationId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const em = resolveEm(ctx)\n\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n {\n id: input.warehouseId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope as { organizationId: string; tenantId: string },\n )\n if (!warehouse) throw new CrudHttpError(404, { error: 'Warehouse not found.' })\n ensureTenantScope(ctx, warehouse.tenantId)\n ensureOrganizationScope(ctx, warehouse.organizationId)\n if (!warehouse.isActive) throw new CrudHttpError(422, { error: 'Warehouse is inactive.' })\n\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n\n if (existing) {\n existing.warehouse = warehouse\n existing.notes = input.notes ?? null\n existing.assignedBy = ctx.auth?.sub ?? null\n existing.updatedAt = new Date()\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n return { assignmentId: existing.id, warehouseId: warehouse.id }\n }\n\n const assignment = em.create(SalesOrderWarehouseAssignment, {\n salesOrderId: input.salesOrderId,\n warehouse,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n assignedBy: ctx.auth?.sub ?? null,\n notes: input.notes ?? null,\n })\n em.persist(assignment)\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n return { assignmentId: assignment.id, warehouseId: warehouse.id }\n },\n\n captureAfter: async (input, _result, ctx) => {\n const scope = resolveScope(ctx, input)\n const em = resolveEm(ctx)\n const updated = await loadAssignment(em, input.salesOrderId, scope)\n return { after: snapshotAssignment(updated) }\n },\n\n buildLog: async ({ input, result, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('wms.audit.salesOrder.assignWarehouse', 'Assign warehouse to order'),\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: result?.assignmentId ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n payload: {\n undo: {\n before: (snapshots as { before?: AssignmentSnapshot | null })?.before ?? null,\n after: (snapshots as { after?: AssignmentSnapshot | null })?.after ?? null,\n } satisfies AssignWarehouseUndoPayload,\n },\n }\n },\n\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<AssignWarehouseUndoPayload>(logEntry)\n if (!payload) return\n const em = resolveEm(ctx)\n\n const after = payload.after\n const before = payload.before\n\n if (after) {\n const scope = { tenantId: after.tenantId, organizationId: after.organizationId }\n const assignment = await findOneWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n { id: after.id, organizationId: after.organizationId, tenantId: after.tenantId },\n undefined,\n scope,\n )\n if (!assignment) return\n\n if (!before) {\n assignment.deletedAt = new Date()\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n return\n }\n\n const previousWarehouse = await findOneWithDecryption(\n em,\n Warehouse,\n {\n id: before.warehouseId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!previousWarehouse) {\n assignment.deletedAt = new Date()\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n return\n }\n\n assignment.warehouse = previousWarehouse\n assignment.notes = before.notes ?? null\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n }\n },\n}\n\nconst unassignWarehouseHandler: CommandHandler<\n SalesOrderWarehouseUnassignInput,\n { ok: true }\n> = {\n id: 'wms.sales-order.unassign-warehouse',\n\n prepare: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n const em = resolveEm(ctx)\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n return { before: snapshotAssignment(existing) }\n },\n\n execute: async (input, ctx) => {\n const scope = resolveScope(ctx, input)\n if (!scope.tenantId || !scope.organizationId) {\n throw new CrudHttpError(401, { error: 'Unauthorized' })\n }\n const em = resolveEm(ctx)\n const existing = await loadAssignment(em, input.salesOrderId, scope)\n\n if (existing) {\n existing.deletedAt = new Date()\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n }\n\n return { ok: true as const }\n },\n\n buildLog: async ({ input, ctx, snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = (snapshots as { before?: AssignmentSnapshot | null })?.before ?? null\n return {\n actionLabel: translate('wms.audit.salesOrder.unassignWarehouse', 'Remove warehouse assignment from order'),\n resourceKind: 'wms.sales_order_warehouse_assignment',\n resourceId: before?.id ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n payload: {\n undo: { before } satisfies UnassignWarehouseUndoPayload,\n },\n }\n },\n\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<UnassignWarehouseUndoPayload>(logEntry)\n const before = payload?.before\n if (!before?.salesOrderId || !before.warehouseId) return\n\n const scope = { tenantId: before.tenantId, organizationId: before.organizationId }\n const em = resolveEm(ctx)\n\n const existingDeleted = await findOneWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n { id: before.id, organizationId: before.organizationId, tenantId: before.tenantId },\n undefined,\n scope,\n )\n\n if (existingDeleted) {\n existingDeleted.deletedAt = null\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n return\n }\n\n const warehouse = await findOneWithDecryption(\n em,\n Warehouse,\n {\n id: before.warehouseId,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!warehouse) return\n\n const restored = em.create(SalesOrderWarehouseAssignment, {\n salesOrderId: before.salesOrderId,\n warehouse,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n notes: before.notes ?? null,\n })\n em.persist(restored)\n await em.flush()\n await invalidateAssignmentEnricherCache(ctx, scope.tenantId)\n },\n}\n\nregisterCommand(assignWarehouseHandler)\nregisterCommand(unassignWarehouseHandler)\n\nexport const reRunReservationInputSchema = z.object({\n salesOrderId: z.string().uuid(),\n organizationId: z.string().uuid(),\n tenantId: z.string().uuid(),\n})\nexport type ReRunReservationInput = z.infer<typeof reRunReservationInputSchema>\n\nconst reRunReservationHandler: CommandHandler<ReRunReservationInput, { ok: boolean }> = {\n id: 'wms.sales-order.re-run-reservation',\n isUndoable: false,\n async execute(rawInput, ctx) {\n const input = reRunReservationInputSchema.parse(rawInput)\n const eventCtx = {\n resolve: <T>(name: string) => ctx.container.resolve<T>(name),\n }\n await reserveInventoryForConfirmedOrder(\n { orderId: input.salesOrderId, tenantId: input.tenantId, organizationId: input.organizationId },\n eventCtx,\n )\n return { ok: true }\n },\n async buildLog({ input, ctx }) {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('wms.audit.salesOrder.reRunReservation', 'Re-run reservation for order'),\n resourceKind: 'wms.sales_order_reservation',\n resourceId: input?.salesOrderId ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nregisterCommand(reRunReservationHandler)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -2,6 +2,11 @@ import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
2
  import { E } from "../../../generated/entities.ids.generated.js";
3
3
  import { InventoryBalance, InventoryReservation, ProductInventoryProfile, SalesOrderWarehouseAssignment, Warehouse } from "./entities.js";
4
4
  import { resolvePrimaryWarehouseId } from "../lib/primaryWarehousePolicy.js";
5
+ import {
6
+ WMS_ENRICHER_CACHE_TTL_MS,
7
+ WMS_INVENTORY_CACHE_TAG,
8
+ WMS_WAREHOUSE_CACHE_TAG
9
+ } from "../lib/enricherCacheTags.js";
5
10
  import { resolveWmsIntegrationToggleEnabled } from "../lib/wmsIntegrationToggles.js";
6
11
  const EMPTY_ENRICHMENT = {
7
12
  _wms: {
@@ -262,6 +267,13 @@ const salesOrderInventoryEnricher = {
262
267
  priority: 40,
263
268
  timeout: 2e3,
264
269
  fallback: EMPTY_ENRICHMENT,
270
+ // Reads reservations, balances, the primary warehouse and the explicit
271
+ // assignment, so it depends on both the inventory and the warehouse tags.
272
+ cache: {
273
+ strategy: "read-through",
274
+ ttl: WMS_ENRICHER_CACHE_TTL_MS,
275
+ tags: [WMS_INVENTORY_CACHE_TAG, WMS_WAREHOUSE_CACHE_TAG]
276
+ },
265
277
  async enrichOne(record, context) {
266
278
  return (await this.enrichMany([record], context))[0];
267
279
  },
@@ -393,6 +405,13 @@ const catalogProductInventoryEnricher = {
393
405
  priority: 40,
394
406
  timeout: 2e3,
395
407
  fallback: EMPTY_CATALOG_ENRICHMENT,
408
+ // Reads inventory profiles and balances; also reads catalog variants, so the
409
+ // catalog variant events invalidate the inventory tag too.
410
+ cache: {
411
+ strategy: "read-through",
412
+ ttl: WMS_ENRICHER_CACHE_TTL_MS,
413
+ tags: [WMS_INVENTORY_CACHE_TAG]
414
+ },
396
415
  async enrichOne(record, context) {
397
416
  return (await this.enrichMany([record], context))[0];
398
417
  },
@@ -453,6 +472,12 @@ const catalogVariantInventoryEnricher = {
453
472
  priority: 40,
454
473
  timeout: 2e3,
455
474
  fallback: EMPTY_CATALOG_ENRICHMENT,
475
+ // Reads inventory profiles and balances for the variant only.
476
+ cache: {
477
+ strategy: "read-through",
478
+ ttl: WMS_ENRICHER_CACHE_TTL_MS,
479
+ tags: [WMS_INVENTORY_CACHE_TAG]
480
+ },
456
481
  async enrichOne(record, context) {
457
482
  return (await this.enrichMany([record], context))[0];
458
483
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/wms/data/enrichers.ts"],
4
- "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { ResponseEnricher, EnricherContext } from '@open-mercato/shared/lib/crud/response-enricher'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { FeatureTogglesService } from '@open-mercato/core/modules/feature_toggles/lib/feature-flag-check'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { InventoryBalance, InventoryReservation, ProductInventoryProfile, SalesOrderWarehouseAssignment, Warehouse } from './entities'\nimport { resolvePrimaryWarehouseId } from '../lib/primaryWarehousePolicy'\n\ntype SalesOrderRecord = Record<string, unknown> & { id?: string }\ntype CatalogProductRecord = Record<string, unknown> & { id?: string }\ntype CatalogVariantRecord = Record<string, unknown> & { id?: string; product_id?: string; productId?: string }\n\ntype SalesOrderLineRow = {\n id?: string\n order_id?: string | null\n product_variant_id?: string | null\n quantity?: string | number | null\n line_number?: number | null\n status?: string | null\n}\n\ntype CatalogVariantRow = {\n id?: string\n product_id?: string | null\n}\ntype ReservationStatus = 'unreserved' | 'partially_reserved' | 'fully_reserved'\ntype ReorderState = 'no_profile' | 'healthy' | 'below_reorder_point' | 'below_safety_stock'\n\ntype InventoryProfileSummary = {\n profileId: string\n catalogProductId: string\n catalogVariantId: string | null\n defaultUom: string\n defaultStrategy: string\n trackLot: boolean\n trackSerial: boolean\n trackExpiration: boolean\n reorderPoint: string\n safetyStock: string\n}\n\ntype StockSummaryItem = {\n catalogVariantId: string\n onHand: string\n reserved: string\n allocated: string\n available: string\n}\n\ntype ReorderStatus = {\n state: ReorderState\n available: string\n reorderPoint: string\n safetyStock: string\n}\n\ntype SalesOrderWmsEnrichment = {\n _wms: {\n assignedWarehouseId: string | null\n assignedWarehouseName: string | null\n isExplicitlyAssigned: boolean\n stockSummary: Array<{\n catalogVariantId: string\n available: string\n reserved: string\n }>\n reservationSummary: {\n status: ReservationStatus\n reservationIds: string[]\n }\n }\n}\n\ntype CatalogWmsEnrichment = {\n _wms: {\n inventoryProfile: InventoryProfileSummary | null\n stockSummary: StockSummaryItem[]\n reorderStatus: ReorderStatus\n }\n}\n\ntype EnricherScope = EnricherContext & { em: EntityManager }\ntype Scope = { organizationId: string; tenantId: string }\ntype BalanceAggregate = { onHand: number; reserved: number; allocated: number; available: number }\n\nimport { resolveWmsIntegrationToggleEnabled } from '../lib/wmsIntegrationToggles'\nconst EMPTY_ENRICHMENT: SalesOrderWmsEnrichment = {\n _wms: {\n assignedWarehouseId: null,\n assignedWarehouseName: null,\n isExplicitlyAssigned: false,\n stockSummary: [],\n reservationSummary: {\n status: 'unreserved',\n reservationIds: [],\n },\n },\n}\n\nconst EMPTY_CATALOG_ENRICHMENT: CatalogWmsEnrichment = {\n _wms: {\n inventoryProfile: null,\n stockSummary: [],\n reorderStatus: {\n state: 'no_profile',\n available: '0',\n reorderPoint: '0',\n safetyStock: '0',\n },\n },\n}\n\nfunction extractRecordId(record: SalesOrderRecord): string | null {\n return typeof record.id === 'string' && record.id.trim().length > 0 ? record.id : null\n}\n\nfunction extractOrderIdFromLine(line: SalesOrderLineRow): string | null {\n return typeof line.order_id === 'string' && line.order_id.length > 0 ? line.order_id : null\n}\n\nfunction extractProductIdFromVariant(variant: CatalogVariantRow): string | null {\n return typeof variant.product_id === 'string' && variant.product_id.length > 0\n ? variant.product_id\n : null\n}\n\nfunction extractWarehouseId(reservation: InventoryReservation): string | null {\n const relation = reservation.warehouse as { id?: string } | undefined\n return typeof relation?.id === 'string' ? relation.id : null\n}\n\nfunction addToMap(map: Map<string, number>, key: string, value: string | number | null | undefined) {\n const numeric = typeof value === 'number' ? value : Number(value ?? 0)\n map.set(key, (map.get(key) ?? 0) + numeric)\n}\n\nfunction formatQuantity(value: number): string {\n if (!Number.isFinite(value) || value === 0) return '0'\n const normalized = value.toFixed(4).replace(/\\.?0+$/, '')\n return normalized.length > 0 ? normalized : '0'\n}\n\nfunction toInventoryProfileSummary(profile: ProductInventoryProfile): InventoryProfileSummary {\n return {\n profileId: profile.id,\n catalogProductId: profile.catalogProductId,\n catalogVariantId: profile.catalogVariantId ?? null,\n defaultUom: profile.defaultUom,\n defaultStrategy: profile.defaultStrategy,\n trackLot: profile.trackLot,\n trackSerial: profile.trackSerial,\n trackExpiration: profile.trackExpiration,\n reorderPoint: profile.reorderPoint,\n safetyStock: profile.safetyStock,\n }\n}\n\nfunction resolveReservationStatus(requiredQuantity: number, reservedQuantity: number): ReservationStatus {\n if (requiredQuantity <= 0 || reservedQuantity <= 0) return 'unreserved'\n if (reservedQuantity + 0.0001 < requiredQuantity) return 'partially_reserved'\n return 'fully_reserved'\n}\n\nfunction resolveReorderStatus(\n availableQuantity: number,\n profile: ProductInventoryProfile | null | undefined,\n): ReorderStatus {\n if (!profile) {\n return {\n state: 'no_profile',\n available: formatQuantity(availableQuantity),\n reorderPoint: '0',\n safetyStock: '0',\n }\n }\n\n const reorderPoint = Number(profile.reorderPoint)\n const safetyStock = Number(profile.safetyStock)\n let state: ReorderState = 'healthy'\n\n if (availableQuantity <= safetyStock) {\n state = 'below_safety_stock'\n } else if (availableQuantity <= reorderPoint) {\n state = 'below_reorder_point'\n }\n\n return {\n state,\n available: formatQuantity(availableQuantity),\n reorderPoint: profile.reorderPoint,\n safetyStock: profile.safetyStock,\n }\n}\n\nfunction buildBalanceSummaryByVariant(\n balances: InventoryBalance[],\n): Map<string, BalanceAggregate> {\n const byVariant = new Map<string, BalanceAggregate>()\n\n for (const balance of balances) {\n const current = byVariant.get(balance.catalogVariantId) ?? {\n onHand: 0,\n reserved: 0,\n allocated: 0,\n available: 0,\n }\n\n current.onHand += Number(balance.quantityOnHand)\n current.reserved += Number(balance.quantityReserved)\n current.allocated += Number(balance.quantityAllocated)\n current.available +=\n Number(balance.quantityOnHand) - Number(balance.quantityReserved) - Number(balance.quantityAllocated)\n\n byVariant.set(balance.catalogVariantId, current)\n }\n\n return byVariant\n}\n\nfunction buildStockSummaryItem(\n catalogVariantId: string,\n aggregate: BalanceAggregate | undefined,\n): StockSummaryItem {\n return {\n catalogVariantId,\n onHand: formatQuantity(aggregate?.onHand ?? 0),\n reserved: formatQuantity(aggregate?.reserved ?? 0),\n allocated: formatQuantity(aggregate?.allocated ?? 0),\n available: formatQuantity(aggregate?.available ?? 0),\n }\n}\n\nasync function isSalesOrderInventoryEnabled(context: EnricherContext): Promise<boolean> {\n const container = context.container as { resolve?: (name: string) => unknown } | undefined\n if (!container?.resolve) return true\n try {\n const featureTogglesService = container.resolve('featureTogglesService') as FeatureTogglesService | undefined\n const em = container.resolve('em') as EntityManager | undefined\n if (!featureTogglesService || !em) return true\n return resolveWmsIntegrationToggleEnabled(\n featureTogglesService,\n em,\n 'wms_integration_sales_order_inventory',\n context.tenantId,\n )\n } catch {\n return true\n }\n}\n\nasync function loadExplicitAssignments(\n em: EntityManager,\n orderIds: string[],\n scope: Scope,\n): Promise<SalesOrderWarehouseAssignment[]> {\n if (orderIds.length === 0) return []\n return findWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n {\n salesOrderId: { $in: orderIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadWarehousesByIds(\n em: EntityManager,\n warehouseIds: string[],\n scope: Scope,\n): Promise<Warehouse[]> {\n if (warehouseIds.length === 0) return []\n return findWithDecryption(\n em,\n Warehouse,\n {\n id: { $in: warehouseIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadOrderLines(\n context: EnricherContext,\n orderIds: string[],\n scope: Scope,\n): Promise<SalesOrderLineRow[]> {\n if (orderIds.length === 0) return []\n // Read sales order lines via QueryEngine instead of importing the sales ORM\n // entity. Keeps the WMS module decoupled from sales internals; queryEngine\n // resolves the base table via Mikro-ORM metadata.\n const container = context.container as { resolve: (name: string) => unknown }\n const queryEngine = container.resolve('queryEngine') as QueryEngine\n const result = await queryEngine.query<SalesOrderLineRow>(E.sales.sales_order_line, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n filters: { order_id: { $in: orderIds } },\n fields: ['id', 'order_id', 'product_variant_id', 'quantity', 'line_number', 'status'],\n sort: [{ field: 'line_number', dir: 'asc' as never }],\n page: { page: 1, pageSize: 5000 },\n })\n return result.items\n}\n\nasync function loadReservations(\n em: EntityManager,\n orderIds: string[],\n scope: Scope,\n): Promise<InventoryReservation[]> {\n if (orderIds.length === 0) return []\n return findWithDecryption(\n em,\n InventoryReservation,\n {\n sourceType: 'order',\n sourceId: { $in: orderIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n { orderBy: { createdAt: 'asc' } },\n scope,\n )\n}\n\nasync function loadBalances(\n em: EntityManager,\n variantIds: string[],\n scope: Scope,\n): Promise<InventoryBalance[]> {\n if (variantIds.length === 0) return []\n return findWithDecryption(\n em,\n InventoryBalance,\n {\n catalogVariantId: { $in: variantIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadCatalogVariants(\n context: EnricherContext,\n productIds: string[],\n scope: Scope,\n): Promise<CatalogVariantRow[]> {\n if (productIds.length === 0) return []\n const container = context.container as { resolve: (name: string) => unknown }\n const queryEngine = container.resolve('queryEngine') as QueryEngine\n const result = await queryEngine.query<CatalogVariantRow>(E.catalog.catalog_product_variant, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n filters: { product_id: { $in: productIds } },\n fields: ['id', 'product_id'],\n sort: [{ field: 'created_at', dir: 'asc' as never }],\n page: { page: 1, pageSize: 5000 },\n })\n return result.items\n}\n\nasync function loadProductInventoryProfiles(\n em: EntityManager,\n productIds: string[],\n scope: Scope,\n): Promise<ProductInventoryProfile[]> {\n if (productIds.length === 0) return []\n return findWithDecryption(\n em,\n ProductInventoryProfile,\n {\n catalogProductId: { $in: productIds },\n catalogVariantId: null,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadVariantInventoryProfiles(\n em: EntityManager,\n variantIds: string[],\n scope: Scope,\n): Promise<ProductInventoryProfile[]> {\n if (variantIds.length === 0) return []\n return findWithDecryption(\n em,\n ProductInventoryProfile,\n {\n catalogVariantId: { $in: variantIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nconst salesOrderInventoryEnricher: ResponseEnricher<SalesOrderRecord, SalesOrderWmsEnrichment> = {\n id: 'wms.sales-order-inventory',\n targetEntity: E.sales.sales_order,\n features: ['wms.view'],\n priority: 40,\n timeout: 2000,\n fallback: EMPTY_ENRICHMENT,\n\n async enrichOne(record, context: EnricherScope) {\n return (await this.enrichMany!([record], context))[0]\n },\n\n async enrichMany(records, context: EnricherScope) {\n if (records.length === 0) return records as Array<SalesOrderRecord & SalesOrderWmsEnrichment>\n const enabled = await isSalesOrderInventoryEnabled(context)\n if (!enabled) return records as Array<SalesOrderRecord & SalesOrderWmsEnrichment>\n\n const orderIds = records\n .map(extractRecordId)\n .filter((value): value is string => Boolean(value))\n\n if (orderIds.length === 0) {\n return records.map((record) => ({ ...record, ...EMPTY_ENRICHMENT }))\n }\n\n const em = context.em.fork()\n const scope = { organizationId: context.organizationId, tenantId: context.tenantId }\n\n const lines = await loadOrderLines(context, orderIds, scope)\n\n const variantIds = Array.from(\n new Set(\n lines\n .map((line) => line.product_variant_id)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n ),\n )\n\n const [reservations, balances, primaryWarehouseId, explicitAssignments] = await Promise.all([\n loadReservations(em, orderIds, scope),\n loadBalances(em, variantIds, scope),\n resolvePrimaryWarehouseId(em, scope),\n loadExplicitAssignments(em, orderIds, scope),\n ])\n\n const explicitWarehouseIdsByOrder = new Map<string, string>()\n for (const assignment of explicitAssignments) {\n const warehouseRel = assignment.warehouse as { id?: string } | undefined\n const warehouseId = warehouseRel?.id\n if (warehouseId) {\n explicitWarehouseIdsByOrder.set(assignment.salesOrderId, warehouseId)\n }\n }\n\n const reservationWarehouseIds = reservations\n .map(extractWarehouseId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n const allRelevantWarehouseIds = Array.from(\n new Set([\n ...Array.from(explicitWarehouseIdsByOrder.values()),\n ...reservationWarehouseIds,\n ...(primaryWarehouseId ? [primaryWarehouseId] : []),\n ]),\n )\n const warehouses = await loadWarehousesByIds(em, allRelevantWarehouseIds, scope)\n const warehouseNamesById = new Map(warehouses.map((w) => [w.id, w.name]))\n\n const variantAvailability = new Map<string, number>()\n const variantReserved = new Map<string, number>()\n for (const balance of balances) {\n addToMap(\n variantAvailability,\n balance.catalogVariantId,\n Number(balance.quantityOnHand) - Number(balance.quantityReserved) - Number(balance.quantityAllocated),\n )\n addToMap(variantReserved, balance.catalogVariantId, balance.quantityReserved)\n }\n\n const variantOrderBySalesOrder = new Map<string, string[]>()\n const requiredBySalesOrder = new Map<string, number>()\n\n for (const line of lines) {\n const orderId = extractOrderIdFromLine(line)\n const variantId = line.product_variant_id ?? null\n if (!orderId || !variantId) continue\n\n const variantOrder = variantOrderBySalesOrder.get(orderId) ?? []\n if (!variantOrder.includes(variantId)) {\n variantOrder.push(variantId)\n variantOrderBySalesOrder.set(orderId, variantOrder)\n }\n requiredBySalesOrder.set(orderId, (requiredBySalesOrder.get(orderId) ?? 0) + Number(line.quantity))\n }\n\n const activeReservationsBySalesOrder = new Map<string, InventoryReservation[]>()\n const reservedBySalesOrder = new Map<string, number>()\n\n for (const reservation of reservations) {\n if (reservation.status !== 'active') continue\n const orderId = reservation.sourceId\n const activeReservations = activeReservationsBySalesOrder.get(orderId) ?? []\n activeReservations.push(reservation)\n activeReservationsBySalesOrder.set(orderId, activeReservations)\n reservedBySalesOrder.set(orderId, (reservedBySalesOrder.get(orderId) ?? 0) + Number(reservation.quantity))\n }\n\n return records.map((record) => {\n const orderId = extractRecordId(record)\n if (!orderId) {\n return { ...record, ...EMPTY_ENRICHMENT }\n }\n\n const reservationsForOrder = activeReservationsBySalesOrder.get(orderId) ?? []\n const warehouseIds = Array.from(\n new Set(\n reservationsForOrder\n .map(extractWarehouseId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n ),\n )\n const variantIdsForOrder = variantOrderBySalesOrder.get(orderId) ?? []\n\n const explicitWarehouseId = explicitWarehouseIdsByOrder.get(orderId) ?? null\n const isExplicitlyAssigned = explicitWarehouseId !== null\n\n let assignedWarehouseId: string | null\n if (isExplicitlyAssigned) {\n assignedWarehouseId = explicitWarehouseId\n } else if (warehouseIds.length === 1) {\n assignedWarehouseId = warehouseIds[0]\n } else if (warehouseIds.length === 0 && primaryWarehouseId) {\n assignedWarehouseId = primaryWarehouseId\n } else {\n assignedWarehouseId = null\n }\n\n const assignedWarehouseName = assignedWarehouseId\n ? (warehouseNamesById.get(assignedWarehouseId) ?? null)\n : null\n\n return {\n ...record,\n _wms: {\n assignedWarehouseId,\n assignedWarehouseName,\n isExplicitlyAssigned,\n stockSummary: variantIdsForOrder.map((catalogVariantId) => ({\n catalogVariantId,\n available: formatQuantity(variantAvailability.get(catalogVariantId) ?? 0),\n reserved: formatQuantity(variantReserved.get(catalogVariantId) ?? 0),\n })),\n reservationSummary: {\n status: resolveReservationStatus(\n requiredBySalesOrder.get(orderId) ?? 0,\n reservedBySalesOrder.get(orderId) ?? 0,\n ),\n reservationIds: reservationsForOrder.map((reservation) => reservation.id),\n },\n },\n }\n })\n },\n}\n\nconst catalogProductInventoryEnricher: ResponseEnricher<CatalogProductRecord, CatalogWmsEnrichment> = {\n id: 'wms.catalog-product-inventory',\n targetEntity: E.catalog.catalog_product,\n features: ['wms.view'],\n priority: 40,\n timeout: 2000,\n fallback: EMPTY_CATALOG_ENRICHMENT,\n\n async enrichOne(record, context: EnricherScope) {\n return (await this.enrichMany!([record], context))[0]\n },\n\n async enrichMany(records, context: EnricherScope) {\n if (records.length === 0) return records as Array<CatalogProductRecord & CatalogWmsEnrichment>\n\n const productIds = records\n .map(extractRecordId)\n .filter((value): value is string => Boolean(value))\n\n if (productIds.length === 0) {\n return records.map((record) => ({ ...record, ...EMPTY_CATALOG_ENRICHMENT }))\n }\n\n const em = context.em.fork()\n const scope = { organizationId: context.organizationId, tenantId: context.tenantId }\n\n const variants = await loadCatalogVariants(context, productIds, scope)\n const variantIds = variants\n .map((variant) => variant.id)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n const [productProfiles, balances] = await Promise.all([\n loadProductInventoryProfiles(em, productIds, scope),\n loadBalances(em, variantIds, scope),\n ])\n\n const profileByProductId = new Map(\n productProfiles.map((profile) => [profile.catalogProductId, profile] as const),\n )\n const balanceByVariantId = buildBalanceSummaryByVariant(balances)\n const variantIdsByProductId = new Map<string, string[]>()\n\n for (const variant of variants) {\n const productId = extractProductIdFromVariant(variant)\n if (!productId || typeof variant.id !== 'string') continue\n const entries = variantIdsByProductId.get(productId) ?? []\n entries.push(variant.id)\n variantIdsByProductId.set(productId, entries)\n }\n\n return records.map((record) => {\n const productId = extractRecordId(record)\n if (!productId) {\n return { ...record, ...EMPTY_CATALOG_ENRICHMENT }\n }\n\n const profile = profileByProductId.get(productId) ?? null\n const stockSummary = (variantIdsByProductId.get(productId) ?? []).map((variantId) =>\n buildStockSummaryItem(variantId, balanceByVariantId.get(variantId)),\n )\n const totalAvailable = stockSummary.reduce(\n (sum, item) => sum + Number(item.available),\n 0,\n )\n\n return {\n ...record,\n _wms: {\n inventoryProfile: profile ? toInventoryProfileSummary(profile) : null,\n stockSummary,\n reorderStatus: resolveReorderStatus(totalAvailable, profile),\n },\n }\n })\n },\n}\n\nconst catalogVariantInventoryEnricher: ResponseEnricher<CatalogVariantRecord, CatalogWmsEnrichment> = {\n id: 'wms.catalog-variant-inventory',\n targetEntity: E.catalog.catalog_product_variant,\n features: ['wms.view'],\n priority: 40,\n timeout: 2000,\n fallback: EMPTY_CATALOG_ENRICHMENT,\n\n async enrichOne(record, context: EnricherScope) {\n return (await this.enrichMany!([record], context))[0]\n },\n\n async enrichMany(records, context: EnricherScope) {\n if (records.length === 0) return records as Array<CatalogVariantRecord & CatalogWmsEnrichment>\n\n const variantIds = records\n .map(extractRecordId)\n .filter((value): value is string => Boolean(value))\n\n if (variantIds.length === 0) {\n return records.map((record) => ({ ...record, ...EMPTY_CATALOG_ENRICHMENT }))\n }\n\n const em = context.em.fork()\n const scope = { organizationId: context.organizationId, tenantId: context.tenantId }\n\n const [profiles, balances] = await Promise.all([\n loadVariantInventoryProfiles(em, variantIds, scope),\n loadBalances(em, variantIds, scope),\n ])\n\n const profileByVariantId = new Map(\n profiles\n .filter((profile): profile is ProductInventoryProfile & { catalogVariantId: string } => typeof profile.catalogVariantId === 'string')\n .map((profile) => [profile.catalogVariantId, profile] as const),\n )\n const balanceByVariantId = buildBalanceSummaryByVariant(balances)\n\n return records.map((record) => {\n const variantId = extractRecordId(record)\n if (!variantId) {\n return { ...record, ...EMPTY_CATALOG_ENRICHMENT }\n }\n\n const profile = profileByVariantId.get(variantId) ?? null\n const stockSummary = [buildStockSummaryItem(variantId, balanceByVariantId.get(variantId))]\n\n return {\n ...record,\n _wms: {\n inventoryProfile: profile ? toInventoryProfileSummary(profile) : null,\n stockSummary,\n reorderStatus: resolveReorderStatus(Number(stockSummary[0]?.available ?? 0), profile),\n },\n }\n })\n },\n}\n\nexport const enrichers: ResponseEnricher[] = [\n salesOrderInventoryEnricher,\n catalogProductInventoryEnricher,\n catalogVariantInventoryEnricher,\n]\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { ResponseEnricher, EnricherContext } from '@open-mercato/shared/lib/crud/response-enricher'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { FeatureTogglesService } from '@open-mercato/core/modules/feature_toggles/lib/feature-flag-check'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { InventoryBalance, InventoryReservation, ProductInventoryProfile, SalesOrderWarehouseAssignment, Warehouse } from './entities'\nimport { resolvePrimaryWarehouseId } from '../lib/primaryWarehousePolicy'\nimport {\n WMS_ENRICHER_CACHE_TTL_MS,\n WMS_INVENTORY_CACHE_TAG,\n WMS_WAREHOUSE_CACHE_TAG,\n} from '../lib/enricherCacheTags'\n\ntype SalesOrderRecord = Record<string, unknown> & { id?: string }\ntype CatalogProductRecord = Record<string, unknown> & { id?: string }\ntype CatalogVariantRecord = Record<string, unknown> & { id?: string; product_id?: string; productId?: string }\n\ntype SalesOrderLineRow = {\n id?: string\n order_id?: string | null\n product_variant_id?: string | null\n quantity?: string | number | null\n line_number?: number | null\n status?: string | null\n}\n\ntype CatalogVariantRow = {\n id?: string\n product_id?: string | null\n}\ntype ReservationStatus = 'unreserved' | 'partially_reserved' | 'fully_reserved'\ntype ReorderState = 'no_profile' | 'healthy' | 'below_reorder_point' | 'below_safety_stock'\n\ntype InventoryProfileSummary = {\n profileId: string\n catalogProductId: string\n catalogVariantId: string | null\n defaultUom: string\n defaultStrategy: string\n trackLot: boolean\n trackSerial: boolean\n trackExpiration: boolean\n reorderPoint: string\n safetyStock: string\n}\n\ntype StockSummaryItem = {\n catalogVariantId: string\n onHand: string\n reserved: string\n allocated: string\n available: string\n}\n\ntype ReorderStatus = {\n state: ReorderState\n available: string\n reorderPoint: string\n safetyStock: string\n}\n\ntype SalesOrderWmsEnrichment = {\n _wms: {\n assignedWarehouseId: string | null\n assignedWarehouseName: string | null\n isExplicitlyAssigned: boolean\n stockSummary: Array<{\n catalogVariantId: string\n available: string\n reserved: string\n }>\n reservationSummary: {\n status: ReservationStatus\n reservationIds: string[]\n }\n }\n}\n\ntype CatalogWmsEnrichment = {\n _wms: {\n inventoryProfile: InventoryProfileSummary | null\n stockSummary: StockSummaryItem[]\n reorderStatus: ReorderStatus\n }\n}\n\ntype EnricherScope = EnricherContext & { em: EntityManager }\ntype Scope = { organizationId: string; tenantId: string }\ntype BalanceAggregate = { onHand: number; reserved: number; allocated: number; available: number }\n\nimport { resolveWmsIntegrationToggleEnabled } from '../lib/wmsIntegrationToggles'\nconst EMPTY_ENRICHMENT: SalesOrderWmsEnrichment = {\n _wms: {\n assignedWarehouseId: null,\n assignedWarehouseName: null,\n isExplicitlyAssigned: false,\n stockSummary: [],\n reservationSummary: {\n status: 'unreserved',\n reservationIds: [],\n },\n },\n}\n\nconst EMPTY_CATALOG_ENRICHMENT: CatalogWmsEnrichment = {\n _wms: {\n inventoryProfile: null,\n stockSummary: [],\n reorderStatus: {\n state: 'no_profile',\n available: '0',\n reorderPoint: '0',\n safetyStock: '0',\n },\n },\n}\n\nfunction extractRecordId(record: SalesOrderRecord): string | null {\n return typeof record.id === 'string' && record.id.trim().length > 0 ? record.id : null\n}\n\nfunction extractOrderIdFromLine(line: SalesOrderLineRow): string | null {\n return typeof line.order_id === 'string' && line.order_id.length > 0 ? line.order_id : null\n}\n\nfunction extractProductIdFromVariant(variant: CatalogVariantRow): string | null {\n return typeof variant.product_id === 'string' && variant.product_id.length > 0\n ? variant.product_id\n : null\n}\n\nfunction extractWarehouseId(reservation: InventoryReservation): string | null {\n const relation = reservation.warehouse as { id?: string } | undefined\n return typeof relation?.id === 'string' ? relation.id : null\n}\n\nfunction addToMap(map: Map<string, number>, key: string, value: string | number | null | undefined) {\n const numeric = typeof value === 'number' ? value : Number(value ?? 0)\n map.set(key, (map.get(key) ?? 0) + numeric)\n}\n\nfunction formatQuantity(value: number): string {\n if (!Number.isFinite(value) || value === 0) return '0'\n const normalized = value.toFixed(4).replace(/\\.?0+$/, '')\n return normalized.length > 0 ? normalized : '0'\n}\n\nfunction toInventoryProfileSummary(profile: ProductInventoryProfile): InventoryProfileSummary {\n return {\n profileId: profile.id,\n catalogProductId: profile.catalogProductId,\n catalogVariantId: profile.catalogVariantId ?? null,\n defaultUom: profile.defaultUom,\n defaultStrategy: profile.defaultStrategy,\n trackLot: profile.trackLot,\n trackSerial: profile.trackSerial,\n trackExpiration: profile.trackExpiration,\n reorderPoint: profile.reorderPoint,\n safetyStock: profile.safetyStock,\n }\n}\n\nfunction resolveReservationStatus(requiredQuantity: number, reservedQuantity: number): ReservationStatus {\n if (requiredQuantity <= 0 || reservedQuantity <= 0) return 'unreserved'\n if (reservedQuantity + 0.0001 < requiredQuantity) return 'partially_reserved'\n return 'fully_reserved'\n}\n\nfunction resolveReorderStatus(\n availableQuantity: number,\n profile: ProductInventoryProfile | null | undefined,\n): ReorderStatus {\n if (!profile) {\n return {\n state: 'no_profile',\n available: formatQuantity(availableQuantity),\n reorderPoint: '0',\n safetyStock: '0',\n }\n }\n\n const reorderPoint = Number(profile.reorderPoint)\n const safetyStock = Number(profile.safetyStock)\n let state: ReorderState = 'healthy'\n\n if (availableQuantity <= safetyStock) {\n state = 'below_safety_stock'\n } else if (availableQuantity <= reorderPoint) {\n state = 'below_reorder_point'\n }\n\n return {\n state,\n available: formatQuantity(availableQuantity),\n reorderPoint: profile.reorderPoint,\n safetyStock: profile.safetyStock,\n }\n}\n\nfunction buildBalanceSummaryByVariant(\n balances: InventoryBalance[],\n): Map<string, BalanceAggregate> {\n const byVariant = new Map<string, BalanceAggregate>()\n\n for (const balance of balances) {\n const current = byVariant.get(balance.catalogVariantId) ?? {\n onHand: 0,\n reserved: 0,\n allocated: 0,\n available: 0,\n }\n\n current.onHand += Number(balance.quantityOnHand)\n current.reserved += Number(balance.quantityReserved)\n current.allocated += Number(balance.quantityAllocated)\n current.available +=\n Number(balance.quantityOnHand) - Number(balance.quantityReserved) - Number(balance.quantityAllocated)\n\n byVariant.set(balance.catalogVariantId, current)\n }\n\n return byVariant\n}\n\nfunction buildStockSummaryItem(\n catalogVariantId: string,\n aggregate: BalanceAggregate | undefined,\n): StockSummaryItem {\n return {\n catalogVariantId,\n onHand: formatQuantity(aggregate?.onHand ?? 0),\n reserved: formatQuantity(aggregate?.reserved ?? 0),\n allocated: formatQuantity(aggregate?.allocated ?? 0),\n available: formatQuantity(aggregate?.available ?? 0),\n }\n}\n\nasync function isSalesOrderInventoryEnabled(context: EnricherContext): Promise<boolean> {\n const container = context.container as { resolve?: (name: string) => unknown } | undefined\n if (!container?.resolve) return true\n try {\n const featureTogglesService = container.resolve('featureTogglesService') as FeatureTogglesService | undefined\n const em = container.resolve('em') as EntityManager | undefined\n if (!featureTogglesService || !em) return true\n return resolveWmsIntegrationToggleEnabled(\n featureTogglesService,\n em,\n 'wms_integration_sales_order_inventory',\n context.tenantId,\n )\n } catch {\n return true\n }\n}\n\nasync function loadExplicitAssignments(\n em: EntityManager,\n orderIds: string[],\n scope: Scope,\n): Promise<SalesOrderWarehouseAssignment[]> {\n if (orderIds.length === 0) return []\n return findWithDecryption(\n em,\n SalesOrderWarehouseAssignment,\n {\n salesOrderId: { $in: orderIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadWarehousesByIds(\n em: EntityManager,\n warehouseIds: string[],\n scope: Scope,\n): Promise<Warehouse[]> {\n if (warehouseIds.length === 0) return []\n return findWithDecryption(\n em,\n Warehouse,\n {\n id: { $in: warehouseIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadOrderLines(\n context: EnricherContext,\n orderIds: string[],\n scope: Scope,\n): Promise<SalesOrderLineRow[]> {\n if (orderIds.length === 0) return []\n // Read sales order lines via QueryEngine instead of importing the sales ORM\n // entity. Keeps the WMS module decoupled from sales internals; queryEngine\n // resolves the base table via Mikro-ORM metadata.\n const container = context.container as { resolve: (name: string) => unknown }\n const queryEngine = container.resolve('queryEngine') as QueryEngine\n const result = await queryEngine.query<SalesOrderLineRow>(E.sales.sales_order_line, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n filters: { order_id: { $in: orderIds } },\n fields: ['id', 'order_id', 'product_variant_id', 'quantity', 'line_number', 'status'],\n sort: [{ field: 'line_number', dir: 'asc' as never }],\n page: { page: 1, pageSize: 5000 },\n })\n return result.items\n}\n\nasync function loadReservations(\n em: EntityManager,\n orderIds: string[],\n scope: Scope,\n): Promise<InventoryReservation[]> {\n if (orderIds.length === 0) return []\n return findWithDecryption(\n em,\n InventoryReservation,\n {\n sourceType: 'order',\n sourceId: { $in: orderIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n { orderBy: { createdAt: 'asc' } },\n scope,\n )\n}\n\nasync function loadBalances(\n em: EntityManager,\n variantIds: string[],\n scope: Scope,\n): Promise<InventoryBalance[]> {\n if (variantIds.length === 0) return []\n return findWithDecryption(\n em,\n InventoryBalance,\n {\n catalogVariantId: { $in: variantIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadCatalogVariants(\n context: EnricherContext,\n productIds: string[],\n scope: Scope,\n): Promise<CatalogVariantRow[]> {\n if (productIds.length === 0) return []\n const container = context.container as { resolve: (name: string) => unknown }\n const queryEngine = container.resolve('queryEngine') as QueryEngine\n const result = await queryEngine.query<CatalogVariantRow>(E.catalog.catalog_product_variant, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n filters: { product_id: { $in: productIds } },\n fields: ['id', 'product_id'],\n sort: [{ field: 'created_at', dir: 'asc' as never }],\n page: { page: 1, pageSize: 5000 },\n })\n return result.items\n}\n\nasync function loadProductInventoryProfiles(\n em: EntityManager,\n productIds: string[],\n scope: Scope,\n): Promise<ProductInventoryProfile[]> {\n if (productIds.length === 0) return []\n return findWithDecryption(\n em,\n ProductInventoryProfile,\n {\n catalogProductId: { $in: productIds },\n catalogVariantId: null,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nasync function loadVariantInventoryProfiles(\n em: EntityManager,\n variantIds: string[],\n scope: Scope,\n): Promise<ProductInventoryProfile[]> {\n if (variantIds.length === 0) return []\n return findWithDecryption(\n em,\n ProductInventoryProfile,\n {\n catalogVariantId: { $in: variantIds },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n}\n\nconst salesOrderInventoryEnricher: ResponseEnricher<SalesOrderRecord, SalesOrderWmsEnrichment> = {\n id: 'wms.sales-order-inventory',\n targetEntity: E.sales.sales_order,\n features: ['wms.view'],\n priority: 40,\n timeout: 2000,\n fallback: EMPTY_ENRICHMENT,\n // Reads reservations, balances, the primary warehouse and the explicit\n // assignment, so it depends on both the inventory and the warehouse tags.\n cache: {\n strategy: 'read-through',\n ttl: WMS_ENRICHER_CACHE_TTL_MS,\n tags: [WMS_INVENTORY_CACHE_TAG, WMS_WAREHOUSE_CACHE_TAG],\n },\n\n async enrichOne(record, context: EnricherScope) {\n return (await this.enrichMany!([record], context))[0]\n },\n\n async enrichMany(records, context: EnricherScope) {\n if (records.length === 0) return records as Array<SalesOrderRecord & SalesOrderWmsEnrichment>\n const enabled = await isSalesOrderInventoryEnabled(context)\n if (!enabled) return records as Array<SalesOrderRecord & SalesOrderWmsEnrichment>\n\n const orderIds = records\n .map(extractRecordId)\n .filter((value): value is string => Boolean(value))\n\n if (orderIds.length === 0) {\n return records.map((record) => ({ ...record, ...EMPTY_ENRICHMENT }))\n }\n\n const em = context.em.fork()\n const scope = { organizationId: context.organizationId, tenantId: context.tenantId }\n\n const lines = await loadOrderLines(context, orderIds, scope)\n\n const variantIds = Array.from(\n new Set(\n lines\n .map((line) => line.product_variant_id)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n ),\n )\n\n const [reservations, balances, primaryWarehouseId, explicitAssignments] = await Promise.all([\n loadReservations(em, orderIds, scope),\n loadBalances(em, variantIds, scope),\n resolvePrimaryWarehouseId(em, scope),\n loadExplicitAssignments(em, orderIds, scope),\n ])\n\n const explicitWarehouseIdsByOrder = new Map<string, string>()\n for (const assignment of explicitAssignments) {\n const warehouseRel = assignment.warehouse as { id?: string } | undefined\n const warehouseId = warehouseRel?.id\n if (warehouseId) {\n explicitWarehouseIdsByOrder.set(assignment.salesOrderId, warehouseId)\n }\n }\n\n const reservationWarehouseIds = reservations\n .map(extractWarehouseId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n const allRelevantWarehouseIds = Array.from(\n new Set([\n ...Array.from(explicitWarehouseIdsByOrder.values()),\n ...reservationWarehouseIds,\n ...(primaryWarehouseId ? [primaryWarehouseId] : []),\n ]),\n )\n const warehouses = await loadWarehousesByIds(em, allRelevantWarehouseIds, scope)\n const warehouseNamesById = new Map(warehouses.map((w) => [w.id, w.name]))\n\n const variantAvailability = new Map<string, number>()\n const variantReserved = new Map<string, number>()\n for (const balance of balances) {\n addToMap(\n variantAvailability,\n balance.catalogVariantId,\n Number(balance.quantityOnHand) - Number(balance.quantityReserved) - Number(balance.quantityAllocated),\n )\n addToMap(variantReserved, balance.catalogVariantId, balance.quantityReserved)\n }\n\n const variantOrderBySalesOrder = new Map<string, string[]>()\n const requiredBySalesOrder = new Map<string, number>()\n\n for (const line of lines) {\n const orderId = extractOrderIdFromLine(line)\n const variantId = line.product_variant_id ?? null\n if (!orderId || !variantId) continue\n\n const variantOrder = variantOrderBySalesOrder.get(orderId) ?? []\n if (!variantOrder.includes(variantId)) {\n variantOrder.push(variantId)\n variantOrderBySalesOrder.set(orderId, variantOrder)\n }\n requiredBySalesOrder.set(orderId, (requiredBySalesOrder.get(orderId) ?? 0) + Number(line.quantity))\n }\n\n const activeReservationsBySalesOrder = new Map<string, InventoryReservation[]>()\n const reservedBySalesOrder = new Map<string, number>()\n\n for (const reservation of reservations) {\n if (reservation.status !== 'active') continue\n const orderId = reservation.sourceId\n const activeReservations = activeReservationsBySalesOrder.get(orderId) ?? []\n activeReservations.push(reservation)\n activeReservationsBySalesOrder.set(orderId, activeReservations)\n reservedBySalesOrder.set(orderId, (reservedBySalesOrder.get(orderId) ?? 0) + Number(reservation.quantity))\n }\n\n return records.map((record) => {\n const orderId = extractRecordId(record)\n if (!orderId) {\n return { ...record, ...EMPTY_ENRICHMENT }\n }\n\n const reservationsForOrder = activeReservationsBySalesOrder.get(orderId) ?? []\n const warehouseIds = Array.from(\n new Set(\n reservationsForOrder\n .map(extractWarehouseId)\n .filter((value): value is string => typeof value === 'string' && value.length > 0),\n ),\n )\n const variantIdsForOrder = variantOrderBySalesOrder.get(orderId) ?? []\n\n const explicitWarehouseId = explicitWarehouseIdsByOrder.get(orderId) ?? null\n const isExplicitlyAssigned = explicitWarehouseId !== null\n\n let assignedWarehouseId: string | null\n if (isExplicitlyAssigned) {\n assignedWarehouseId = explicitWarehouseId\n } else if (warehouseIds.length === 1) {\n assignedWarehouseId = warehouseIds[0]\n } else if (warehouseIds.length === 0 && primaryWarehouseId) {\n assignedWarehouseId = primaryWarehouseId\n } else {\n assignedWarehouseId = null\n }\n\n const assignedWarehouseName = assignedWarehouseId\n ? (warehouseNamesById.get(assignedWarehouseId) ?? null)\n : null\n\n return {\n ...record,\n _wms: {\n assignedWarehouseId,\n assignedWarehouseName,\n isExplicitlyAssigned,\n stockSummary: variantIdsForOrder.map((catalogVariantId) => ({\n catalogVariantId,\n available: formatQuantity(variantAvailability.get(catalogVariantId) ?? 0),\n reserved: formatQuantity(variantReserved.get(catalogVariantId) ?? 0),\n })),\n reservationSummary: {\n status: resolveReservationStatus(\n requiredBySalesOrder.get(orderId) ?? 0,\n reservedBySalesOrder.get(orderId) ?? 0,\n ),\n reservationIds: reservationsForOrder.map((reservation) => reservation.id),\n },\n },\n }\n })\n },\n}\n\nconst catalogProductInventoryEnricher: ResponseEnricher<CatalogProductRecord, CatalogWmsEnrichment> = {\n id: 'wms.catalog-product-inventory',\n targetEntity: E.catalog.catalog_product,\n features: ['wms.view'],\n priority: 40,\n timeout: 2000,\n fallback: EMPTY_CATALOG_ENRICHMENT,\n // Reads inventory profiles and balances; also reads catalog variants, so the\n // catalog variant events invalidate the inventory tag too.\n cache: {\n strategy: 'read-through',\n ttl: WMS_ENRICHER_CACHE_TTL_MS,\n tags: [WMS_INVENTORY_CACHE_TAG],\n },\n\n async enrichOne(record, context: EnricherScope) {\n return (await this.enrichMany!([record], context))[0]\n },\n\n async enrichMany(records, context: EnricherScope) {\n if (records.length === 0) return records as Array<CatalogProductRecord & CatalogWmsEnrichment>\n\n const productIds = records\n .map(extractRecordId)\n .filter((value): value is string => Boolean(value))\n\n if (productIds.length === 0) {\n return records.map((record) => ({ ...record, ...EMPTY_CATALOG_ENRICHMENT }))\n }\n\n const em = context.em.fork()\n const scope = { organizationId: context.organizationId, tenantId: context.tenantId }\n\n const variants = await loadCatalogVariants(context, productIds, scope)\n const variantIds = variants\n .map((variant) => variant.id)\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n const [productProfiles, balances] = await Promise.all([\n loadProductInventoryProfiles(em, productIds, scope),\n loadBalances(em, variantIds, scope),\n ])\n\n const profileByProductId = new Map(\n productProfiles.map((profile) => [profile.catalogProductId, profile] as const),\n )\n const balanceByVariantId = buildBalanceSummaryByVariant(balances)\n const variantIdsByProductId = new Map<string, string[]>()\n\n for (const variant of variants) {\n const productId = extractProductIdFromVariant(variant)\n if (!productId || typeof variant.id !== 'string') continue\n const entries = variantIdsByProductId.get(productId) ?? []\n entries.push(variant.id)\n variantIdsByProductId.set(productId, entries)\n }\n\n return records.map((record) => {\n const productId = extractRecordId(record)\n if (!productId) {\n return { ...record, ...EMPTY_CATALOG_ENRICHMENT }\n }\n\n const profile = profileByProductId.get(productId) ?? null\n const stockSummary = (variantIdsByProductId.get(productId) ?? []).map((variantId) =>\n buildStockSummaryItem(variantId, balanceByVariantId.get(variantId)),\n )\n const totalAvailable = stockSummary.reduce(\n (sum, item) => sum + Number(item.available),\n 0,\n )\n\n return {\n ...record,\n _wms: {\n inventoryProfile: profile ? toInventoryProfileSummary(profile) : null,\n stockSummary,\n reorderStatus: resolveReorderStatus(totalAvailable, profile),\n },\n }\n })\n },\n}\n\nconst catalogVariantInventoryEnricher: ResponseEnricher<CatalogVariantRecord, CatalogWmsEnrichment> = {\n id: 'wms.catalog-variant-inventory',\n targetEntity: E.catalog.catalog_product_variant,\n features: ['wms.view'],\n priority: 40,\n timeout: 2000,\n fallback: EMPTY_CATALOG_ENRICHMENT,\n // Reads inventory profiles and balances for the variant only.\n cache: {\n strategy: 'read-through',\n ttl: WMS_ENRICHER_CACHE_TTL_MS,\n tags: [WMS_INVENTORY_CACHE_TAG],\n },\n\n async enrichOne(record, context: EnricherScope) {\n return (await this.enrichMany!([record], context))[0]\n },\n\n async enrichMany(records, context: EnricherScope) {\n if (records.length === 0) return records as Array<CatalogVariantRecord & CatalogWmsEnrichment>\n\n const variantIds = records\n .map(extractRecordId)\n .filter((value): value is string => Boolean(value))\n\n if (variantIds.length === 0) {\n return records.map((record) => ({ ...record, ...EMPTY_CATALOG_ENRICHMENT }))\n }\n\n const em = context.em.fork()\n const scope = { organizationId: context.organizationId, tenantId: context.tenantId }\n\n const [profiles, balances] = await Promise.all([\n loadVariantInventoryProfiles(em, variantIds, scope),\n loadBalances(em, variantIds, scope),\n ])\n\n const profileByVariantId = new Map(\n profiles\n .filter((profile): profile is ProductInventoryProfile & { catalogVariantId: string } => typeof profile.catalogVariantId === 'string')\n .map((profile) => [profile.catalogVariantId, profile] as const),\n )\n const balanceByVariantId = buildBalanceSummaryByVariant(balances)\n\n return records.map((record) => {\n const variantId = extractRecordId(record)\n if (!variantId) {\n return { ...record, ...EMPTY_CATALOG_ENRICHMENT }\n }\n\n const profile = profileByVariantId.get(variantId) ?? null\n const stockSummary = [buildStockSummaryItem(variantId, balanceByVariantId.get(variantId))]\n\n return {\n ...record,\n _wms: {\n inventoryProfile: profile ? toInventoryProfileSummary(profile) : null,\n stockSummary,\n reorderStatus: resolveReorderStatus(Number(stockSummary[0]?.available ?? 0), profile),\n },\n }\n })\n },\n}\n\nexport const enrichers: ResponseEnricher[] = [\n salesOrderInventoryEnricher,\n catalogProductInventoryEnricher,\n catalogVariantInventoryEnricher,\n]\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,9 @@
1
+ const WMS_INVENTORY_CACHE_TAG = "wms:inventory";
2
+ const WMS_WAREHOUSE_CACHE_TAG = "wms:warehouse";
3
+ const WMS_ENRICHER_CACHE_TTL_MS = 3e4;
4
+ export {
5
+ WMS_ENRICHER_CACHE_TTL_MS,
6
+ WMS_INVENTORY_CACHE_TAG,
7
+ WMS_WAREHOUSE_CACHE_TAG
8
+ };
9
+ //# sourceMappingURL=enricherCacheTags.js.map