@open-mercato/core 0.4.7-develop-78d7541539 → 0.4.7-develop-74069040de

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 (187) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/modules/catalog/api/bulk-delete/route.js +86 -0
  3. package/dist/modules/catalog/api/bulk-delete/route.js.map +7 -0
  4. package/dist/modules/catalog/api/prices/route.js +39 -6
  5. package/dist/modules/catalog/api/prices/route.js.map +2 -2
  6. package/dist/modules/catalog/api/products/route.js +6 -11
  7. package/dist/modules/catalog/api/products/route.js.map +2 -2
  8. package/dist/modules/catalog/commands/products.js +2 -0
  9. package/dist/modules/catalog/commands/products.js.map +2 -2
  10. package/dist/modules/catalog/components/products/ProductsDataTable.js +9 -1
  11. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  12. package/dist/modules/catalog/lib/bulkDelete.js +70 -0
  13. package/dist/modules/catalog/lib/bulkDelete.js.map +7 -0
  14. package/dist/modules/catalog/widgets/injection/product-bulk-delete/widget.js +185 -0
  15. package/dist/modules/catalog/widgets/injection/product-bulk-delete/widget.js.map +7 -0
  16. package/dist/modules/catalog/widgets/injection-table.js +9 -1
  17. package/dist/modules/catalog/widgets/injection-table.js.map +2 -2
  18. package/dist/modules/catalog/workers/catalog-product-bulk-delete.js +40 -0
  19. package/dist/modules/catalog/workers/catalog-product-bulk-delete.js.map +7 -0
  20. package/dist/modules/data_sync/api/options.js +52 -0
  21. package/dist/modules/data_sync/api/options.js.map +7 -0
  22. package/dist/modules/data_sync/api/run.js +30 -35
  23. package/dist/modules/data_sync/api/run.js.map +2 -2
  24. package/dist/modules/data_sync/api/runs/[id]/cancel.js +2 -2
  25. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  26. package/dist/modules/data_sync/api/runs/[id]/retry.js +15 -30
  27. package/dist/modules/data_sync/api/runs/[id]/retry.js.map +2 -2
  28. package/dist/modules/data_sync/api/schedules/[id]/route.js +109 -0
  29. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +7 -0
  30. package/dist/modules/data_sync/api/schedules/route.js +72 -0
  31. package/dist/modules/data_sync/api/schedules/route.js.map +7 -0
  32. package/dist/modules/data_sync/api/schedules/serialize.js +21 -0
  33. package/dist/modules/data_sync/api/schedules/serialize.js.map +7 -0
  34. package/dist/modules/data_sync/backend/data-sync/page.js +656 -47
  35. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  36. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +116 -34
  37. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  38. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +394 -0
  39. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +7 -0
  40. package/dist/modules/data_sync/data/validators.js +32 -0
  41. package/dist/modules/data_sync/data/validators.js.map +2 -2
  42. package/dist/modules/data_sync/di.js +2 -0
  43. package/dist/modules/data_sync/di.js.map +2 -2
  44. package/dist/modules/data_sync/lib/id-mapping.js +24 -2
  45. package/dist/modules/data_sync/lib/id-mapping.js.map +2 -2
  46. package/dist/modules/data_sync/lib/start-run.js +57 -0
  47. package/dist/modules/data_sync/lib/start-run.js.map +7 -0
  48. package/dist/modules/data_sync/lib/sync-engine.js +93 -4
  49. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  50. package/dist/modules/data_sync/lib/sync-run-service.js +5 -1
  51. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  52. package/dist/modules/data_sync/lib/sync-schedule-service.js +138 -0
  53. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +7 -0
  54. package/dist/modules/data_sync/workers/sync-export.js +28 -2
  55. package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
  56. package/dist/modules/data_sync/workers/sync-import.js +28 -2
  57. package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
  58. package/dist/modules/data_sync/workers/sync-scheduled.js +5 -0
  59. package/dist/modules/data_sync/workers/sync-scheduled.js.map +2 -2
  60. package/dist/modules/entities/api/definitions.js +5 -2
  61. package/dist/modules/entities/api/definitions.js.map +2 -2
  62. package/dist/modules/entities/lib/field-definitions.js +3 -1
  63. package/dist/modules/entities/lib/field-definitions.js.map +2 -2
  64. package/dist/modules/integrations/api/[id]/route.js +14 -15
  65. package/dist/modules/integrations/api/[id]/route.js.map +2 -2
  66. package/dist/modules/integrations/api/route.js +3 -3
  67. package/dist/modules/integrations/api/route.js.map +2 -2
  68. package/dist/modules/integrations/backend/integrations/[id]/page.js +148 -33
  69. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  70. package/dist/modules/integrations/lib/state-service.js +15 -1
  71. package/dist/modules/integrations/lib/state-service.js.map +2 -2
  72. package/dist/modules/messages/api/[id]/route.js +24 -22
  73. package/dist/modules/messages/api/[id]/route.js.map +2 -2
  74. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
  75. package/dist/modules/progress/api/active/route.js +3 -1
  76. package/dist/modules/progress/api/active/route.js.map +2 -2
  77. package/dist/modules/progress/api/jobs/[id]/route.js +1 -1
  78. package/dist/modules/progress/api/jobs/[id]/route.js.map +2 -2
  79. package/dist/modules/progress/api/jobs/route.js +1 -1
  80. package/dist/modules/progress/api/jobs/route.js.map +2 -2
  81. package/dist/modules/progress/lib/events.js.map +1 -1
  82. package/dist/modules/progress/lib/progressService.js.map +2 -2
  83. package/dist/modules/progress/lib/progressServiceImpl.js +42 -1
  84. package/dist/modules/progress/lib/progressServiceImpl.js.map +2 -2
  85. package/dist/modules/query_index/lib/document.js +35 -1
  86. package/dist/modules/query_index/lib/document.js.map +2 -2
  87. package/dist/modules/query_index/lib/engine.js +91 -4
  88. package/dist/modules/query_index/lib/engine.js.map +2 -2
  89. package/dist/modules/query_index/lib/indexer.js +2 -0
  90. package/dist/modules/query_index/lib/indexer.js.map +2 -2
  91. package/dist/modules/sales/api/adjustment-kinds/route.js +3 -9
  92. package/dist/modules/sales/api/adjustment-kinds/route.js.map +2 -2
  93. package/dist/modules/sales/api/channels/route.js +3 -10
  94. package/dist/modules/sales/api/channels/route.js.map +2 -2
  95. package/dist/modules/sales/api/delivery-windows/route.js +3 -10
  96. package/dist/modules/sales/api/delivery-windows/route.js.map +2 -2
  97. package/dist/modules/sales/api/payment-methods/route.js +3 -11
  98. package/dist/modules/sales/api/payment-methods/route.js.map +2 -2
  99. package/dist/modules/sales/api/price-kinds/route.js +3 -5
  100. package/dist/modules/sales/api/price-kinds/route.js.map +2 -2
  101. package/dist/modules/sales/api/shipping-methods/route.js +3 -11
  102. package/dist/modules/sales/api/shipping-methods/route.js.map +2 -2
  103. package/dist/modules/sales/api/tags/route.js +3 -9
  104. package/dist/modules/sales/api/tags/route.js.map +2 -2
  105. package/dist/modules/sales/api/tax-rates/route.js +3 -13
  106. package/dist/modules/sales/api/tax-rates/route.js.map +2 -2
  107. package/dist/modules/sales/api/utils.js +9 -0
  108. package/dist/modules/sales/api/utils.js.map +2 -2
  109. package/dist/modules/sales/lib/makeStatusDictionaryRoute.js +3 -9
  110. package/dist/modules/sales/lib/makeStatusDictionaryRoute.js.map +2 -2
  111. package/dist/modules/workflows/api/definitions/[id]/route.js +3 -2
  112. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  113. package/dist/modules/workflows/api/definitions/route.js +4 -3
  114. package/dist/modules/workflows/api/definitions/route.js.map +2 -2
  115. package/dist/modules/workflows/api/definitions/serialize.js +25 -0
  116. package/dist/modules/workflows/api/definitions/serialize.js.map +7 -0
  117. package/package.json +3 -3
  118. package/src/modules/catalog/api/bulk-delete/route.ts +93 -0
  119. package/src/modules/catalog/api/prices/route.ts +53 -6
  120. package/src/modules/catalog/api/products/route.ts +6 -11
  121. package/src/modules/catalog/commands/products.ts +2 -0
  122. package/src/modules/catalog/components/products/ProductsDataTable.tsx +8 -0
  123. package/src/modules/catalog/i18n/de.json +10 -0
  124. package/src/modules/catalog/i18n/en.json +10 -0
  125. package/src/modules/catalog/i18n/es.json +10 -0
  126. package/src/modules/catalog/i18n/pl.json +10 -0
  127. package/src/modules/catalog/lib/bulkDelete.ts +106 -0
  128. package/src/modules/catalog/widgets/injection/product-bulk-delete/widget.ts +242 -0
  129. package/src/modules/catalog/widgets/injection-table.ts +8 -0
  130. package/src/modules/catalog/workers/catalog-product-bulk-delete.ts +48 -0
  131. package/src/modules/data_sync/AGENTS.md +11 -3
  132. package/src/modules/data_sync/api/options.ts +58 -0
  133. package/src/modules/data_sync/api/run.ts +34 -36
  134. package/src/modules/data_sync/api/runs/[id]/cancel.ts +2 -2
  135. package/src/modules/data_sync/api/runs/[id]/retry.ts +14 -31
  136. package/src/modules/data_sync/api/schedules/[id]/route.ts +130 -0
  137. package/src/modules/data_sync/api/schedules/route.ts +77 -0
  138. package/src/modules/data_sync/api/schedules/serialize.ts +31 -0
  139. package/src/modules/data_sync/backend/data-sync/page.tsx +756 -2
  140. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +179 -53
  141. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +512 -0
  142. package/src/modules/data_sync/data/validators.ts +35 -0
  143. package/src/modules/data_sync/di.ts +6 -0
  144. package/src/modules/data_sync/i18n/de.json +72 -0
  145. package/src/modules/data_sync/i18n/en.json +72 -0
  146. package/src/modules/data_sync/i18n/es.json +72 -0
  147. package/src/modules/data_sync/i18n/pl.json +72 -0
  148. package/src/modules/data_sync/lib/adapter.ts +4 -1
  149. package/src/modules/data_sync/lib/id-mapping.ts +32 -2
  150. package/src/modules/data_sync/lib/start-run.ts +90 -0
  151. package/src/modules/data_sync/lib/sync-engine.ts +111 -4
  152. package/src/modules/data_sync/lib/sync-run-service.ts +5 -1
  153. package/src/modules/data_sync/lib/sync-schedule-service.ts +207 -0
  154. package/src/modules/data_sync/workers/sync-export.ts +33 -2
  155. package/src/modules/data_sync/workers/sync-import.ts +33 -2
  156. package/src/modules/data_sync/workers/sync-scheduled.ts +7 -0
  157. package/src/modules/entities/api/definitions.ts +12 -2
  158. package/src/modules/entities/lib/field-definitions.ts +2 -0
  159. package/src/modules/integrations/AGENTS.md +16 -3
  160. package/src/modules/integrations/api/[id]/route.ts +14 -15
  161. package/src/modules/integrations/api/route.ts +3 -3
  162. package/src/modules/integrations/backend/integrations/[id]/page.tsx +176 -54
  163. package/src/modules/integrations/lib/state-service.ts +25 -1
  164. package/src/modules/messages/api/[id]/route.ts +25 -22
  165. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +3 -3
  166. package/src/modules/progress/api/active/route.ts +4 -1
  167. package/src/modules/progress/api/jobs/[id]/route.ts +1 -1
  168. package/src/modules/progress/api/jobs/route.ts +1 -1
  169. package/src/modules/progress/lib/events.ts +6 -0
  170. package/src/modules/progress/lib/progressService.ts +1 -0
  171. package/src/modules/progress/lib/progressServiceImpl.ts +47 -1
  172. package/src/modules/query_index/lib/document.ts +52 -1
  173. package/src/modules/query_index/lib/engine.ts +104 -4
  174. package/src/modules/query_index/lib/indexer.ts +2 -0
  175. package/src/modules/sales/api/adjustment-kinds/route.ts +3 -9
  176. package/src/modules/sales/api/channels/route.ts +3 -10
  177. package/src/modules/sales/api/delivery-windows/route.ts +3 -10
  178. package/src/modules/sales/api/payment-methods/route.ts +3 -11
  179. package/src/modules/sales/api/price-kinds/route.ts +3 -5
  180. package/src/modules/sales/api/shipping-methods/route.ts +3 -11
  181. package/src/modules/sales/api/tags/route.ts +3 -9
  182. package/src/modules/sales/api/tax-rates/route.ts +3 -13
  183. package/src/modules/sales/api/utils.ts +9 -0
  184. package/src/modules/sales/lib/makeStatusDictionaryRoute.ts +3 -9
  185. package/src/modules/workflows/api/definitions/[id]/route.ts +3 -2
  186. package/src/modules/workflows/api/definitions/route.ts +4 -3
  187. package/src/modules/workflows/api/definitions/serialize.ts +23 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/catalog/commands/products.ts"],
4
- "sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport { registerCommand } from \"@open-mercato/shared/lib/commands\";\nimport type {\n CommandHandler,\n CommandRuntimeContext,\n} from \"@open-mercato/shared/lib/commands\";\nimport {\n buildChanges,\n requireId,\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n} from \"@open-mercato/shared/lib/commands/helpers\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { UniqueConstraintViolationException } from \"@mikro-orm/core\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport { CrudHttpError } from \"@open-mercato/shared/lib/crud/errors\";\nimport type {\n CrudEventAction,\n CrudEventsConfig,\n CrudIndexerConfig,\n} from \"@open-mercato/shared/lib/crud/types\";\nimport type { DataEngine } from \"@open-mercato/shared/lib/data/engine\";\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from \"@open-mercato/shared/lib/commands/customFieldSnapshots\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport { slugifyTagLabel } from \"@open-mercato/shared/lib/utils\";\nimport { parseObjectLike } from \"@open-mercato/shared/lib/json/parseObjectLike\";\nimport {\n CatalogOffer,\n CatalogProduct,\n CatalogProductVariant,\n CatalogProductPrice,\n CatalogProductUnitConversion,\n CatalogOptionSchemaTemplate,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductTag,\n CatalogProductTagAssignment,\n} from \"../data/entities\";\nimport { SalesTaxRate } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n productCreateSchema,\n productUpdateSchema,\n type OfferInput,\n type ProductCreateInput,\n type ProductUpdateInput,\n} from \"../data/validators\";\nimport type {\n CatalogProductOptionSchema,\n CatalogProductType,\n} from \"../data/types\";\nimport {\n cloneJson,\n ensureOrganizationScope,\n ensureSameScope,\n ensureTenantScope,\n extractUndoPayload,\n requireOptionSchemaTemplate,\n resolveOptionSchemaCode,\n emitCatalogQueryIndexEvent,\n randomSuffix,\n toNumericString,\n getErrorConstraint,\n getErrorMessage,\n} from \"./shared\";\nimport {\n findWithDecryption,\n findOneWithDecryption,\n} from \"@open-mercato/shared/lib/encryption/find\";\nimport { canonicalizeUnitCode } from \"../lib/unitCodes\";\nimport {\n resolveCanonicalUnitCode,\n} from \"../lib/unitResolution\";\n\ntype ProductSnapshot = {\n id: string;\n organizationId: string;\n tenantId: string;\n title: string;\n subtitle: string | null;\n description: string | null;\n sku: string | null;\n handle: string | null;\n taxRateId: string | null;\n taxRate: string | null;\n productType: CatalogProductType;\n statusEntryId: string | null;\n primaryCurrencyCode: string | null;\n defaultUnit: string | null;\n defaultSalesUnit: string | null;\n defaultSalesUnitQuantity: string;\n uomRoundingScale: number;\n uomRoundingMode: \"half_up\" | \"down\" | \"up\";\n unitPriceEnabled: boolean;\n unitPriceReferenceUnit: \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null;\n unitPriceBaseQuantity: string | null;\n defaultMediaId: string | null;\n defaultMediaUrl: string | null;\n weightValue: string | null;\n weightUnit: string | null;\n dimensions: Record<string, unknown> | null;\n optionSchemaId: string | null;\n customFieldsetCode: string | null;\n metadata: Record<string, unknown> | null;\n isConfigurable: boolean;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n offers: OfferSnapshot[];\n tags: string[];\n categoryIds: string[];\n custom: Record<string, unknown> | null;\n};\n\nasync function resolveProductUnitDefaults(\n em: EntityManager,\n params: {\n organizationId: string;\n tenantId: string;\n defaultUnit: string | null | undefined;\n defaultSalesUnit: string | null | undefined;\n },\n): Promise<{ defaultUnit: string | null; defaultSalesUnit: string | null }> {\n const defaultUnitInput = canonicalizeUnitCode(params.defaultUnit);\n const defaultSalesUnitInput = canonicalizeUnitCode(params.defaultSalesUnit);\n if (!defaultUnitInput && defaultSalesUnitInput) {\n throw new CrudHttpError(400, { error: \"uom.default_unit_missing\" });\n }\n const defaultUnit = defaultUnitInput\n ? await resolveCanonicalUnitCode(em, {\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n unitCode: defaultUnitInput,\n })\n : null;\n const defaultSalesUnit = defaultSalesUnitInput\n ? await resolveCanonicalUnitCode(em, {\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n unitCode: defaultSalesUnitInput,\n })\n : null;\n return { defaultUnit, defaultSalesUnit };\n}\n\nasync function ensureBaseUnitCanBeRemoved(\n em: EntityManager,\n params: {\n productId: string;\n organizationId: string;\n tenantId: string;\n defaultUnit: string | null;\n defaultSalesUnit: string | null;\n },\n): Promise<void> {\n if (params.defaultUnit) return;\n if (params.defaultSalesUnit) {\n throw new CrudHttpError(400, { error: \"uom.default_unit_missing\" });\n }\n const activeConversionCount = await em.count(CatalogProductUnitConversion, {\n product: params.productId,\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n deletedAt: null,\n isActive: true,\n });\n if (activeConversionCount > 0) {\n throw new CrudHttpError(400, { error: \"uom.default_unit_missing\" });\n }\n}\n\n/**\n * Resolves unit-price configuration from product input.\n * Supports two input paths:\n * - Nested: `unitPrice.enabled`, `unitPrice.referenceUnit`, `unitPrice.baseQuantity` (preferred)\n * - Flat: `unitPriceEnabled`, `unitPriceReferenceUnit`, `unitPriceBaseQuantity` (legacy compat)\n * Nested values take precedence when both are provided.\n */\nfunction resolveUnitPriceInput(\n parsed: ProductCreateInput | ProductUpdateInput,\n): {\n enabled?: boolean;\n referenceUnit?: \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null;\n baseQuantity?: string | null;\n enabledProvided: boolean;\n referenceProvided: boolean;\n baseProvided: boolean;\n} {\n const enabledFromNested = parsed.unitPrice?.enabled;\n const enabledFromFlat = parsed.unitPriceEnabled;\n const referenceFromNested = parsed.unitPrice?.referenceUnit;\n const referenceFromFlat = parsed.unitPriceReferenceUnit;\n const baseFromNested = parsed.unitPrice?.baseQuantity;\n const baseFromFlat = parsed.unitPriceBaseQuantity;\n const enabledProvided =\n enabledFromNested !== undefined || enabledFromFlat !== undefined;\n const referenceProvided =\n referenceFromNested !== undefined || referenceFromFlat !== undefined;\n const baseProvided =\n baseFromNested !== undefined || baseFromFlat !== undefined;\n const enabled = enabledFromNested ?? enabledFromFlat;\n const referenceUnit = canonicalizeUnitCode(\n referenceFromNested ?? referenceFromFlat ?? null,\n ) as \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null | undefined;\n const baseQuantitySource = baseFromNested ?? baseFromFlat;\n const baseQuantity =\n baseQuantitySource === undefined\n ? undefined\n : (toNumericString(baseQuantitySource) ?? null);\n return {\n enabled,\n referenceUnit,\n baseQuantity,\n enabledProvided,\n referenceProvided,\n baseProvided,\n };\n}\n\ntype ProductUndoPayload = {\n before?: ProductSnapshot | null;\n after?: ProductSnapshot | null;\n};\n\nconst productCrudEvents: CrudEventsConfig<CatalogProduct> = {\n module: \"catalog\",\n entity: \"product\",\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n productType: ctx.entity.productType,\n statusEntryId: ctx.entity.statusEntryId ?? null,\n isActive: ctx.entity.isActive,\n }),\n};\n\nconst productCrudIndexer: CrudIndexerConfig<CatalogProduct> = {\n entityType: E.catalog.catalog_product,\n buildUpsertPayload: (ctx) => ({\n entityType: E.catalog.catalog_product,\n recordId: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n buildDeletePayload: (ctx) => ({\n entityType: E.catalog.catalog_product,\n recordId: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n};\n\nfunction buildProductCrudIdentifiers(product: CatalogProduct) {\n return {\n id: product.id,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n };\n}\n\nasync function emitProductCrudChange(opts: {\n dataEngine: DataEngine;\n action: CrudEventAction;\n product: CatalogProduct;\n}) {\n const { dataEngine, action, product } = opts;\n await emitCrudSideEffects({\n dataEngine,\n action,\n entity: product,\n identifiers: buildProductCrudIdentifiers(product),\n events: productCrudEvents,\n indexer: productCrudIndexer,\n });\n}\n\nasync function emitProductCrudUndoChange(opts: {\n dataEngine: DataEngine;\n action: CrudEventAction;\n product: CatalogProduct;\n}) {\n const { dataEngine, action, product } = opts;\n await emitCrudUndoSideEffects({\n dataEngine,\n action,\n entity: product,\n identifiers: buildProductCrudIdentifiers(product),\n events: productCrudEvents,\n indexer: productCrudIndexer,\n });\n}\n\ntype OfferSnapshot = {\n id: string;\n channelId: string;\n title: string;\n description: string | null;\n defaultMediaId: string | null;\n defaultMediaUrl: string | null;\n metadata: Record<string, unknown> | null;\n isActive: boolean;\n};\n\nasync function resolveScopedTaxRate(\n em: EntityManager,\n taxRateId: string | null | undefined,\n taxRateInput: number | string | null | undefined,\n organizationId: string,\n tenantId: string,\n): Promise<{ taxRateId: string | null; taxRate: string | null }> {\n const normalizedRate =\n taxRateInput === null || taxRateInput === undefined\n ? null\n : (() => {\n const numeric =\n typeof taxRateInput === \"string\"\n ? Number(taxRateInput)\n : taxRateInput;\n return Number.isFinite(numeric) ? toNumericString(numeric) : null;\n })();\n if (!taxRateId) {\n return { taxRateId: null, taxRate: normalizedRate };\n }\n const record = await findOneWithDecryption(em, SalesTaxRate, {\n id: taxRateId,\n organizationId,\n tenantId,\n deletedAt: null,\n });\n if (!record) {\n const { translate } = await resolveTranslations();\n throw new CrudHttpError(400, {\n error: translate(\n \"catalog.products.errors.taxClassNotFound\",\n \"Tax class not found\",\n ),\n });\n }\n return { taxRateId, taxRate: record.rate ?? normalizedRate };\n}\n\nfunction slugifyCode(input: string): string {\n return input\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9\\-]+/g, \"-\")\n .replace(/(?:^-+|-+$)/g, \"\");\n}\n\nfunction normalizeCatalogOptionSchema(\n input?: CatalogProductOptionSchema | null,\n): CatalogProductOptionSchema | null {\n if (!input || !Array.isArray(input.options) || !input.options.length)\n return null;\n const options = input.options\n .map((option) => {\n if (!option) return null;\n const label =\n typeof option.label === \"string\" && option.label.trim().length\n ? option.label.trim()\n : null;\n const codeSource =\n typeof option.code === \"string\" && option.code.trim().length\n ? option.code.trim()\n : label;\n const code = slugifyCode(codeSource ?? \"\");\n if (!label && !code) return null;\n const choices = Array.isArray(option.choices)\n ? option.choices\n .map((choice) => {\n if (!choice) return null;\n const choiceLabel =\n typeof choice.label === \"string\" && choice.label.trim().length\n ? choice.label.trim()\n : null;\n const choiceCodeSource =\n typeof choice.code === \"string\" && choice.code.trim().length\n ? choice.code.trim()\n : choiceLabel;\n const choiceCode = slugifyCode(choiceCodeSource ?? \"\");\n if (!choiceLabel && !choiceCode) return null;\n return {\n code: choiceCode || `choice-${randomSuffix()}`,\n label:\n choiceLabel ?? (choiceCode || `Choice ${randomSuffix()}`),\n };\n })\n .filter(\n (entry): entry is { code: string; label: string } =>\n !!entry &&\n entry.code.trim().length > 0 &&\n entry.label.trim().length > 0,\n )\n : [];\n return {\n code: code || `option-${randomSuffix()}`,\n label: label ?? (code || `Option ${randomSuffix()}`),\n description:\n typeof option.description === \"string\" &&\n option.description.trim().length\n ? option.description.trim()\n : null,\n inputType:\n option.inputType === \"text\" ||\n option.inputType === \"textarea\" ||\n option.inputType === \"number\"\n ? option.inputType\n : \"select\",\n isRequired: option.isRequired ?? false,\n isMultiple: option.isMultiple ?? false,\n choices,\n };\n })\n .filter((entry) => !!entry && entry.code.trim().length > 0) as Array<\n CatalogProductOptionSchema[\"options\"][number]\n >;\n if (!options.length) return null;\n return {\n version:\n typeof input.version === \"number\" && input.version > 0\n ? input.version\n : 1,\n name:\n typeof input.name === \"string\" && input.name.trim().length\n ? input.name.trim()\n : undefined,\n description:\n typeof input.description === \"string\" && input.description.trim().length\n ? input.description.trim()\n : undefined,\n options,\n };\n}\n\nfunction convertLegacyOptionSchema(\n raw: unknown,\n): CatalogProductOptionSchema | null {\n if (!Array.isArray(raw)) return null;\n const options = raw\n .map((entry) => {\n if (!entry || typeof entry !== \"object\") return null;\n const source = entry as Record<string, unknown>;\n const title =\n typeof source[\"title\"] === \"string\" &&\n (source[\"title\"] as string).trim().length\n ? (source[\"title\"] as string).trim()\n : null;\n if (!title) return null;\n const values = Array.isArray(source[\"values\"])\n ? (source[\"values\"] as unknown[])\n .map((value: unknown) => {\n if (!value || typeof value !== \"object\") return null;\n const choice = value as Record<string, unknown>;\n const label =\n typeof choice.label === \"string\" && (choice.label as string).trim().length\n ? (choice.label as string).trim()\n : null;\n if (!label) return null;\n return { code: slugifyCode(label), label };\n })\n .filter(\n (choice): choice is { code: string; label: string } => !!choice,\n )\n : [];\n return {\n code: slugifyCode(title),\n label: title,\n inputType: \"select\" as const,\n choices: values,\n };\n })\n .filter((option) => !!option) as CatalogProductOptionSchema[\"options\"];\n if (!options.length) return null;\n return {\n version: 1,\n options,\n };\n}\n\nfunction extractOptionSchemaInput(source: {\n metadata?: Record<string, unknown> | null | undefined;\n optionSchema?: CatalogProductOptionSchema | null | undefined;\n}): {\n schema: CatalogProductOptionSchema | null;\n metadata: Record<string, unknown> | null;\n} {\n const metadata =\n source.metadata && typeof source.metadata === \"object\"\n ? { ...(source.metadata as Record<string, unknown>) }\n : null;\n let schema = normalizeCatalogOptionSchema(source.optionSchema);\n if (!schema && metadata) {\n const legacy = convertLegacyOptionSchema(\n (metadata as Record<string, unknown>)[\"optionSchema\"] ??\n (metadata as Record<string, unknown>)[\"option_schema\"],\n );\n schema = normalizeCatalogOptionSchema(legacy);\n }\n if (metadata) {\n delete (metadata as Record<string, unknown>)[\"optionSchema\"];\n delete (metadata as Record<string, unknown>)[\"option_schema\"];\n delete (metadata as Record<string, unknown>)[\"dimensions\"];\n delete (metadata as Record<string, unknown>)[\"weight\"];\n }\n return {\n schema,\n metadata: metadata && Object.keys(metadata).length ? metadata : null,\n };\n}\n\nfunction parseNumeric(value: unknown): number | null {\n const numeric = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(numeric) || numeric < 0) return null;\n return numeric;\n}\n\nfunction normalizeDimensionsInput(raw: unknown): {\n width?: number;\n height?: number;\n depth?: number;\n unit?: string;\n} | null {\n const source = parseObjectLike(raw);\n if (!source) return null;\n const clean: Record<string, unknown> = {};\n const width = parseNumeric(source.width);\n const height = parseNumeric(source.height);\n const depth = parseNumeric(source.depth);\n const unit =\n typeof source.unit === \"string\" && source.unit.trim().length\n ? source.unit.trim()\n : null;\n if (width !== null) clean.width = width;\n if (height !== null) clean.height = height;\n if (depth !== null) clean.depth = depth;\n if (unit) clean.unit = unit;\n return Object.keys(clean).length\n ? (clean as {\n width?: number;\n height?: number;\n depth?: number;\n unit?: string;\n })\n : null;\n}\n\nfunction normalizeWeightInput(\n raw: unknown,\n): { value?: number; unit?: string } | null {\n const source = parseObjectLike(raw);\n if (!source) return null;\n const value = parseNumeric(source.value);\n const unit =\n typeof source.unit === \"string\" && source.unit.trim().length\n ? source.unit.trim()\n : null;\n if (value === null && !unit) return null;\n const clean: { value?: number; unit?: string } = {};\n if (value !== null) clean.value = value;\n if (unit) clean.unit = unit;\n return clean;\n}\n\nfunction extractMeasurementsFromMetadata(\n metadata: Record<string, unknown> | null | undefined,\n): {\n metadata: Record<string, unknown> | null;\n dimensions: {\n width?: number;\n height?: number;\n depth?: number;\n unit?: string;\n } | null;\n weightValue: number | null;\n weightUnit: string | null;\n} {\n if (!metadata || typeof metadata !== \"object\") {\n return {\n metadata: null,\n dimensions: null,\n weightValue: null,\n weightUnit: null,\n };\n }\n const clone = { ...(metadata as Record<string, unknown>) };\n const dimensions = normalizeDimensionsInput(clone.dimensions);\n const weight = normalizeWeightInput(clone.weight);\n delete clone.dimensions;\n delete clone.weight;\n const cleanedMetadata = Object.keys(clone).length ? clone : null;\n return {\n metadata: cleanedMetadata,\n dimensions,\n weightValue: weight?.value ?? null,\n weightUnit: weight?.unit ?? null,\n };\n}\n\nfunction ensureSchemaName(\n name?: string | null,\n fallback?: string | null,\n): string {\n if (name && name.trim().length) return name.trim();\n if (fallback && fallback.trim().length) return fallback.trim();\n return \"Product option schema\";\n}\n\nasync function assignOptionSchemaTemplate(\n em: EntityManager,\n product: CatalogProduct,\n schema: CatalogProductOptionSchema,\n preferredName?: string | null,\n): Promise<CatalogOptionSchemaTemplate> {\n const resolvedName = ensureSchemaName(\n schema.name,\n preferredName ?? product.title,\n );\n const templateCode = resolveOptionSchemaCode({\n name: schema.name ?? resolvedName,\n fallback: `${resolvedName}-${product.id}`,\n uniqueHint: product.id?.slice(0, 8),\n });\n let template = product.optionSchemaTemplate ?? null;\n if (!template) {\n template = await em.findOne(CatalogOptionSchemaTemplate, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n code: templateCode,\n deletedAt: null,\n });\n }\n if (!template) {\n template = em.create(CatalogOptionSchemaTemplate, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n name: resolvedName,\n code: templateCode,\n description: schema.description ?? null,\n schema: cloneJson(schema),\n metadata: { source: \"product\" },\n isActive: true,\n });\n em.persist(template);\n } else {\n template.code = templateCode;\n template.name = resolvedName;\n template.description = schema.description ?? template.description ?? null;\n template.schema = cloneJson(schema);\n }\n product.optionSchemaTemplate = template;\n return template;\n}\n\nfunction serializeOffer(record: CatalogOffer): OfferSnapshot {\n return {\n id: record.id,\n channelId: record.channelId,\n title: record.title,\n description: record.description ?? null,\n defaultMediaId: record.defaultMediaId ?? null,\n defaultMediaUrl: record.defaultMediaUrl ?? null,\n metadata: record.metadata ? cloneJson(record.metadata) : null,\n isActive: record.isActive,\n };\n}\n\nasync function loadOfferSnapshots(\n em: EntityManager,\n productId: string,\n): Promise<OfferSnapshot[]> {\n const offerRecords = await em.find(\n CatalogOffer,\n { product: productId },\n { orderBy: { createdAt: \"asc\" } },\n );\n return offerRecords.map((offer) => serializeOffer(offer));\n}\n\nasync function restoreOffersFromSnapshot(\n em: EntityManager,\n product: CatalogProduct,\n snapshot: OfferSnapshot[] | null | undefined,\n): Promise<void> {\n const existing = await em.find(CatalogOffer, { product });\n const keepIds = new Set<string>();\n const list = Array.isArray(snapshot) ? snapshot : [];\n for (const offer of existing) {\n if (!list.some((snap) => snap.id === offer.id)) {\n em.remove(offer);\n } else {\n keepIds.add(offer.id);\n }\n }\n for (const snap of list) {\n let target = existing.find((entry) => entry.id === snap.id);\n if (!target) {\n target = em.create(CatalogOffer, {\n id: snap.id,\n product,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n channelId: snap.channelId,\n title: snap.title,\n isActive: snap.isActive,\n });\n em.persist(target);\n }\n target.channelId = snap.channelId;\n target.title = snap.title;\n target.description = snap.description ?? null;\n target.defaultMediaId = snap.defaultMediaId ?? null;\n target.defaultMediaUrl = snap.defaultMediaUrl ?? null;\n target.metadata = snap.metadata ? cloneJson(snap.metadata) : null;\n target.isActive = snap.isActive;\n keepIds.add(target.id);\n }\n const toRemove = existing.filter((offer) => !keepIds.has(offer.id));\n if (toRemove.length) {\n for (const offer of toRemove) {\n em.remove(offer);\n }\n }\n}\n\nasync function syncOffers(\n em: EntityManager,\n product: CatalogProduct,\n inputs: OfferInput[] | undefined,\n): Promise<void> {\n if (!inputs) return;\n const normalized = inputs.map((input) => ({\n ...input,\n title: input.title?.trim().length ? input.title.trim() : product.title,\n description:\n input.description != null && input.description.trim().length\n ? input.description.trim()\n : (product.description ?? null),\n defaultMediaId:\n typeof input.defaultMediaId === \"string\" &&\n input.defaultMediaId.trim().length\n ? input.defaultMediaId.trim()\n : null,\n defaultMediaUrl:\n typeof input.defaultMediaUrl === \"string\" &&\n input.defaultMediaUrl.trim().length\n ? input.defaultMediaUrl.trim()\n : null,\n metadata: input.metadata ? cloneJson(input.metadata) : null,\n isActive: input.isActive !== false,\n }));\n const existing = await em.find(CatalogOffer, { product });\n const claimed = new Set<string>();\n const channelMap = new Map<string, CatalogOffer>();\n for (const offer of existing) {\n channelMap.set(offer.channelId, offer);\n }\n const updates: CatalogOffer[] = [];\n for (const input of normalized) {\n if (!input.channelId) continue;\n let target: CatalogOffer | undefined;\n if (input.id) {\n target = existing.find((item) => item.id === input.id);\n }\n if (!target) {\n const existingByChannel = channelMap.get(input.channelId);\n if (existingByChannel && !claimed.has(existingByChannel.id)) {\n target = existingByChannel;\n }\n }\n if (!target) {\n target = em.create(CatalogOffer, {\n product,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n channelId: input.channelId,\n title: input.title || product.title,\n isActive: input.isActive !== false,\n });\n em.persist(target);\n existing.push(target);\n channelMap.set(input.channelId, target);\n }\n target.channelId = input.channelId;\n target.title = input.title || product.title;\n target.description = input.description ?? null;\n target.defaultMediaId = input.defaultMediaId ?? null;\n target.defaultMediaUrl = input.defaultMediaUrl ?? null;\n target.metadata = input.metadata ? cloneJson(input.metadata) : null;\n target.isActive = input.isActive !== false;\n claimed.add(target.id);\n updates.push(target);\n }\n const toRemove = existing.filter((offer) => !claimed.has(offer.id));\n for (const offer of toRemove) {\n em.remove(offer);\n }\n}\n\nasync function syncCategoryAssignments(\n em: EntityManager,\n product: CatalogProduct,\n categoryIds: string[] | undefined,\n): Promise<void> {\n const normalized = Array.from(\n new Set(\n (Array.isArray(categoryIds) ? categoryIds : [])\n .map((id) => (typeof id === \"string\" ? id.trim() : \"\"))\n .filter((id) => id.length),\n ),\n );\n const existing = await em.find(CatalogProductCategoryAssignment, { product });\n if (!normalized.length) {\n if (existing.length) {\n for (const assignment of existing) {\n em.remove(assignment);\n }\n }\n return;\n }\n const categories = await em.find(CatalogProductCategory, {\n id: { $in: normalized },\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n });\n const categoryMap = new Map(\n categories.map((category) => [category.id, category]),\n );\n const claimed = new Set<string>();\n normalized.forEach((categoryId, index) => {\n const category = categoryMap.get(categoryId);\n if (!category) return;\n let assignment = existing.find((item) => {\n const value =\n typeof item.category === \"string\" ? item.category : item.category?.id;\n return value === categoryId;\n });\n if (!assignment) {\n assignment = em.create(CatalogProductCategoryAssignment, {\n product,\n category,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n position: index,\n });\n em.persist(assignment);\n existing.push(assignment);\n }\n assignment.position = index;\n claimed.add(assignment.id);\n });\n for (const assignment of existing) {\n if (!claimed.has(assignment.id)) {\n em.remove(assignment);\n }\n }\n}\n\nasync function syncProductTags(\n em: EntityManager,\n product: CatalogProduct,\n tags: string[] | undefined,\n): Promise<void> {\n const labelMap = new Map<string, string>();\n if (Array.isArray(tags)) {\n tags.forEach((raw) => {\n const label = typeof raw === \"string\" ? raw.trim() : \"\";\n if (!label) return;\n const slug = slugifyTagLabel(label);\n if (!labelMap.has(slug)) {\n labelMap.set(slug, label);\n }\n });\n }\n const slugs = Array.from(labelMap.keys());\n const existingAssignments = await findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { product },\n { populate: [\"tag\"] },\n { tenantId: product.tenantId, organizationId: product.organizationId },\n );\n if (!slugs.length) {\n if (existingAssignments.length) {\n for (const assignment of existingAssignments) {\n em.remove(assignment);\n }\n }\n return;\n }\n const existingTags = await em.find(CatalogProductTag, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n slug: { $in: slugs },\n });\n const tagsBySlug = new Map(existingTags.map((tag) => [tag.slug, tag]));\n for (const slug of slugs) {\n if (tagsBySlug.has(slug)) continue;\n const label = labelMap.get(slug) ?? slug;\n const tag = em.create(CatalogProductTag, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n slug,\n label,\n });\n em.persist(tag);\n tagsBySlug.set(slug, tag);\n }\n const assignmentByTagId = new Map(\n existingAssignments.map((assignment) => [\n typeof assignment.tag === \"string\" ? assignment.tag : assignment.tag.id,\n assignment,\n ]),\n );\n const keepIds = new Set<string>();\n for (const slug of slugs) {\n const tag = tagsBySlug.get(slug);\n if (!tag) continue;\n const tagId = tag.id;\n let assignment = assignmentByTagId.get(tagId);\n if (!assignment) {\n assignment = em.create(CatalogProductTagAssignment, {\n product,\n tag,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n });\n em.persist(assignment);\n }\n keepIds.add(assignment.id);\n }\n for (const assignment of existingAssignments) {\n if (!keepIds.has(assignment.id)) {\n em.remove(assignment);\n }\n }\n}\n\ntype VariantCleanupSnapshot = {\n id: string;\n organizationId: string;\n tenantId: string;\n custom: Record<string, unknown> | null;\n};\n\nasync function deleteProductVariantsAndRelatedData(opts: {\n em: EntityManager;\n product: CatalogProduct;\n dataEngine: DataEngine;\n ctx: CommandRuntimeContext;\n}): Promise<void> {\n const { em, product, dataEngine, ctx } = opts;\n const variants = await em.find(CatalogProductVariant, { product });\n if (!variants.length) return;\n const cleanupEntries: VariantCleanupSnapshot[] = await Promise.all(\n variants.map(async (variant) => {\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: variant.organizationId,\n tenantId: variant.tenantId,\n });\n return {\n id: variant.id,\n organizationId: variant.organizationId,\n tenantId: variant.tenantId,\n custom: Object.keys(custom).length ? custom : null,\n };\n }),\n );\n const variantIds = variants.map((variant) => variant.id);\n if (variantIds.length) {\n await em.nativeDelete(CatalogProductPrice, {\n variant: { $in: variantIds },\n });\n }\n for (const variant of variants) {\n em.remove(variant);\n }\n await em.flush();\n for (const cleanup of cleanupEntries) {\n if (!cleanup.custom) continue;\n const resetValues = buildCustomFieldResetMap(cleanup.custom, undefined);\n if (!Object.keys(resetValues).length) continue;\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product_variant,\n recordId: cleanup.id,\n organizationId: cleanup.organizationId,\n tenantId: cleanup.tenantId,\n values: resetValues,\n });\n }\n for (const cleanup of cleanupEntries) {\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: cleanup.id,\n organizationId: cleanup.organizationId,\n tenantId: cleanup.tenantId,\n action: \"deleted\",\n });\n }\n}\n\nfunction isProductOwnedOptionSchemaTemplate(\n template: CatalogOptionSchemaTemplate | string | null | undefined,\n): template is CatalogOptionSchemaTemplate {\n if (!template || typeof template === \"string\") return false;\n const metadata = template.metadata;\n if (!metadata || typeof metadata !== \"object\") return false;\n const source = (metadata as Record<string, unknown>).source;\n return source === \"product\";\n}\n\nasync function resolveOptionSchemaTemplateForRemoval(\n em: EntityManager,\n product: CatalogProduct,\n): Promise<CatalogOptionSchemaTemplate | null> {\n const template = product.optionSchemaTemplate;\n if (!isProductOwnedOptionSchemaTemplate(template)) {\n return null;\n }\n const otherUsage = await em.count(CatalogProduct, {\n optionSchemaTemplate: template,\n id: { $ne: product.id },\n deletedAt: null,\n });\n if (otherUsage > 0) return null;\n return template;\n}\n\nasync function loadProductSnapshot(\n em: EntityManager,\n id: string,\n): Promise<ProductSnapshot | null> {\n const record = await findOneWithDecryption(\n em,\n CatalogProduct,\n { id, deletedAt: null },\n { populate: [\"optionSchemaTemplate\"] },\n );\n if (!record) return null;\n const [offers, tagAssignments, categoryAssignments] = await Promise.all([\n loadOfferSnapshots(em, record.id),\n findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { product: record.id },\n { populate: [\"tag\"] },\n { tenantId: record.tenantId, organizationId: record.organizationId },\n ),\n findWithDecryption(\n em,\n CatalogProductCategoryAssignment,\n { product: record.id },\n { populate: [\"category\"] },\n { tenantId: record.tenantId, organizationId: record.organizationId },\n ),\n ]);\n const tags = tagAssignments\n .map((assignment) => {\n const tag =\n typeof assignment.tag === \"string\" ? null : (assignment.tag ?? null);\n const label = tag?.label ?? null;\n return typeof label === \"string\" && label.trim().length ? label : null;\n })\n .filter((label): label is string => !!label)\n .sort((a, b) => a.localeCompare(b));\n const categoryIds = categoryAssignments\n .slice()\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))\n .map((assignment) => {\n if (typeof assignment.category === \"string\") return assignment.category;\n return assignment.category?.id ?? null;\n })\n .filter((value): value is string => !!value);\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n });\n const optionSchemaTemplate = record.optionSchemaTemplate;\n const optionTemplateId =\n typeof optionSchemaTemplate === \"string\"\n ? optionSchemaTemplate\n : (optionSchemaTemplate?.id ?? null);\n const measurements = extractMeasurementsFromMetadata(\n record.metadata ? cloneJson(record.metadata) : null,\n );\n const dimensions =\n record.dimensions && Object.keys(record.dimensions).length\n ? cloneJson(record.dimensions)\n : measurements.dimensions\n ? cloneJson(measurements.dimensions)\n : null;\n const weightValue =\n record.weightValue ??\n (measurements.weightValue !== null\n ? toNumericString(measurements.weightValue)\n : null);\n const weightUnit = record.weightUnit ?? measurements.weightUnit ?? null;\n const metadata = measurements.metadata\n ? cloneJson(measurements.metadata)\n : null;\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n title: record.title,\n subtitle: record.subtitle ?? null,\n description: record.description ?? null,\n sku: record.sku ?? null,\n handle: record.handle ?? null,\n taxRateId: record.taxRateId ?? null,\n taxRate: record.taxRate ?? null,\n productType: record.productType,\n statusEntryId: record.statusEntryId ?? null,\n primaryCurrencyCode: record.primaryCurrencyCode ?? null,\n defaultUnit: record.defaultUnit ?? null,\n defaultSalesUnit: record.defaultSalesUnit ?? null,\n defaultSalesUnitQuantity: record.defaultSalesUnitQuantity ?? \"1\",\n uomRoundingScale: record.uomRoundingScale ?? 4,\n uomRoundingMode: record.uomRoundingMode ?? \"half_up\",\n unitPriceEnabled: record.unitPriceEnabled ?? false,\n unitPriceReferenceUnit: record.unitPriceReferenceUnit ?? null,\n unitPriceBaseQuantity: record.unitPriceBaseQuantity ?? null,\n defaultMediaId: record.defaultMediaId ?? null,\n defaultMediaUrl: record.defaultMediaUrl ?? null,\n weightValue,\n weightUnit,\n dimensions,\n customFieldsetCode: record.customFieldsetCode ?? null,\n metadata,\n isConfigurable: record.isConfigurable,\n isActive: record.isActive,\n optionSchemaId: optionTemplateId,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n offers,\n tags,\n categoryIds,\n custom: Object.keys(custom).length ? custom : null,\n };\n}\n\nfunction applyProductSnapshot(\n em: EntityManager,\n record: CatalogProduct,\n snapshot: ProductSnapshot,\n): void {\n record.organizationId = snapshot.organizationId;\n record.tenantId = snapshot.tenantId;\n record.title = snapshot.title;\n record.subtitle = snapshot.subtitle ?? null;\n record.description = snapshot.description ?? null;\n record.sku = snapshot.sku ?? null;\n record.handle = snapshot.handle ?? null;\n record.taxRateId = snapshot.taxRateId ?? null;\n record.taxRate = snapshot.taxRate ?? null;\n record.productType = snapshot.productType;\n record.statusEntryId = snapshot.statusEntryId ?? null;\n record.primaryCurrencyCode = snapshot.primaryCurrencyCode ?? null;\n record.defaultUnit = snapshot.defaultUnit ?? null;\n record.defaultSalesUnit = snapshot.defaultSalesUnit ?? null;\n record.defaultSalesUnitQuantity = snapshot.defaultSalesUnitQuantity ?? \"1\";\n record.uomRoundingScale = snapshot.uomRoundingScale;\n record.uomRoundingMode = snapshot.uomRoundingMode;\n record.unitPriceEnabled = snapshot.unitPriceEnabled;\n record.unitPriceReferenceUnit = snapshot.unitPriceReferenceUnit ?? null;\n record.unitPriceBaseQuantity = snapshot.unitPriceBaseQuantity ?? null;\n record.defaultMediaId = snapshot.defaultMediaId ?? null;\n record.defaultMediaUrl = snapshot.defaultMediaUrl ?? null;\n record.weightValue = snapshot.weightValue ?? null;\n record.weightUnit = snapshot.weightUnit ?? null;\n record.dimensions = snapshot.dimensions\n ? cloneJson(snapshot.dimensions)\n : null;\n record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null;\n record.customFieldsetCode = snapshot.customFieldsetCode ?? null;\n record.optionSchemaTemplate = snapshot.optionSchemaId\n ? em.getReference(CatalogOptionSchemaTemplate, snapshot.optionSchemaId)\n : null;\n record.isConfigurable = snapshot.isConfigurable;\n record.isActive = snapshot.isActive;\n record.createdAt = new Date(snapshot.createdAt);\n record.updatedAt = new Date(snapshot.updatedAt);\n}\n\nconst createProductCommand: CommandHandler<\n ProductCreateInput,\n { productId: string }\n> = {\n id: \"catalog.products.create\",\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(\n productCreateSchema,\n rawInput,\n );\n ensureTenantScope(ctx, parsed.tenantId);\n ensureOrganizationScope(ctx, parsed.organizationId);\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const now = new Date();\n const { taxRateId, taxRate } = await resolveScopedTaxRate(\n em,\n parsed.taxRateId ?? null,\n parsed.taxRate,\n parsed.organizationId,\n parsed.tenantId,\n );\n const { schema: optionSchemaDefinition, metadata: sanitizedMetadata } =\n extractOptionSchemaInput(parsed);\n const measurements = extractMeasurementsFromMetadata(sanitizedMetadata);\n const dimensions =\n normalizeDimensionsInput(parsed.dimensions) ?? measurements.dimensions;\n const weightValue =\n parsed.weightValue !== undefined\n ? toNumericString(parsed.weightValue)\n : measurements.weightValue !== null\n ? toNumericString(measurements.weightValue)\n : null;\n const weightUnit =\n parsed.weightUnit !== undefined\n ? (parsed.weightUnit ?? null)\n : (measurements.weightUnit ?? null);\n const metadata = measurements.metadata\n ? cloneJson(measurements.metadata)\n : null;\n const unitPriceInput = resolveUnitPriceInput(parsed);\n const unitPriceEnabled = unitPriceInput.enabled ?? false;\n const resolvedUnits = await resolveProductUnitDefaults(em, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n defaultUnit: parsed.defaultUnit ?? null,\n defaultSalesUnit: parsed.defaultSalesUnit ?? parsed.defaultUnit ?? null,\n });\n const productId = randomUUID();\n const record = em.create(CatalogProduct, {\n id: productId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n title: parsed.title,\n subtitle: parsed.subtitle ?? null,\n description: parsed.description ?? null,\n sku: parsed.sku ?? null,\n handle: parsed.handle ?? null,\n taxRateId,\n taxRate,\n productType: parsed.productType ?? \"simple\",\n statusEntryId: parsed.statusEntryId ?? null,\n primaryCurrencyCode: parsed.primaryCurrencyCode ?? null,\n defaultUnit: resolvedUnits.defaultUnit,\n defaultSalesUnit:\n resolvedUnits.defaultSalesUnit ?? resolvedUnits.defaultUnit,\n defaultSalesUnitQuantity:\n toNumericString(parsed.defaultSalesUnitQuantity ?? 1) ?? \"1\",\n uomRoundingScale: parsed.uomRoundingScale ?? 4,\n uomRoundingMode: parsed.uomRoundingMode ?? \"half_up\",\n unitPriceEnabled,\n unitPriceReferenceUnit: unitPriceEnabled\n ? (unitPriceInput.referenceUnit ?? null)\n : null,\n unitPriceBaseQuantity: unitPriceEnabled\n ? (unitPriceInput.baseQuantity ?? null)\n : null,\n defaultMediaId: parsed.defaultMediaId ?? null,\n defaultMediaUrl: parsed.defaultMediaUrl ?? null,\n weightValue,\n weightUnit,\n dimensions,\n metadata,\n customFieldsetCode: parsed.customFieldsetCode ?? null,\n isConfigurable: parsed.isConfigurable ?? false,\n isActive: parsed.isActive ?? true,\n createdAt: now,\n updatedAt: now,\n });\n let optionSchemaTemplate: CatalogOptionSchemaTemplate | null = null;\n if (parsed.optionSchemaId) {\n optionSchemaTemplate = await requireOptionSchemaTemplate(\n em,\n parsed.optionSchemaId,\n translate(\"catalog.errors.optionSchemaNotFound\", \"Option schema not found\"),\n );\n ensureSameScope(\n optionSchemaTemplate,\n parsed.organizationId,\n parsed.tenantId,\n );\n record.optionSchemaTemplate = optionSchemaTemplate;\n } else if (optionSchemaDefinition) {\n optionSchemaTemplate = await assignOptionSchemaTemplate(\n em,\n record,\n optionSchemaDefinition,\n optionSchemaDefinition.name ?? parsed.title,\n );\n }\n em.persist(record);\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n await syncOffers(em, record, parsed.offers);\n await syncCategoryAssignments(em, record, parsed.categoryIds);\n await syncProductTags(em, record, parsed.tags);\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n });\n await emitProductCrudChange({\n dataEngine,\n action: \"created\",\n product: record,\n });\n return { productId: record.id };\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n return loadProductSnapshot(em, result.productId);\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as ProductSnapshot | undefined;\n if (!after) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.products.create\",\n \"Create catalog product\",\n ),\n resourceKind: \"catalog.product\",\n resourceId: result.productId,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n } satisfies ProductUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ProductUndoPayload>(logEntry);\n const after = payload?.after;\n if (!after) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const record = await findOneWithDecryption(em, CatalogProduct, { id: after.id });\n if (!record) return;\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n em.remove(record);\n await em.flush();\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n const resetValues = buildCustomFieldResetMap(\n undefined,\n after.custom ?? undefined,\n );\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n values: resetValues,\n });\n }\n await emitProductCrudUndoChange({\n dataEngine,\n action: \"deleted\",\n product: record,\n });\n },\n};\n\nconst updateProductCommand: CommandHandler<\n ProductUpdateInput,\n { productId: string }\n> = {\n id: \"catalog.products.update\",\n async prepare(input, ctx) {\n const id = requireId(input, \"Product id is required\");\n const em = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadProductSnapshot(em, id);\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId);\n ensureOrganizationScope(ctx, snapshot.organizationId);\n }\n return snapshot ? { before: snapshot } : {};\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(\n productUpdateSchema,\n rawInput,\n );\n const rawPayload =\n rawInput && typeof rawInput === \"object\"\n ? (rawInput as Record<string, unknown>)\n : null;\n const hasDefaultUnit = Boolean(\n rawPayload &&\n Object.prototype.hasOwnProperty.call(rawPayload, \"defaultUnit\"),\n );\n const hasDefaultSalesUnit = Boolean(\n rawPayload &&\n Object.prototype.hasOwnProperty.call(rawPayload, \"defaultSalesUnit\"),\n );\n const requestedDefaultUnit = hasDefaultUnit\n ? rawPayload?.defaultUnit\n : parsed.defaultUnit;\n const requestedDefaultSalesUnit = hasDefaultSalesUnit\n ? rawPayload?.defaultSalesUnit\n : parsed.defaultSalesUnit;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const record = await findOneWithDecryption(em, CatalogProduct, {\n id: parsed.id,\n deletedAt: null,\n });\n if (!record)\n throw new CrudHttpError(404, {\n error: translate(\"catalog.errors.productNotFound\", \"Catalog product not found\"),\n });\n const organizationId = parsed.organizationId ?? record.organizationId;\n const tenantId = parsed.tenantId ?? record.tenantId;\n ensureTenantScope(ctx, tenantId);\n ensureOrganizationScope(ctx, organizationId);\n ensureSameScope(record, organizationId, tenantId);\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n const lookupEm = em.fork();\n const taxRateProvided =\n parsed.taxRateId !== undefined || parsed.taxRate !== undefined;\n const resolvedTaxRate = taxRateProvided\n ? await resolveScopedTaxRate(\n lookupEm,\n parsed.taxRateId ?? null,\n parsed.taxRate,\n organizationId,\n tenantId,\n )\n : null;\n record.organizationId = organizationId;\n record.tenantId = tenantId;\n\n if (parsed.title !== undefined) record.title = parsed.title;\n if (parsed.subtitle !== undefined)\n record.subtitle = parsed.subtitle ?? null;\n if (parsed.description !== undefined)\n record.description = parsed.description ?? null;\n if (parsed.sku !== undefined) record.sku = parsed.sku ?? null;\n if (parsed.handle !== undefined) record.handle = parsed.handle ?? null;\n if (taxRateProvided) {\n record.taxRateId = resolvedTaxRate?.taxRateId ?? null;\n record.taxRate = resolvedTaxRate?.taxRate ?? null;\n }\n if (parsed.productType !== undefined)\n record.productType = parsed.productType;\n if (parsed.statusEntryId !== undefined)\n record.statusEntryId = parsed.statusEntryId ?? null;\n if (parsed.primaryCurrencyCode !== undefined) {\n record.primaryCurrencyCode = parsed.primaryCurrencyCode ?? null;\n }\n const uomDefaultsTouched =\n hasDefaultUnit ||\n hasDefaultSalesUnit ||\n parsed.defaultUnit !== undefined ||\n parsed.defaultSalesUnit !== undefined ||\n parsed.organizationId !== undefined ||\n parsed.tenantId !== undefined;\n if (uomDefaultsTouched) {\n const resolvedUnits = await resolveProductUnitDefaults(lookupEm, {\n organizationId,\n tenantId,\n defaultUnit: hasDefaultUnit\n ? (requestedDefaultUnit as string | null | undefined)\n : parsed.defaultUnit !== undefined\n ? parsed.defaultUnit\n : record.defaultUnit,\n defaultSalesUnit: hasDefaultSalesUnit\n ? (requestedDefaultSalesUnit as string | null | undefined)\n : parsed.defaultSalesUnit !== undefined\n ? parsed.defaultSalesUnit\n : record.defaultSalesUnit,\n });\n await ensureBaseUnitCanBeRemoved(lookupEm, {\n productId: record.id,\n organizationId,\n tenantId,\n defaultUnit: resolvedUnits.defaultUnit,\n defaultSalesUnit: resolvedUnits.defaultSalesUnit,\n });\n record.defaultUnit = resolvedUnits.defaultUnit;\n record.defaultSalesUnit = resolvedUnits.defaultSalesUnit;\n }\n if (parsed.defaultSalesUnitQuantity !== undefined) {\n record.defaultSalesUnitQuantity =\n toNumericString(parsed.defaultSalesUnitQuantity) ?? \"1\";\n }\n if (parsed.uomRoundingScale !== undefined) {\n record.uomRoundingScale = parsed.uomRoundingScale;\n }\n if (parsed.uomRoundingMode !== undefined) {\n record.uomRoundingMode = parsed.uomRoundingMode;\n }\n const unitPriceInput = resolveUnitPriceInput(parsed);\n if (unitPriceInput.enabledProvided) {\n record.unitPriceEnabled = unitPriceInput.enabled ?? false;\n if (!record.unitPriceEnabled) {\n record.unitPriceReferenceUnit = null;\n record.unitPriceBaseQuantity = null;\n }\n }\n if (unitPriceInput.referenceProvided && record.unitPriceEnabled) {\n record.unitPriceReferenceUnit = unitPriceInput.referenceUnit ?? null;\n }\n if (unitPriceInput.baseProvided && record.unitPriceEnabled) {\n record.unitPriceBaseQuantity = unitPriceInput.baseQuantity ?? null;\n }\n if (parsed.defaultMediaId !== undefined) {\n record.defaultMediaId = parsed.defaultMediaId ?? null;\n }\n if (parsed.defaultMediaUrl !== undefined) {\n record.defaultMediaUrl = parsed.defaultMediaUrl ?? null;\n }\n const metadataProvided =\n rawInput &&\n typeof rawInput === \"object\" &&\n Object.prototype.hasOwnProperty.call(rawInput, \"metadata\");\n const { schema: optionSchemaDefinition, metadata: sanitizedMetadata } =\n extractOptionSchemaInput(parsed);\n const measurements = extractMeasurementsFromMetadata(sanitizedMetadata);\n const normalizedDimensions =\n parsed.dimensions !== undefined\n ? normalizeDimensionsInput(parsed.dimensions)\n : measurements.dimensions;\n const weightValueFromInput =\n parsed.weightValue === null\n ? null\n : parsed.weightValue !== undefined\n ? toNumericString(parsed.weightValue)\n : measurements.weightValue !== null\n ? toNumericString(measurements.weightValue)\n : null;\n const weightUnitFromInput =\n parsed.weightUnit !== undefined\n ? (parsed.weightUnit ?? null)\n : (measurements.weightUnit ?? null);\n const weightProvided =\n parsed.weightValue !== undefined ||\n parsed.weightUnit !== undefined ||\n measurements.weightValue !== null ||\n measurements.weightUnit !== null;\n if (normalizedDimensions !== null || parsed.dimensions !== undefined) {\n record.dimensions = normalizedDimensions\n ? cloneJson(normalizedDimensions)\n : null;\n }\n if (weightProvided) {\n record.weightValue = weightValueFromInput;\n record.weightUnit = weightUnitFromInput;\n }\n if (metadataProvided) {\n record.metadata = measurements.metadata\n ? cloneJson(measurements.metadata)\n : null;\n }\n if (parsed.optionSchemaId !== undefined) {\n if (!parsed.optionSchemaId) {\n record.optionSchemaTemplate = null;\n } else {\n const optionTemplate = await requireOptionSchemaTemplate(\n lookupEm,\n parsed.optionSchemaId,\n translate(\"catalog.errors.optionSchemaNotFound\", \"Option schema not found\"),\n );\n ensureSameScope(optionTemplate, organizationId, tenantId);\n record.optionSchemaTemplate = optionTemplate;\n }\n }\n if (optionSchemaDefinition) {\n await assignOptionSchemaTemplate(\n em,\n record,\n optionSchemaDefinition,\n optionSchemaDefinition.name ?? parsed.title ?? record.title,\n );\n }\n if (parsed.customFieldsetCode !== undefined) {\n record.customFieldsetCode = parsed.customFieldsetCode ?? null;\n }\n if (parsed.isConfigurable !== undefined)\n record.isConfigurable = parsed.isConfigurable;\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive;\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n await syncOffers(em, record, parsed.offers);\n await syncCategoryAssignments(em, record, parsed.categoryIds);\n await syncProductTags(em, record, parsed.tags);\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n if (custom && Object.keys(custom).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n });\n }\n await emitProductCrudChange({\n dataEngine,\n action: \"updated\",\n product: record,\n });\n return { productId: record.id };\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n return loadProductSnapshot(em, result.productId);\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as ProductSnapshot | undefined;\n const after = snapshots.after as ProductSnapshot | undefined;\n if (!before || !after) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.products.update\",\n \"Update catalog product\",\n ),\n resourceKind: \"catalog.product\",\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n changes: buildChanges(before, after, [\n \"title\",\n \"sku\",\n \"productType\",\n \"defaultUnit\",\n \"defaultSalesUnit\",\n \"defaultSalesUnitQuantity\",\n \"uomRoundingScale\",\n \"uomRoundingMode\",\n \"unitPriceEnabled\",\n \"unitPriceReferenceUnit\",\n \"unitPriceBaseQuantity\",\n \"isActive\",\n ]),\n snapshotBefore: before,\n snapshotAfter: after,\n payload: {\n undo: {\n before,\n after,\n } satisfies ProductUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ProductUndoPayload>(logEntry);\n const before = payload?.before;\n if (!before) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n let record = await findOneWithDecryption(em, CatalogProduct, { id: before.id });\n if (!record) {\n record = em.create(CatalogProduct, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n title: before.title,\n subtitle: before.subtitle ?? null,\n description: before.description ?? null,\n sku: before.sku ?? null,\n handle: before.handle ?? null,\n taxRateId: before.taxRateId ?? null,\n taxRate: before.taxRate ?? null,\n statusEntryId: before.statusEntryId ?? null,\n primaryCurrencyCode: before.primaryCurrencyCode ?? null,\n defaultUnit: before.defaultUnit ?? null,\n defaultSalesUnit: before.defaultSalesUnit ?? null,\n defaultSalesUnitQuantity: before.defaultSalesUnitQuantity ?? \"1\",\n uomRoundingScale: before.uomRoundingScale,\n uomRoundingMode: before.uomRoundingMode,\n unitPriceEnabled: before.unitPriceEnabled,\n unitPriceReferenceUnit: before.unitPriceReferenceUnit ?? null,\n unitPriceBaseQuantity: before.unitPriceBaseQuantity ?? null,\n weightValue: before.weightValue ?? null,\n weightUnit: before.weightUnit ?? null,\n dimensions: before.dimensions ? cloneJson(before.dimensions) : null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n customFieldsetCode: before.customFieldsetCode ?? null,\n optionSchemaTemplate: before.optionSchemaId\n ? em.getReference(CatalogOptionSchemaTemplate, before.optionSchemaId)\n : null,\n productType: before.productType ?? \"simple\",\n isConfigurable: before.isConfigurable,\n isActive: before.isActive,\n createdAt: new Date(before.createdAt),\n updatedAt: new Date(before.updatedAt),\n });\n em.persist(record);\n }\n ensureTenantScope(ctx, before.tenantId);\n ensureOrganizationScope(ctx, before.organizationId);\n applyProductSnapshot(em, record, before);\n await em.flush();\n\n const relationEm = em.fork();\n const relationRecord = await findOneWithDecryption(relationEm, CatalogProduct, { id: before.id });\n if (relationRecord) {\n await restoreOffersFromSnapshot(relationEm, relationRecord, before.offers);\n await syncCategoryAssignments(relationEm, relationRecord, before.categoryIds);\n await syncProductTags(relationEm, relationRecord, before.tags);\n await relationEm.flush();\n }\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n const resetValues = buildCustomFieldResetMap(\n before.custom ?? undefined,\n payload?.after?.custom ?? undefined,\n );\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: resetValues,\n });\n }\n await emitProductCrudUndoChange({\n dataEngine,\n action: \"updated\",\n product: record,\n });\n },\n};\n\nconst deleteProductCommand: CommandHandler<\n { body?: Record<string, unknown>; query?: Record<string, unknown> },\n { productId: string }\n> = {\n id: \"catalog.products.delete\",\n async prepare(input, ctx) {\n const id = requireId(input, \"Product id is required\");\n const em = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadProductSnapshot(em, id);\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId);\n ensureOrganizationScope(ctx, snapshot.organizationId);\n }\n return snapshot ? { before: snapshot } : {};\n },\n async execute(input, ctx) {\n const id = requireId(input, \"Product id is required\");\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const record = await findOneWithDecryption(\n em,\n CatalogProduct,\n { id },\n { populate: [\"optionSchemaTemplate\"] },\n );\n if (!record) {\n const { translate } = await resolveTranslations();\n throw new CrudHttpError(404, {\n error: translate(\n \"catalog.products.errors.notFound\",\n \"Catalog product not found\",\n ),\n });\n }\n const baseEm = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadProductSnapshot(baseEm, id);\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await deleteProductVariantsAndRelatedData({\n em,\n product: record,\n dataEngine,\n ctx,\n });\n await em.nativeDelete(CatalogProductPrice, { product: record.id });\n const templateToRemove = await resolveOptionSchemaTemplateForRemoval(\n em,\n record,\n );\n if (templateToRemove) {\n record.optionSchemaTemplate = null;\n em.remove(templateToRemove);\n }\n em.remove(record);\n await em.flush();\n if (snapshot?.custom && Object.keys(snapshot.custom).length) {\n const resetValues = buildCustomFieldResetMap(snapshot.custom, undefined);\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: resetValues,\n });\n }\n }\n await emitProductCrudChange({\n dataEngine,\n action: \"deleted\",\n product: record,\n });\n return { productId: id };\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as ProductSnapshot | undefined;\n if (!before) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.products.delete\",\n \"Delete catalog product\",\n ),\n resourceKind: \"catalog.product\",\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies ProductUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ProductUndoPayload>(logEntry);\n const before = payload?.before;\n if (!before) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n let record = await findOneWithDecryption(em, CatalogProduct, { id: before.id });\n if (!record) {\n record = em.create(CatalogProduct, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n title: before.title,\n subtitle: before.subtitle ?? null,\n description: before.description ?? null,\n sku: before.sku ?? null,\n handle: before.handle ?? null,\n taxRateId: before.taxRateId ?? null,\n taxRate: before.taxRate ?? null,\n statusEntryId: before.statusEntryId ?? null,\n primaryCurrencyCode: before.primaryCurrencyCode ?? null,\n defaultUnit: before.defaultUnit ?? null,\n defaultSalesUnit: before.defaultSalesUnit ?? null,\n defaultSalesUnitQuantity: before.defaultSalesUnitQuantity ?? \"1\",\n uomRoundingScale: before.uomRoundingScale,\n uomRoundingMode: before.uomRoundingMode,\n unitPriceEnabled: before.unitPriceEnabled,\n unitPriceReferenceUnit: before.unitPriceReferenceUnit ?? null,\n unitPriceBaseQuantity: before.unitPriceBaseQuantity ?? null,\n weightValue: before.weightValue ?? null,\n weightUnit: before.weightUnit ?? null,\n dimensions: before.dimensions ? cloneJson(before.dimensions) : null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n customFieldsetCode: before.customFieldsetCode ?? null,\n optionSchemaTemplate: before.optionSchemaId\n ? em.getReference(CatalogOptionSchemaTemplate, before.optionSchemaId)\n : null,\n productType: before.productType ?? \"simple\",\n isConfigurable: before.isConfigurable,\n isActive: before.isActive,\n createdAt: new Date(before.createdAt),\n updatedAt: new Date(before.updatedAt),\n });\n em.persist(record);\n }\n ensureTenantScope(ctx, before.tenantId);\n ensureOrganizationScope(ctx, before.organizationId);\n applyProductSnapshot(em, record, before);\n await em.flush();\n\n const relationEm = em.fork();\n const relationRecord = await findOneWithDecryption(relationEm, CatalogProduct, { id: before.id });\n if (relationRecord) {\n await restoreOffersFromSnapshot(relationEm, relationRecord, before.offers);\n await syncCategoryAssignments(relationEm, relationRecord, before.categoryIds);\n await syncProductTags(relationEm, relationRecord, before.tags);\n await relationEm.flush();\n }\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n if (before.custom && Object.keys(before.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: before.custom,\n });\n }\n await emitProductCrudUndoChange({\n dataEngine,\n action: \"created\",\n product: record,\n });\n },\n};\n\nregisterCommand(createProductCommand);\nregisterCommand(updateProductCommand);\nregisterCommand(deleteProductCommand);\n\nfunction resolveProductUniqueConstraint(\n error: unknown,\n): \"handle\" | \"sku\" | null {\n if (!(error instanceof UniqueConstraintViolationException)) return null;\n const constraint = getErrorConstraint(error);\n if (constraint === \"catalog_products_handle_scope_unique\") return \"handle\";\n if (constraint === \"catalog_products_sku_scope_unique\") return \"sku\";\n const message = getErrorMessage(error).toLowerCase();\n if (\n message.includes(\"catalog_products_handle_scope_unique\") ||\n message.includes(\" handle\")\n ) {\n return \"handle\";\n }\n if (\n message.includes(\"catalog_products_sku_scope_unique\") ||\n message.includes(\" sku\")\n ) {\n return \"sku\";\n }\n return null;\n}\n\nasync function rethrowProductUniqueConstraint(error: unknown): Promise<never> {\n const target = resolveProductUniqueConstraint(error);\n if (target === \"handle\") await throwDuplicateHandleError();\n if (target === \"sku\") await throwDuplicateSkuError();\n throw error;\n}\n\nasync function throwDuplicateHandleError(): Promise<never> {\n const { translate } = await resolveTranslations();\n const message = translate(\n \"catalog.products.errors.handleExists\",\n \"Handle already in use.\",\n );\n throw new CrudHttpError(400, {\n error: message,\n fieldErrors: { handle: message },\n details: [\n { path: [\"handle\"], message, code: \"duplicate\", origin: \"validation\" },\n ],\n });\n}\n\nasync function throwDuplicateSkuError(): Promise<never> {\n const { translate } = await resolveTranslations();\n const message = translate(\n \"catalog.products.errors.skuExists\",\n \"SKU already in use.\",\n );\n throw new CrudHttpError(400, {\n error: message,\n fieldErrors: { sku: message },\n details: [\n { path: [\"sku\"], message, code: \"duplicate\", origin: \"validation\" },\n ],\n });\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport { registerCommand } from \"@open-mercato/shared/lib/commands\";\nimport type {\n CommandHandler,\n CommandRuntimeContext,\n} from \"@open-mercato/shared/lib/commands\";\nimport {\n buildChanges,\n requireId,\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n} from \"@open-mercato/shared/lib/commands/helpers\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { UniqueConstraintViolationException } from \"@mikro-orm/core\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport { CrudHttpError } from \"@open-mercato/shared/lib/crud/errors\";\nimport type {\n CrudEventAction,\n CrudEventsConfig,\n CrudIndexerConfig,\n} from \"@open-mercato/shared/lib/crud/types\";\nimport type { DataEngine } from \"@open-mercato/shared/lib/data/engine\";\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n} from \"@open-mercato/shared/lib/commands/customFieldSnapshots\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport { slugifyTagLabel } from \"@open-mercato/shared/lib/utils\";\nimport { parseObjectLike } from \"@open-mercato/shared/lib/json/parseObjectLike\";\nimport {\n CatalogOffer,\n CatalogProduct,\n CatalogProductVariant,\n CatalogProductPrice,\n CatalogProductUnitConversion,\n CatalogOptionSchemaTemplate,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductTag,\n CatalogProductTagAssignment,\n} from \"../data/entities\";\nimport { SalesTaxRate } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n productCreateSchema,\n productUpdateSchema,\n type OfferInput,\n type ProductCreateInput,\n type ProductUpdateInput,\n} from \"../data/validators\";\nimport type {\n CatalogProductOptionSchema,\n CatalogProductType,\n} from \"../data/types\";\nimport {\n cloneJson,\n ensureOrganizationScope,\n ensureSameScope,\n ensureTenantScope,\n extractUndoPayload,\n requireOptionSchemaTemplate,\n resolveOptionSchemaCode,\n emitCatalogQueryIndexEvent,\n randomSuffix,\n toNumericString,\n getErrorConstraint,\n getErrorMessage,\n} from \"./shared\";\nimport {\n findWithDecryption,\n findOneWithDecryption,\n} from \"@open-mercato/shared/lib/encryption/find\";\nimport { canonicalizeUnitCode } from \"../lib/unitCodes\";\nimport {\n resolveCanonicalUnitCode,\n} from \"../lib/unitResolution\";\n\ntype ProductSnapshot = {\n id: string;\n organizationId: string;\n tenantId: string;\n title: string;\n subtitle: string | null;\n description: string | null;\n sku: string | null;\n handle: string | null;\n taxRateId: string | null;\n taxRate: string | null;\n productType: CatalogProductType;\n statusEntryId: string | null;\n primaryCurrencyCode: string | null;\n defaultUnit: string | null;\n defaultSalesUnit: string | null;\n defaultSalesUnitQuantity: string;\n uomRoundingScale: number;\n uomRoundingMode: \"half_up\" | \"down\" | \"up\";\n unitPriceEnabled: boolean;\n unitPriceReferenceUnit: \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null;\n unitPriceBaseQuantity: string | null;\n defaultMediaId: string | null;\n defaultMediaUrl: string | null;\n weightValue: string | null;\n weightUnit: string | null;\n dimensions: Record<string, unknown> | null;\n optionSchemaId: string | null;\n customFieldsetCode: string | null;\n metadata: Record<string, unknown> | null;\n isConfigurable: boolean;\n isActive: boolean;\n createdAt: string;\n updatedAt: string;\n offers: OfferSnapshot[];\n tags: string[];\n categoryIds: string[];\n custom: Record<string, unknown> | null;\n};\n\nasync function resolveProductUnitDefaults(\n em: EntityManager,\n params: {\n organizationId: string;\n tenantId: string;\n defaultUnit: string | null | undefined;\n defaultSalesUnit: string | null | undefined;\n },\n): Promise<{ defaultUnit: string | null; defaultSalesUnit: string | null }> {\n const defaultUnitInput = canonicalizeUnitCode(params.defaultUnit);\n const defaultSalesUnitInput = canonicalizeUnitCode(params.defaultSalesUnit);\n if (!defaultUnitInput && defaultSalesUnitInput) {\n throw new CrudHttpError(400, { error: \"uom.default_unit_missing\" });\n }\n const defaultUnit = defaultUnitInput\n ? await resolveCanonicalUnitCode(em, {\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n unitCode: defaultUnitInput,\n })\n : null;\n const defaultSalesUnit = defaultSalesUnitInput\n ? await resolveCanonicalUnitCode(em, {\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n unitCode: defaultSalesUnitInput,\n })\n : null;\n return { defaultUnit, defaultSalesUnit };\n}\n\nasync function ensureBaseUnitCanBeRemoved(\n em: EntityManager,\n params: {\n productId: string;\n organizationId: string;\n tenantId: string;\n defaultUnit: string | null;\n defaultSalesUnit: string | null;\n },\n): Promise<void> {\n if (params.defaultUnit) return;\n if (params.defaultSalesUnit) {\n throw new CrudHttpError(400, { error: \"uom.default_unit_missing\" });\n }\n const activeConversionCount = await em.count(CatalogProductUnitConversion, {\n product: params.productId,\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n deletedAt: null,\n isActive: true,\n });\n if (activeConversionCount > 0) {\n throw new CrudHttpError(400, { error: \"uom.default_unit_missing\" });\n }\n}\n\n/**\n * Resolves unit-price configuration from product input.\n * Supports two input paths:\n * - Nested: `unitPrice.enabled`, `unitPrice.referenceUnit`, `unitPrice.baseQuantity` (preferred)\n * - Flat: `unitPriceEnabled`, `unitPriceReferenceUnit`, `unitPriceBaseQuantity` (legacy compat)\n * Nested values take precedence when both are provided.\n */\nfunction resolveUnitPriceInput(\n parsed: ProductCreateInput | ProductUpdateInput,\n): {\n enabled?: boolean;\n referenceUnit?: \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null;\n baseQuantity?: string | null;\n enabledProvided: boolean;\n referenceProvided: boolean;\n baseProvided: boolean;\n} {\n const enabledFromNested = parsed.unitPrice?.enabled;\n const enabledFromFlat = parsed.unitPriceEnabled;\n const referenceFromNested = parsed.unitPrice?.referenceUnit;\n const referenceFromFlat = parsed.unitPriceReferenceUnit;\n const baseFromNested = parsed.unitPrice?.baseQuantity;\n const baseFromFlat = parsed.unitPriceBaseQuantity;\n const enabledProvided =\n enabledFromNested !== undefined || enabledFromFlat !== undefined;\n const referenceProvided =\n referenceFromNested !== undefined || referenceFromFlat !== undefined;\n const baseProvided =\n baseFromNested !== undefined || baseFromFlat !== undefined;\n const enabled = enabledFromNested ?? enabledFromFlat;\n const referenceUnit = canonicalizeUnitCode(\n referenceFromNested ?? referenceFromFlat ?? null,\n ) as \"kg\" | \"l\" | \"m2\" | \"m3\" | \"pc\" | null | undefined;\n const baseQuantitySource = baseFromNested ?? baseFromFlat;\n const baseQuantity =\n baseQuantitySource === undefined\n ? undefined\n : (toNumericString(baseQuantitySource) ?? null);\n return {\n enabled,\n referenceUnit,\n baseQuantity,\n enabledProvided,\n referenceProvided,\n baseProvided,\n };\n}\n\ntype ProductUndoPayload = {\n before?: ProductSnapshot | null;\n after?: ProductSnapshot | null;\n};\n\nconst productCrudEvents: CrudEventsConfig<CatalogProduct> = {\n module: \"catalog\",\n entity: \"product\",\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n productType: ctx.entity.productType,\n statusEntryId: ctx.entity.statusEntryId ?? null,\n isActive: ctx.entity.isActive,\n }),\n};\n\nconst productCrudIndexer: CrudIndexerConfig<CatalogProduct> = {\n entityType: E.catalog.catalog_product,\n buildUpsertPayload: (ctx) => ({\n entityType: E.catalog.catalog_product,\n recordId: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n buildDeletePayload: (ctx) => ({\n entityType: E.catalog.catalog_product,\n recordId: ctx.identifiers.id,\n tenantId: ctx.identifiers.tenantId,\n organizationId: ctx.identifiers.organizationId,\n }),\n};\n\nfunction buildProductCrudIdentifiers(product: CatalogProduct) {\n return {\n id: product.id,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n };\n}\n\nasync function emitProductCrudChange(opts: {\n dataEngine: DataEngine;\n action: CrudEventAction;\n product: CatalogProduct;\n}) {\n const { dataEngine, action, product } = opts;\n await emitCrudSideEffects({\n dataEngine,\n action,\n entity: product,\n identifiers: buildProductCrudIdentifiers(product),\n events: productCrudEvents,\n indexer: productCrudIndexer,\n });\n}\n\nasync function emitProductCrudUndoChange(opts: {\n dataEngine: DataEngine;\n action: CrudEventAction;\n product: CatalogProduct;\n}) {\n const { dataEngine, action, product } = opts;\n await emitCrudUndoSideEffects({\n dataEngine,\n action,\n entity: product,\n identifiers: buildProductCrudIdentifiers(product),\n events: productCrudEvents,\n indexer: productCrudIndexer,\n });\n}\n\ntype OfferSnapshot = {\n id: string;\n channelId: string;\n title: string;\n description: string | null;\n defaultMediaId: string | null;\n defaultMediaUrl: string | null;\n metadata: Record<string, unknown> | null;\n isActive: boolean;\n};\n\nasync function resolveScopedTaxRate(\n em: EntityManager,\n taxRateId: string | null | undefined,\n taxRateInput: number | string | null | undefined,\n organizationId: string,\n tenantId: string,\n): Promise<{ taxRateId: string | null; taxRate: string | null }> {\n const normalizedRate =\n taxRateInput === null || taxRateInput === undefined\n ? null\n : (() => {\n const numeric =\n typeof taxRateInput === \"string\"\n ? Number(taxRateInput)\n : taxRateInput;\n return Number.isFinite(numeric) ? toNumericString(numeric) : null;\n })();\n if (!taxRateId) {\n return { taxRateId: null, taxRate: normalizedRate };\n }\n const record = await findOneWithDecryption(em, SalesTaxRate, {\n id: taxRateId,\n organizationId,\n tenantId,\n deletedAt: null,\n });\n if (!record) {\n const { translate } = await resolveTranslations();\n throw new CrudHttpError(400, {\n error: translate(\n \"catalog.products.errors.taxClassNotFound\",\n \"Tax class not found\",\n ),\n });\n }\n return { taxRateId, taxRate: record.rate ?? normalizedRate };\n}\n\nfunction slugifyCode(input: string): string {\n return input\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9\\-]+/g, \"-\")\n .replace(/(?:^-+|-+$)/g, \"\");\n}\n\nfunction normalizeCatalogOptionSchema(\n input?: CatalogProductOptionSchema | null,\n): CatalogProductOptionSchema | null {\n if (!input || !Array.isArray(input.options) || !input.options.length)\n return null;\n const options = input.options\n .map((option) => {\n if (!option) return null;\n const label =\n typeof option.label === \"string\" && option.label.trim().length\n ? option.label.trim()\n : null;\n const codeSource =\n typeof option.code === \"string\" && option.code.trim().length\n ? option.code.trim()\n : label;\n const code = slugifyCode(codeSource ?? \"\");\n if (!label && !code) return null;\n const choices = Array.isArray(option.choices)\n ? option.choices\n .map((choice) => {\n if (!choice) return null;\n const choiceLabel =\n typeof choice.label === \"string\" && choice.label.trim().length\n ? choice.label.trim()\n : null;\n const choiceCodeSource =\n typeof choice.code === \"string\" && choice.code.trim().length\n ? choice.code.trim()\n : choiceLabel;\n const choiceCode = slugifyCode(choiceCodeSource ?? \"\");\n if (!choiceLabel && !choiceCode) return null;\n return {\n code: choiceCode || `choice-${randomSuffix()}`,\n label:\n choiceLabel ?? (choiceCode || `Choice ${randomSuffix()}`),\n };\n })\n .filter(\n (entry): entry is { code: string; label: string } =>\n !!entry &&\n entry.code.trim().length > 0 &&\n entry.label.trim().length > 0,\n )\n : [];\n return {\n code: code || `option-${randomSuffix()}`,\n label: label ?? (code || `Option ${randomSuffix()}`),\n description:\n typeof option.description === \"string\" &&\n option.description.trim().length\n ? option.description.trim()\n : null,\n inputType:\n option.inputType === \"text\" ||\n option.inputType === \"textarea\" ||\n option.inputType === \"number\"\n ? option.inputType\n : \"select\",\n isRequired: option.isRequired ?? false,\n isMultiple: option.isMultiple ?? false,\n choices,\n };\n })\n .filter((entry) => !!entry && entry.code.trim().length > 0) as Array<\n CatalogProductOptionSchema[\"options\"][number]\n >;\n if (!options.length) return null;\n return {\n version:\n typeof input.version === \"number\" && input.version > 0\n ? input.version\n : 1,\n name:\n typeof input.name === \"string\" && input.name.trim().length\n ? input.name.trim()\n : undefined,\n description:\n typeof input.description === \"string\" && input.description.trim().length\n ? input.description.trim()\n : undefined,\n options,\n };\n}\n\nfunction convertLegacyOptionSchema(\n raw: unknown,\n): CatalogProductOptionSchema | null {\n if (!Array.isArray(raw)) return null;\n const options = raw\n .map((entry) => {\n if (!entry || typeof entry !== \"object\") return null;\n const source = entry as Record<string, unknown>;\n const title =\n typeof source[\"title\"] === \"string\" &&\n (source[\"title\"] as string).trim().length\n ? (source[\"title\"] as string).trim()\n : null;\n if (!title) return null;\n const values = Array.isArray(source[\"values\"])\n ? (source[\"values\"] as unknown[])\n .map((value: unknown) => {\n if (!value || typeof value !== \"object\") return null;\n const choice = value as Record<string, unknown>;\n const label =\n typeof choice.label === \"string\" && (choice.label as string).trim().length\n ? (choice.label as string).trim()\n : null;\n if (!label) return null;\n return { code: slugifyCode(label), label };\n })\n .filter(\n (choice): choice is { code: string; label: string } => !!choice,\n )\n : [];\n return {\n code: slugifyCode(title),\n label: title,\n inputType: \"select\" as const,\n choices: values,\n };\n })\n .filter((option) => !!option) as CatalogProductOptionSchema[\"options\"];\n if (!options.length) return null;\n return {\n version: 1,\n options,\n };\n}\n\nfunction extractOptionSchemaInput(source: {\n metadata?: Record<string, unknown> | null | undefined;\n optionSchema?: CatalogProductOptionSchema | null | undefined;\n}): {\n schema: CatalogProductOptionSchema | null;\n metadata: Record<string, unknown> | null;\n} {\n const metadata =\n source.metadata && typeof source.metadata === \"object\"\n ? { ...(source.metadata as Record<string, unknown>) }\n : null;\n let schema = normalizeCatalogOptionSchema(source.optionSchema);\n if (!schema && metadata) {\n const legacy = convertLegacyOptionSchema(\n (metadata as Record<string, unknown>)[\"optionSchema\"] ??\n (metadata as Record<string, unknown>)[\"option_schema\"],\n );\n schema = normalizeCatalogOptionSchema(legacy);\n }\n if (metadata) {\n delete (metadata as Record<string, unknown>)[\"optionSchema\"];\n delete (metadata as Record<string, unknown>)[\"option_schema\"];\n delete (metadata as Record<string, unknown>)[\"dimensions\"];\n delete (metadata as Record<string, unknown>)[\"weight\"];\n }\n return {\n schema,\n metadata: metadata && Object.keys(metadata).length ? metadata : null,\n };\n}\n\nfunction parseNumeric(value: unknown): number | null {\n const numeric = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(numeric) || numeric < 0) return null;\n return numeric;\n}\n\nfunction normalizeDimensionsInput(raw: unknown): {\n width?: number;\n height?: number;\n depth?: number;\n unit?: string;\n} | null {\n const source = parseObjectLike(raw);\n if (!source) return null;\n const clean: Record<string, unknown> = {};\n const width = parseNumeric(source.width);\n const height = parseNumeric(source.height);\n const depth = parseNumeric(source.depth);\n const unit =\n typeof source.unit === \"string\" && source.unit.trim().length\n ? source.unit.trim()\n : null;\n if (width !== null) clean.width = width;\n if (height !== null) clean.height = height;\n if (depth !== null) clean.depth = depth;\n if (unit) clean.unit = unit;\n return Object.keys(clean).length\n ? (clean as {\n width?: number;\n height?: number;\n depth?: number;\n unit?: string;\n })\n : null;\n}\n\nfunction normalizeWeightInput(\n raw: unknown,\n): { value?: number; unit?: string } | null {\n const source = parseObjectLike(raw);\n if (!source) return null;\n const value = parseNumeric(source.value);\n const unit =\n typeof source.unit === \"string\" && source.unit.trim().length\n ? source.unit.trim()\n : null;\n if (value === null && !unit) return null;\n const clean: { value?: number; unit?: string } = {};\n if (value !== null) clean.value = value;\n if (unit) clean.unit = unit;\n return clean;\n}\n\nfunction extractMeasurementsFromMetadata(\n metadata: Record<string, unknown> | null | undefined,\n): {\n metadata: Record<string, unknown> | null;\n dimensions: {\n width?: number;\n height?: number;\n depth?: number;\n unit?: string;\n } | null;\n weightValue: number | null;\n weightUnit: string | null;\n} {\n if (!metadata || typeof metadata !== \"object\") {\n return {\n metadata: null,\n dimensions: null,\n weightValue: null,\n weightUnit: null,\n };\n }\n const clone = { ...(metadata as Record<string, unknown>) };\n const dimensions = normalizeDimensionsInput(clone.dimensions);\n const weight = normalizeWeightInput(clone.weight);\n delete clone.dimensions;\n delete clone.weight;\n const cleanedMetadata = Object.keys(clone).length ? clone : null;\n return {\n metadata: cleanedMetadata,\n dimensions,\n weightValue: weight?.value ?? null,\n weightUnit: weight?.unit ?? null,\n };\n}\n\nfunction ensureSchemaName(\n name?: string | null,\n fallback?: string | null,\n): string {\n if (name && name.trim().length) return name.trim();\n if (fallback && fallback.trim().length) return fallback.trim();\n return \"Product option schema\";\n}\n\nasync function assignOptionSchemaTemplate(\n em: EntityManager,\n product: CatalogProduct,\n schema: CatalogProductOptionSchema,\n preferredName?: string | null,\n): Promise<CatalogOptionSchemaTemplate> {\n const resolvedName = ensureSchemaName(\n schema.name,\n preferredName ?? product.title,\n );\n const templateCode = resolveOptionSchemaCode({\n name: schema.name ?? resolvedName,\n fallback: `${resolvedName}-${product.id}`,\n uniqueHint: product.id?.slice(0, 8),\n });\n let template = product.optionSchemaTemplate ?? null;\n if (!template) {\n template = await em.findOne(CatalogOptionSchemaTemplate, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n code: templateCode,\n deletedAt: null,\n });\n }\n if (!template) {\n template = em.create(CatalogOptionSchemaTemplate, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n name: resolvedName,\n code: templateCode,\n description: schema.description ?? null,\n schema: cloneJson(schema),\n metadata: { source: \"product\" },\n isActive: true,\n });\n em.persist(template);\n } else {\n template.code = templateCode;\n template.name = resolvedName;\n template.description = schema.description ?? template.description ?? null;\n template.schema = cloneJson(schema);\n }\n product.optionSchemaTemplate = template;\n return template;\n}\n\nfunction serializeOffer(record: CatalogOffer): OfferSnapshot {\n return {\n id: record.id,\n channelId: record.channelId,\n title: record.title,\n description: record.description ?? null,\n defaultMediaId: record.defaultMediaId ?? null,\n defaultMediaUrl: record.defaultMediaUrl ?? null,\n metadata: record.metadata ? cloneJson(record.metadata) : null,\n isActive: record.isActive,\n };\n}\n\nasync function loadOfferSnapshots(\n em: EntityManager,\n productId: string,\n): Promise<OfferSnapshot[]> {\n const offerRecords = await em.find(\n CatalogOffer,\n { product: productId },\n { orderBy: { createdAt: \"asc\" } },\n );\n return offerRecords.map((offer) => serializeOffer(offer));\n}\n\nasync function restoreOffersFromSnapshot(\n em: EntityManager,\n product: CatalogProduct,\n snapshot: OfferSnapshot[] | null | undefined,\n): Promise<void> {\n const existing = await em.find(CatalogOffer, { product });\n const keepIds = new Set<string>();\n const list = Array.isArray(snapshot) ? snapshot : [];\n for (const offer of existing) {\n if (!list.some((snap) => snap.id === offer.id)) {\n em.remove(offer);\n } else {\n keepIds.add(offer.id);\n }\n }\n for (const snap of list) {\n let target = existing.find((entry) => entry.id === snap.id);\n if (!target) {\n target = em.create(CatalogOffer, {\n id: snap.id,\n product,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n channelId: snap.channelId,\n title: snap.title,\n isActive: snap.isActive,\n });\n em.persist(target);\n }\n target.channelId = snap.channelId;\n target.title = snap.title;\n target.description = snap.description ?? null;\n target.defaultMediaId = snap.defaultMediaId ?? null;\n target.defaultMediaUrl = snap.defaultMediaUrl ?? null;\n target.metadata = snap.metadata ? cloneJson(snap.metadata) : null;\n target.isActive = snap.isActive;\n keepIds.add(target.id);\n }\n const toRemove = existing.filter((offer) => !keepIds.has(offer.id));\n if (toRemove.length) {\n for (const offer of toRemove) {\n em.remove(offer);\n }\n }\n}\n\nasync function syncOffers(\n em: EntityManager,\n product: CatalogProduct,\n inputs: OfferInput[] | undefined,\n): Promise<void> {\n if (!inputs) return;\n const normalized = inputs.map((input) => ({\n ...input,\n title: input.title?.trim().length ? input.title.trim() : product.title,\n description:\n input.description != null && input.description.trim().length\n ? input.description.trim()\n : (product.description ?? null),\n defaultMediaId:\n typeof input.defaultMediaId === \"string\" &&\n input.defaultMediaId.trim().length\n ? input.defaultMediaId.trim()\n : null,\n defaultMediaUrl:\n typeof input.defaultMediaUrl === \"string\" &&\n input.defaultMediaUrl.trim().length\n ? input.defaultMediaUrl.trim()\n : null,\n metadata: input.metadata ? cloneJson(input.metadata) : null,\n isActive: input.isActive !== false,\n }));\n const existing = await em.find(CatalogOffer, { product });\n const claimed = new Set<string>();\n const channelMap = new Map<string, CatalogOffer>();\n for (const offer of existing) {\n channelMap.set(offer.channelId, offer);\n }\n const updates: CatalogOffer[] = [];\n for (const input of normalized) {\n if (!input.channelId) continue;\n let target: CatalogOffer | undefined;\n if (input.id) {\n target = existing.find((item) => item.id === input.id);\n }\n if (!target) {\n const existingByChannel = channelMap.get(input.channelId);\n if (existingByChannel && !claimed.has(existingByChannel.id)) {\n target = existingByChannel;\n }\n }\n if (!target) {\n target = em.create(CatalogOffer, {\n product,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n channelId: input.channelId,\n title: input.title || product.title,\n isActive: input.isActive !== false,\n });\n em.persist(target);\n existing.push(target);\n channelMap.set(input.channelId, target);\n }\n target.channelId = input.channelId;\n target.title = input.title || product.title;\n target.description = input.description ?? null;\n target.defaultMediaId = input.defaultMediaId ?? null;\n target.defaultMediaUrl = input.defaultMediaUrl ?? null;\n target.metadata = input.metadata ? cloneJson(input.metadata) : null;\n target.isActive = input.isActive !== false;\n claimed.add(target.id);\n updates.push(target);\n }\n const toRemove = existing.filter((offer) => !claimed.has(offer.id));\n for (const offer of toRemove) {\n em.remove(offer);\n }\n}\n\nasync function syncCategoryAssignments(\n em: EntityManager,\n product: CatalogProduct,\n categoryIds: string[] | undefined,\n): Promise<void> {\n if (categoryIds === undefined) return;\n const normalized = Array.from(\n new Set(\n (Array.isArray(categoryIds) ? categoryIds : [])\n .map((id) => (typeof id === \"string\" ? id.trim() : \"\"))\n .filter((id) => id.length),\n ),\n );\n const existing = await em.find(CatalogProductCategoryAssignment, { product });\n if (!normalized.length) {\n if (existing.length) {\n for (const assignment of existing) {\n em.remove(assignment);\n }\n }\n return;\n }\n const categories = await em.find(CatalogProductCategory, {\n id: { $in: normalized },\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n });\n const categoryMap = new Map(\n categories.map((category) => [category.id, category]),\n );\n const claimed = new Set<string>();\n normalized.forEach((categoryId, index) => {\n const category = categoryMap.get(categoryId);\n if (!category) return;\n let assignment = existing.find((item) => {\n const value =\n typeof item.category === \"string\" ? item.category : item.category?.id;\n return value === categoryId;\n });\n if (!assignment) {\n assignment = em.create(CatalogProductCategoryAssignment, {\n product,\n category,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n position: index,\n });\n em.persist(assignment);\n existing.push(assignment);\n }\n assignment.position = index;\n claimed.add(assignment.id);\n });\n for (const assignment of existing) {\n if (!claimed.has(assignment.id)) {\n em.remove(assignment);\n }\n }\n}\n\nasync function syncProductTags(\n em: EntityManager,\n product: CatalogProduct,\n tags: string[] | undefined,\n): Promise<void> {\n if (tags === undefined) return;\n const labelMap = new Map<string, string>();\n if (Array.isArray(tags)) {\n tags.forEach((raw) => {\n const label = typeof raw === \"string\" ? raw.trim() : \"\";\n if (!label) return;\n const slug = slugifyTagLabel(label);\n if (!labelMap.has(slug)) {\n labelMap.set(slug, label);\n }\n });\n }\n const slugs = Array.from(labelMap.keys());\n const existingAssignments = await findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { product },\n { populate: [\"tag\"] },\n { tenantId: product.tenantId, organizationId: product.organizationId },\n );\n if (!slugs.length) {\n if (existingAssignments.length) {\n for (const assignment of existingAssignments) {\n em.remove(assignment);\n }\n }\n return;\n }\n const existingTags = await em.find(CatalogProductTag, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n slug: { $in: slugs },\n });\n const tagsBySlug = new Map(existingTags.map((tag) => [tag.slug, tag]));\n for (const slug of slugs) {\n if (tagsBySlug.has(slug)) continue;\n const label = labelMap.get(slug) ?? slug;\n const tag = em.create(CatalogProductTag, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n slug,\n label,\n });\n em.persist(tag);\n tagsBySlug.set(slug, tag);\n }\n const assignmentByTagId = new Map(\n existingAssignments.map((assignment) => [\n typeof assignment.tag === \"string\" ? assignment.tag : assignment.tag.id,\n assignment,\n ]),\n );\n const keepIds = new Set<string>();\n for (const slug of slugs) {\n const tag = tagsBySlug.get(slug);\n if (!tag) continue;\n const tagId = tag.id;\n let assignment = assignmentByTagId.get(tagId);\n if (!assignment) {\n assignment = em.create(CatalogProductTagAssignment, {\n product,\n tag,\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n });\n em.persist(assignment);\n }\n keepIds.add(assignment.id);\n }\n for (const assignment of existingAssignments) {\n if (!keepIds.has(assignment.id)) {\n em.remove(assignment);\n }\n }\n}\n\ntype VariantCleanupSnapshot = {\n id: string;\n organizationId: string;\n tenantId: string;\n custom: Record<string, unknown> | null;\n};\n\nasync function deleteProductVariantsAndRelatedData(opts: {\n em: EntityManager;\n product: CatalogProduct;\n dataEngine: DataEngine;\n ctx: CommandRuntimeContext;\n}): Promise<void> {\n const { em, product, dataEngine, ctx } = opts;\n const variants = await em.find(CatalogProductVariant, { product });\n if (!variants.length) return;\n const cleanupEntries: VariantCleanupSnapshot[] = await Promise.all(\n variants.map(async (variant) => {\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: variant.organizationId,\n tenantId: variant.tenantId,\n });\n return {\n id: variant.id,\n organizationId: variant.organizationId,\n tenantId: variant.tenantId,\n custom: Object.keys(custom).length ? custom : null,\n };\n }),\n );\n const variantIds = variants.map((variant) => variant.id);\n if (variantIds.length) {\n await em.nativeDelete(CatalogProductPrice, {\n variant: { $in: variantIds },\n });\n }\n for (const variant of variants) {\n em.remove(variant);\n }\n await em.flush();\n for (const cleanup of cleanupEntries) {\n if (!cleanup.custom) continue;\n const resetValues = buildCustomFieldResetMap(cleanup.custom, undefined);\n if (!Object.keys(resetValues).length) continue;\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product_variant,\n recordId: cleanup.id,\n organizationId: cleanup.organizationId,\n tenantId: cleanup.tenantId,\n values: resetValues,\n });\n }\n for (const cleanup of cleanupEntries) {\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: cleanup.id,\n organizationId: cleanup.organizationId,\n tenantId: cleanup.tenantId,\n action: \"deleted\",\n });\n }\n}\n\nfunction isProductOwnedOptionSchemaTemplate(\n template: CatalogOptionSchemaTemplate | string | null | undefined,\n): template is CatalogOptionSchemaTemplate {\n if (!template || typeof template === \"string\") return false;\n const metadata = template.metadata;\n if (!metadata || typeof metadata !== \"object\") return false;\n const source = (metadata as Record<string, unknown>).source;\n return source === \"product\";\n}\n\nasync function resolveOptionSchemaTemplateForRemoval(\n em: EntityManager,\n product: CatalogProduct,\n): Promise<CatalogOptionSchemaTemplate | null> {\n const template = product.optionSchemaTemplate;\n if (!isProductOwnedOptionSchemaTemplate(template)) {\n return null;\n }\n const otherUsage = await em.count(CatalogProduct, {\n optionSchemaTemplate: template,\n id: { $ne: product.id },\n deletedAt: null,\n });\n if (otherUsage > 0) return null;\n return template;\n}\n\nasync function loadProductSnapshot(\n em: EntityManager,\n id: string,\n): Promise<ProductSnapshot | null> {\n const record = await findOneWithDecryption(\n em,\n CatalogProduct,\n { id, deletedAt: null },\n { populate: [\"optionSchemaTemplate\"] },\n );\n if (!record) return null;\n const [offers, tagAssignments, categoryAssignments] = await Promise.all([\n loadOfferSnapshots(em, record.id),\n findWithDecryption(\n em,\n CatalogProductTagAssignment,\n { product: record.id },\n { populate: [\"tag\"] },\n { tenantId: record.tenantId, organizationId: record.organizationId },\n ),\n findWithDecryption(\n em,\n CatalogProductCategoryAssignment,\n { product: record.id },\n { populate: [\"category\"] },\n { tenantId: record.tenantId, organizationId: record.organizationId },\n ),\n ]);\n const tags = tagAssignments\n .map((assignment) => {\n const tag =\n typeof assignment.tag === \"string\" ? null : (assignment.tag ?? null);\n const label = tag?.label ?? null;\n return typeof label === \"string\" && label.trim().length ? label : null;\n })\n .filter((label): label is string => !!label)\n .sort((a, b) => a.localeCompare(b));\n const categoryIds = categoryAssignments\n .slice()\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))\n .map((assignment) => {\n if (typeof assignment.category === \"string\") return assignment.category;\n return assignment.category?.id ?? null;\n })\n .filter((value): value is string => !!value);\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n });\n const optionSchemaTemplate = record.optionSchemaTemplate;\n const optionTemplateId =\n typeof optionSchemaTemplate === \"string\"\n ? optionSchemaTemplate\n : (optionSchemaTemplate?.id ?? null);\n const measurements = extractMeasurementsFromMetadata(\n record.metadata ? cloneJson(record.metadata) : null,\n );\n const dimensions =\n record.dimensions && Object.keys(record.dimensions).length\n ? cloneJson(record.dimensions)\n : measurements.dimensions\n ? cloneJson(measurements.dimensions)\n : null;\n const weightValue =\n record.weightValue ??\n (measurements.weightValue !== null\n ? toNumericString(measurements.weightValue)\n : null);\n const weightUnit = record.weightUnit ?? measurements.weightUnit ?? null;\n const metadata = measurements.metadata\n ? cloneJson(measurements.metadata)\n : null;\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n title: record.title,\n subtitle: record.subtitle ?? null,\n description: record.description ?? null,\n sku: record.sku ?? null,\n handle: record.handle ?? null,\n taxRateId: record.taxRateId ?? null,\n taxRate: record.taxRate ?? null,\n productType: record.productType,\n statusEntryId: record.statusEntryId ?? null,\n primaryCurrencyCode: record.primaryCurrencyCode ?? null,\n defaultUnit: record.defaultUnit ?? null,\n defaultSalesUnit: record.defaultSalesUnit ?? null,\n defaultSalesUnitQuantity: record.defaultSalesUnitQuantity ?? \"1\",\n uomRoundingScale: record.uomRoundingScale ?? 4,\n uomRoundingMode: record.uomRoundingMode ?? \"half_up\",\n unitPriceEnabled: record.unitPriceEnabled ?? false,\n unitPriceReferenceUnit: record.unitPriceReferenceUnit ?? null,\n unitPriceBaseQuantity: record.unitPriceBaseQuantity ?? null,\n defaultMediaId: record.defaultMediaId ?? null,\n defaultMediaUrl: record.defaultMediaUrl ?? null,\n weightValue,\n weightUnit,\n dimensions,\n customFieldsetCode: record.customFieldsetCode ?? null,\n metadata,\n isConfigurable: record.isConfigurable,\n isActive: record.isActive,\n optionSchemaId: optionTemplateId,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n offers,\n tags,\n categoryIds,\n custom: Object.keys(custom).length ? custom : null,\n };\n}\n\nfunction applyProductSnapshot(\n em: EntityManager,\n record: CatalogProduct,\n snapshot: ProductSnapshot,\n): void {\n record.organizationId = snapshot.organizationId;\n record.tenantId = snapshot.tenantId;\n record.title = snapshot.title;\n record.subtitle = snapshot.subtitle ?? null;\n record.description = snapshot.description ?? null;\n record.sku = snapshot.sku ?? null;\n record.handle = snapshot.handle ?? null;\n record.taxRateId = snapshot.taxRateId ?? null;\n record.taxRate = snapshot.taxRate ?? null;\n record.productType = snapshot.productType;\n record.statusEntryId = snapshot.statusEntryId ?? null;\n record.primaryCurrencyCode = snapshot.primaryCurrencyCode ?? null;\n record.defaultUnit = snapshot.defaultUnit ?? null;\n record.defaultSalesUnit = snapshot.defaultSalesUnit ?? null;\n record.defaultSalesUnitQuantity = snapshot.defaultSalesUnitQuantity ?? \"1\";\n record.uomRoundingScale = snapshot.uomRoundingScale;\n record.uomRoundingMode = snapshot.uomRoundingMode;\n record.unitPriceEnabled = snapshot.unitPriceEnabled;\n record.unitPriceReferenceUnit = snapshot.unitPriceReferenceUnit ?? null;\n record.unitPriceBaseQuantity = snapshot.unitPriceBaseQuantity ?? null;\n record.defaultMediaId = snapshot.defaultMediaId ?? null;\n record.defaultMediaUrl = snapshot.defaultMediaUrl ?? null;\n record.weightValue = snapshot.weightValue ?? null;\n record.weightUnit = snapshot.weightUnit ?? null;\n record.dimensions = snapshot.dimensions\n ? cloneJson(snapshot.dimensions)\n : null;\n record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null;\n record.customFieldsetCode = snapshot.customFieldsetCode ?? null;\n record.optionSchemaTemplate = snapshot.optionSchemaId\n ? em.getReference(CatalogOptionSchemaTemplate, snapshot.optionSchemaId)\n : null;\n record.isConfigurable = snapshot.isConfigurable;\n record.isActive = snapshot.isActive;\n record.createdAt = new Date(snapshot.createdAt);\n record.updatedAt = new Date(snapshot.updatedAt);\n}\n\nconst createProductCommand: CommandHandler<\n ProductCreateInput,\n { productId: string }\n> = {\n id: \"catalog.products.create\",\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(\n productCreateSchema,\n rawInput,\n );\n ensureTenantScope(ctx, parsed.tenantId);\n ensureOrganizationScope(ctx, parsed.organizationId);\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const now = new Date();\n const { taxRateId, taxRate } = await resolveScopedTaxRate(\n em,\n parsed.taxRateId ?? null,\n parsed.taxRate,\n parsed.organizationId,\n parsed.tenantId,\n );\n const { schema: optionSchemaDefinition, metadata: sanitizedMetadata } =\n extractOptionSchemaInput(parsed);\n const measurements = extractMeasurementsFromMetadata(sanitizedMetadata);\n const dimensions =\n normalizeDimensionsInput(parsed.dimensions) ?? measurements.dimensions;\n const weightValue =\n parsed.weightValue !== undefined\n ? toNumericString(parsed.weightValue)\n : measurements.weightValue !== null\n ? toNumericString(measurements.weightValue)\n : null;\n const weightUnit =\n parsed.weightUnit !== undefined\n ? (parsed.weightUnit ?? null)\n : (measurements.weightUnit ?? null);\n const metadata = measurements.metadata\n ? cloneJson(measurements.metadata)\n : null;\n const unitPriceInput = resolveUnitPriceInput(parsed);\n const unitPriceEnabled = unitPriceInput.enabled ?? false;\n const resolvedUnits = await resolveProductUnitDefaults(em, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n defaultUnit: parsed.defaultUnit ?? null,\n defaultSalesUnit: parsed.defaultSalesUnit ?? parsed.defaultUnit ?? null,\n });\n const productId = randomUUID();\n const record = em.create(CatalogProduct, {\n id: productId,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n title: parsed.title,\n subtitle: parsed.subtitle ?? null,\n description: parsed.description ?? null,\n sku: parsed.sku ?? null,\n handle: parsed.handle ?? null,\n taxRateId,\n taxRate,\n productType: parsed.productType ?? \"simple\",\n statusEntryId: parsed.statusEntryId ?? null,\n primaryCurrencyCode: parsed.primaryCurrencyCode ?? null,\n defaultUnit: resolvedUnits.defaultUnit,\n defaultSalesUnit:\n resolvedUnits.defaultSalesUnit ?? resolvedUnits.defaultUnit,\n defaultSalesUnitQuantity:\n toNumericString(parsed.defaultSalesUnitQuantity ?? 1) ?? \"1\",\n uomRoundingScale: parsed.uomRoundingScale ?? 4,\n uomRoundingMode: parsed.uomRoundingMode ?? \"half_up\",\n unitPriceEnabled,\n unitPriceReferenceUnit: unitPriceEnabled\n ? (unitPriceInput.referenceUnit ?? null)\n : null,\n unitPriceBaseQuantity: unitPriceEnabled\n ? (unitPriceInput.baseQuantity ?? null)\n : null,\n defaultMediaId: parsed.defaultMediaId ?? null,\n defaultMediaUrl: parsed.defaultMediaUrl ?? null,\n weightValue,\n weightUnit,\n dimensions,\n metadata,\n customFieldsetCode: parsed.customFieldsetCode ?? null,\n isConfigurable: parsed.isConfigurable ?? false,\n isActive: parsed.isActive ?? true,\n createdAt: now,\n updatedAt: now,\n });\n let optionSchemaTemplate: CatalogOptionSchemaTemplate | null = null;\n if (parsed.optionSchemaId) {\n optionSchemaTemplate = await requireOptionSchemaTemplate(\n em,\n parsed.optionSchemaId,\n translate(\"catalog.errors.optionSchemaNotFound\", \"Option schema not found\"),\n );\n ensureSameScope(\n optionSchemaTemplate,\n parsed.organizationId,\n parsed.tenantId,\n );\n record.optionSchemaTemplate = optionSchemaTemplate;\n } else if (optionSchemaDefinition) {\n optionSchemaTemplate = await assignOptionSchemaTemplate(\n em,\n record,\n optionSchemaDefinition,\n optionSchemaDefinition.name ?? parsed.title,\n );\n }\n em.persist(record);\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n await syncOffers(em, record, parsed.offers);\n await syncCategoryAssignments(em, record, parsed.categoryIds);\n await syncProductTags(em, record, parsed.tags);\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n });\n await emitProductCrudChange({\n dataEngine,\n action: \"created\",\n product: record,\n });\n return { productId: record.id };\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n return loadProductSnapshot(em, result.productId);\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as ProductSnapshot | undefined;\n if (!after) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.products.create\",\n \"Create catalog product\",\n ),\n resourceKind: \"catalog.product\",\n resourceId: result.productId,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n } satisfies ProductUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ProductUndoPayload>(logEntry);\n const after = payload?.after;\n if (!after) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const record = await findOneWithDecryption(em, CatalogProduct, { id: after.id });\n if (!record) return;\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n em.remove(record);\n await em.flush();\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n const resetValues = buildCustomFieldResetMap(\n undefined,\n after.custom ?? undefined,\n );\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n values: resetValues,\n });\n }\n await emitProductCrudUndoChange({\n dataEngine,\n action: \"deleted\",\n product: record,\n });\n },\n};\n\nconst updateProductCommand: CommandHandler<\n ProductUpdateInput,\n { productId: string }\n> = {\n id: \"catalog.products.update\",\n async prepare(input, ctx) {\n const id = requireId(input, \"Product id is required\");\n const em = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadProductSnapshot(em, id);\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId);\n ensureOrganizationScope(ctx, snapshot.organizationId);\n }\n return snapshot ? { before: snapshot } : {};\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(\n productUpdateSchema,\n rawInput,\n );\n const rawPayload =\n rawInput && typeof rawInput === \"object\"\n ? (rawInput as Record<string, unknown>)\n : null;\n const hasDefaultUnit = Boolean(\n rawPayload &&\n Object.prototype.hasOwnProperty.call(rawPayload, \"defaultUnit\"),\n );\n const hasDefaultSalesUnit = Boolean(\n rawPayload &&\n Object.prototype.hasOwnProperty.call(rawPayload, \"defaultSalesUnit\"),\n );\n const requestedDefaultUnit = hasDefaultUnit\n ? rawPayload?.defaultUnit\n : parsed.defaultUnit;\n const requestedDefaultSalesUnit = hasDefaultSalesUnit\n ? rawPayload?.defaultSalesUnit\n : parsed.defaultSalesUnit;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const { translate } = await resolveTranslations();\n const record = await findOneWithDecryption(em, CatalogProduct, {\n id: parsed.id,\n deletedAt: null,\n });\n if (!record)\n throw new CrudHttpError(404, {\n error: translate(\"catalog.errors.productNotFound\", \"Catalog product not found\"),\n });\n const organizationId = parsed.organizationId ?? record.organizationId;\n const tenantId = parsed.tenantId ?? record.tenantId;\n ensureTenantScope(ctx, tenantId);\n ensureOrganizationScope(ctx, organizationId);\n ensureSameScope(record, organizationId, tenantId);\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n const lookupEm = em.fork();\n const taxRateProvided =\n parsed.taxRateId !== undefined || parsed.taxRate !== undefined;\n const resolvedTaxRate = taxRateProvided\n ? await resolveScopedTaxRate(\n lookupEm,\n parsed.taxRateId ?? null,\n parsed.taxRate,\n organizationId,\n tenantId,\n )\n : null;\n record.organizationId = organizationId;\n record.tenantId = tenantId;\n\n if (parsed.title !== undefined) record.title = parsed.title;\n if (parsed.subtitle !== undefined)\n record.subtitle = parsed.subtitle ?? null;\n if (parsed.description !== undefined)\n record.description = parsed.description ?? null;\n if (parsed.sku !== undefined) record.sku = parsed.sku ?? null;\n if (parsed.handle !== undefined) record.handle = parsed.handle ?? null;\n if (taxRateProvided) {\n record.taxRateId = resolvedTaxRate?.taxRateId ?? null;\n record.taxRate = resolvedTaxRate?.taxRate ?? null;\n }\n if (parsed.productType !== undefined)\n record.productType = parsed.productType;\n if (parsed.statusEntryId !== undefined)\n record.statusEntryId = parsed.statusEntryId ?? null;\n if (parsed.primaryCurrencyCode !== undefined) {\n record.primaryCurrencyCode = parsed.primaryCurrencyCode ?? null;\n }\n const uomDefaultsTouched =\n hasDefaultUnit ||\n hasDefaultSalesUnit ||\n parsed.defaultUnit !== undefined ||\n parsed.defaultSalesUnit !== undefined ||\n parsed.organizationId !== undefined ||\n parsed.tenantId !== undefined;\n if (uomDefaultsTouched) {\n const resolvedUnits = await resolveProductUnitDefaults(lookupEm, {\n organizationId,\n tenantId,\n defaultUnit: hasDefaultUnit\n ? (requestedDefaultUnit as string | null | undefined)\n : parsed.defaultUnit !== undefined\n ? parsed.defaultUnit\n : record.defaultUnit,\n defaultSalesUnit: hasDefaultSalesUnit\n ? (requestedDefaultSalesUnit as string | null | undefined)\n : parsed.defaultSalesUnit !== undefined\n ? parsed.defaultSalesUnit\n : record.defaultSalesUnit,\n });\n await ensureBaseUnitCanBeRemoved(lookupEm, {\n productId: record.id,\n organizationId,\n tenantId,\n defaultUnit: resolvedUnits.defaultUnit,\n defaultSalesUnit: resolvedUnits.defaultSalesUnit,\n });\n record.defaultUnit = resolvedUnits.defaultUnit;\n record.defaultSalesUnit = resolvedUnits.defaultSalesUnit;\n }\n if (parsed.defaultSalesUnitQuantity !== undefined) {\n record.defaultSalesUnitQuantity =\n toNumericString(parsed.defaultSalesUnitQuantity) ?? \"1\";\n }\n if (parsed.uomRoundingScale !== undefined) {\n record.uomRoundingScale = parsed.uomRoundingScale;\n }\n if (parsed.uomRoundingMode !== undefined) {\n record.uomRoundingMode = parsed.uomRoundingMode;\n }\n const unitPriceInput = resolveUnitPriceInput(parsed);\n if (unitPriceInput.enabledProvided) {\n record.unitPriceEnabled = unitPriceInput.enabled ?? false;\n if (!record.unitPriceEnabled) {\n record.unitPriceReferenceUnit = null;\n record.unitPriceBaseQuantity = null;\n }\n }\n if (unitPriceInput.referenceProvided && record.unitPriceEnabled) {\n record.unitPriceReferenceUnit = unitPriceInput.referenceUnit ?? null;\n }\n if (unitPriceInput.baseProvided && record.unitPriceEnabled) {\n record.unitPriceBaseQuantity = unitPriceInput.baseQuantity ?? null;\n }\n if (parsed.defaultMediaId !== undefined) {\n record.defaultMediaId = parsed.defaultMediaId ?? null;\n }\n if (parsed.defaultMediaUrl !== undefined) {\n record.defaultMediaUrl = parsed.defaultMediaUrl ?? null;\n }\n const metadataProvided =\n rawInput &&\n typeof rawInput === \"object\" &&\n Object.prototype.hasOwnProperty.call(rawInput, \"metadata\");\n const { schema: optionSchemaDefinition, metadata: sanitizedMetadata } =\n extractOptionSchemaInput(parsed);\n const measurements = extractMeasurementsFromMetadata(sanitizedMetadata);\n const normalizedDimensions =\n parsed.dimensions !== undefined\n ? normalizeDimensionsInput(parsed.dimensions)\n : measurements.dimensions;\n const weightValueFromInput =\n parsed.weightValue === null\n ? null\n : parsed.weightValue !== undefined\n ? toNumericString(parsed.weightValue)\n : measurements.weightValue !== null\n ? toNumericString(measurements.weightValue)\n : null;\n const weightUnitFromInput =\n parsed.weightUnit !== undefined\n ? (parsed.weightUnit ?? null)\n : (measurements.weightUnit ?? null);\n const weightProvided =\n parsed.weightValue !== undefined ||\n parsed.weightUnit !== undefined ||\n measurements.weightValue !== null ||\n measurements.weightUnit !== null;\n if (normalizedDimensions !== null || parsed.dimensions !== undefined) {\n record.dimensions = normalizedDimensions\n ? cloneJson(normalizedDimensions)\n : null;\n }\n if (weightProvided) {\n record.weightValue = weightValueFromInput;\n record.weightUnit = weightUnitFromInput;\n }\n if (metadataProvided) {\n record.metadata = measurements.metadata\n ? cloneJson(measurements.metadata)\n : null;\n }\n if (parsed.optionSchemaId !== undefined) {\n if (!parsed.optionSchemaId) {\n record.optionSchemaTemplate = null;\n } else {\n const optionTemplate = await requireOptionSchemaTemplate(\n lookupEm,\n parsed.optionSchemaId,\n translate(\"catalog.errors.optionSchemaNotFound\", \"Option schema not found\"),\n );\n ensureSameScope(optionTemplate, organizationId, tenantId);\n record.optionSchemaTemplate = optionTemplate;\n }\n }\n if (optionSchemaDefinition) {\n await assignOptionSchemaTemplate(\n em,\n record,\n optionSchemaDefinition,\n optionSchemaDefinition.name ?? parsed.title ?? record.title,\n );\n }\n if (parsed.customFieldsetCode !== undefined) {\n record.customFieldsetCode = parsed.customFieldsetCode ?? null;\n }\n if (parsed.isConfigurable !== undefined)\n record.isConfigurable = parsed.isConfigurable;\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive;\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n await syncOffers(em, record, parsed.offers);\n await syncCategoryAssignments(em, record, parsed.categoryIds);\n await syncProductTags(em, record, parsed.tags);\n try {\n await em.flush();\n } catch (error) {\n await rethrowProductUniqueConstraint(error);\n }\n if (custom && Object.keys(custom).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n });\n }\n await emitProductCrudChange({\n dataEngine,\n action: \"updated\",\n product: record,\n });\n return { productId: record.id };\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n return loadProductSnapshot(em, result.productId);\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as ProductSnapshot | undefined;\n const after = snapshots.after as ProductSnapshot | undefined;\n if (!before || !after) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.products.update\",\n \"Update catalog product\",\n ),\n resourceKind: \"catalog.product\",\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n changes: buildChanges(before, after, [\n \"title\",\n \"sku\",\n \"productType\",\n \"defaultUnit\",\n \"defaultSalesUnit\",\n \"defaultSalesUnitQuantity\",\n \"uomRoundingScale\",\n \"uomRoundingMode\",\n \"unitPriceEnabled\",\n \"unitPriceReferenceUnit\",\n \"unitPriceBaseQuantity\",\n \"isActive\",\n ]),\n snapshotBefore: before,\n snapshotAfter: after,\n payload: {\n undo: {\n before,\n after,\n } satisfies ProductUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ProductUndoPayload>(logEntry);\n const before = payload?.before;\n if (!before) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n let record = await findOneWithDecryption(em, CatalogProduct, { id: before.id });\n if (!record) {\n record = em.create(CatalogProduct, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n title: before.title,\n subtitle: before.subtitle ?? null,\n description: before.description ?? null,\n sku: before.sku ?? null,\n handle: before.handle ?? null,\n taxRateId: before.taxRateId ?? null,\n taxRate: before.taxRate ?? null,\n statusEntryId: before.statusEntryId ?? null,\n primaryCurrencyCode: before.primaryCurrencyCode ?? null,\n defaultUnit: before.defaultUnit ?? null,\n defaultSalesUnit: before.defaultSalesUnit ?? null,\n defaultSalesUnitQuantity: before.defaultSalesUnitQuantity ?? \"1\",\n uomRoundingScale: before.uomRoundingScale,\n uomRoundingMode: before.uomRoundingMode,\n unitPriceEnabled: before.unitPriceEnabled,\n unitPriceReferenceUnit: before.unitPriceReferenceUnit ?? null,\n unitPriceBaseQuantity: before.unitPriceBaseQuantity ?? null,\n weightValue: before.weightValue ?? null,\n weightUnit: before.weightUnit ?? null,\n dimensions: before.dimensions ? cloneJson(before.dimensions) : null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n customFieldsetCode: before.customFieldsetCode ?? null,\n optionSchemaTemplate: before.optionSchemaId\n ? em.getReference(CatalogOptionSchemaTemplate, before.optionSchemaId)\n : null,\n productType: before.productType ?? \"simple\",\n isConfigurable: before.isConfigurable,\n isActive: before.isActive,\n createdAt: new Date(before.createdAt),\n updatedAt: new Date(before.updatedAt),\n });\n em.persist(record);\n }\n ensureTenantScope(ctx, before.tenantId);\n ensureOrganizationScope(ctx, before.organizationId);\n applyProductSnapshot(em, record, before);\n await em.flush();\n\n const relationEm = em.fork();\n const relationRecord = await findOneWithDecryption(relationEm, CatalogProduct, { id: before.id });\n if (relationRecord) {\n await restoreOffersFromSnapshot(relationEm, relationRecord, before.offers);\n await syncCategoryAssignments(relationEm, relationRecord, before.categoryIds);\n await syncProductTags(relationEm, relationRecord, before.tags);\n await relationEm.flush();\n }\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n const resetValues = buildCustomFieldResetMap(\n before.custom ?? undefined,\n payload?.after?.custom ?? undefined,\n );\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: resetValues,\n });\n }\n await emitProductCrudUndoChange({\n dataEngine,\n action: \"updated\",\n product: record,\n });\n },\n};\n\nconst deleteProductCommand: CommandHandler<\n { body?: Record<string, unknown>; query?: Record<string, unknown> },\n { productId: string }\n> = {\n id: \"catalog.products.delete\",\n async prepare(input, ctx) {\n const id = requireId(input, \"Product id is required\");\n const em = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadProductSnapshot(em, id);\n if (snapshot) {\n ensureTenantScope(ctx, snapshot.tenantId);\n ensureOrganizationScope(ctx, snapshot.organizationId);\n }\n return snapshot ? { before: snapshot } : {};\n },\n async execute(input, ctx) {\n const id = requireId(input, \"Product id is required\");\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n const record = await findOneWithDecryption(\n em,\n CatalogProduct,\n { id },\n { populate: [\"optionSchemaTemplate\"] },\n );\n if (!record) {\n const { translate } = await resolveTranslations();\n throw new CrudHttpError(404, {\n error: translate(\n \"catalog.products.errors.notFound\",\n \"Catalog product not found\",\n ),\n });\n }\n const baseEm = ctx.container.resolve(\"em\") as EntityManager;\n const snapshot = await loadProductSnapshot(baseEm, id);\n ensureTenantScope(ctx, record.tenantId);\n ensureOrganizationScope(ctx, record.organizationId);\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n await deleteProductVariantsAndRelatedData({\n em,\n product: record,\n dataEngine,\n ctx,\n });\n await em.nativeDelete(CatalogProductPrice, { product: record.id });\n const templateToRemove = await resolveOptionSchemaTemplateForRemoval(\n em,\n record,\n );\n if (templateToRemove) {\n record.optionSchemaTemplate = null;\n em.remove(templateToRemove);\n }\n em.remove(record);\n await em.flush();\n if (snapshot?.custom && Object.keys(snapshot.custom).length) {\n const resetValues = buildCustomFieldResetMap(snapshot.custom, undefined);\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: resetValues,\n });\n }\n }\n await emitProductCrudChange({\n dataEngine,\n action: \"deleted\",\n product: record,\n });\n return { productId: id };\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as ProductSnapshot | undefined;\n if (!before) return null;\n const { translate } = await resolveTranslations();\n return {\n actionLabel: translate(\n \"catalog.audit.products.delete\",\n \"Delete catalog product\",\n ),\n resourceKind: \"catalog.product\",\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies ProductUndoPayload,\n },\n };\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ProductUndoPayload>(logEntry);\n const before = payload?.before;\n if (!before) return;\n const em = (ctx.container.resolve(\"em\") as EntityManager).fork();\n let record = await findOneWithDecryption(em, CatalogProduct, { id: before.id });\n if (!record) {\n record = em.create(CatalogProduct, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n title: before.title,\n subtitle: before.subtitle ?? null,\n description: before.description ?? null,\n sku: before.sku ?? null,\n handle: before.handle ?? null,\n taxRateId: before.taxRateId ?? null,\n taxRate: before.taxRate ?? null,\n statusEntryId: before.statusEntryId ?? null,\n primaryCurrencyCode: before.primaryCurrencyCode ?? null,\n defaultUnit: before.defaultUnit ?? null,\n defaultSalesUnit: before.defaultSalesUnit ?? null,\n defaultSalesUnitQuantity: before.defaultSalesUnitQuantity ?? \"1\",\n uomRoundingScale: before.uomRoundingScale,\n uomRoundingMode: before.uomRoundingMode,\n unitPriceEnabled: before.unitPriceEnabled,\n unitPriceReferenceUnit: before.unitPriceReferenceUnit ?? null,\n unitPriceBaseQuantity: before.unitPriceBaseQuantity ?? null,\n weightValue: before.weightValue ?? null,\n weightUnit: before.weightUnit ?? null,\n dimensions: before.dimensions ? cloneJson(before.dimensions) : null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n customFieldsetCode: before.customFieldsetCode ?? null,\n optionSchemaTemplate: before.optionSchemaId\n ? em.getReference(CatalogOptionSchemaTemplate, before.optionSchemaId)\n : null,\n productType: before.productType ?? \"simple\",\n isConfigurable: before.isConfigurable,\n isActive: before.isActive,\n createdAt: new Date(before.createdAt),\n updatedAt: new Date(before.updatedAt),\n });\n em.persist(record);\n }\n ensureTenantScope(ctx, before.tenantId);\n ensureOrganizationScope(ctx, before.organizationId);\n applyProductSnapshot(em, record, before);\n await em.flush();\n\n const relationEm = em.fork();\n const relationRecord = await findOneWithDecryption(relationEm, CatalogProduct, { id: before.id });\n if (relationRecord) {\n await restoreOffersFromSnapshot(relationEm, relationRecord, before.offers);\n await syncCategoryAssignments(relationEm, relationRecord, before.categoryIds);\n await syncProductTags(relationEm, relationRecord, before.tags);\n await relationEm.flush();\n }\n const dataEngine = ctx.container.resolve(\"dataEngine\") as DataEngine;\n if (before.custom && Object.keys(before.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: before.custom,\n });\n }\n await emitProductCrudUndoChange({\n dataEngine,\n action: \"created\",\n product: record,\n });\n },\n};\n\nregisterCommand(createProductCommand);\nregisterCommand(updateProductCommand);\nregisterCommand(deleteProductCommand);\n\nfunction resolveProductUniqueConstraint(\n error: unknown,\n): \"handle\" | \"sku\" | null {\n if (!(error instanceof UniqueConstraintViolationException)) return null;\n const constraint = getErrorConstraint(error);\n if (constraint === \"catalog_products_handle_scope_unique\") return \"handle\";\n if (constraint === \"catalog_products_sku_scope_unique\") return \"sku\";\n const message = getErrorMessage(error).toLowerCase();\n if (\n message.includes(\"catalog_products_handle_scope_unique\") ||\n message.includes(\" handle\")\n ) {\n return \"handle\";\n }\n if (\n message.includes(\"catalog_products_sku_scope_unique\") ||\n message.includes(\" sku\")\n ) {\n return \"sku\";\n }\n return null;\n}\n\nasync function rethrowProductUniqueConstraint(error: unknown): Promise<never> {\n const target = resolveProductUniqueConstraint(error);\n if (target === \"handle\") await throwDuplicateHandleError();\n if (target === \"sku\") await throwDuplicateSkuError();\n throw error;\n}\n\nasync function throwDuplicateHandleError(): Promise<never> {\n const { translate } = await resolveTranslations();\n const message = translate(\n \"catalog.products.errors.handleExists\",\n \"Handle already in use.\",\n );\n throw new CrudHttpError(400, {\n error: message,\n fieldErrors: { handle: message },\n details: [\n { path: [\"handle\"], message, code: \"duplicate\", origin: \"validation\" },\n ],\n });\n}\n\nasync function throwDuplicateSkuError(): Promise<never> {\n const { translate } = await resolveTranslations();\n const message = translate(\n \"catalog.products.errors.skuExists\",\n \"SKU already in use.\",\n );\n throw new CrudHttpError(400, {\n error: message,\n fieldErrors: { sku: message },\n details: [\n { path: [\"sku\"], message, code: \"duplicate\", origin: \"validation\" },\n ],\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -66,6 +66,7 @@ function ProductsDataTable() {
66
66
  const [page, setPage] = React.useState(1);
67
67
  const [total, setTotal] = React.useState(0);
68
68
  const [totalPages, setTotalPages] = React.useState(1);
69
+ const [cacheStatus, setCacheStatus] = React.useState(null);
69
70
  const [sorting, setSorting] = React.useState([{ id: "title", desc: false }]);
70
71
  const [search, setSearch] = React.useState("");
71
72
  const [filterValues, setFilterValues] = React.useState({});
@@ -411,6 +412,7 @@ function ProductsDataTable() {
411
412
  let cancelled = false;
412
413
  async function load() {
413
414
  setIsLoading(true);
415
+ setCacheStatus(null);
414
416
  try {
415
417
  const fallback = { items: [], total: 0, totalPages: 1 };
416
418
  const call = await apiCall(
@@ -421,10 +423,12 @@ function ProductsDataTable() {
421
423
  if (!call.ok) {
422
424
  const message = t("catalog.products.list.error.load", "Failed to load products");
423
425
  flash(message, "error");
426
+ if (!cancelled) setCacheStatus(null);
424
427
  return;
425
428
  }
426
429
  const payload = call.result ?? fallback;
427
430
  if (cancelled) return;
431
+ setCacheStatus(call.cacheStatus ?? null);
428
432
  const items = Array.isArray(payload.items) ? payload.items : [];
429
433
  const normalized = items.filter((item) => typeof item?.id === "string");
430
434
  setRows(normalized);
@@ -432,6 +436,7 @@ function ProductsDataTable() {
432
436
  setTotalPages(typeof payload.totalPages === "number" ? payload.totalPages : 1);
433
437
  } catch (error) {
434
438
  if (!cancelled) {
439
+ setCacheStatus(null);
435
440
  const message = error instanceof Error ? error.message : t("catalog.products.list.error.load", "Failed to load products");
436
441
  flash(message, "error");
437
442
  }
@@ -498,7 +503,9 @@ function ProductsDataTable() {
498
503
  injectionContext: {
499
504
  search,
500
505
  filters: filterValues,
506
+ customFieldset: customFieldsetFilter,
501
507
  page,
508
+ sorting,
502
509
  scopeVersion
503
510
  },
504
511
  pagination: {
@@ -506,7 +513,8 @@ function ProductsDataTable() {
506
513
  pageSize: PAGE_SIZE,
507
514
  total,
508
515
  totalPages,
509
- onPageChange: setPage
516
+ onPageChange: setPage,
517
+ cacheStatus
510
518
  },
511
519
  exporter: exportConfig,
512
520
  isLoading,