@open-mercato/core 0.6.4-develop.4000.1.450e315cec → 0.6.4-develop.4011.1.4f3ed9ae3e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.js +70 -57
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/acl.js +30 -5
- package/dist/modules/catalog/acl.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +17 -5
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/commands/offers.js +26 -7
- package/dist/modules/catalog/commands/offers.js.map +2 -2
- package/dist/modules/catalog/commands/prices.js +41 -26
- package/dist/modules/catalog/commands/prices.js.map +2 -2
- package/dist/modules/catalog/commands/productUnitConversions.js +7 -1
- package/dist/modules/catalog/commands/productUnitConversions.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +2 -0
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/shared.js +58 -11
- package/dist/modules/catalog/commands/shared.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +18 -5
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +17 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +20 -1
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +28 -6
- package/src/modules/auth/i18n/de.json +1 -0
- package/src/modules/auth/i18n/en.json +1 -0
- package/src/modules/auth/i18n/es.json +1 -0
- package/src/modules/auth/i18n/pl.json +1 -0
- package/src/modules/catalog/acl.ts +30 -5
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -5
- package/src/modules/catalog/commands/offers.ts +26 -7
- package/src/modules/catalog/commands/prices.ts +41 -26
- package/src/modules/catalog/commands/productUnitConversions.ts +7 -1
- package/src/modules/catalog/commands/products.ts +2 -0
- package/src/modules/catalog/commands/shared.ts +70 -6
- package/src/modules/catalog/commands/variants.ts +18 -5
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +21 -2
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +28 -1
- package/src/modules/sales/i18n/de.json +3 -0
- package/src/modules/sales/i18n/en.json +3 -0
- package/src/modules/sales/i18n/es.json +3 -0
- package/src/modules/sales/i18n/pl.json +3 -0
|
@@ -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(/(?:^-+|-+$)/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
|
|
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,gBAAgB,EAAE;AAC7B,SAAO,KAAK,MAAM,GAAG,6BAA6B;AACpD;AAEO,SAAS,wBAAwB,MAK7B;AACT,QAAM,gBACJ,0BAA0B,KAAK,IAAI,KACnC,0BAA0B,KAAK,IAAI,KACnC,0BAA0B,KAAK,QAAQ;AACzC,MAAI,WAAW,iBAAiB;AAChC,MAAI,CAAC,UAAU;AACb,eAAW,UAAU,aAAa,CAAC;AAAA,EACrC;AACA,MAAI,KAAK,YAAY;AACnB,UAAM,SAAS,0BAA0B,GAAG,QAAQ,IAAI,KAAK,UAAU,EAAE;AACzE,QAAI,QAAQ;AACV,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO,YAAY,UAAU,aAAa,CAAC;AAC7C;AAEO,SAAS,gBAAgB,OAAiD;AAC/E,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,SAAO,MAAM,SAAS;AACxB;AAEA,eAAsB,eACpB,IACA,IACA,UAAU,6BACe;AACzB,QAAM,UAAU,MAAM,
|
|
4
|
+
"sourcesContent": ["import {\n CatalogProduct,\n CatalogOffer,\n CatalogProductVariant,\n CatalogOptionSchemaTemplate,\n CatalogPriceKind,\n} from '../data/entities'\nimport type { EntityManager, FilterQuery } 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 type RequireScope = {\n tenantId: string | null\n organizationId: string | null\n}\n\n// Derives the actor's effective tenant/org scope for entry-point lookups, mirroring\n// the bypass semantics of ensureTenantScope/ensureOrganizationScope: tenant is always\n// strict, organization is left unrestricted for super-admins and global-org actors.\nexport function commandActorScope(ctx: CommandRuntimeContext): RequireScope {\n const orgUnrestricted = ctx.auth?.isSuperAdmin === true || ctx.organizationScope?.allowedIds === null\n return {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: orgUnrestricted ? null : (ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null),\n }\n}\n\nfunction applyScopeToWhere(where: Record<string, unknown>, scope: RequireScope): void {\n if (scope.tenantId != null) where.tenantId = scope.tenantId\n if (scope.organizationId != null) where.organizationId = scope.organizationId\n}\n\nexport async function requireProduct(\n em: EntityManager,\n id: string,\n scope: RequireScope,\n message = 'Catalog product not found'\n): Promise<CatalogProduct> {\n const where: Record<string, unknown> = { id, deletedAt: null }\n applyScopeToWhere(where, scope)\n const product = await findOneWithDecryption(\n em,\n CatalogProduct,\n where as FilterQuery<CatalogProduct>,\n undefined,\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\n )\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 scope: RequireScope,\n message = 'Catalog variant not found'\n): Promise<CatalogProductVariant> {\n const where: Record<string, unknown> = { id, deletedAt: null }\n applyScopeToWhere(where, scope)\n const variant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n where as FilterQuery<CatalogProductVariant>,\n { populate: ['product'] },\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\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 scope: RequireScope,\n message = 'Catalog offer not found'\n): Promise<CatalogOffer> {\n const where: Record<string, unknown> = { id }\n applyScopeToWhere(where, scope)\n const offer = await findOneWithDecryption(\n em,\n CatalogOffer,\n where as FilterQuery<CatalogOffer>,\n undefined,\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\n )\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 scope: RequireScope,\n message = 'Catalog price kind not found'\n): Promise<CatalogPriceKind> {\n // Price kinds are tenant-global: organization_id is always null and the unique key is\n // (tenant_id, code). Scope by tenant only \u2014 applying a concrete org would never match the\n // null row. Tenant scoping still closes the cross-tenant read hole this helper guards.\n const where: Record<string, unknown> = { id, deletedAt: null }\n applyScopeToWhere(where, { tenantId: scope.tenantId, organizationId: null })\n const priceKind = await findOneWithDecryption(\n em,\n CatalogPriceKind,\n where as FilterQuery<CatalogPriceKind>,\n undefined,\n { tenantId: scope.tenantId, organizationId: null },\n )\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 scope: RequireScope,\n message = 'Option schema not found'\n): Promise<CatalogOptionSchemaTemplate> {\n const where: Record<string, unknown> = { id, deletedAt: null }\n applyScopeToWhere(where, scope)\n const schema = await findOneWithDecryption(\n em,\n CatalogOptionSchemaTemplate,\n where as FilterQuery<CatalogOptionSchemaTemplate>,\n undefined,\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\n )\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, {\n tenantId: params.tenantId ?? null,\n organizationId: params.organizationId ?? null,\n }).catch(() => undefined)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "../data/validators.js";
|
|
21
21
|
import {
|
|
22
22
|
cloneJson,
|
|
23
|
+
commandActorScope,
|
|
23
24
|
ensureOrganizationScope,
|
|
24
25
|
ensureTenantScope,
|
|
25
26
|
emitCatalogQueryIndexEvent,
|
|
@@ -199,7 +200,10 @@ async function loadVariantPriceSnapshots(em, variantId, scope) {
|
|
|
199
200
|
}
|
|
200
201
|
async function restoreVariantPricesFromSnapshots(em, variant, snapshots, dataEngine) {
|
|
201
202
|
if (!snapshots.length) return;
|
|
202
|
-
const productRef = typeof variant.product === "string" ? await requireProduct(em, variant.product
|
|
203
|
+
const productRef = typeof variant.product === "string" ? await requireProduct(em, variant.product, {
|
|
204
|
+
tenantId: variant.tenantId,
|
|
205
|
+
organizationId: variant.organizationId
|
|
206
|
+
}) : variant.product;
|
|
203
207
|
for (const snapshot of snapshots) {
|
|
204
208
|
const product = snapshot.productId && snapshot.productId !== productRef.id ? em.getReference(CatalogProduct, snapshot.productId) : productRef;
|
|
205
209
|
const offer = snapshot.offerId ? em.getReference(CatalogOffer, snapshot.offerId) : null;
|
|
@@ -399,7 +403,7 @@ const createVariantCommand = {
|
|
|
399
403
|
async execute(rawInput, ctx) {
|
|
400
404
|
const { parsed, custom } = parseWithCustomFields(variantCreateSchema, rawInput);
|
|
401
405
|
const em = ctx.container.resolve("em").fork();
|
|
402
|
-
const product = await requireProduct(em, parsed.productId);
|
|
406
|
+
const product = await requireProduct(em, parsed.productId, commandActorScope(ctx));
|
|
403
407
|
ensureTenantScope(ctx, product.tenantId);
|
|
404
408
|
ensureOrganizationScope(ctx, product.organizationId);
|
|
405
409
|
const { taxRateId, taxRate } = await resolveVariantTaxRate(
|
|
@@ -553,7 +557,10 @@ const updateVariantCommand = {
|
|
|
553
557
|
if (!record) throw new CrudHttpError(404, { error: "Catalog variant not found" });
|
|
554
558
|
ensureTenantScope(ctx, record.tenantId);
|
|
555
559
|
ensureOrganizationScope(ctx, record.organizationId);
|
|
556
|
-
const product = await requireProduct(em, record.product.id
|
|
560
|
+
const product = await requireProduct(em, record.product.id, {
|
|
561
|
+
tenantId: record.tenantId,
|
|
562
|
+
organizationId: record.organizationId
|
|
563
|
+
});
|
|
557
564
|
if (!product) throw new CrudHttpError(400, { error: "Variant product missing" });
|
|
558
565
|
const taxRateProvided = parsed.taxRateId !== void 0 || parsed.taxRate !== void 0;
|
|
559
566
|
const resolvedTaxRate = taxRateProvided ? await resolveVariantTaxRate(em, product, parsed.taxRateId ?? null, parsed.taxRate) : null;
|
|
@@ -668,7 +675,10 @@ const updateVariantCommand = {
|
|
|
668
675
|
const em = ctx.container.resolve("em").fork();
|
|
669
676
|
let record = await em.findOne(CatalogProductVariant, { id: before.id });
|
|
670
677
|
if (!record) {
|
|
671
|
-
const product = await requireProduct(em, before.productId
|
|
678
|
+
const product = await requireProduct(em, before.productId, {
|
|
679
|
+
tenantId: before.tenantId,
|
|
680
|
+
organizationId: before.organizationId
|
|
681
|
+
});
|
|
672
682
|
record = em.create(CatalogProductVariant, {
|
|
673
683
|
id: before.id,
|
|
674
684
|
product,
|
|
@@ -826,7 +836,10 @@ const deleteVariantCommand = {
|
|
|
826
836
|
const em = ctx.container.resolve("em").fork();
|
|
827
837
|
let record = await em.findOne(CatalogProductVariant, { id: before.id });
|
|
828
838
|
if (!record) {
|
|
829
|
-
const product = await requireProduct(em, before.productId
|
|
839
|
+
const product = await requireProduct(em, before.productId, {
|
|
840
|
+
tenantId: before.tenantId,
|
|
841
|
+
organizationId: before.organizationId
|
|
842
|
+
});
|
|
830
843
|
record = em.create(CatalogProductVariant, {
|
|
831
844
|
id: before.id,
|
|
832
845
|
product,
|
|
@@ -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\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": "AAAA,SAAS,uBAAuB;AAEhC,SAAS,cAAc,WAAW,uBAAuB,sBAAsB,2BAA2B;AAE1G,SAAS,0CAA0C;AACnD,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,yBAAyB,gCAAgC;AAClE,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,kBAAkB;AAC3B;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,oBAAoB;AAG7B,MAAM,oBAAsC;AAAA,EAC1C,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,gBAAgB,IAAI,YAAY;AAAA,IAChC,UAAU,IAAI,YAAY;AAAA,EAC5B;AACF;AAiCA,MAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAe,oBACb,IACA,IACA,UAAuC,CAAC,GACP;AACjC,QAAM,SAAS,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,WAAW,KAAK,CAAC;AAC9E,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,SAAS,QAAQ,gBACnB,MAAM,0BAA0B,IAAI,OAAO,IAAI;AAAA,IAC7C,UAAU,OAAO;AAAA,IACjB,gBAAgB,OAAO;AAAA,EACzB,CAAC,IACD;AACJ,QAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,IAC/C,UAAU,EAAE,QAAQ;AAAA,IACpB,UAAU,OAAO;AAAA,IACjB,UAAU,OAAO;AAAA,IACjB,gBAAgB,OAAO;AAAA,EACzB,CAAC;AACD,QAAM,YAAY,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,OAAO,QAAQ;AACvF,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX;AAAA,IACA,gBAAgB,OAAO;AAAA,IACvB,UAAU,OAAO;AAAA,IACjB,MAAM,OAAO,QAAQ;AAAA,IACrB,KAAK,OAAO,OAAO;AAAA,IACnB,SAAS,OAAO,WAAW;AAAA,IAC3B,eAAe,OAAO,iBAAiB;AAAA,IACvC,WAAW,OAAO;AAAA,IAClB,UAAU,OAAO;AAAA,IACjB,aAAa,OAAO,eAAe;AAAA,IACnC,YAAY,OAAO,cAAc;AAAA,IACjC,WAAW,OAAO,aAAa;AAAA,IAC/B,SAAS,OAAO,WAAW;AAAA,IAC3B,YAAY,OAAO,aAAa,UAAU,OAAO,UAAU,IAAI;AAAA,IAC/D,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,IACzD,cAAc,OAAO,eAAe,UAAU,OAAO,YAAY,IAAI;AAAA,IACrE,oBAAoB,OAAO,sBAAsB;AAAA,IACjD,WAAW,OAAO,UAAU,YAAY;AAAA,IACxC,WAAW,OAAO,UAAU,YAAY;AAAA,IACxC,QAAQ,OAAO,KAAK,MAAM,EAAE,SAAS,SAAS;AAAA,IAC9C,QAAQ,UAAU,OAAO,SAAS,SAAS;AAAA,EAC7C;AACF;AAEA,SAAS,qBAAqB,QAA+B,UAAiC;AAC5F,SAAO,iBAAiB,SAAS;AACjC,SAAO,WAAW,SAAS;AAC3B,SAAO,OAAO,SAAS,QAAQ;AAC/B,SAAO,MAAM,SAAS,OAAO;AAC7B,SAAO,UAAU,SAAS,WAAW;AACrC,SAAO,gBAAgB,SAAS,iBAAiB;AACjD,SAAO,YAAY,SAAS;AAC5B,SAAO,WAAW,SAAS;AAC3B,SAAO,cAAc,SAAS,eAAe;AAC7C,SAAO,aAAa,SAAS,cAAc;AAC3C,SAAO,YAAY,SAAS,aAAa;AACzC,SAAO,UAAU,SAAS,WAAW;AACrC,SAAO,aAAa,SAAS,aAAa,UAAU,SAAS,UAAU,IAAI;AAC3E,SAAO,WAAW,SAAS,WAAW,UAAU,SAAS,QAAQ,IAAI;AACrE,SAAO,eAAe,SAAS,eAAe,UAAU,SAAS,YAAY,IAAI;AACjF,SAAO,qBAAqB,SAAS,sBAAsB;AAC3D,SAAO,YAAY,IAAI,KAAK,SAAS,SAAS;AAC9C,SAAO,YAAY,IAAI,KAAK,SAAS,SAAS;AAChD;AAEA,eAAe,sBACb,IACA,SACA,gBACA,cAC+D;AAC/D,QAAM,iBAAiB,QAAQ;AAC/B,QAAM,WAAW,QAAQ;AACzB,QAAM,iBACJ,iBAAiB,QAAQ,iBAAiB,SACtC,QACC,MAAM;AACL,UAAM,UAAU,OAAO,iBAAiB,WAAW,OAAO,YAAY,IAAI;AAC1E,WAAO,OAAO,SAAS,OAAO,IAAI,gBAAgB,OAAO,IAAI;AAAA,EAC/D,GAAG;AACT,MAAI,mBAAmB,MAAM;AAC3B,WAAO,EAAE,WAAW,QAAQ,aAAa,MAAM,SAAS,QAAQ,WAAW,KAAK;AAAA,EAClF;AACA,MAAI,CAAC,gBAAgB;AACnB,WAAO,EAAE,WAAW,QAAQ,aAAa,MAAM,SAAS,QAAQ,WAAW,eAAe;AAAA,EAC5F;AACA,QAAM,SAAS,MAAM,GAAG,QAAQ,cAAc;AAAA,IAC5C,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AACD,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,sBAAsB,CAAC;AAAA,EAC/D;AACA,SAAO,EAAE,WAAW,gBAAgB,SAAS,OAAO,QAAQ,eAAe;AAC7E;AAgCA,eAAe,0BACb,IACA,WACA,OACiC;AACjC,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA,EAAE,SAAS,WAAW,UAAU,MAAM,UAAU,gBAAgB,MAAM,eAAe;AAAA,IACrF,EAAE,UAAU,CAAC,aAAa,WAAW,OAAO,EAAE;AAAA,IAC9C,EAAE,UAAU,MAAM,UAAU,gBAAgB,MAAM,eAAe;AAAA,EACnE;AACA,QAAM,YAAoC,CAAC;AAC3C,aAAW,SAAS,QAAQ;AAC1B,UAAM,aAAa,MAAM;AACzB,UAAM,iBACJ,OAAO,eAAe,WAClB,aACA,aACE,WAAW,KACX;AACR,UAAM,aAAa,MAAM,UACrB,MAAM,UACN,OAAO,MAAM,YAAY,YAAY,MAAM,UACzC,MAAM,QAAQ,UACd;AACN,UAAM,YACJ,OAAO,eAAe,WAClB,aACA,aACE,WAAW,KACX;AACR,UAAM,eAAe,MAAM;AAC3B,UAAM,cACJ,OAAO,iBAAiB,WACpB,eACA,eACE,aAAa,KACb;AACR,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,wCAAwC,CAAC;AAAA,IACjF;AACA,UAAM,gBACJ,OAAO,iBAAiB,YAAY,eAAe,aAAa,OAAO,MAAM;AAC/E,UAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,MAC/C,UAAU,EAAE,QAAQ;AAAA,MACpB,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB,CAAC;AACD,cAAU,KAAK;AAAA,MACb,IAAI,MAAM;AAAA,MACV,WAAW;AAAA,MACX;AAAA,MACA,SAAS,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,MAAM,QAAQ,MAAM,MAAM,KAAK;AAAA,MACxF,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB;AAAA,MACA;AAAA,MACA,cAAc,MAAM;AAAA,MACpB,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM,eAAe;AAAA,MAClC,cAAc,MAAM,gBAAgB;AAAA,MACpC,gBAAgB,MAAM,kBAAkB;AAAA,MACxC,SAAS,MAAM,WAAW;AAAA,MAC1B,WAAW,MAAM,aAAa;AAAA,MAC9B,WAAW,MAAM,aAAa;AAAA,MAC9B,QAAQ,MAAM,UAAU;AAAA,MACxB,aAAa,MAAM,eAAe;AAAA,MAClC,YAAY,MAAM,cAAc;AAAA,MAChC,iBAAiB,MAAM,mBAAmB;AAAA,MAC1C,UAAU,MAAM,WAAW,UAAU,MAAM,QAAQ,IAAI;AAAA,MACvD,UAAU,MAAM,WAAW,MAAM,SAAS,YAAY,IAAI;AAAA,MAC1D,QAAQ,MAAM,SAAS,MAAM,OAAO,YAAY,IAAI;AAAA,MACpD,WAAW,MAAM,UAAU,YAAY;AAAA,MACvC,WAAW,MAAM,UAAU,YAAY;AAAA,MACvC,QAAQ,OAAO,KAAK,MAAM,EAAE,SAAS,SAAS;AAAA,IAChD,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,eAAe,kCACb,IACA,SACA,WACA,YACe;AACf,MAAI,CAAC,UAAU,OAAQ;AACvB,QAAM,aACJ,OAAO,QAAQ,YAAY,WACvB,MAAM,eAAe,IAAI,QAAQ,OAAO,IACxC,QAAQ;AACd,aAAW,YAAY,WAAW;AAChC,UAAM,UACJ,SAAS,aAAa,SAAS,cAAc,WAAW,KACpD,GAAG,aAAa,gBAAgB,SAAS,SAAS,IAClD;AACN,UAAM,QAAQ,SAAS,UAAU,GAAG,aAAa,cAAc,SAAS,OAAO,IAAI;AACnF,UAAM,YAAY,GAAG,aAAa,kBAAkB,SAAS,WAAW;AACxE,QAAI,SAAS,MAAM,GAAG,QAAQ,qBAAqB,EAAE,IAAI,SAAS,GAAG,CAAC;AACtE,QAAI,CAAC,QAAQ;AACX,eAAS,GAAG,OAAO,qBAAqB;AAAA,QACtC,IAAI,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB,SAAS;AAAA,QACzB,UAAU,SAAS;AAAA,QACnB,cAAc,SAAS;AAAA,QACvB;AAAA,QACA,MAAM,SAAS,iBAAiB,SAAS;AAAA,QACzC,aAAa,SAAS;AAAA,QACtB,aAAa,SAAS,eAAe;AAAA,QACrC,cAAc,SAAS,gBAAgB;AAAA,QACvC,gBAAgB,SAAS,kBAAkB;AAAA,QAC3C,SAAS,SAAS,WAAW;AAAA,QAC7B,WAAW,SAAS,aAAa;AAAA,QACjC,WAAW,SAAS,aAAa;AAAA,QACjC,QAAQ,SAAS,UAAU;AAAA,QAC3B,aAAa,SAAS,eAAe;AAAA,QACrC,YAAY,SAAS,cAAc;AAAA,QACnC,iBAAiB,SAAS,mBAAmB;AAAA,QAC7C,UAAU,SAAS,WAAW,UAAU,SAAS,QAAQ,IAAI;AAAA,QAC7D,UAAU,SAAS,WAAW,IAAI,KAAK,SAAS,QAAQ,IAAI;AAAA,QAC5D,QAAQ,SAAS,SAAS,IAAI,KAAK,SAAS,MAAM,IAAI;AAAA,QACtD,WAAW,IAAI,KAAK,SAAS,SAAS;AAAA,QACtC,WAAW,IAAI,KAAK,SAAS,SAAS;AAAA,MACxC,CAAC;AACD,SAAG,QAAQ,MAAM;AAAA,IACnB,OAAO;AACL,aAAO,UAAU;AACjB,aAAO,UAAU;AACjB,aAAO,QAAQ;AACf,aAAO,YAAY;AACnB,aAAO,iBAAiB,SAAS;AACjC,aAAO,WAAW,SAAS;AAC3B,aAAO,eAAe,SAAS;AAC/B,aAAO,OAAO,SAAS,iBAAiB,SAAS;AACjD,aAAO,cAAc,SAAS;AAC9B,aAAO,cAAc,SAAS,eAAe;AAC7C,aAAO,eAAe,SAAS,gBAAgB;AAC/C,aAAO,iBAAiB,SAAS,kBAAkB;AACnD,aAAO,UAAU,SAAS,WAAW;AACrC,aAAO,YAAY,SAAS,aAAa;AACzC,aAAO,YAAY,SAAS,aAAa;AACzC,aAAO,SAAS,SAAS,UAAU;AACnC,aAAO,cAAc,SAAS,eAAe;AAC7C,aAAO,aAAa,SAAS,cAAc;AAC3C,aAAO,kBAAkB,SAAS,mBAAmB;AACrD,aAAO,WAAW,SAAS,WAAW,UAAU,SAAS,QAAQ,IAAI;AACrE,aAAO,WAAW,SAAS,WAAW,IAAI,KAAK,SAAS,QAAQ,IAAI;AACpE,aAAO,SAAS,SAAS,SAAS,IAAI,KAAK,SAAS,MAAM,IAAI;AAC9D,aAAO,YAAY,IAAI,KAAK,SAAS,SAAS;AAC9C,aAAO,YAAY,IAAI,KAAK,SAAS,SAAS;AAAA,IAChD;AAAA,EACF;AACA,QAAM,GAAG,MAAM;AACf,aAAW,YAAY,WAAW;AAChC,QAAI,CAAC,SAAS,UAAU,CAAC,OAAO,KAAK,SAAS,MAAM,EAAE,OAAQ;AAC9D,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA,UAAU,EAAE,QAAQ;AAAA,MACpB,UAAU,SAAS;AAAA,MACnB,gBAAgB,SAAS;AAAA,MACzB,UAAU,SAAS;AAAA,MACnB,QAAQ,SAAS;AAAA,IACnB,CAAC;AAAA,EACH;AACF;AAQA,SAAS,8BACP,UACqB;AACrB,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,MAAM,QAAQ,QAAQ,GAAG;AACxE,WAAO;AAAA,MACL,UAAU,WAAW,UAAU,QAAQ,IAAI;AAAA,MAC3C,cAAc;AAAA,MACd,iBAAiB;AAAA,IACnB;AAAA,EACF;AACA,QAAM,EAAE,cAAc,GAAG,KAAK,IAAI;AAGlC,QAAM,qBAAqB,OAAO,KAAK,IAAI,EAAE,SAAS,UAAU,IAAI,IAAI;AACxE,SAAO;AAAA,IACL,UAAU;AAAA,IACV,cAAc,sBAAsB,YAAY;AAAA,IAChD,iBAAiB,iBAAiB;AAAA,EACpC;AACF;AAEA,SAAS,sBAAsB,OAA+C;AAC5E,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,QAAM,aAAqC,CAAC;AAC5C,aAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,KAAK,GAAG;AACtD,QAAI,OAAO,aAAa,SAAU;AAClC,UAAM,MAAM,OAAO,KAAK;AACxB,UAAM,QAAQ,SAAS,KAAK;AAC5B,QAAI,CAAC,OAAO,CAAC,MAAO;AACpB,eAAW,GAAG,IAAI;AAAA,EACpB;AACA,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,aAAa;AACvD;AAEA,SAAS,iBAAiB,QAAuC;AAC/D,SAAO,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,OAAO,QAAQ;AAC9E;AAEA,eAAe,4BACb,IACA,SACwB;AACxB,MAAI,CAAC,QAAQ,UAAW,QAAO;AAC/B,QAAM,YAAY,iBAAiB,OAAO;AAC1C,QAAM,kBAAkB,MAAM,GAAG;AAAA,IAC/B;AAAA,IACA,EAAE,SAAS,WAAW,WAAW,MAAM,WAAW,MAAM,IAAI,EAAE,KAAK,QAAQ,GAAG,EAAE;AAAA,IAChF,EAAE,QAAQ,CAAC,MAAM,WAAW,EAAE;AAAA,EAChC;AACA,MAAI,iBAAiB;AACnB,oBAAgB,YAAY;AAC5B,WAAO,gBAAgB;AAAA,EACzB;AACA,SAAO;AACT;AAEA,eAAe,+BACb,IACA,SACe;AACf,QAAM,YAAY,iBAAiB,OAAO;AAC1C,QAAM,WAAW,CACf,eAEA;AAAA,IACE,WAAW,UAAU,KAAK,KAAK;AAAA,IAC/B,WAAW,YAAY;AAAA,IACvB,WAAW,iBAAiB;AAAA,IAC5B,WAAW,iBAAiB;AAAA,EAC9B,EAAE,KAAK,GAAG;AACZ,QAAM,cAAc,MAAM,GAAG;AAAA,IAC3B;AAAA,IACA;AAAA,MACE,UAAU,EAAE,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,UAAU,QAAQ,YAAY;AAAA,IAChC;AAAA,IACA;AAAA,MACE,QAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,YAAY,OAAQ;AACzB,QAAM,WAAW,MAAM,GAAG;AAAA,IACxB;AAAA,IACA;AAAA,MACE,UAAU,EAAE,QAAQ;AAAA,MACpB,UAAU;AAAA,MACV,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,UAAU,QAAQ,YAAY;AAAA,IAChC;AAAA,IACA;AAAA,MACE,QAAQ,CAAC,eAAe,YAAY,YAAY,iBAAiB,eAAe;AAAA,IAClF;AAAA,EACF;AACA,QAAM,eAAe,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,SAAS,IAAI,CAAC,CAAC;AACnE,MAAI,UAAU;AACd,aAAW,UAAU,aAAa;AAChC,UAAM,MAAM,SAAS,MAAM;AAC3B,QAAI,aAAa,IAAI,GAAG,EAAG;AAC3B,UAAM,QAAQ,GAAG,OAAO,YAAY;AAAA,MAClC,UAAU,EAAE,QAAQ;AAAA,MACpB,UAAU;AAAA,MACV,gBAAgB,OAAO,kBAAkB,QAAQ,kBAAkB;AAAA,MACnE,UAAU,OAAO,YAAY,QAAQ,YAAY;AAAA,MACjD,eAAe,OAAO;AAAA,MACtB,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,eAAe,OAAO;AAAA,MACtB,aAAa,OAAO;AAAA,MACpB,iBAAiB,OAAO,kBAAkB,UAAU,OAAO,eAAe,IAAI;AAAA,MAC9E,KAAK,OAAO;AAAA,IACd,CAAC;AACD,OAAG,QAAQ,KAAK;AAChB,iBAAa,IAAI,GAAG;AACpB,eAAW;AAAA,EACb;AACA,MAAI,UAAU,GAAG;AACf,UAAM,GAAG,MAAM;AAAA,EACjB;AACF;AAEA,MAAM,uBAA4H;AAAA,EAChI,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,OAAO,IAAI,sBAAsB,qBAAqB,QAAQ;AAC9E,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,UAAU,MAAM,eAAe,IAAI,OAAO,SAAS;AACzD,sBAAkB,KAAK,QAAQ,QAAQ;AACvC,4BAAwB,KAAK,QAAQ,cAAc;AACnD,UAAM,EAAE,WAAW,QAAQ,IAAI,MAAM;AAAA,MACnC;AAAA,MACA;AAAA,MACA,OAAO,aAAa;AAAA,MACpB,OAAO;AAAA,IACT;AAEA,UAAM,gBAAgB,8BAA8B,OAAO,QAAQ;AACnE,UAAM,uBACJ,OAAO,iBAAiB,cAAc,kBAAkB,cAAc,eAAe;AAEvF,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,SAAS,GAAG,OAAO,uBAAuB;AAAA,MAC9C,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB;AAAA,MACA,MAAM,OAAO,QAAQ;AAAA,MACrB,KAAK,OAAO,OAAO;AAAA,MACnB,SAAS,OAAO,WAAW;AAAA,MAC3B,eAAe,OAAO,iBAAiB;AAAA,MACvC,WAAW,OAAO,aAAa;AAAA,MAC/B,UAAU,OAAO,YAAY;AAAA,MAC7B,aAAa,gBAAgB,OAAO,WAAW;AAAA,MAC/C,YAAY,OAAO,cAAc;AAAA,MACjC;AAAA,MACA;AAAA,MACA,YAAY,OAAO,aAAa,UAAU,OAAO,UAAU,IAAI;AAAA,MAC/D,UAAU,cAAc;AAAA,MACxB,cAAc,uBAAuB,UAAU,oBAAoB,IAAI;AAAA,MACvE,oBAAoB,OAAO,sBAAsB;AAAA,MACjD,WAAW;AAAA,MACX,WAAW;AAAA,IACb,CAAC;AACD,OAAG,QAAQ,MAAM;AACjB,QAAI;AACF,YAAM,GAAG,MAAM;AAAA,IACjB,SAAS,OAAO;AACd,YAAM,+BAA+B,KAAK;AAAA,IAC5C;AACA,QAAI,2BAA0C;AAC9C,QAAI,OAAO,WAAW;AACpB,iCAA2B,MAAM,4BAA4B,IAAI,MAAM;AACvE,UAAI;AACF,cAAM,GAAG,MAAM;AAAA,MACjB,SAAS,OAAO;AACd,cAAM,+BAA+B,KAAK;AAAA,MAC5C;AAAA,IACF;AACA,UAAM,+BAA+B,IAAI,MAAM;AAC/C,UAAM,qBAAqB;AAAA,MACzB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,MAC9C,UAAU,EAAE,QAAQ;AAAA,MACpB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,2BAA2B,KAAK;AAAA,MACpC,YAAY,EAAE,QAAQ;AAAA,MACtB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,oBAAoB;AAAA,MACxB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,MAC9C,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,OAAO;AAAA,QACX,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,EAAE,WAAW,OAAO,IAAI,yBAAyB;AAAA,EAC1D;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,oBAAoB,IAAI,OAAO,SAAS;AAAA,EACjD;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,UAAU,MAAM;AACzC,UAAM,QAAQ,UAAU;AACxB,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO;AAAA,MACL,aAAa,UAAU,iCAAiC,wBAAwB;AAAA,MAChF,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB,MAAM,aAAa;AAAA,MACrC,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,MACtB,eAAe;AAAA,MACf,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACA,0BAA2B,QAAyD,4BAA4B;AAAA,QAClH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAuC,QAAQ;AAC/D,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO;AACZ,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,SAAS,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,MAAM,GAAG,CAAC;AACvE,QAAI,CAAC,OAAQ;AACb,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,OAAG,OAAO,MAAM;AAChB,UAAM,GAAG,MAAM;AACf,QAAI,SAAS,0BAA0B;AACrC,YAAM,kBAAkB,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,QAAQ,yBAAyB,CAAC;AACxG,UAAI,iBAAiB;AACnB,0BAAkB,KAAK,gBAAgB,QAAQ;AAC/C,gCAAwB,KAAK,gBAAgB,cAAc;AAC3D,wBAAgB,YAAY;AAC5B,cAAM,GAAG,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM,cAAc,yBAAyB,QAAW,MAAM,UAAU,MAAS;AACjF,QAAI,OAAO,KAAK,WAAW,EAAE,QAAQ;AACnC,YAAM,qBAAqB;AAAA,QACzB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,QAC9C,UAAU,EAAE,QAAQ;AAAA,QACpB,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,QACtB,UAAU,MAAM;AAAA,QAChB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,uBAA4H;AAAA,EAChI,IAAI;AAAA,EACJ,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,wBAAwB;AACpD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI;AACtC,UAAM,WAAW,MAAM,oBAAoB,IAAI,EAAE;AACjD,QAAI,UAAU;AACZ,wBAAkB,KAAK,SAAS,QAAQ;AACxC,8BAAwB,KAAK,SAAS,cAAc;AAAA,IACtD;AACA,WAAO,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA,EACA,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,OAAO,IAAI,sBAAsB,qBAAqB,QAAQ;AAC9E,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,SAAS,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,OAAO,IAAI,WAAW,KAAK,CAAC;AACzF,QAAI,CAAC,OAAQ,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAChF,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,UAAM,UAAU,MAAM,eAAe,IAAI,OAAO,QAAQ,EAAE;AAE1D,QAAI,CAAC,QAAS,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAE/E,UAAM,kBAAkB,OAAO,cAAc,UAAa,OAAO,YAAY;AAC7E,UAAM,kBAAkB,kBACpB,MAAM,sBAAsB,IAAI,SAAS,OAAO,aAAa,MAAM,OAAO,OAAO,IACjF;AAEJ,QAAI,OAAO,SAAS,OAAW,QAAO,OAAO,OAAO,QAAQ;AAC5D,QAAI,OAAO,QAAQ,OAAW,QAAO,MAAM,OAAO,OAAO;AACzD,QAAI,OAAO,YAAY,OAAW,QAAO,UAAU,OAAO,WAAW;AACrE,QAAI,OAAO,kBAAkB,OAAW,QAAO,gBAAgB,OAAO,iBAAiB;AACvF,QAAI,OAAO,cAAc,OAAW,QAAO,YAAY,OAAO;AAC9D,QAAI,OAAO,aAAa,OAAW,QAAO,WAAW,OAAO;AAC5D,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,aAAa,GAAG;AAC/D,aAAO,cAAc,gBAAgB,OAAO,WAAW;AAAA,IACzD;AACA,QAAI,OAAO,eAAe,OAAW,QAAO,aAAa,OAAO,cAAc;AAC9E,QAAI,OAAO,eAAe,QAAW;AACnC,aAAO,aAAa,OAAO,aAAa,UAAU,OAAO,UAAU,IAAI;AAAA,IACzE;AACA,QAAI,gBAA4C;AAChD,QAAI,OAAO,aAAa,QAAW;AACjC,sBAAgB,8BAA8B,OAAO,QAAQ;AAC7D,aAAO,WAAW,cAAc;AAAA,IAClC;AACA,QAAI,OAAO,iBAAiB,QAAW;AACrC,aAAO,eAAe,OAAO,eAAe,UAAU,OAAO,YAAY,IAAI;AAAA,IAC/E,WAAW,eAAe,iBAAiB;AACzC,aAAO,eAAe,cAAc,eAAe,UAAU,cAAc,YAAY,IAAI;AAAA,IAC7F;AACA,QAAI,iBAAiB;AACnB,aAAO,YAAY,iBAAiB,aAAa;AACjD,aAAO,UAAU,iBAAiB,WAAW;AAAA,IAC/C;AACA,QAAI,OAAO,uBAAuB,QAAW;AAC3C,aAAO,qBAAqB,OAAO,sBAAsB;AAAA,IAC3D;AAEA,QAAI,2BAA0C;AAC9C,QAAI,OAAO,cAAc,MAAM;AAC7B,iCAA2B,MAAM,4BAA4B,IAAI,MAAM;AAAA,IACzE;AACA,QAAI;AACF,YAAM,GAAG,MAAM;AAAA,IACjB,SAAS,OAAO;AACd,YAAM,+BAA+B,KAAK;AAAA,IAC5C;AACA,UAAM,+BAA+B,IAAI,MAAM;AAC/C,QAAI,UAAU,OAAO,KAAK,MAAM,EAAE,QAAQ;AACxC,YAAM,qBAAqB;AAAA,QACzB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,QAC9C,UAAU,EAAE,QAAQ;AAAA,QACpB,UAAU,OAAO;AAAA,QACjB,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,UAAM,2BAA2B,KAAK;AAAA,MACpC,YAAY,EAAE,QAAQ;AAAA,MACtB,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,UAAU,OAAO;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,oBAAoB;AAAA,MACxB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,MAC9C,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,OAAO;AAAA,QACX,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,MACnB;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,EAAE,WAAW,OAAO,IAAI,yBAAyB;AAAA,EAC1D;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,oBAAoB,IAAI,OAAO,SAAS;AAAA,EACjD;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,UAAU,MAAM;AACzC,UAAM,SAAS,UAAU;AACzB,UAAM,QAAQ,UAAU;AACxB,QAAI,CAAC,UAAU,CAAC,MAAO,QAAO;AAC9B,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO;AAAA,MACL,aAAa,UAAU,iCAAiC,wBAAwB;AAAA,MAChF,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB,OAAO,aAAa;AAAA,MACtC,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,gBAAgB;AAAA,MAChB,eAAe;AAAA,MACf,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,UACA,0BACG,QAAyD,4BAA4B;AAAA,QAC1F;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAuC,QAAQ;AAC/D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,SAAS;AACvB,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,SAAS,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,OAAO,GAAG,CAAC;AACtE,QAAI,CAAC,QAAQ;AACX,YAAM,UAAU,MAAM,eAAe,IAAI,OAAO,SAAS;AACzD,eAAS,GAAG,OAAO,uBAAuB;AAAA,QACxC,IAAI,OAAO;AAAA,QACX;AAAA,QACA,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,MAAM,OAAO,QAAQ;AAAA,QACrB,KAAK,OAAO,OAAO;AAAA,QACnB,SAAS,OAAO,WAAW;AAAA,QAC3B,eAAe,OAAO,iBAAiB;AAAA,QACvC,WAAW,OAAO;AAAA,QAClB,UAAU,OAAO;AAAA,QACjB,aAAa,OAAO,eAAe;AAAA,QACnC,YAAY,OAAO,cAAc;AAAA,QACjC,YAAY,OAAO,aAAa,UAAU,OAAO,UAAU,IAAI;AAAA,QAC/D,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,QACzD,cAAc,OAAO,eAAe,UAAU,OAAO,YAAY,IAAI;AAAA,QACrE,oBAAoB,OAAO,sBAAsB;AAAA,QACjD,WAAW,IAAI,KAAK,OAAO,SAAS;AAAA,QACpC,WAAW,IAAI,KAAK,OAAO,SAAS;AAAA,MACtC,CAAC;AACD,SAAG,QAAQ,MAAM;AAAA,IACnB;AACA,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,yBAAqB,QAAQ,MAAM;AACnC,UAAM,GAAG,MAAM;AACf,UAAM,oBAAoB,SAAS;AACnC,QAAI,mBAAmB;AACrB,YAAM,kBAAkB,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,kBAAkB,CAAC;AACzF,UAAI,iBAAiB;AACnB,0BAAkB,KAAK,gBAAgB,QAAQ;AAC/C,gCAAwB,KAAK,gBAAgB,cAAc;AAC3D,wBAAgB,YAAY;AAC5B,cAAM,GAAG,MAAM;AAAA,MACjB;AAAA,IACF;AACA,UAAM,cAAc;AAAA,MAClB,OAAO,UAAU;AAAA,MACjB,OAAO,UAAU;AAAA,IACnB;AACA,QAAI,OAAO,KAAK,WAAW,EAAE,QAAQ;AACnC,YAAM,qBAAqB;AAAA,QACzB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,QAC9C,UAAU,EAAE,QAAQ;AAAA,QACpB,UAAU,OAAO;AAAA,QACjB,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,uBAGF;AAAA,EACF,IAAI;AAAA,EACJ,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,wBAAwB;AACpD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI;AACtC,UAAM,WAAW,MAAM,oBAAoB,IAAI,IAAI,EAAE,eAAe,KAAK,CAAC;AAC1E,QAAI,UAAU;AACZ,wBAAkB,KAAK,SAAS,QAAQ;AACxC,8BAAwB,KAAK,SAAS,cAAc;AAAA,IACtD;AACA,WAAO,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA,EACA,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,wBAAwB;AACpD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,SAAS,MAAM,GAAG,QAAQ,uBAAuB,EAAE,GAAG,CAAC;AAC7D,QAAI,CAAC,OAAQ,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,4BAA4B,CAAC;AAChF,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAElD,UAAM,SAAU,IAAI,UAAU,QAAQ,IAAI;AAC1C,UAAM,WAAW,MAAM,oBAAoB,QAAQ,IAAI,EAAE,eAAe,KAAK,CAAC;AAC9E,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,UAAM,iBACJ,UAAU,UAAU,SAAS,OAAO,SAChC,SAAS,SACT,MAAM,0BAA0B,QAAQ,IAAI;AAAA,MAC1C,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,IACzB,CAAC;AAEP,QAAI,eAAe,QAAQ;AACzB,YAAM,GAAG,aAAa,qBAAqB,EAAE,IAAI,EAAE,KAAK,eAAe,IAAI,CAAC,UAAU,MAAM,EAAE,EAAE,EAAE,CAAC;AAAA,IACrG,OAAO;AACL,YAAM,GAAG,aAAa,qBAAqB,EAAE,SAAS,OAAO,CAAC;AAAA,IAChE;AACA,OAAG,OAAO,MAAM;AAChB,UAAM,GAAG,MAAM;AACf,eAAW,iBAAiB,gBAAgB;AAC1C,YAAM,cAAc,yBAAyB,cAAc,UAAU,QAAW,MAAS;AACzF,UAAI,CAAC,OAAO,KAAK,WAAW,EAAE,OAAQ;AACtC,YAAM,qBAAqB;AAAA,QACzB;AAAA,QACA,UAAU,EAAE,QAAQ;AAAA,QACpB,UAAU,cAAc;AAAA,QACxB,gBAAgB,cAAc;AAAA,QAC9B,UAAU,cAAc;AAAA,QACxB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,QAAI,UAAU,UAAU,OAAO,KAAK,SAAS,MAAM,EAAE,QAAQ;AAC3D,YAAM,cAAc,yBAAyB,SAAS,QAAQ,MAAS;AACvE,UAAI,OAAO,KAAK,WAAW,EAAE,QAAQ;AACnC,cAAM,qBAAqB;AAAA,UACzB;AAAA,UACA,UAAU,EAAE,QAAQ;AAAA,UACpB,UAAU;AAAA,UACV,gBAAgB,SAAS;AAAA,UACzB,UAAU,SAAS;AAAA,UACnB,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AACA,UAAM,2BAA2B,KAAK;AAAA,MACpC,YAAY,EAAE,QAAQ;AAAA,MACtB,UAAU;AAAA,MACV,gBAAgB,UAAU,kBAAkB,OAAO;AAAA,MACnD,UAAU,UAAU,YAAY,OAAO;AAAA,MACvC,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,oBAAoB;AAAA,MACxB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,MAC9C,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX;AAAA,QACA,gBAAgB,UAAU,kBAAkB,OAAO;AAAA,QACnD,UAAU,UAAU,YAAY,OAAO;AAAA,MACzC;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,EAAE,WAAW,GAAG;AAAA,EACzB;AAAA,EACA,UAAU,OAAO,EAAE,UAAU,MAAM;AACjC,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO;AAAA,MACL,aAAa,UAAU,iCAAiC,wBAAwB;AAAA,MAChF,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,oBAAoB;AAAA,MACpB,kBAAkB,OAAO,aAAa;AAAA,MACtC,UAAU,OAAO;AAAA,MACjB,gBAAgB,OAAO;AAAA,MACvB,gBAAgB;AAAA,MAChB,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAuC,QAAQ;AAC/D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,SAAS,MAAM,GAAG,QAAQ,uBAAuB,EAAE,IAAI,OAAO,GAAG,CAAC;AACtE,QAAI,CAAC,QAAQ;AACX,YAAM,UAAU,MAAM,eAAe,IAAI,OAAO,SAAS;AACzD,eAAS,GAAG,OAAO,uBAAuB;AAAA,QACxC,IAAI,OAAO;AAAA,QACX;AAAA,QACA,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,MAAM,OAAO,QAAQ;AAAA,QACrB,KAAK,OAAO,OAAO;AAAA,QACnB,SAAS,OAAO,WAAW;AAAA,QAC3B,eAAe,OAAO,iBAAiB;AAAA,QACvC,WAAW,OAAO;AAAA,QAClB,UAAU,OAAO;AAAA,QACjB,aAAa,OAAO,eAAe;AAAA,QACnC,YAAY,OAAO,cAAc;AAAA,QACjC,YAAY,OAAO,aAAa,UAAU,OAAO,UAAU,IAAI;AAAA,QAC/D,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,QACzD,oBAAoB,OAAO,sBAAsB;AAAA,QACjD,WAAW,IAAI,KAAK,OAAO,SAAS;AAAA,QACpC,WAAW,IAAI,KAAK,OAAO,SAAS;AAAA,MACtC,CAAC;AACD,SAAG,QAAQ,MAAM;AAAA,IACnB;AACA,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,yBAAqB,QAAQ,MAAM;AACnC,QAAI,OAAO,QAAQ,QAAQ;AACzB,YAAM,aAAa,IAAI,UAAU,QAAQ,YAAY;AACrD,YAAM,kCAAkC,IAAI,QAAQ,OAAO,QAAQ,UAAU;AAAA,IAC/E;AACA,UAAM,GAAG,MAAM;AACf,QAAI,OAAO,UAAU,OAAO,KAAK,OAAO,MAAM,EAAE,QAAQ;AACtD,YAAM,qBAAqB;AAAA,QACzB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,QAC9C,UAAU,EAAE,QAAQ;AAAA,QACpB,UAAU,OAAO;AAAA,QACjB,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,eAAe,gCAAgD;AAC7D,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,QAAM,UAAU,UAAU,qCAAqC,qBAAqB;AACpF,QAAM,IAAI,cAAc,KAAK;AAAA,IAC3B,OAAO;AAAA,IACP,aAAa,EAAE,KAAK,QAAQ;AAAA,IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC,KAAK,GAAG,SAAS,MAAM,aAAa,QAAQ,aAAa,CAAC;AAAA,EAC/E,CAAC;AACH;AAEA,eAAe,+BAA+B,OAAgC;AAC5E,MAAI,iBAAiB,oCAAoC;AACvD,UAAM,aAAa,mBAAmB,KAAK;AAC3C,UAAM,UAAU,gBAAgB,KAAK,EAAE,YAAY;AACnD,QACE,eAAe,yCACf,QAAQ,SAAS,qCAAqC,GACtD;AACA,YAAM,8BAA8B;AAAA,IACtC;AAAA,EACF;AACA,QAAM;AACR;AAEA,gBAAgB,oBAAoB;AACpC,gBAAgB,oBAAoB;AACpC,gBAAgB,oBAAoB;",
|
|
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 commandActorScope,\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 tenantId: variant.tenantId,\n organizationId: variant.organizationId,\n })\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, commandActorScope(ctx))\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 tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\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 tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\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 tenantId: before.tenantId,\n organizationId: before.organizationId,\n })\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
|
}
|
|
@@ -10,7 +10,7 @@ import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customF
|
|
|
10
10
|
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
11
11
|
import { updateCrud, deleteCrud } from "@open-mercato/ui/backend/utils/crud";
|
|
12
12
|
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
13
|
-
import { ActivitiesSection, NotesSection } from "@open-mercato/ui/backend/detail";
|
|
13
|
+
import { ActivitiesSection, NotesSection, RecordNotFoundState } from "@open-mercato/ui/backend/detail";
|
|
14
14
|
import { VersionHistoryAction } from "@open-mercato/ui/backend/version-history";
|
|
15
15
|
import { SendObjectMessageDialog } from "@open-mercato/ui/backend/messages";
|
|
16
16
|
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
@@ -48,6 +48,7 @@ function ResourcesResourceDetailPage({ params }) {
|
|
|
48
48
|
const router = useRouter();
|
|
49
49
|
const searchParams = useSearchParams();
|
|
50
50
|
const [initialValues, setInitialValues] = React.useState(null);
|
|
51
|
+
const [isNotFound, setIsNotFound] = React.useState(false);
|
|
51
52
|
const [tags, setTags] = React.useState([]);
|
|
52
53
|
const [activeTab, setActiveTab] = React.useState("details");
|
|
53
54
|
const [activeDetailTab, setActiveDetailTab] = React.useState("notes");
|
|
@@ -325,6 +326,7 @@ function ResourcesResourceDetailPage({ params }) {
|
|
|
325
326
|
const { resourceTypesLoaded, resolveFieldsetCode } = formConfig;
|
|
326
327
|
React.useEffect(() => {
|
|
327
328
|
if (!resourceId || !resourceTypesLoaded) return;
|
|
329
|
+
setIsNotFound(false);
|
|
328
330
|
let cancelled = false;
|
|
329
331
|
async function loadResource() {
|
|
330
332
|
try {
|
|
@@ -335,7 +337,10 @@ function ResourcesResourceDetailPage({ params }) {
|
|
|
335
337
|
const record = await readApiResultOrThrow(`/api/resources/resources?${params2.toString()}`);
|
|
336
338
|
const resourceRaw = Array.isArray(record?.items) ? record.items[0] : null;
|
|
337
339
|
const resource = resourceRaw ? normalizeResourceRecord(resourceRaw) : null;
|
|
338
|
-
if (!resource)
|
|
340
|
+
if (!resource) {
|
|
341
|
+
if (!cancelled) setIsNotFound(true);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
339
344
|
if (!cancelled) {
|
|
340
345
|
const customValues = extractCustomFieldEntries(resource);
|
|
341
346
|
setTags(Array.isArray(resource.tags) ? resource.tags : []);
|
|
@@ -382,6 +387,16 @@ function ResourcesResourceDetailPage({ params }) {
|
|
|
382
387
|
flash(t("resources.resources.availability.ruleset.updateSuccess", "Schedule updated."), "success");
|
|
383
388
|
}, [resourceId, t]);
|
|
384
389
|
const resourceTitle = typeof initialValues?.name === "string" && initialValues.name.trim().length > 0 ? initialValues.name.trim() : t("resources.resources.detail.untitled", "Unnamed resource");
|
|
390
|
+
if (isNotFound) {
|
|
391
|
+
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
|
|
392
|
+
RecordNotFoundState,
|
|
393
|
+
{
|
|
394
|
+
label: t("resources.resources.form.errors.notFound", "Resource not found."),
|
|
395
|
+
backHref: "/backend/resources/resources",
|
|
396
|
+
backLabel: t("resources.resources.detail.back", "Back to resources")
|
|
397
|
+
}
|
|
398
|
+
) }) });
|
|
399
|
+
}
|
|
385
400
|
return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
386
401
|
/* @__PURE__ */ jsx(
|
|
387
402
|
FormHeader,
|