@open-mercato/core 0.6.4-develop.3944.1.4100aa7fbe → 0.6.4-develop.3962.1.70f30e284c

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.
@@ -1,4 +1,4 @@
1
- [build:core] found 2634 entry points
1
+ [build:core] found 2636 entry points
2
2
  [build:core] built successfully
3
3
  [build:core:generated] found 172 entry points
4
4
  [build:core:generated] built successfully
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=global.d.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -59,7 +59,10 @@ const VARIANT_CHANGE_KEYS = [
59
59
  async function loadVariantSnapshot(em, id, options = {}) {
60
60
  const record = await em.findOne(CatalogProductVariant, { id, deletedAt: null });
61
61
  if (!record) return null;
62
- const prices = options.includePrices ? await loadVariantPriceSnapshots(em, record.id) : null;
62
+ const prices = options.includePrices ? await loadVariantPriceSnapshots(em, record.id, {
63
+ tenantId: record.tenantId,
64
+ organizationId: record.organizationId
65
+ }) : null;
63
66
  const custom = await loadCustomFieldSnapshot(em, {
64
67
  entityId: E.catalog.catalog_product_variant,
65
68
  recordId: record.id,
@@ -136,13 +139,13 @@ async function resolveVariantTaxRate(em, product, taxRateIdInput, taxRateInput)
136
139
  }
137
140
  return { taxRateId: taxRateIdInput, taxRate: record.rate ?? normalizedRate };
138
141
  }
139
- async function loadVariantPriceSnapshots(em, variantId) {
142
+ async function loadVariantPriceSnapshots(em, variantId, scope) {
140
143
  const prices = await findWithDecryption(
141
144
  em,
142
145
  CatalogProductPrice,
143
- { variant: variantId },
146
+ { variant: variantId, tenantId: scope.tenantId, organizationId: scope.organizationId },
144
147
  { populate: ["priceKind", "product", "offer"] },
145
- { tenantId: null, organizationId: null }
148
+ { tenantId: scope.tenantId, organizationId: scope.organizationId }
146
149
  );
147
150
  const snapshots = [];
148
151
  for (const price of prices) {
@@ -740,7 +743,10 @@ const deleteVariantCommand = {
740
743
  const baseEm = ctx.container.resolve("em");
741
744
  const snapshot = await loadVariantSnapshot(baseEm, id, { includePrices: true });
742
745
  const dataEngine = ctx.container.resolve("dataEngine");
743
- const priceSnapshots = snapshot?.prices && snapshot.prices.length ? snapshot.prices : await loadVariantPriceSnapshots(baseEm, id);
746
+ const priceSnapshots = snapshot?.prices && snapshot.prices.length ? snapshot.prices : await loadVariantPriceSnapshots(baseEm, id, {
747
+ tenantId: record.tenantId,
748
+ organizationId: record.organizationId
749
+ });
744
750
  if (priceSnapshots.length) {
745
751
  await em.nativeDelete(CatalogProductPrice, { id: { $in: priceSnapshots.map((price) => price.id) } });
746
752
  } else {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/catalog/commands/variants.ts"],
4
- "sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { buildChanges, requireId, parseWithCustomFields, setCustomFieldsIfAny, emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { UniqueConstraintViolationException } from '@mikro-orm/core'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { loadCustomFieldSnapshot, buildCustomFieldResetMap } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { E } from '#generated/entities.ids.generated'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CatalogProductVariant,\n CatalogProductPrice,\n CatalogProduct,\n CatalogOffer,\n CatalogPriceKind,\n} from '../data/entities'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport {\n variantCreateSchema,\n variantUpdateSchema,\n type VariantCreateInput,\n type VariantUpdateInput,\n} from '../data/validators'\nimport {\n cloneJson,\n ensureOrganizationScope,\n ensureTenantScope,\n emitCatalogQueryIndexEvent,\n extractUndoPayload,\n requireProduct,\n toNumericString,\n getErrorConstraint,\n getErrorMessage,\n} from './shared'\nimport { SalesTaxRate } from '@open-mercato/core/modules/sales/data/entities'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\n\nconst variantCrudEvents: CrudEventsConfig = {\n module: 'catalog',\n entity: 'variant',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype VariantSnapshot = {\n id: string\n productId: string\n organizationId: string\n tenantId: string\n name: string | null\n sku: string | null\n barcode: string | null\n statusEntryId: string | null\n isDefault: boolean\n isActive: boolean\n weightValue: string | null\n weightUnit: string | null\n taxRateId: string | null\n taxRate: string | null\n dimensions: Record<string, unknown> | null\n metadata: Record<string, unknown> | null\n optionValues: Record<string, string> | null\n customFieldsetCode: string | null\n createdAt: string\n updatedAt: string\n custom: Record<string, unknown> | null\n prices?: VariantPriceSnapshot[] | null\n}\n\ntype VariantUndoPayload = {\n before?: VariantSnapshot | null\n after?: VariantSnapshot | null\n previousDefaultVariantId?: string | null\n}\n\nconst VARIANT_CHANGE_KEYS = [\n 'name',\n 'sku',\n 'barcode',\n 'statusEntryId',\n 'isDefault',\n 'isActive',\n 'weightValue',\n 'weightUnit',\n 'taxRateId',\n 'taxRate',\n 'dimensions',\n 'optionValues',\n 'customFieldsetCode',\n 'metadata',\n] as const satisfies readonly string[]\n\nasync function loadVariantSnapshot(\n em: EntityManager,\n id: string,\n options: { includePrices?: boolean } = {}\n): Promise<VariantSnapshot | null> {\n const record = await em.findOne(CatalogProductVariant, { id, deletedAt: null })\n if (!record) return null\n const prices = options.includePrices ? await loadVariantPriceSnapshots(em, record.id) : null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_variant,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n const productId = typeof record.product === 'string' ? record.product : record.product.id\n return {\n id: record.id,\n productId,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n name: record.name ?? null,\n sku: record.sku ?? null,\n barcode: record.barcode ?? null,\n statusEntryId: record.statusEntryId ?? null,\n isDefault: record.isDefault,\n isActive: record.isActive,\n weightValue: record.weightValue ?? null,\n weightUnit: record.weightUnit ?? null,\n taxRateId: record.taxRateId ?? null,\n taxRate: record.taxRate ?? null,\n dimensions: record.dimensions ? cloneJson(record.dimensions) : null,\n metadata: record.metadata ? cloneJson(record.metadata) : null,\n optionValues: record.optionValues ? cloneJson(record.optionValues) : null,\n customFieldsetCode: record.customFieldsetCode ?? null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n custom: Object.keys(custom).length ? custom : null,\n prices: prices && prices.length ? prices : null,\n }\n}\n\nfunction applyVariantSnapshot(record: CatalogProductVariant, snapshot: VariantSnapshot): void {\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.name = snapshot.name ?? null\n record.sku = snapshot.sku ?? null\n record.barcode = snapshot.barcode ?? null\n record.statusEntryId = snapshot.statusEntryId ?? null\n record.isDefault = snapshot.isDefault\n record.isActive = snapshot.isActive\n record.weightValue = snapshot.weightValue ?? null\n record.weightUnit = snapshot.weightUnit ?? null\n record.taxRateId = snapshot.taxRateId ?? null\n record.taxRate = snapshot.taxRate ?? null\n record.dimensions = snapshot.dimensions ? cloneJson(snapshot.dimensions) : null\n record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null\n record.optionValues = snapshot.optionValues ? cloneJson(snapshot.optionValues) : null\n record.customFieldsetCode = snapshot.customFieldsetCode ?? null\n record.createdAt = new Date(snapshot.createdAt)\n record.updatedAt = new Date(snapshot.updatedAt)\n}\n\nasync function resolveVariantTaxRate(\n em: EntityManager,\n product: CatalogProduct,\n taxRateIdInput: string | null | undefined,\n taxRateInput: number | string | null | undefined\n): Promise<{ taxRateId: string | null; taxRate: string | null }> {\n const organizationId = product.organizationId\n const tenantId = product.tenantId\n const normalizedRate =\n taxRateInput === null || taxRateInput === undefined\n ? null\n : (() => {\n const numeric = typeof taxRateInput === 'string' ? Number(taxRateInput) : taxRateInput\n return Number.isFinite(numeric) ? toNumericString(numeric) : null\n })()\n if (taxRateIdInput === null) {\n return { taxRateId: product.taxRateId ?? null, taxRate: product.taxRate ?? null }\n }\n if (!taxRateIdInput) {\n return { taxRateId: product.taxRateId ?? null, taxRate: product.taxRate ?? normalizedRate }\n }\n const record = await em.findOne(SalesTaxRate, {\n id: taxRateIdInput,\n organizationId,\n tenantId,\n deletedAt: null,\n })\n if (!record) {\n throw new CrudHttpError(400, { error: 'Tax class not found' })\n }\n return { taxRateId: taxRateIdInput, taxRate: record.rate ?? normalizedRate }\n}\n\ntype VariantPriceSnapshot = {\n id: string\n variantId: string | null\n productId: string | null\n offerId: string | null\n organizationId: string\n tenantId: string\n priceKindId: string\n priceKindCode: string\n currencyCode: string\n kind: string\n minQuantity: number\n maxQuantity: number | null\n unitPriceNet: string | null\n unitPriceGross: string | null\n taxRate: string | null\n taxAmount: string | null\n channelId: string | null\n userId: string | null\n userGroupId: string | null\n customerId: string | null\n customerGroupId: string | null\n metadata: Record<string, unknown> | null\n startsAt: string | null\n endsAt: string | null\n createdAt: string\n updatedAt: string\n custom: Record<string, unknown> | null\n}\n\nasync function loadVariantPriceSnapshots(\n em: EntityManager,\n variantId: string\n): Promise<VariantPriceSnapshot[]> {\n const prices = await findWithDecryption(\n em,\n CatalogProductPrice,\n { variant: variantId },\n { populate: ['priceKind', 'product', 'offer'] },\n { tenantId: null, organizationId: null },\n )\n const snapshots: VariantPriceSnapshot[] = []\n for (const price of prices) {\n const variantRef = price.variant\n const variantIdValue =\n typeof variantRef === 'string'\n ? variantRef\n : variantRef\n ? variantRef.id\n : null\n const productRef = price.product\n ? price.product\n : typeof price.variant === 'object' && price.variant\n ? price.variant.product\n : null\n const productId =\n typeof productRef === 'string'\n ? productRef\n : productRef\n ? productRef.id\n : null\n const priceKindRef = price.priceKind\n const priceKindId =\n typeof priceKindRef === 'string'\n ? priceKindRef\n : priceKindRef\n ? priceKindRef.id\n : null\n if (!priceKindId) {\n throw new CrudHttpError(400, { error: 'Price is missing price kind metadata.' })\n }\n const priceKindCode =\n typeof priceKindRef === 'object' && priceKindRef ? priceKindRef.code : price.kind\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_price,\n recordId: price.id,\n tenantId: price.tenantId,\n organizationId: price.organizationId,\n })\n snapshots.push({\n id: price.id,\n variantId: variantIdValue,\n productId,\n offerId: typeof price.offer === 'string' ? price.offer : price.offer ? price.offer.id : null,\n organizationId: price.organizationId,\n tenantId: price.tenantId,\n priceKindId,\n priceKindCode,\n currencyCode: price.currencyCode,\n kind: price.kind,\n minQuantity: price.minQuantity,\n maxQuantity: price.maxQuantity ?? null,\n unitPriceNet: price.unitPriceNet ?? null,\n unitPriceGross: price.unitPriceGross ?? null,\n taxRate: price.taxRate ?? null,\n taxAmount: price.taxAmount ?? null,\n channelId: price.channelId ?? null,\n userId: price.userId ?? null,\n userGroupId: price.userGroupId ?? null,\n customerId: price.customerId ?? null,\n customerGroupId: price.customerGroupId ?? null,\n metadata: price.metadata ? cloneJson(price.metadata) : null,\n startsAt: price.startsAt ? price.startsAt.toISOString() : null,\n endsAt: price.endsAt ? price.endsAt.toISOString() : null,\n createdAt: price.createdAt.toISOString(),\n updatedAt: price.updatedAt.toISOString(),\n custom: Object.keys(custom).length ? custom : null,\n })\n }\n return snapshots\n}\n\nasync function restoreVariantPricesFromSnapshots(\n em: EntityManager,\n variant: CatalogProductVariant,\n snapshots: VariantPriceSnapshot[],\n dataEngine: DataEngine\n): Promise<void> {\n if (!snapshots.length) return\n const productRef =\n typeof variant.product === 'string'\n ? await requireProduct(em, variant.product)\n : variant.product\n for (const snapshot of snapshots) {\n const product =\n snapshot.productId && snapshot.productId !== productRef.id\n ? em.getReference(CatalogProduct, snapshot.productId)\n : productRef\n const offer = snapshot.offerId ? em.getReference(CatalogOffer, snapshot.offerId) : null\n const priceKind = em.getReference(CatalogPriceKind, snapshot.priceKindId)\n let record = await em.findOne(CatalogProductPrice, { id: snapshot.id })\n if (!record) {\n record = em.create(CatalogProductPrice, {\n id: snapshot.id,\n variant,\n product,\n offer,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n currencyCode: snapshot.currencyCode,\n priceKind,\n kind: snapshot.priceKindCode || snapshot.kind,\n minQuantity: snapshot.minQuantity,\n maxQuantity: snapshot.maxQuantity ?? null,\n unitPriceNet: snapshot.unitPriceNet ?? null,\n unitPriceGross: snapshot.unitPriceGross ?? null,\n taxRate: snapshot.taxRate ?? null,\n taxAmount: snapshot.taxAmount ?? null,\n channelId: snapshot.channelId ?? null,\n userId: snapshot.userId ?? null,\n userGroupId: snapshot.userGroupId ?? null,\n customerId: snapshot.customerId ?? null,\n customerGroupId: snapshot.customerGroupId ?? null,\n metadata: snapshot.metadata ? cloneJson(snapshot.metadata) : null,\n startsAt: snapshot.startsAt ? new Date(snapshot.startsAt) : null,\n endsAt: snapshot.endsAt ? new Date(snapshot.endsAt) : null,\n createdAt: new Date(snapshot.createdAt),\n updatedAt: new Date(snapshot.updatedAt),\n })\n em.persist(record)\n } else {\n record.variant = variant\n record.product = product\n record.offer = offer\n record.priceKind = priceKind\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.currencyCode = snapshot.currencyCode\n record.kind = snapshot.priceKindCode || snapshot.kind\n record.minQuantity = snapshot.minQuantity\n record.maxQuantity = snapshot.maxQuantity ?? null\n record.unitPriceNet = snapshot.unitPriceNet ?? null\n record.unitPriceGross = snapshot.unitPriceGross ?? null\n record.taxRate = snapshot.taxRate ?? null\n record.taxAmount = snapshot.taxAmount ?? null\n record.channelId = snapshot.channelId ?? null\n record.userId = snapshot.userId ?? null\n record.userGroupId = snapshot.userGroupId ?? null\n record.customerId = snapshot.customerId ?? null\n record.customerGroupId = snapshot.customerGroupId ?? null\n record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null\n record.startsAt = snapshot.startsAt ? new Date(snapshot.startsAt) : null\n record.endsAt = snapshot.endsAt ? new Date(snapshot.endsAt) : null\n record.createdAt = new Date(snapshot.createdAt)\n record.updatedAt = new Date(snapshot.updatedAt)\n }\n }\n await em.flush()\n for (const snapshot of snapshots) {\n if (!snapshot.custom || !Object.keys(snapshot.custom).length) continue\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product_price,\n recordId: snapshot.id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n values: snapshot.custom,\n })\n }\n}\n\ntype MetadataSplitResult = {\n metadata: Record<string, unknown> | null\n optionValues: Record<string, string> | null\n hadOptionValues: boolean\n}\n\nfunction splitOptionValuesFromMetadata(\n metadata?: Record<string, unknown> | null\n): MetadataSplitResult {\n if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) {\n return {\n metadata: metadata ? cloneJson(metadata) : null,\n optionValues: null,\n hadOptionValues: false,\n }\n }\n const { optionValues, ...rest } = metadata as Record<string, unknown> & {\n optionValues?: unknown\n }\n const normalizedMetadata = Object.keys(rest).length ? cloneJson(rest) : null\n return {\n metadata: normalizedMetadata,\n optionValues: normalizeOptionValues(optionValues),\n hadOptionValues: optionValues !== undefined,\n }\n}\n\nfunction normalizeOptionValues(input: unknown): Record<string, string> | null {\n if (!input || typeof input !== 'object' || Array.isArray(input)) return null\n const normalized: Record<string, string> = {}\n for (const [rawKey, rawValue] of Object.entries(input)) {\n if (typeof rawValue !== 'string') continue\n const key = rawKey.trim()\n const value = rawValue.trim()\n if (!key || !value) continue\n normalized[key] = value\n }\n return Object.keys(normalized).length ? normalized : null\n}\n\nfunction resolveProductId(record: CatalogProductVariant): string {\n return typeof record.product === 'string' ? record.product : record.product.id\n}\n\nasync function enforceSingleDefaultVariant(\n em: EntityManager,\n variant: CatalogProductVariant\n): Promise<string | null> {\n if (!variant.isDefault) return null\n const productId = resolveProductId(variant)\n const existingDefault = await em.findOne(\n CatalogProductVariant,\n { product: productId, isDefault: true, deletedAt: null, id: { $ne: variant.id } },\n { fields: ['id', 'isDefault'] }\n )\n if (existingDefault) {\n existingDefault.isDefault = false\n return existingDefault.id\n }\n return null\n}\n\nasync function aggregateVariantMediaToProduct(\n em: EntityManager,\n variant: CatalogProductVariant\n): Promise<void> {\n const productId = resolveProductId(variant)\n const buildKey = (\n attachment: Pick<Attachment, 'fileName' | 'fileSize' | 'storageDriver' | 'partitionCode' | 'storagePath'>\n ) =>\n [\n attachment.fileName?.trim() ?? '',\n attachment.fileSize ?? '',\n attachment.storageDriver ?? '',\n attachment.partitionCode ?? '',\n ].join('|')\n const attachments = await em.find(\n Attachment,\n {\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: variant.organizationId ?? undefined,\n tenantId: variant.tenantId ?? undefined,\n },\n {\n fields: [\n 'id',\n 'partitionCode',\n 'fileName',\n 'mimeType',\n 'fileSize',\n 'storageDriver',\n 'storagePath',\n 'storageMetadata',\n 'url',\n 'organizationId',\n 'tenantId',\n 'fileSize',\n 'storageDriver',\n 'partitionCode',\n ],\n }\n )\n if (!attachments.length) return\n const existing = await em.find(\n Attachment,\n {\n entityId: E.catalog.catalog_product,\n recordId: productId,\n organizationId: variant.organizationId ?? undefined,\n tenantId: variant.tenantId ?? undefined,\n },\n {\n fields: ['storagePath', 'fileName', 'fileSize', 'storageDriver', 'partitionCode'],\n }\n )\n const existingKeys = new Set(existing.map((item) => buildKey(item)))\n let created = 0\n for (const source of attachments) {\n const key = buildKey(source)\n if (existingKeys.has(key)) continue\n const clone = em.create(Attachment, {\n entityId: E.catalog.catalog_product,\n recordId: productId,\n organizationId: source.organizationId ?? variant.organizationId ?? null,\n tenantId: source.tenantId ?? variant.tenantId ?? null,\n partitionCode: source.partitionCode,\n fileName: source.fileName,\n mimeType: source.mimeType,\n fileSize: source.fileSize,\n storageDriver: source.storageDriver,\n storagePath: source.storagePath,\n storageMetadata: source.storageMetadata ? cloneJson(source.storageMetadata) : null,\n url: source.url,\n })\n em.persist(clone)\n existingKeys.add(key)\n created += 1\n }\n if (created > 0) {\n await em.flush()\n }\n}\n\nconst createVariantCommand: CommandHandler<VariantCreateInput, { variantId: string; previousDefaultVariantId?: string | null }> = {\n id: 'catalog.variants.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(variantCreateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const product = await requireProduct(em, parsed.productId)\n ensureTenantScope(ctx, product.tenantId)\n ensureOrganizationScope(ctx, product.organizationId)\n const { taxRateId, taxRate } = await resolveVariantTaxRate(\n em,\n product,\n parsed.taxRateId ?? null,\n parsed.taxRate\n )\n\n const metadataSplit = splitOptionValuesFromMetadata(parsed.metadata)\n const resolvedOptionValues =\n parsed.optionValues ?? (metadataSplit.hadOptionValues ? metadataSplit.optionValues : null)\n\n const now = new Date()\n const record = em.create(CatalogProductVariant, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n product,\n name: parsed.name ?? null,\n sku: parsed.sku ?? null,\n barcode: parsed.barcode ?? null,\n statusEntryId: parsed.statusEntryId ?? null,\n isDefault: parsed.isDefault ?? false,\n isActive: parsed.isActive ?? true,\n weightValue: toNumericString(parsed.weightValue),\n weightUnit: parsed.weightUnit ?? null,\n taxRateId,\n taxRate,\n dimensions: parsed.dimensions ? cloneJson(parsed.dimensions) : null,\n metadata: metadataSplit.metadata,\n optionValues: resolvedOptionValues ? cloneJson(resolvedOptionValues) : null,\n customFieldsetCode: parsed.customFieldsetCode ?? null,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n try {\n await em.flush()\n } catch (error) {\n await rethrowVariantUniqueConstraint(error)\n }\n let previousDefaultVariantId: string | null = null\n if (record.isDefault) {\n previousDefaultVariantId = await enforceSingleDefaultVariant(em, record)\n try {\n await em.flush()\n } catch (error) {\n await rethrowVariantUniqueConstraint(error)\n }\n }\n await aggregateVariantMediaToProduct(em, record)\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n action: 'created',\n })\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: variantCrudEvents,\n })\n return { variantId: record.id, previousDefaultVariantId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadVariantSnapshot(em, result.variantId)\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as VariantSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.variants.create', 'Create product variant'),\n resourceKind: 'catalog.variant',\n resourceId: result.variantId,\n parentResourceKind: 'catalog.product',\n parentResourceId: after.productId ?? null,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n previousDefaultVariantId: (result as { previousDefaultVariantId?: string | null })?.previousDefaultVariantId ?? null,\n } satisfies VariantUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<VariantUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(CatalogProductVariant, { 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 if (payload?.previousDefaultVariantId) {\n const previousDefault = await em.findOne(CatalogProductVariant, { id: payload.previousDefaultVariantId })\n if (previousDefault) {\n ensureTenantScope(ctx, previousDefault.tenantId)\n ensureOrganizationScope(ctx, previousDefault.organizationId)\n previousDefault.isDefault = true\n await em.flush()\n }\n }\n const resetValues = buildCustomFieldResetMap(undefined, after.custom ?? undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n values: resetValues,\n })\n }\n },\n}\n\nconst updateVariantCommand: CommandHandler<VariantUpdateInput, { variantId: string; previousDefaultVariantId?: string | null }> = {\n id: 'catalog.variants.update',\n async prepare(input, ctx) {\n const id = requireId(input, 'Variant id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadVariantSnapshot(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(variantUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(CatalogProductVariant, { id: parsed.id, deletedAt: null })\n if (!record) throw new CrudHttpError(404, { error: 'Catalog variant not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const product = await requireProduct(em, record.product.id)\n\n if (!product) throw new CrudHttpError(400, { error: 'Variant product missing' })\n\n const taxRateProvided = parsed.taxRateId !== undefined || parsed.taxRate !== undefined\n const resolvedTaxRate = taxRateProvided\n ? await resolveVariantTaxRate(em, product, parsed.taxRateId ?? null, parsed.taxRate)\n : null\n\n if (parsed.name !== undefined) record.name = parsed.name ?? null\n if (parsed.sku !== undefined) record.sku = parsed.sku ?? null\n if (parsed.barcode !== undefined) record.barcode = parsed.barcode ?? null\n if (parsed.statusEntryId !== undefined) record.statusEntryId = parsed.statusEntryId ?? null\n if (parsed.isDefault !== undefined) record.isDefault = parsed.isDefault\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive\n if (Object.prototype.hasOwnProperty.call(parsed, 'weightValue')) {\n record.weightValue = toNumericString(parsed.weightValue)\n }\n if (parsed.weightUnit !== undefined) record.weightUnit = parsed.weightUnit ?? null\n if (parsed.dimensions !== undefined) {\n record.dimensions = parsed.dimensions ? cloneJson(parsed.dimensions) : null\n }\n let metadataSplit: MetadataSplitResult | null = null\n if (parsed.metadata !== undefined) {\n metadataSplit = splitOptionValuesFromMetadata(parsed.metadata)\n record.metadata = metadataSplit.metadata\n }\n if (parsed.optionValues !== undefined) {\n record.optionValues = parsed.optionValues ? cloneJson(parsed.optionValues) : null\n } else if (metadataSplit?.hadOptionValues) {\n record.optionValues = metadataSplit.optionValues ? cloneJson(metadataSplit.optionValues) : null\n }\n if (taxRateProvided) {\n record.taxRateId = resolvedTaxRate?.taxRateId ?? null\n record.taxRate = resolvedTaxRate?.taxRate ?? null\n }\n if (parsed.customFieldsetCode !== undefined) {\n record.customFieldsetCode = parsed.customFieldsetCode ?? null\n }\n\n let previousDefaultVariantId: string | null = null\n if (parsed.isDefault === true) {\n previousDefaultVariantId = await enforceSingleDefaultVariant(em, record)\n }\n try {\n await em.flush()\n } catch (error) {\n await rethrowVariantUniqueConstraint(error)\n }\n await aggregateVariantMediaToProduct(em, record)\n if (custom && Object.keys(custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n }\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n action: 'updated',\n })\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: variantCrudEvents,\n })\n return { variantId: record.id, previousDefaultVariantId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadVariantSnapshot(em, result.variantId)\n },\n buildLog: async ({ result, snapshots }) => {\n const before = snapshots.before as VariantSnapshot | undefined\n const after = snapshots.after as VariantSnapshot | undefined\n if (!before || !after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.variants.update', 'Update product variant'),\n resourceKind: 'catalog.variant',\n resourceId: before.id,\n parentResourceKind: 'catalog.product',\n parentResourceId: before.productId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n changes: buildChanges(\n before as Record<string, unknown>,\n after as Record<string, unknown>,\n VARIANT_CHANGE_KEYS\n ),\n payload: {\n undo: {\n before,\n after,\n previousDefaultVariantId:\n (result as { previousDefaultVariantId?: string | null })?.previousDefaultVariantId ?? null,\n } satisfies VariantUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<VariantUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const after = payload?.after\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(CatalogProductVariant, { id: before.id })\n if (!record) {\n const product = await requireProduct(em, before.productId)\n record = em.create(CatalogProductVariant, {\n id: before.id,\n product,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n name: before.name ?? null,\n sku: before.sku ?? null,\n barcode: before.barcode ?? null,\n statusEntryId: before.statusEntryId ?? null,\n isDefault: before.isDefault,\n isActive: before.isActive,\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 optionValues: before.optionValues ? cloneJson(before.optionValues) : null,\n customFieldsetCode: before.customFieldsetCode ?? null,\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 applyVariantSnapshot(record, before)\n await em.flush()\n const previousDefaultId = payload?.previousDefaultVariantId\n if (previousDefaultId) {\n const previousDefault = await em.findOne(CatalogProductVariant, { id: previousDefaultId })\n if (previousDefault) {\n ensureTenantScope(ctx, previousDefault.tenantId)\n ensureOrganizationScope(ctx, previousDefault.organizationId)\n previousDefault.isDefault = true\n await em.flush()\n }\n }\n const resetValues = buildCustomFieldResetMap(\n before.custom ?? undefined,\n after?.custom ?? undefined\n )\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: resetValues,\n })\n }\n },\n}\n\nconst deleteVariantCommand: CommandHandler<\n { body?: Record<string, unknown>; query?: Record<string, unknown> },\n { variantId: string }\n> = {\n id: 'catalog.variants.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Variant id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadVariantSnapshot(em, id, { includePrices: true })\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, 'Variant id is required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(CatalogProductVariant, { id })\n if (!record) throw new CrudHttpError(404, { error: 'Catalog variant not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n\n const baseEm = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadVariantSnapshot(baseEm, id, { includePrices: true })\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const priceSnapshots =\n snapshot?.prices && snapshot.prices.length\n ? snapshot.prices\n : await loadVariantPriceSnapshots(baseEm, id)\n\n if (priceSnapshots.length) {\n await em.nativeDelete(CatalogProductPrice, { id: { $in: priceSnapshots.map((price) => price.id) } })\n } else {\n await em.nativeDelete(CatalogProductPrice, { variant: record })\n }\n em.remove(record)\n await em.flush()\n for (const priceSnapshot of priceSnapshots) {\n const resetValues = buildCustomFieldResetMap(priceSnapshot.custom ?? undefined, undefined)\n if (!Object.keys(resetValues).length) continue\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product_price,\n recordId: priceSnapshot.id,\n organizationId: priceSnapshot.organizationId,\n tenantId: priceSnapshot.tenantId,\n values: resetValues,\n })\n }\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_variant,\n recordId: id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n values: resetValues,\n })\n }\n }\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: id,\n organizationId: snapshot?.organizationId ?? record.organizationId,\n tenantId: snapshot?.tenantId ?? record.tenantId,\n action: 'deleted',\n })\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id,\n organizationId: snapshot?.organizationId ?? record.organizationId,\n tenantId: snapshot?.tenantId ?? record.tenantId,\n },\n events: variantCrudEvents,\n })\n return { variantId: id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as VariantSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.variants.delete', 'Delete product variant'),\n resourceKind: 'catalog.variant',\n resourceId: before.id,\n parentResourceKind: 'catalog.product',\n parentResourceId: before.productId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies VariantUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<VariantUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(CatalogProductVariant, { id: before.id })\n if (!record) {\n const product = await requireProduct(em, before.productId)\n record = em.create(CatalogProductVariant, {\n id: before.id,\n product,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n name: before.name ?? null,\n sku: before.sku ?? null,\n barcode: before.barcode ?? null,\n statusEntryId: before.statusEntryId ?? null,\n isDefault: before.isDefault,\n isActive: before.isActive,\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 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 applyVariantSnapshot(record, before)\n if (before.prices?.length) {\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n await restoreVariantPricesFromSnapshots(em, record, before.prices, dataEngine)\n }\n await em.flush()\n if (before.custom && Object.keys(before.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: before.custom,\n })\n }\n },\n}\n\nasync function throwDuplicateVariantSkuError(): Promise<never> {\n const { translate } = await resolveTranslations()\n const message = translate('catalog.variants.errors.skuExists', 'SKU already in use.')\n throw new CrudHttpError(400, {\n error: message,\n fieldErrors: { sku: message },\n details: [{ path: ['sku'], message, code: 'duplicate', origin: 'validation' }],\n })\n}\n\nasync function rethrowVariantUniqueConstraint(error: unknown): Promise<never> {\n if (error instanceof UniqueConstraintViolationException) {\n const constraint = getErrorConstraint(error)\n const message = getErrorMessage(error).toLowerCase()\n if (\n constraint === 'catalog_product_variants_sku_unique' ||\n message.includes('catalog_product_variants_sku_unique')\n ) {\n await throwDuplicateVariantSkuError()\n }\n }\n throw error\n}\n\nregisterCommand(createVariantCommand)\nregisterCommand(updateVariantCommand)\nregisterCommand(deleteVariantCommand)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { buildChanges, requireId, parseWithCustomFields, setCustomFieldsIfAny, emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { UniqueConstraintViolationException } from '@mikro-orm/core'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { loadCustomFieldSnapshot, buildCustomFieldResetMap } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { E } from '#generated/entities.ids.generated'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CatalogProductVariant,\n CatalogProductPrice,\n CatalogProduct,\n CatalogOffer,\n CatalogPriceKind,\n} from '../data/entities'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport {\n variantCreateSchema,\n variantUpdateSchema,\n type VariantCreateInput,\n type VariantUpdateInput,\n} from '../data/validators'\nimport {\n cloneJson,\n ensureOrganizationScope,\n ensureTenantScope,\n emitCatalogQueryIndexEvent,\n extractUndoPayload,\n requireProduct,\n toNumericString,\n getErrorConstraint,\n getErrorMessage,\n} from './shared'\nimport { SalesTaxRate } from '@open-mercato/core/modules/sales/data/entities'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\n\nconst variantCrudEvents: CrudEventsConfig = {\n module: 'catalog',\n entity: 'variant',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype VariantSnapshot = {\n id: string\n productId: string\n organizationId: string\n tenantId: string\n name: string | null\n sku: string | null\n barcode: string | null\n statusEntryId: string | null\n isDefault: boolean\n isActive: boolean\n weightValue: string | null\n weightUnit: string | null\n taxRateId: string | null\n taxRate: string | null\n dimensions: Record<string, unknown> | null\n metadata: Record<string, unknown> | null\n optionValues: Record<string, string> | null\n customFieldsetCode: string | null\n createdAt: string\n updatedAt: string\n custom: Record<string, unknown> | null\n prices?: VariantPriceSnapshot[] | null\n}\n\ntype VariantUndoPayload = {\n before?: VariantSnapshot | null\n after?: VariantSnapshot | null\n previousDefaultVariantId?: string | null\n}\n\nconst VARIANT_CHANGE_KEYS = [\n 'name',\n 'sku',\n 'barcode',\n 'statusEntryId',\n 'isDefault',\n 'isActive',\n 'weightValue',\n 'weightUnit',\n 'taxRateId',\n 'taxRate',\n 'dimensions',\n 'optionValues',\n 'customFieldsetCode',\n 'metadata',\n] as const satisfies readonly string[]\n\nasync function loadVariantSnapshot(\n em: EntityManager,\n id: string,\n options: { includePrices?: boolean } = {}\n): Promise<VariantSnapshot | null> {\n const record = await em.findOne(CatalogProductVariant, { id, deletedAt: null })\n if (!record) return null\n const prices = options.includePrices\n ? await loadVariantPriceSnapshots(em, record.id, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n : null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_variant,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n const productId = typeof record.product === 'string' ? record.product : record.product.id\n return {\n id: record.id,\n productId,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n name: record.name ?? null,\n sku: record.sku ?? null,\n barcode: record.barcode ?? null,\n statusEntryId: record.statusEntryId ?? null,\n isDefault: record.isDefault,\n isActive: record.isActive,\n weightValue: record.weightValue ?? null,\n weightUnit: record.weightUnit ?? null,\n taxRateId: record.taxRateId ?? null,\n taxRate: record.taxRate ?? null,\n dimensions: record.dimensions ? cloneJson(record.dimensions) : null,\n metadata: record.metadata ? cloneJson(record.metadata) : null,\n optionValues: record.optionValues ? cloneJson(record.optionValues) : null,\n customFieldsetCode: record.customFieldsetCode ?? null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n custom: Object.keys(custom).length ? custom : null,\n prices: prices && prices.length ? prices : null,\n }\n}\n\nfunction applyVariantSnapshot(record: CatalogProductVariant, snapshot: VariantSnapshot): void {\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.name = snapshot.name ?? null\n record.sku = snapshot.sku ?? null\n record.barcode = snapshot.barcode ?? null\n record.statusEntryId = snapshot.statusEntryId ?? null\n record.isDefault = snapshot.isDefault\n record.isActive = snapshot.isActive\n record.weightValue = snapshot.weightValue ?? null\n record.weightUnit = snapshot.weightUnit ?? null\n record.taxRateId = snapshot.taxRateId ?? null\n record.taxRate = snapshot.taxRate ?? null\n record.dimensions = snapshot.dimensions ? cloneJson(snapshot.dimensions) : null\n record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null\n record.optionValues = snapshot.optionValues ? cloneJson(snapshot.optionValues) : null\n record.customFieldsetCode = snapshot.customFieldsetCode ?? null\n record.createdAt = new Date(snapshot.createdAt)\n record.updatedAt = new Date(snapshot.updatedAt)\n}\n\nasync function resolveVariantTaxRate(\n em: EntityManager,\n product: CatalogProduct,\n taxRateIdInput: string | null | undefined,\n taxRateInput: number | string | null | undefined\n): Promise<{ taxRateId: string | null; taxRate: string | null }> {\n const organizationId = product.organizationId\n const tenantId = product.tenantId\n const normalizedRate =\n taxRateInput === null || taxRateInput === undefined\n ? null\n : (() => {\n const numeric = typeof taxRateInput === 'string' ? Number(taxRateInput) : taxRateInput\n return Number.isFinite(numeric) ? toNumericString(numeric) : null\n })()\n if (taxRateIdInput === null) {\n return { taxRateId: product.taxRateId ?? null, taxRate: product.taxRate ?? null }\n }\n if (!taxRateIdInput) {\n return { taxRateId: product.taxRateId ?? null, taxRate: product.taxRate ?? normalizedRate }\n }\n const record = await em.findOne(SalesTaxRate, {\n id: taxRateIdInput,\n organizationId,\n tenantId,\n deletedAt: null,\n })\n if (!record) {\n throw new CrudHttpError(400, { error: 'Tax class not found' })\n }\n return { taxRateId: taxRateIdInput, taxRate: record.rate ?? normalizedRate }\n}\n\ntype VariantPriceSnapshot = {\n id: string\n variantId: string | null\n productId: string | null\n offerId: string | null\n organizationId: string\n tenantId: string\n priceKindId: string\n priceKindCode: string\n currencyCode: string\n kind: string\n minQuantity: number\n maxQuantity: number | null\n unitPriceNet: string | null\n unitPriceGross: string | null\n taxRate: string | null\n taxAmount: string | null\n channelId: string | null\n userId: string | null\n userGroupId: string | null\n customerId: string | null\n customerGroupId: string | null\n metadata: Record<string, unknown> | null\n startsAt: string | null\n endsAt: string | null\n createdAt: string\n updatedAt: string\n custom: Record<string, unknown> | null\n}\n\nasync function loadVariantPriceSnapshots(\n em: EntityManager,\n variantId: string,\n scope: { tenantId: string; organizationId: string }\n): Promise<VariantPriceSnapshot[]> {\n const prices = await findWithDecryption(\n em,\n CatalogProductPrice,\n { variant: variantId, tenantId: scope.tenantId, organizationId: scope.organizationId },\n { populate: ['priceKind', 'product', 'offer'] },\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\n )\n const snapshots: VariantPriceSnapshot[] = []\n for (const price of prices) {\n const variantRef = price.variant\n const variantIdValue =\n typeof variantRef === 'string'\n ? variantRef\n : variantRef\n ? variantRef.id\n : null\n const productRef = price.product\n ? price.product\n : typeof price.variant === 'object' && price.variant\n ? price.variant.product\n : null\n const productId =\n typeof productRef === 'string'\n ? productRef\n : productRef\n ? productRef.id\n : null\n const priceKindRef = price.priceKind\n const priceKindId =\n typeof priceKindRef === 'string'\n ? priceKindRef\n : priceKindRef\n ? priceKindRef.id\n : null\n if (!priceKindId) {\n throw new CrudHttpError(400, { error: 'Price is missing price kind metadata.' })\n }\n const priceKindCode =\n typeof priceKindRef === 'object' && priceKindRef ? priceKindRef.code : price.kind\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_price,\n recordId: price.id,\n tenantId: price.tenantId,\n organizationId: price.organizationId,\n })\n snapshots.push({\n id: price.id,\n variantId: variantIdValue,\n productId,\n offerId: typeof price.offer === 'string' ? price.offer : price.offer ? price.offer.id : null,\n organizationId: price.organizationId,\n tenantId: price.tenantId,\n priceKindId,\n priceKindCode,\n currencyCode: price.currencyCode,\n kind: price.kind,\n minQuantity: price.minQuantity,\n maxQuantity: price.maxQuantity ?? null,\n unitPriceNet: price.unitPriceNet ?? null,\n unitPriceGross: price.unitPriceGross ?? null,\n taxRate: price.taxRate ?? null,\n taxAmount: price.taxAmount ?? null,\n channelId: price.channelId ?? null,\n userId: price.userId ?? null,\n userGroupId: price.userGroupId ?? null,\n customerId: price.customerId ?? null,\n customerGroupId: price.customerGroupId ?? null,\n metadata: price.metadata ? cloneJson(price.metadata) : null,\n startsAt: price.startsAt ? price.startsAt.toISOString() : null,\n endsAt: price.endsAt ? price.endsAt.toISOString() : null,\n createdAt: price.createdAt.toISOString(),\n updatedAt: price.updatedAt.toISOString(),\n custom: Object.keys(custom).length ? custom : null,\n })\n }\n return snapshots\n}\n\nasync function restoreVariantPricesFromSnapshots(\n em: EntityManager,\n variant: CatalogProductVariant,\n snapshots: VariantPriceSnapshot[],\n dataEngine: DataEngine\n): Promise<void> {\n if (!snapshots.length) return\n const productRef =\n typeof variant.product === 'string'\n ? await requireProduct(em, variant.product)\n : variant.product\n for (const snapshot of snapshots) {\n const product =\n snapshot.productId && snapshot.productId !== productRef.id\n ? em.getReference(CatalogProduct, snapshot.productId)\n : productRef\n const offer = snapshot.offerId ? em.getReference(CatalogOffer, snapshot.offerId) : null\n const priceKind = em.getReference(CatalogPriceKind, snapshot.priceKindId)\n let record = await em.findOne(CatalogProductPrice, { id: snapshot.id })\n if (!record) {\n record = em.create(CatalogProductPrice, {\n id: snapshot.id,\n variant,\n product,\n offer,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n currencyCode: snapshot.currencyCode,\n priceKind,\n kind: snapshot.priceKindCode || snapshot.kind,\n minQuantity: snapshot.minQuantity,\n maxQuantity: snapshot.maxQuantity ?? null,\n unitPriceNet: snapshot.unitPriceNet ?? null,\n unitPriceGross: snapshot.unitPriceGross ?? null,\n taxRate: snapshot.taxRate ?? null,\n taxAmount: snapshot.taxAmount ?? null,\n channelId: snapshot.channelId ?? null,\n userId: snapshot.userId ?? null,\n userGroupId: snapshot.userGroupId ?? null,\n customerId: snapshot.customerId ?? null,\n customerGroupId: snapshot.customerGroupId ?? null,\n metadata: snapshot.metadata ? cloneJson(snapshot.metadata) : null,\n startsAt: snapshot.startsAt ? new Date(snapshot.startsAt) : null,\n endsAt: snapshot.endsAt ? new Date(snapshot.endsAt) : null,\n createdAt: new Date(snapshot.createdAt),\n updatedAt: new Date(snapshot.updatedAt),\n })\n em.persist(record)\n } else {\n record.variant = variant\n record.product = product\n record.offer = offer\n record.priceKind = priceKind\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.currencyCode = snapshot.currencyCode\n record.kind = snapshot.priceKindCode || snapshot.kind\n record.minQuantity = snapshot.minQuantity\n record.maxQuantity = snapshot.maxQuantity ?? null\n record.unitPriceNet = snapshot.unitPriceNet ?? null\n record.unitPriceGross = snapshot.unitPriceGross ?? null\n record.taxRate = snapshot.taxRate ?? null\n record.taxAmount = snapshot.taxAmount ?? null\n record.channelId = snapshot.channelId ?? null\n record.userId = snapshot.userId ?? null\n record.userGroupId = snapshot.userGroupId ?? null\n record.customerId = snapshot.customerId ?? null\n record.customerGroupId = snapshot.customerGroupId ?? null\n record.metadata = snapshot.metadata ? cloneJson(snapshot.metadata) : null\n record.startsAt = snapshot.startsAt ? new Date(snapshot.startsAt) : null\n record.endsAt = snapshot.endsAt ? new Date(snapshot.endsAt) : null\n record.createdAt = new Date(snapshot.createdAt)\n record.updatedAt = new Date(snapshot.updatedAt)\n }\n }\n await em.flush()\n for (const snapshot of snapshots) {\n if (!snapshot.custom || !Object.keys(snapshot.custom).length) continue\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product_price,\n recordId: snapshot.id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n values: snapshot.custom,\n })\n }\n}\n\ntype MetadataSplitResult = {\n metadata: Record<string, unknown> | null\n optionValues: Record<string, string> | null\n hadOptionValues: boolean\n}\n\nfunction splitOptionValuesFromMetadata(\n metadata?: Record<string, unknown> | null\n): MetadataSplitResult {\n if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) {\n return {\n metadata: metadata ? cloneJson(metadata) : null,\n optionValues: null,\n hadOptionValues: false,\n }\n }\n const { optionValues, ...rest } = metadata as Record<string, unknown> & {\n optionValues?: unknown\n }\n const normalizedMetadata = Object.keys(rest).length ? cloneJson(rest) : null\n return {\n metadata: normalizedMetadata,\n optionValues: normalizeOptionValues(optionValues),\n hadOptionValues: optionValues !== undefined,\n }\n}\n\nfunction normalizeOptionValues(input: unknown): Record<string, string> | null {\n if (!input || typeof input !== 'object' || Array.isArray(input)) return null\n const normalized: Record<string, string> = {}\n for (const [rawKey, rawValue] of Object.entries(input)) {\n if (typeof rawValue !== 'string') continue\n const key = rawKey.trim()\n const value = rawValue.trim()\n if (!key || !value) continue\n normalized[key] = value\n }\n return Object.keys(normalized).length ? normalized : null\n}\n\nfunction resolveProductId(record: CatalogProductVariant): string {\n return typeof record.product === 'string' ? record.product : record.product.id\n}\n\nasync function enforceSingleDefaultVariant(\n em: EntityManager,\n variant: CatalogProductVariant\n): Promise<string | null> {\n if (!variant.isDefault) return null\n const productId = resolveProductId(variant)\n const existingDefault = await em.findOne(\n CatalogProductVariant,\n { product: productId, isDefault: true, deletedAt: null, id: { $ne: variant.id } },\n { fields: ['id', 'isDefault'] }\n )\n if (existingDefault) {\n existingDefault.isDefault = false\n return existingDefault.id\n }\n return null\n}\n\nasync function aggregateVariantMediaToProduct(\n em: EntityManager,\n variant: CatalogProductVariant\n): Promise<void> {\n const productId = resolveProductId(variant)\n const buildKey = (\n attachment: Pick<Attachment, 'fileName' | 'fileSize' | 'storageDriver' | 'partitionCode' | 'storagePath'>\n ) =>\n [\n attachment.fileName?.trim() ?? '',\n attachment.fileSize ?? '',\n attachment.storageDriver ?? '',\n attachment.partitionCode ?? '',\n ].join('|')\n const attachments = await em.find(\n Attachment,\n {\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: variant.organizationId ?? undefined,\n tenantId: variant.tenantId ?? undefined,\n },\n {\n fields: [\n 'id',\n 'partitionCode',\n 'fileName',\n 'mimeType',\n 'fileSize',\n 'storageDriver',\n 'storagePath',\n 'storageMetadata',\n 'url',\n 'organizationId',\n 'tenantId',\n 'fileSize',\n 'storageDriver',\n 'partitionCode',\n ],\n }\n )\n if (!attachments.length) return\n const existing = await em.find(\n Attachment,\n {\n entityId: E.catalog.catalog_product,\n recordId: productId,\n organizationId: variant.organizationId ?? undefined,\n tenantId: variant.tenantId ?? undefined,\n },\n {\n fields: ['storagePath', 'fileName', 'fileSize', 'storageDriver', 'partitionCode'],\n }\n )\n const existingKeys = new Set(existing.map((item) => buildKey(item)))\n let created = 0\n for (const source of attachments) {\n const key = buildKey(source)\n if (existingKeys.has(key)) continue\n const clone = em.create(Attachment, {\n entityId: E.catalog.catalog_product,\n recordId: productId,\n organizationId: source.organizationId ?? variant.organizationId ?? null,\n tenantId: source.tenantId ?? variant.tenantId ?? null,\n partitionCode: source.partitionCode,\n fileName: source.fileName,\n mimeType: source.mimeType,\n fileSize: source.fileSize,\n storageDriver: source.storageDriver,\n storagePath: source.storagePath,\n storageMetadata: source.storageMetadata ? cloneJson(source.storageMetadata) : null,\n url: source.url,\n })\n em.persist(clone)\n existingKeys.add(key)\n created += 1\n }\n if (created > 0) {\n await em.flush()\n }\n}\n\nconst createVariantCommand: CommandHandler<VariantCreateInput, { variantId: string; previousDefaultVariantId?: string | null }> = {\n id: 'catalog.variants.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(variantCreateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const product = await requireProduct(em, parsed.productId)\n ensureTenantScope(ctx, product.tenantId)\n ensureOrganizationScope(ctx, product.organizationId)\n const { taxRateId, taxRate } = await resolveVariantTaxRate(\n em,\n product,\n parsed.taxRateId ?? null,\n parsed.taxRate\n )\n\n const metadataSplit = splitOptionValuesFromMetadata(parsed.metadata)\n const resolvedOptionValues =\n parsed.optionValues ?? (metadataSplit.hadOptionValues ? metadataSplit.optionValues : null)\n\n const now = new Date()\n const record = em.create(CatalogProductVariant, {\n organizationId: product.organizationId,\n tenantId: product.tenantId,\n product,\n name: parsed.name ?? null,\n sku: parsed.sku ?? null,\n barcode: parsed.barcode ?? null,\n statusEntryId: parsed.statusEntryId ?? null,\n isDefault: parsed.isDefault ?? false,\n isActive: parsed.isActive ?? true,\n weightValue: toNumericString(parsed.weightValue),\n weightUnit: parsed.weightUnit ?? null,\n taxRateId,\n taxRate,\n dimensions: parsed.dimensions ? cloneJson(parsed.dimensions) : null,\n metadata: metadataSplit.metadata,\n optionValues: resolvedOptionValues ? cloneJson(resolvedOptionValues) : null,\n customFieldsetCode: parsed.customFieldsetCode ?? null,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n try {\n await em.flush()\n } catch (error) {\n await rethrowVariantUniqueConstraint(error)\n }\n let previousDefaultVariantId: string | null = null\n if (record.isDefault) {\n previousDefaultVariantId = await enforceSingleDefaultVariant(em, record)\n try {\n await em.flush()\n } catch (error) {\n await rethrowVariantUniqueConstraint(error)\n }\n }\n await aggregateVariantMediaToProduct(em, record)\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n action: 'created',\n })\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: variantCrudEvents,\n })\n return { variantId: record.id, previousDefaultVariantId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadVariantSnapshot(em, result.variantId)\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as VariantSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.variants.create', 'Create product variant'),\n resourceKind: 'catalog.variant',\n resourceId: result.variantId,\n parentResourceKind: 'catalog.product',\n parentResourceId: after.productId ?? null,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n previousDefaultVariantId: (result as { previousDefaultVariantId?: string | null })?.previousDefaultVariantId ?? null,\n } satisfies VariantUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<VariantUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(CatalogProductVariant, { 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 if (payload?.previousDefaultVariantId) {\n const previousDefault = await em.findOne(CatalogProductVariant, { id: payload.previousDefaultVariantId })\n if (previousDefault) {\n ensureTenantScope(ctx, previousDefault.tenantId)\n ensureOrganizationScope(ctx, previousDefault.organizationId)\n previousDefault.isDefault = true\n await em.flush()\n }\n }\n const resetValues = buildCustomFieldResetMap(undefined, after.custom ?? undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n values: resetValues,\n })\n }\n },\n}\n\nconst updateVariantCommand: CommandHandler<VariantUpdateInput, { variantId: string; previousDefaultVariantId?: string | null }> = {\n id: 'catalog.variants.update',\n async prepare(input, ctx) {\n const id = requireId(input, 'Variant id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadVariantSnapshot(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(variantUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(CatalogProductVariant, { id: parsed.id, deletedAt: null })\n if (!record) throw new CrudHttpError(404, { error: 'Catalog variant not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const product = await requireProduct(em, record.product.id)\n\n if (!product) throw new CrudHttpError(400, { error: 'Variant product missing' })\n\n const taxRateProvided = parsed.taxRateId !== undefined || parsed.taxRate !== undefined\n const resolvedTaxRate = taxRateProvided\n ? await resolveVariantTaxRate(em, product, parsed.taxRateId ?? null, parsed.taxRate)\n : null\n\n if (parsed.name !== undefined) record.name = parsed.name ?? null\n if (parsed.sku !== undefined) record.sku = parsed.sku ?? null\n if (parsed.barcode !== undefined) record.barcode = parsed.barcode ?? null\n if (parsed.statusEntryId !== undefined) record.statusEntryId = parsed.statusEntryId ?? null\n if (parsed.isDefault !== undefined) record.isDefault = parsed.isDefault\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive\n if (Object.prototype.hasOwnProperty.call(parsed, 'weightValue')) {\n record.weightValue = toNumericString(parsed.weightValue)\n }\n if (parsed.weightUnit !== undefined) record.weightUnit = parsed.weightUnit ?? null\n if (parsed.dimensions !== undefined) {\n record.dimensions = parsed.dimensions ? cloneJson(parsed.dimensions) : null\n }\n let metadataSplit: MetadataSplitResult | null = null\n if (parsed.metadata !== undefined) {\n metadataSplit = splitOptionValuesFromMetadata(parsed.metadata)\n record.metadata = metadataSplit.metadata\n }\n if (parsed.optionValues !== undefined) {\n record.optionValues = parsed.optionValues ? cloneJson(parsed.optionValues) : null\n } else if (metadataSplit?.hadOptionValues) {\n record.optionValues = metadataSplit.optionValues ? cloneJson(metadataSplit.optionValues) : null\n }\n if (taxRateProvided) {\n record.taxRateId = resolvedTaxRate?.taxRateId ?? null\n record.taxRate = resolvedTaxRate?.taxRate ?? null\n }\n if (parsed.customFieldsetCode !== undefined) {\n record.customFieldsetCode = parsed.customFieldsetCode ?? null\n }\n\n let previousDefaultVariantId: string | null = null\n if (parsed.isDefault === true) {\n previousDefaultVariantId = await enforceSingleDefaultVariant(em, record)\n }\n try {\n await em.flush()\n } catch (error) {\n await rethrowVariantUniqueConstraint(error)\n }\n await aggregateVariantMediaToProduct(em, record)\n if (custom && Object.keys(custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n }\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n action: 'updated',\n })\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: variantCrudEvents,\n })\n return { variantId: record.id, previousDefaultVariantId }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadVariantSnapshot(em, result.variantId)\n },\n buildLog: async ({ result, snapshots }) => {\n const before = snapshots.before as VariantSnapshot | undefined\n const after = snapshots.after as VariantSnapshot | undefined\n if (!before || !after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.variants.update', 'Update product variant'),\n resourceKind: 'catalog.variant',\n resourceId: before.id,\n parentResourceKind: 'catalog.product',\n parentResourceId: before.productId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n changes: buildChanges(\n before as Record<string, unknown>,\n after as Record<string, unknown>,\n VARIANT_CHANGE_KEYS\n ),\n payload: {\n undo: {\n before,\n after,\n previousDefaultVariantId:\n (result as { previousDefaultVariantId?: string | null })?.previousDefaultVariantId ?? null,\n } satisfies VariantUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<VariantUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const after = payload?.after\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(CatalogProductVariant, { id: before.id })\n if (!record) {\n const product = await requireProduct(em, before.productId)\n record = em.create(CatalogProductVariant, {\n id: before.id,\n product,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n name: before.name ?? null,\n sku: before.sku ?? null,\n barcode: before.barcode ?? null,\n statusEntryId: before.statusEntryId ?? null,\n isDefault: before.isDefault,\n isActive: before.isActive,\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 optionValues: before.optionValues ? cloneJson(before.optionValues) : null,\n customFieldsetCode: before.customFieldsetCode ?? null,\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 applyVariantSnapshot(record, before)\n await em.flush()\n const previousDefaultId = payload?.previousDefaultVariantId\n if (previousDefaultId) {\n const previousDefault = await em.findOne(CatalogProductVariant, { id: previousDefaultId })\n if (previousDefault) {\n ensureTenantScope(ctx, previousDefault.tenantId)\n ensureOrganizationScope(ctx, previousDefault.organizationId)\n previousDefault.isDefault = true\n await em.flush()\n }\n }\n const resetValues = buildCustomFieldResetMap(\n before.custom ?? undefined,\n after?.custom ?? undefined\n )\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: resetValues,\n })\n }\n },\n}\n\nconst deleteVariantCommand: CommandHandler<\n { body?: Record<string, unknown>; query?: Record<string, unknown> },\n { variantId: string }\n> = {\n id: 'catalog.variants.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Variant id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadVariantSnapshot(em, id, { includePrices: true })\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, 'Variant id is required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(CatalogProductVariant, { id })\n if (!record) throw new CrudHttpError(404, { error: 'Catalog variant not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n\n const baseEm = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadVariantSnapshot(baseEm, id, { includePrices: true })\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const priceSnapshots =\n snapshot?.prices && snapshot.prices.length\n ? snapshot.prices\n : await loadVariantPriceSnapshots(baseEm, id, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n\n if (priceSnapshots.length) {\n await em.nativeDelete(CatalogProductPrice, { id: { $in: priceSnapshots.map((price) => price.id) } })\n } else {\n await em.nativeDelete(CatalogProductPrice, { variant: record })\n }\n em.remove(record)\n await em.flush()\n for (const priceSnapshot of priceSnapshots) {\n const resetValues = buildCustomFieldResetMap(priceSnapshot.custom ?? undefined, undefined)\n if (!Object.keys(resetValues).length) continue\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.catalog.catalog_product_price,\n recordId: priceSnapshot.id,\n organizationId: priceSnapshot.organizationId,\n tenantId: priceSnapshot.tenantId,\n values: resetValues,\n })\n }\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_variant,\n recordId: id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n values: resetValues,\n })\n }\n }\n await emitCatalogQueryIndexEvent(ctx, {\n entityType: E.catalog.catalog_product_variant,\n recordId: id,\n organizationId: snapshot?.organizationId ?? record.organizationId,\n tenantId: snapshot?.tenantId ?? record.tenantId,\n action: 'deleted',\n })\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id,\n organizationId: snapshot?.organizationId ?? record.organizationId,\n tenantId: snapshot?.tenantId ?? record.tenantId,\n },\n events: variantCrudEvents,\n })\n return { variantId: id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as VariantSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.variants.delete', 'Delete product variant'),\n resourceKind: 'catalog.variant',\n resourceId: before.id,\n parentResourceKind: 'catalog.product',\n parentResourceId: before.productId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies VariantUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<VariantUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(CatalogProductVariant, { id: before.id })\n if (!record) {\n const product = await requireProduct(em, before.productId)\n record = em.create(CatalogProductVariant, {\n id: before.id,\n product,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n name: before.name ?? null,\n sku: before.sku ?? null,\n barcode: before.barcode ?? null,\n statusEntryId: before.statusEntryId ?? null,\n isDefault: before.isDefault,\n isActive: before.isActive,\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 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 applyVariantSnapshot(record, before)\n if (before.prices?.length) {\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n await restoreVariantPricesFromSnapshots(em, record, before.prices, dataEngine)\n }\n await em.flush()\n if (before.custom && Object.keys(before.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_variant,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: before.custom,\n })\n }\n },\n}\n\nasync function throwDuplicateVariantSkuError(): Promise<never> {\n const { translate } = await resolveTranslations()\n const message = translate('catalog.variants.errors.skuExists', 'SKU already in use.')\n throw new CrudHttpError(400, {\n error: message,\n fieldErrors: { sku: message },\n details: [{ path: ['sku'], message, code: 'duplicate', origin: 'validation' }],\n })\n}\n\nasync function rethrowVariantUniqueConstraint(error: unknown): Promise<never> {\n if (error instanceof UniqueConstraintViolationException) {\n const constraint = getErrorConstraint(error)\n const message = getErrorMessage(error).toLowerCase()\n if (\n constraint === 'catalog_product_variants_sku_unique' ||\n message.includes('catalog_product_variants_sku_unique')\n ) {\n await throwDuplicateVariantSkuError()\n }\n }\n throw error\n}\n\nregisterCommand(createVariantCommand)\nregisterCommand(updateVariantCommand)\nregisterCommand(deleteVariantCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,193 +1,36 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useCallback, useMemo, useEffect, useState } from "react";
4
- import {
5
- ReactFlow,
6
- Controls,
7
- Background,
8
- BackgroundVariant,
9
- MiniMap,
10
- Panel,
11
- useNodesState,
12
- useEdgesState,
13
- addEdge,
14
- ConnectionMode,
15
- MarkerType
16
- } from "@xyflow/react";
17
- import { StartNode, EndNode, UserTaskNode, AutomatedNode, SubWorkflowNode, WaitForSignalNode, WaitForTimerNode } from "./nodes/index.js";
18
- import { WorkflowTransitionEdge } from "./WorkflowTransitionEdge.js";
19
- import { STATUS_COLORS } from "../lib/status-colors.js";
20
- import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
21
- import { Edit3 } from "lucide-react";
22
- import { useTheme } from "@open-mercato/ui/theme";
23
- import { useT } from "@open-mercato/shared/lib/i18n/context";
24
- function WorkflowGraph({
25
- initialNodes = [],
26
- initialEdges = [],
27
- onNodesChange: onNodesChangeProp,
28
- onEdgesChange: onEdgesChangeProp,
29
- onNodeClick: onNodeClickProp,
30
- onEdgeClick: onEdgeClickProp,
31
- onConnect: onConnectProp,
32
- editable = false,
33
- className = "",
34
- height = "600px"
35
- }) {
36
- const t = useT();
37
- const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
38
- const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
39
- const { resolvedTheme } = useTheme();
40
- const isDark = resolvedTheme === "dark";
41
- const backgroundDotColor = isDark ? "#374151" : "#e5e7eb";
42
- const [isCompactViewport, setIsCompactViewport] = useState(false);
43
- useEffect(() => {
44
- if (typeof window === "undefined") return;
45
- const mediaQuery = window.matchMedia("(max-width: 1279px)");
46
- const updateViewportMode = () => setIsCompactViewport(mediaQuery.matches);
47
- updateViewportMode();
48
- mediaQuery.addEventListener("change", updateViewportMode);
2
+ import { jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import dynamic from "next/dynamic";
5
+ import { Spinner } from "@open-mercato/ui/primitives/spinner";
6
+ const WorkflowGraphImpl = dynamic(() => import("./WorkflowGraphImpl.js"), {
7
+ ssr: false,
8
+ loading: () => null
9
+ });
10
+ function WorkflowGraphPlaceholder({ height }) {
11
+ return /* @__PURE__ */ jsx(
12
+ "div",
13
+ {
14
+ className: "workflow-graph-container flex items-center justify-center rounded-lg border border-border bg-muted/30",
15
+ style: { height },
16
+ children: /* @__PURE__ */ jsx(Spinner, { className: "h-6 w-6 text-muted-foreground" })
17
+ }
18
+ );
19
+ }
20
+ function WorkflowGraph(props) {
21
+ const { height = "600px" } = props;
22
+ const [isImplReady, setIsImplReady] = React.useState(false);
23
+ React.useEffect(() => {
24
+ let cancelled = false;
25
+ void import("./WorkflowGraphImpl.js").then(() => {
26
+ if (!cancelled) setIsImplReady(true);
27
+ });
49
28
  return () => {
50
- mediaQuery.removeEventListener("change", updateViewportMode);
29
+ cancelled = true;
51
30
  };
52
31
  }, []);
53
- useEffect(() => {
54
- setNodes(initialNodes);
55
- }, [initialNodes, setNodes]);
56
- useEffect(() => {
57
- setEdges(initialEdges);
58
- }, [initialEdges, setEdges]);
59
- const onConnect = useCallback(
60
- (connection) => {
61
- if (onConnectProp) {
62
- onConnectProp(connection);
63
- } else {
64
- const newEdge = {
65
- ...connection,
66
- type: "workflowTransition",
67
- animated: false,
68
- markerEnd: {
69
- type: MarkerType.ArrowClosed,
70
- width: 16,
71
- height: 16,
72
- color: "#9ca3af"
73
- }
74
- };
75
- setEdges((eds) => addEdge(newEdge, eds));
76
- }
77
- },
78
- [setEdges, onConnectProp]
79
- );
80
- const handleNodesChange = useCallback(
81
- (changes) => {
82
- onNodesChange(changes);
83
- if (onNodesChangeProp) {
84
- onNodesChangeProp(changes);
85
- }
86
- },
87
- [onNodesChange, onNodesChangeProp]
88
- );
89
- const handleEdgesChange = useCallback(
90
- (changes) => {
91
- onEdgesChange(changes);
92
- if (onEdgesChangeProp) {
93
- onEdgesChangeProp(changes);
94
- }
95
- },
96
- [onEdgesChange, onEdgesChangeProp]
97
- );
98
- const nodeTypes = useMemo(
99
- () => ({
100
- start: StartNode,
101
- end: EndNode,
102
- userTask: UserTaskNode,
103
- automated: AutomatedNode,
104
- subWorkflow: SubWorkflowNode,
105
- waitForSignal: WaitForSignalNode,
106
- waitForTimer: WaitForTimerNode
107
- }),
108
- []
109
- );
110
- const edgeTypes = useMemo(
111
- () => ({
112
- workflowTransition: WorkflowTransitionEdge
113
- }),
114
- []
115
- );
116
- return /* @__PURE__ */ jsx("div", { className: `workflow-graph-container ${className}`, style: { height }, children: /* @__PURE__ */ jsxs(
117
- ReactFlow,
118
- {
119
- nodes,
120
- edges,
121
- nodeTypes,
122
- edgeTypes,
123
- onNodesChange: handleNodesChange,
124
- onEdgesChange: handleEdgesChange,
125
- onConnect: editable ? onConnect : void 0,
126
- onNodeClick: onNodeClickProp,
127
- onEdgeClick: onEdgeClickProp,
128
- connectionMode: ConnectionMode.Loose,
129
- fitView: true,
130
- fitViewOptions: {
131
- padding: 0.2,
132
- maxZoom: isCompactViewport ? 0.9 : 1
133
- },
134
- minZoom: 0.1,
135
- maxZoom: 2,
136
- defaultEdgeOptions: {
137
- type: "workflowTransition",
138
- animated: false,
139
- markerEnd: {
140
- type: MarkerType.ArrowClosed,
141
- width: 16,
142
- height: 16,
143
- color: "#9ca3af"
144
- }
145
- },
146
- nodesDraggable: editable,
147
- nodesConnectable: editable,
148
- elementsSelectable: editable,
149
- proOptions: { hideAttribution: true },
150
- children: [
151
- /* @__PURE__ */ jsx(
152
- Background,
153
- {
154
- variant: BackgroundVariant.Dots,
155
- gap: 16,
156
- size: 1,
157
- color: backgroundDotColor
158
- }
159
- ),
160
- /* @__PURE__ */ jsx(
161
- Controls,
162
- {
163
- showZoom: true,
164
- showFitView: true,
165
- showInteractive: false,
166
- position: isCompactViewport ? "bottom-right" : "top-right",
167
- className: `!bg-card !border-border !shadow-md [&>button]:!bg-card [&>button]:!border-border [&>button]:!fill-foreground [&>button:hover]:!bg-muted ${isCompactViewport ? "scale-90 origin-bottom-right" : ""}`
168
- }
169
- ),
170
- !isCompactViewport && /* @__PURE__ */ jsx(
171
- MiniMap,
172
- {
173
- nodeStrokeWidth: 3,
174
- nodeColor: (node) => {
175
- const status = node.data?.status || "not_started";
176
- return STATUS_COLORS[status]?.hex || STATUS_COLORS.not_started.hex;
177
- },
178
- maskColor: "rgba(0, 0, 0, 0.1)",
179
- position: "bottom-left",
180
- className: "!bg-card !border !border-border !rounded-lg"
181
- }
182
- ),
183
- !editable && !isCompactViewport && /* @__PURE__ */ jsx(Panel, { position: "top-left", style: { margin: 10 }, children: /* @__PURE__ */ jsx("div", { className: "bg-card rounded-lg shadow-sm border border-border px-4 py-2", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground font-medium", children: t("workflows.graph.visualization") }) }) }),
184
- editable && !isCompactViewport && /* @__PURE__ */ jsx(Panel, { position: "top-left", style: { margin: 10 }, children: /* @__PURE__ */ jsxs(Alert, { variant: "info", className: "max-w-sm", children: [
185
- /* @__PURE__ */ jsx(Edit3, { className: "size-4" }),
186
- /* @__PURE__ */ jsx(AlertDescription, { className: "font-medium", children: t("workflows.graph.editModeInfo") })
187
- ] }) })
188
- ]
189
- }
190
- ) });
32
+ if (!isImplReady) return /* @__PURE__ */ jsx(WorkflowGraphPlaceholder, { height });
33
+ return /* @__PURE__ */ jsx(WorkflowGraphImpl, { ...props });
191
34
  }
192
35
  function WorkflowGraphReadOnly({
193
36
  nodes,