@open-mercato/core 0.4.6-develop-e321a4e2a1 → 0.4.6-main-24e64eef39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -22
- package/dist/modules/api_docs/frontend/docs/api/page.js +1 -1
- package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +1 -0
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +1 -1
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/lib/partitionEnv.js +1 -1
- package/dist/modules/attachments/lib/partitionEnv.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +1 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/cli.js +1 -1
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +1 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/business_rules/components/utils/formHelpers.js +1 -1
- package/dist/modules/business_rules/components/utils/formHelpers.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +1 -1
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +1 -1
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/shared.js +1 -1
- package/dist/modules/catalog/commands/shared.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +1 -1
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js +1 -1
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js.map +1 -1
- package/dist/modules/currencies/services/providers/raiffeisen.js +1 -1
- package/dist/modules/currencies/services/providers/raiffeisen.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +3 -3
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +3 -3
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +3 -3
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/cli.js +2 -2
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/lib/detailHelpers.js +1 -1
- package/dist/modules/customers/lib/detailHelpers.js.map +2 -2
- package/dist/modules/entities/cli.js +1 -1
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/lib/field-definitions.js +1 -1
- package/dist/modules/entities/lib/field-definitions.js.map +2 -2
- package/dist/modules/entities/lib/install-from-ce.js +1 -1
- package/dist/modules/entities/lib/install-from-ce.js.map +2 -2
- package/dist/modules/inbox_ops/lib/emailParser.js +1 -1
- package/dist/modules/inbox_ops/lib/emailParser.js.map +2 -2
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js +0 -8
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +1 -1
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +7 -7
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +1 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -3
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/commands/resources.js +1 -1
- package/dist/modules/resources/commands/resources.js.map +2 -2
- package/dist/modules/resources/lib/seeds.js +1 -1
- package/dist/modules/resources/lib/seeds.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js +1 -1
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js +1 -1
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -3
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +2 -2
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/channels/offerTableUtils.js +2 -3
- package/dist/modules/sales/components/channels/offerTableUtils.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -4
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +1 -1
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/lib/shipments/snapshots.js.map +1 -1
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -8
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +2 -2
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -8
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -3
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -3
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -3
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -3
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +2 -2
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +1 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -1
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/lib/graph-utils.js +1 -1
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +1 -1
- package/src/modules/attachments/api/library/[id]/route.ts +1 -0
- package/src/modules/attachments/components/AttachmentLibrary.tsx +1 -1
- package/src/modules/attachments/lib/partitionEnv.ts +1 -1
- package/src/modules/auth/backend/users/page.tsx +1 -1
- package/src/modules/auth/cli.ts +1 -1
- package/src/modules/auth/commands/users.ts +1 -1
- package/src/modules/business_rules/components/utils/formHelpers.ts +1 -1
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +1 -1
- package/src/modules/catalog/commands/products.ts +1 -1
- package/src/modules/catalog/commands/shared.ts +1 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +1 -1
- package/src/modules/catalog/components/products/productForm.ts +1 -1
- package/src/modules/configs/lib/upgrade-actions.ts +1 -1
- package/src/modules/currencies/services/providers/raiffeisen.ts +1 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +3 -3
- package/src/modules/customers/backend/customers/deals/page.tsx +3 -3
- package/src/modules/customers/backend/customers/people/page.tsx +3 -3
- package/src/modules/customers/cli.ts +2 -2
- package/src/modules/customers/lib/detailHelpers.ts +1 -1
- package/src/modules/entities/cli.ts +1 -1
- package/src/modules/entities/lib/field-definitions.ts +1 -1
- package/src/modules/entities/lib/install-from-ce.ts +1 -1
- package/src/modules/inbox_ops/lib/emailParser.ts +1 -1
- package/src/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.tsx +0 -8
- package/src/modules/perspectives/services/perspectiveService.ts +1 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -3
- package/src/modules/query_index/components/QueryIndexesTable.tsx +7 -7
- package/src/modules/query_index/lib/engine.ts +1 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +3 -2
- package/src/modules/resources/backend/resources/resources/page.tsx +3 -3
- package/src/modules/resources/commands/resources.ts +1 -1
- package/src/modules/resources/lib/seeds.ts +1 -1
- package/src/modules/sales/api/dashboard/widgets/new-orders/route.ts +1 -1
- package/src/modules/sales/api/dashboard/widgets/new-quotes/route.ts +1 -1
- package/src/modules/sales/backend/sales/channels/page.tsx +3 -3
- package/src/modules/sales/commands/documents.ts +2 -2
- package/src/modules/sales/components/channels/offerTableUtils.tsx +2 -3
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +4 -4
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +1 -1
- package/src/modules/sales/lib/shipments/snapshots.ts +1 -1
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -8
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -8
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +3 -3
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +3 -3
- package/src/modules/staff/backend/staff/team-members/page.tsx +3 -3
- package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -3
- package/src/modules/staff/backend/staff/teams/page.tsx +3 -2
- package/src/modules/workflows/backend/instances/page.tsx +2 -2
- package/src/modules/workflows/backend/tasks/page.tsx +1 -1
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -1
- package/src/modules/workflows/lib/graph-utils.ts +1 -1
- package/dist/modules/integrations/acl.js +0 -8
- package/dist/modules/integrations/acl.js.map +0 -7
- package/dist/modules/integrations/data/enrichers.js +0 -72
- package/dist/modules/integrations/data/enrichers.js.map +0 -7
- package/dist/modules/integrations/data/entities.js +0 -63
- package/dist/modules/integrations/data/entities.js.map +0 -7
- package/dist/modules/integrations/index.js +0 -9
- package/dist/modules/integrations/index.js.map +0 -7
- package/dist/modules/integrations/setup.js +0 -13
- package/dist/modules/integrations/setup.js.map +0 -7
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +0 -69
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +0 -7
- package/dist/modules/integrations/widgets/injection-table.js +0 -13
- package/dist/modules/integrations/widgets/injection-table.js.map +0 -7
- package/src/modules/integrations/acl.ts +0 -4
- package/src/modules/integrations/data/enrichers.ts +0 -98
- package/src/modules/integrations/data/entities.ts +0 -46
- package/src/modules/integrations/index.ts +0 -5
- package/src/modules/integrations/setup.ts +0 -11
- package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +0 -94
- package/src/modules/integrations/widgets/injection-table.ts +0 -17
|
@@ -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 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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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -26,7 +26,7 @@ function randomSuffix(length = 6) {
|
|
|
26
26
|
function normalizeOptionSchemaCode(value) {
|
|
27
27
|
if (!value || typeof value !== "string") return "";
|
|
28
28
|
const ascii = value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
|
|
29
|
-
const slug = ascii.toLowerCase().trim().replace(/[^a-z0-9\-_]+/g, "-").replace(/-+/g, "-").replace(
|
|
29
|
+
const slug = ascii.toLowerCase().trim().replace(/[^a-z0-9\-_]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
30
30
|
return slug.slice(0, OPTION_SCHEMA_CODE_MAX_LENGTH);
|
|
31
31
|
}
|
|
32
32
|
function resolveOptionSchemaCode(opts) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/catalog/commands/shared.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n CatalogProduct,\n CatalogOffer,\n CatalogProductVariant,\n CatalogOptionSchemaTemplate,\n CatalogPriceKind,\n} from '../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nexport { ensureOrganizationScope, ensureSameScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nexport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\n\ntype QueryIndexCrudAction = 'created' | 'updated' | 'deleted'\n\nexport function ensureSameTenant(entity: Pick<{ tenantId: string }, 'tenantId'>, tenantId: string): void {\n if (entity.tenantId !== tenantId) {\n throw new CrudHttpError(403, { error: 'Cross-tenant relation forbidden' })\n }\n}\n\nexport { assertFound } from '@open-mercato/shared/lib/crud/errors'\n\nexport function cloneJson<T>(value: T): T {\n if (value === null || value === undefined) return value\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nconst OPTION_SCHEMA_CODE_MAX_LENGTH = 150\n\nexport function randomSuffix(length = 6): string {\n return Math.random().toString(36).slice(2, 2 + length)\n}\n\nexport function normalizeOptionSchemaCode(value?: string | null): string {\n if (!value || typeof value !== 'string') return ''\n const ascii = value.normalize('NFKD').replace(/[\\u0300-\\u036f]/g, '')\n const slug = ascii\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9\\-_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(
|
|
5
|
-
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,qBAAqB;AAE9B,SAAS,6BAA6B;AACtC,SAAS,yBAAyB,iBAAiB,yBAAyB;AAC5E,SAAS,0BAA0B;AAI5B,SAAS,iBAAiB,QAAgD,UAAwB;AACvG,MAAI,OAAO,aAAa,UAAU;AAChC,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,kCAAkC,CAAC;AAAA,EAC3E;AACF;AAEA,SAAS,mBAAmB;AAErB,SAAS,UAAa,OAAa;AACxC,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,SAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AACzC;AAEA,MAAM,gCAAgC;AAE/B,SAAS,aAAa,SAAS,GAAW;AAC/C,SAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,IAAI,MAAM;AACvD;AAEO,SAAS,0BAA0B,OAA+B;AACvE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,QAAQ,MAAM,UAAU,MAAM,EAAE,QAAQ,oBAAoB,EAAE;AACpE,QAAM,OAAO,MACV,YAAY,EACZ,KAAK,EACL,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,OAAO,GAAG,EAClB,QAAQ,
|
|
4
|
+
"sourcesContent": ["import {\n CatalogProduct,\n CatalogOffer,\n CatalogProductVariant,\n CatalogOptionSchemaTemplate,\n CatalogPriceKind,\n} from '../data/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nexport { ensureOrganizationScope, ensureSameScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nexport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\n\ntype QueryIndexCrudAction = 'created' | 'updated' | 'deleted'\n\nexport function ensureSameTenant(entity: Pick<{ tenantId: string }, 'tenantId'>, tenantId: string): void {\n if (entity.tenantId !== tenantId) {\n throw new CrudHttpError(403, { error: 'Cross-tenant relation forbidden' })\n }\n}\n\nexport { assertFound } from '@open-mercato/shared/lib/crud/errors'\n\nexport function cloneJson<T>(value: T): T {\n if (value === null || value === undefined) return value\n return JSON.parse(JSON.stringify(value)) as T\n}\n\nconst OPTION_SCHEMA_CODE_MAX_LENGTH = 150\n\nexport function randomSuffix(length = 6): string {\n return Math.random().toString(36).slice(2, 2 + length)\n}\n\nexport function normalizeOptionSchemaCode(value?: string | null): string {\n if (!value || typeof value !== 'string') return ''\n const ascii = value.normalize('NFKD').replace(/[\\u0300-\\u036f]/g, '')\n const slug = ascii\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9\\-_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '')\n return slug.slice(0, OPTION_SCHEMA_CODE_MAX_LENGTH)\n}\n\nexport function resolveOptionSchemaCode(opts: {\n code?: string | null\n name?: string | null\n fallback?: string | null\n uniqueHint?: string | null\n}): string {\n const baseCandidate =\n normalizeOptionSchemaCode(opts.code) ||\n normalizeOptionSchemaCode(opts.name) ||\n normalizeOptionSchemaCode(opts.fallback)\n let resolved = baseCandidate || ''\n if (!resolved) {\n resolved = `schema-${randomSuffix()}`\n }\n if (opts.uniqueHint) {\n const hinted = normalizeOptionSchemaCode(`${resolved}-${opts.uniqueHint}`)\n if (hinted) {\n resolved = hinted\n }\n }\n return resolved || `schema-${randomSuffix()}`\n}\n\nexport function toNumericString(value: number | null | undefined): string | null {\n if (value === undefined || value === null) return null\n return value.toString()\n}\n\nexport async function requireProduct(\n em: EntityManager,\n id: string,\n message = 'Catalog product not found'\n): Promise<CatalogProduct> {\n const product = await findOneWithDecryption(em, CatalogProduct, { id, deletedAt: null })\n if (!product) throw new CrudHttpError(404, { error: message })\n return product\n}\n\nexport async function requireVariant(\n em: EntityManager,\n id: string,\n message = 'Catalog variant not found'\n): Promise<CatalogProductVariant> {\n const variant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n { id, deletedAt: null },\n { populate: ['product'] },\n )\n if (!variant) throw new CrudHttpError(404, { error: message })\n return variant\n}\n\nexport async function requireOffer(\n em: EntityManager,\n id: string,\n message = 'Catalog offer not found'\n): Promise<CatalogOffer> {\n const offer = await findOneWithDecryption(em, CatalogOffer, { id })\n if (!offer) throw new CrudHttpError(404, { error: message })\n return offer\n}\n\nexport async function requirePriceKind(\n em: EntityManager,\n id: string,\n message = 'Catalog price kind not found'\n): Promise<CatalogPriceKind> {\n const priceKind = await findOneWithDecryption(em, CatalogPriceKind, { id, deletedAt: null })\n if (!priceKind) throw new CrudHttpError(404, { error: message })\n return priceKind\n}\n\nexport async function requireOptionSchemaTemplate(\n em: EntityManager,\n id: string,\n message = 'Option schema not found'\n): Promise<CatalogOptionSchemaTemplate> {\n const schema = await findOneWithDecryption(em, CatalogOptionSchemaTemplate, { id, deletedAt: null })\n if (!schema) throw new CrudHttpError(404, { error: message })\n return schema\n}\n\nexport function getErrorConstraint(error: unknown): string | null {\n const errObj = error as { constraint?: unknown; message?: unknown }\n if (typeof errObj.constraint === 'string') return errObj.constraint\n if (typeof errObj.message === 'string') {\n return null\n }\n return null\n}\n\nexport function getErrorMessage(error: unknown): string {\n const errObj = error as { message?: unknown }\n return typeof errObj.message === 'string' ? errObj.message : ''\n}\n\nexport async function emitCatalogQueryIndexEvent(\n ctx: CommandRuntimeContext,\n params: {\n entityType: string\n recordId: string\n organizationId?: string | null\n tenantId?: string | null\n action: QueryIndexCrudAction\n coverageBaseDelta?: number\n },\n): Promise<void> {\n const entityType = String(params.entityType || '')\n const recordId = String(params.recordId || '')\n if (!entityType || !recordId) return\n\n let bus: { emitEvent: (event: string, payload: Record<string, unknown>, options?: Record<string, unknown>) => Promise<void> } | null = null\n try {\n bus = ctx.container.resolve('eventBus')\n } catch {\n bus = null\n }\n if (!bus?.emitEvent) return\n\n const payload: Record<string, unknown> = {\n entityType,\n recordId,\n organizationId: params.organizationId ?? null,\n tenantId: params.tenantId ?? null,\n crudAction: params.action,\n }\n if (params.coverageBaseDelta !== undefined) {\n payload.coverageBaseDelta = params.coverageBaseDelta\n } else if (params.action === 'created') {\n payload.coverageBaseDelta = 1\n } else if (params.action === 'deleted') {\n payload.coverageBaseDelta = -1\n }\n\n const eventName = params.action === 'deleted' ? 'query_index.delete_one' : 'query_index.upsert_one'\n await bus.emitEvent(eventName, payload).catch(() => undefined)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -43,7 +43,7 @@ const normalizePriceKind = (input) => {
|
|
|
43
43
|
return null;
|
|
44
44
|
};
|
|
45
45
|
const toBooleanValue = (value) => typeof value === "boolean" ? value : null;
|
|
46
|
-
const resolveDisplayMode = (value) => value === "including-tax" ? "including-tax" : "excluding-tax";
|
|
46
|
+
const resolveDisplayMode = (value) => value === "including-tax" ? "including-tax" : value === "excluding-tax" ? "excluding-tax" : "excluding-tax";
|
|
47
47
|
const displayMode = resolveDisplayMode(
|
|
48
48
|
toStringValue(raw.displayMode) ?? toStringValue(raw.display_mode)
|
|
49
49
|
);
|