@open-mercato/core 0.10.1-develop.7781.1.079f42c863 → 0.10.1-develop.7782.1.91d78919ba
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.
|
@@ -196,6 +196,19 @@ function resolveAmountInputFromParsed(parsed) {
|
|
|
196
196
|
}
|
|
197
197
|
return null;
|
|
198
198
|
}
|
|
199
|
+
function hasAmountChanged(incoming, current) {
|
|
200
|
+
if (typeof incoming !== "number" || !Number.isFinite(incoming)) return false;
|
|
201
|
+
return numericStringToNumber(current) !== incoming;
|
|
202
|
+
}
|
|
203
|
+
function resolveAmountInputForUpdate(parsed, record) {
|
|
204
|
+
if (hasAmountChanged(parsed.unitPriceNet, record.unitPriceNet)) {
|
|
205
|
+
return { amount: parsed.unitPriceNet, mode: "net" };
|
|
206
|
+
}
|
|
207
|
+
if (hasAmountChanged(parsed.unitPriceGross, record.unitPriceGross)) {
|
|
208
|
+
return { amount: parsed.unitPriceGross, mode: "gross" };
|
|
209
|
+
}
|
|
210
|
+
return resolveAmountInputFromParsed(parsed);
|
|
211
|
+
}
|
|
199
212
|
function resolveAmountInputFromRecord(record) {
|
|
200
213
|
const net = numericStringToNumber(record.unitPriceNet);
|
|
201
214
|
if (net !== null) return { amount: net, mode: "net" };
|
|
@@ -515,7 +528,7 @@ const updatePriceCommand = {
|
|
|
515
528
|
}
|
|
516
529
|
ensureSameTenant(targetPriceKind, targetProduct.tenantId);
|
|
517
530
|
const taxCalculationService = ctx.container.resolve("taxCalculationService");
|
|
518
|
-
const amountInput =
|
|
531
|
+
const amountInput = resolveAmountInputForUpdate(parsed, record);
|
|
519
532
|
const hasNetInput = Object.prototype.hasOwnProperty.call(parsed, "unitPriceNet");
|
|
520
533
|
const hasGrossInput = Object.prototype.hasOwnProperty.call(parsed, "unitPriceGross");
|
|
521
534
|
const hasTaxRateInput = Object.prototype.hasOwnProperty.call(parsed, "taxRate");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/catalog/commands/prices.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 { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CatalogOffer, CatalogProduct, CatalogProductPrice, CatalogProductVariant, CatalogPriceKind } from '../data/entities'\nimport { loadCustomFieldSnapshot, buildCustomFieldResetMap } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n priceCreateSchema,\n priceUpdateSchema,\n type PriceCreateInput,\n type PriceUpdateInput,\n} from '../data/validators'\nimport type { TaxCalculationService } from '@open-mercato/core/modules/sales/services/taxCalculationService'\nimport {\n cloneJson,\n commandActorScope,\n commandScopeWhere,\n ensureOrganizationScope,\n ensureSameScope,\n ensureSameTenant,\n ensureTenantScope,\n extractUndoPayload,\n requireVariant,\n requireProduct,\n requireOffer,\n requirePriceKind,\n toNumericString,\n} from './shared'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport {\n capturePriceHistoryEntry,\n hasPriceHistoryRelevantChange,\n priceHistoryInputFromRecord,\n} from '../lib/omnibus'\nimport { resolveOmnibusCache } from '../lib/omnibusCache'\n\nconst priceCrudEvents: CrudEventsConfig = {\n module: 'catalog',\n entity: 'price',\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 PriceSnapshot = {\n id: string\n variantId: string | null\n productId: string | null\n offerId: string | null\n organizationId: string\n tenantId: string\n currencyCode: string\n priceKindId: string\n priceKindCode: 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\ntype PriceUndoPayload = {\n before?: PriceSnapshot | null\n after?: PriceSnapshot | null\n}\n\nconst PRICE_CHANGE_KEYS = [\n 'currencyCode',\n 'priceKindId',\n 'kind',\n 'minQuantity',\n 'maxQuantity',\n 'unitPriceNet',\n 'unitPriceGross',\n 'taxRate',\n 'taxAmount',\n 'channelId',\n 'userId',\n 'userGroupId',\n 'customerId',\n 'customerGroupId',\n 'metadata',\n 'startsAt',\n 'endsAt',\n] as const satisfies readonly string[]\n\nasync function resolveSnapshotAssociations(\n em: EntityManager,\n snapshot: PriceSnapshot\n): Promise<{\n variant: CatalogProductVariant | null\n product: CatalogProduct\n offer: CatalogOffer | null\n}> {\n const scope = { tenantId: snapshot.tenantId, organizationId: snapshot.organizationId }\n let variant: CatalogProductVariant | null = null\n if (snapshot.variantId) {\n variant = await requireVariant(em, snapshot.variantId, scope)\n }\n let product: CatalogProduct | null = null\n if (snapshot.productId) {\n product = await requireProduct(em, snapshot.productId, scope)\n } else if (variant) {\n product =\n typeof variant.product === 'string'\n ? await requireProduct(em, variant.product, scope)\n : variant.product\n }\n if (!product) {\n throw new CrudHttpError(400, { error: 'Price snapshot missing product association.' })\n }\n let offer: CatalogOffer | null = null\n if (snapshot.offerId) {\n offer = await requireOffer(em, snapshot.offerId, scope)\n }\n return { variant, product, offer }\n}\n\nasync function loadPriceSnapshot(\n em: EntityManager,\n id: string,\n scopeWhere: Record<string, unknown> = {},\n): Promise<PriceSnapshot | null> {\n const record = await findOneWithDecryption(\n em,\n CatalogProductPrice,\n { id, ...scopeWhere },\n { populate: ['priceKind', 'product', 'variant', 'offer'] },\n )\n if (!record) return null\n const variantId =\n typeof record.variant === 'string'\n ? record.variant\n : record.variant\n ? record.variant.id\n : null\n const productRef = record.product\n ? record.product\n : typeof record.variant === 'object' && record.variant\n ? record.variant.product\n : null\n const productId =\n typeof productRef === 'string'\n ? productRef\n : productRef\n ? productRef.id\n : null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_price,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n const priceKind = record.priceKind\n const priceKindId =\n typeof priceKind === 'string'\n ? priceKind\n : priceKind\n ? priceKind.id\n : null\n if (!priceKindId) {\n throw new CrudHttpError(400, { error: 'Price is missing price kind metadata.' })\n }\n const priceKindCode =\n typeof priceKind === 'object' && priceKind ? priceKind.code : record.kind\n return {\n id: record.id,\n variantId,\n productId,\n offerId: typeof record.offer === 'string' ? record.offer : record.offer ? record.offer.id : null,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n currencyCode: record.currencyCode,\n priceKindId,\n priceKindCode,\n kind: record.kind,\n minQuantity: record.minQuantity,\n maxQuantity: record.maxQuantity ?? null,\n unitPriceNet: record.unitPriceNet ?? null,\n unitPriceGross: record.unitPriceGross ?? null,\n taxRate: record.taxRate ?? null,\n taxAmount: record.taxAmount ?? null,\n channelId: record.channelId ?? null,\n userId: record.userId ?? null,\n userGroupId: record.userGroupId ?? null,\n customerId: record.customerId ?? null,\n customerGroupId: record.customerGroupId ?? null,\n metadata: record.metadata ? cloneJson(record.metadata) : null,\n startsAt: record.startsAt ? record.startsAt.toISOString() : null,\n endsAt: record.endsAt ? record.endsAt.toISOString() : null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n custom: Object.keys(custom).length ? custom : null,\n }\n}\n\nfunction applyPriceSnapshot(em: EntityManager, record: CatalogProductPrice, snapshot: PriceSnapshot): void {\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.currencyCode = snapshot.currencyCode\n record.priceKind = em.getReference(CatalogPriceKind, snapshot.priceKindId)\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\nfunction priceSeedFromSnapshot(snapshot: PriceSnapshot): Record<string, unknown> {\n return {\n id: snapshot.id,\n variant: snapshot.variantId ?? null,\n product: snapshot.productId ?? null,\n offer: snapshot.offerId ?? null,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n priceKind: snapshot.priceKindId,\n currencyCode: snapshot.currencyCode,\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}\n\ntype PriceAmountInput = {\n amount: number\n mode: 'net' | 'gross'\n}\n\nfunction resolveAmountInputFromParsed(\n parsed: Partial<Pick<PriceCreateInput, 'unitPriceNet' | 'unitPriceGross'>>\n): PriceAmountInput | null {\n if (typeof parsed.unitPriceNet === 'number' && Number.isFinite(parsed.unitPriceNet)) {\n return { amount: parsed.unitPriceNet, mode: 'net' }\n }\n if (typeof parsed.unitPriceGross === 'number' && Number.isFinite(parsed.unitPriceGross)) {\n return { amount: parsed.unitPriceGross, mode: 'gross' }\n }\n return null\n}\n\nfunction resolveAmountInputFromRecord(record: CatalogProductPrice): PriceAmountInput | null {\n const net = numericStringToNumber(record.unitPriceNet)\n if (net !== null) return { amount: net, mode: 'net' }\n const gross = numericStringToNumber(record.unitPriceGross)\n if (gross !== null) return { amount: gross, mode: 'gross' }\n return null\n}\n\nfunction numericStringToNumber(value: string | null | undefined): number | null {\n if (value === undefined || value === null) return null\n const numeric = Number(value)\n return Number.isFinite(numeric) ? numeric : null\n}\n\nconst createPriceCommand: CommandHandler<PriceCreateInput, { priceId: string }> = {\n id: 'catalog.prices.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(priceCreateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const actorScope = commandActorScope(ctx)\n let variant: CatalogProductVariant | null = null\n let product: CatalogProduct | null = null\n if (parsed.variantId) {\n variant = await requireVariant(em, parsed.variantId, actorScope)\n product =\n typeof variant.product === 'string'\n ? await requireProduct(em, variant.product, {\n tenantId: variant.tenantId,\n organizationId: variant.organizationId,\n })\n : variant.product\n }\n if (parsed.productId) {\n const explicitProduct = await requireProduct(em, parsed.productId, actorScope)\n if (product && explicitProduct.id !== product.id) {\n throw new CrudHttpError(400, { error: 'Variant does not belong to the provided product.' })\n }\n product = explicitProduct\n }\n if (!variant && !product) {\n throw new CrudHttpError(400, { error: 'Provide either a variantId or productId for pricing.' })\n }\n const scopeSource = variant ?? product!\n ensureTenantScope(ctx, scopeSource.tenantId)\n ensureOrganizationScope(ctx, scopeSource.organizationId)\n const scopeSourceScope = {\n tenantId: scopeSource.tenantId,\n organizationId: scopeSource.organizationId,\n }\n\n const priceKind = await requirePriceKind(em, parsed.priceKindId, scopeSourceScope)\n ensureSameTenant(priceKind, scopeSource.tenantId)\n\n let offer: CatalogOffer | null = null\n if (parsed.offerId) {\n offer = await requireOffer(em, parsed.offerId, scopeSourceScope)\n ensureSameScope(offer, scopeSource.organizationId, scopeSource.tenantId)\n const offerProduct =\n typeof offer.product === 'string'\n ? await requireProduct(em, offer.product, {\n tenantId: offer.tenantId,\n organizationId: offer.organizationId,\n })\n : offer.product\n if (product && offerProduct.id !== product.id) {\n throw new CrudHttpError(400, { error: 'Offer does not belong to the selected product.' })\n }\n product = offerProduct\n }\n const productEntity = product\n const channelId = parsed.channelId ?? (offer ? offer.channelId : null)\n const taxCalculationService = ctx.container.resolve<TaxCalculationService>('taxCalculationService')\n const amountInput = resolveAmountInputFromParsed(parsed)\n let unitPriceNetValue = toNumericString(parsed.unitPriceNet)\n let unitPriceGrossValue = toNumericString(parsed.unitPriceGross)\n let taxRateValue = toNumericString(parsed.taxRate)\n let taxAmountValue: string | null = null\n if (amountInput) {\n const calculation = await taxCalculationService.calculateUnitAmounts({\n amount: amountInput.amount,\n mode: amountInput.mode,\n organizationId: scopeSource.organizationId,\n tenantId: scopeSource.tenantId,\n taxRateId: parsed.taxRateId ?? null,\n taxRate: parsed.taxRate ?? null,\n })\n unitPriceNetValue = toNumericString(calculation.netAmount)\n unitPriceGrossValue = toNumericString(calculation.grossAmount)\n taxAmountValue = toNumericString(calculation.taxAmount)\n taxRateValue = toNumericString(calculation.taxRate)\n }\n\n const now = new Date()\n const record = em.create(CatalogProductPrice, {\n organizationId: scopeSource.organizationId,\n tenantId: scopeSource.tenantId,\n variant,\n product: productEntity ?? undefined,\n offer: offer ?? undefined,\n priceKind,\n currencyCode: parsed.currencyCode,\n kind: priceKind.code,\n minQuantity: parsed.minQuantity ?? 1,\n maxQuantity: parsed.maxQuantity ?? null,\n unitPriceNet: unitPriceNetValue,\n unitPriceGross: unitPriceGrossValue,\n taxRate: taxRateValue,\n taxAmount: taxAmountValue,\n channelId,\n userId: parsed.userId ?? null,\n userGroupId: parsed.userGroupId ?? null,\n customerId: parsed.customerId ?? null,\n customerGroupId: parsed.customerGroupId ?? null,\n metadata: parsed.metadata ? cloneJson(parsed.metadata) : null,\n startsAt: parsed.startsAt ?? null,\n endsAt: parsed.endsAt ?? null,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: priceCrudEvents,\n })\n await capturePriceHistoryEntry(em, priceHistoryInputFromRecord(record), 'create', {\n cache: resolveOmnibusCache(ctx.container),\n })\n return { priceId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadPriceSnapshot(em, result.priceId)\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as PriceSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.prices.create', 'Create product price'),\n resourceKind: 'catalog.price',\n resourceId: result.priceId,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n } satisfies PriceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PriceUndoPayload>(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(CatalogProductPrice, { 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 await capturePriceHistoryEntry(em, after, 'undo', {\n metadata: { undoneCommand: 'catalog.prices.create' },\n cache: resolveOmnibusCache(ctx.container),\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_price,\n recordId: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n values: resetValues,\n })\n }\n },\n redo: makeCreateRedo<CatalogProductPrice, PriceSnapshot, PriceCreateInput, { priceId: string }>({\n entityClass: CatalogProductPrice,\n getSnapshotId: (snapshot) => snapshot.id,\n seedFromSnapshot: priceSeedFromSnapshot,\n buildResult: (entity) => ({ priceId: entity.id }),\n events: priceCrudEvents,\n afterRestore: async ({ em, ctx, entity, snapshot }) => {\n if (snapshot.custom && Object.keys(snapshot.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: entity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n values: snapshot.custom,\n })\n }\n await capturePriceHistoryEntry(em, snapshot, 'create', {\n metadata: { redoneCommand: 'catalog.prices.create' },\n cache: resolveOmnibusCache(ctx.container),\n })\n },\n }),\n}\n\nconst updatePriceCommand: CommandHandler<PriceUpdateInput, { priceId: string }> = {\n id: 'catalog.prices.update',\n async prepare(input, ctx) {\n const id = requireId(input, 'Price id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPriceSnapshot(em, id, commandScopeWhere(ctx))\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(priceUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(\n em,\n CatalogProductPrice,\n { id: parsed.id, ...commandScopeWhere(ctx) },\n { populate: ['priceKind'] },\n { tenantId: parsed.tenantId, organizationId: parsed.organizationId },\n )\n if (!record) throw new CrudHttpError(404, { error: 'Catalog price not found' })\n const recordScope = { tenantId: record.tenantId, organizationId: record.organizationId }\n const currentVariantRef = record.variant\n let targetVariant: CatalogProductVariant | null = null\n if (typeof currentVariantRef === 'string') {\n targetVariant = await requireVariant(em, currentVariantRef, recordScope)\n } else if (currentVariantRef) {\n targetVariant = currentVariantRef\n }\n const currentProductRef = record.product ?? (targetVariant ? targetVariant.product : null)\n let targetProduct: CatalogProduct | null = null\n if (typeof currentProductRef === 'string') {\n targetProduct = await requireProduct(em, currentProductRef, recordScope)\n } else if (currentProductRef) {\n targetProduct = currentProductRef\n }\n const recordHistoryInput = priceHistoryInputFromRecord(record)\n const historyBefore = {\n ...recordHistoryInput,\n productId: recordHistoryInput.productId ?? targetProduct?.id ?? null,\n }\n\n if (parsed.variantId !== undefined) {\n if (!parsed.variantId) {\n targetVariant = null\n } else {\n targetVariant = await requireVariant(em, parsed.variantId, recordScope)\n targetProduct =\n typeof targetVariant.product === 'string'\n ? await requireProduct(em, targetVariant.product, recordScope)\n : targetVariant.product\n }\n }\n\n if (targetVariant && (targetVariant as CatalogProductVariant | null)?.product === undefined) {\n targetVariant = await requireVariant(em, targetVariant.id, recordScope)\n }\n\n if (parsed.productId !== undefined) {\n if (!parsed.productId) {\n targetProduct = null\n } else {\n const explicitProduct = await requireProduct(em, parsed.productId, recordScope)\n if (targetVariant) {\n const variantProductId =\n typeof targetVariant.product === 'string'\n ? targetVariant.product\n : targetVariant.product.id\n if (variantProductId !== explicitProduct.id) {\n throw new CrudHttpError(400, { error: 'Variant does not belong to the provided product.' })\n }\n }\n targetProduct = explicitProduct\n }\n }\n\n if (!targetVariant && !targetProduct) {\n throw new CrudHttpError(400, { error: 'Price must remain associated with a product or variant.' })\n }\n if (!targetProduct && targetVariant) {\n targetProduct =\n typeof targetVariant.product === 'string'\n ? await requireProduct(em, targetVariant.product, recordScope)\n : targetVariant.product\n }\n if (!targetProduct) {\n throw new CrudHttpError(400, { error: 'Unable to resolve product for price.' })\n }\n\n let targetOffer: CatalogOffer | null = null\n if (record.offer) {\n targetOffer =\n typeof record.offer === 'string'\n ? await requireOffer(em, record.offer, recordScope)\n : record.offer\n }\n if (parsed.offerId !== undefined) {\n if (!parsed.offerId) {\n targetOffer = null\n } else {\n const explicitOffer = await requireOffer(em, parsed.offerId, recordScope)\n ensureSameScope(explicitOffer, targetProduct.organizationId, targetProduct.tenantId)\n const offerProductId =\n typeof explicitOffer.product === 'string'\n ? explicitOffer.product\n : explicitOffer.product.id\n if (offerProductId !== targetProduct.id) {\n throw new CrudHttpError(400, { error: 'Offer does not belong to the selected product.' })\n }\n targetOffer = explicitOffer\n }\n }\n\n ensureTenantScope(ctx, targetProduct.tenantId)\n ensureOrganizationScope(ctx, targetProduct.organizationId)\n\n let targetPriceKind: CatalogPriceKind | null = null\n if (record.priceKind) {\n targetPriceKind =\n typeof record.priceKind === 'string'\n ? await requirePriceKind(em, record.priceKind, recordScope)\n : record.priceKind\n }\n if (parsed.priceKindId !== undefined) {\n if (!parsed.priceKindId) {\n throw new CrudHttpError(400, { error: 'Price kind is required.' })\n }\n targetPriceKind = await requirePriceKind(em, parsed.priceKindId, recordScope)\n }\n if (!targetPriceKind) {\n throw new CrudHttpError(400, { error: 'Price kind is required.' })\n }\n ensureSameTenant(targetPriceKind, targetProduct.tenantId)\n\n const taxCalculationService = ctx.container.resolve<TaxCalculationService>('taxCalculationService')\n const amountInput = resolveAmountInputFromParsed(parsed)\n const hasNetInput = Object.prototype.hasOwnProperty.call(parsed, 'unitPriceNet')\n const hasGrossInput = Object.prototype.hasOwnProperty.call(parsed, 'unitPriceGross')\n const hasTaxRateInput = Object.prototype.hasOwnProperty.call(parsed, 'taxRate')\n const hasTaxRateIdInput = Object.prototype.hasOwnProperty.call(parsed, 'taxRateId')\n let taxCalculationResult: Awaited<ReturnType<TaxCalculationService['calculateUnitAmounts']>> | null = null\n let calculationBase = amountInput\n if (!calculationBase && (hasTaxRateInput || hasTaxRateIdInput)) {\n calculationBase = resolveAmountInputFromRecord(record)\n }\n if (calculationBase) {\n const taxRateIdForCalculation = hasTaxRateIdInput ? parsed.taxRateId ?? null : undefined\n const taxRateForCalculation = hasTaxRateInput\n ? parsed.taxRate ?? null\n : taxRateIdForCalculation === null\n ? null\n : record.taxRate ?? null\n taxCalculationResult = await taxCalculationService.calculateUnitAmounts({\n amount: calculationBase.amount,\n mode: calculationBase.mode,\n organizationId: targetProduct.organizationId,\n tenantId: targetProduct.tenantId,\n taxRateId: taxRateIdForCalculation,\n taxRate: taxRateForCalculation,\n })\n }\n\n record.variant = targetVariant\n record.product = targetProduct\n record.offer = targetOffer\n record.organizationId = targetProduct.organizationId\n record.tenantId = targetProduct.tenantId\n record.priceKind = targetPriceKind\n record.kind = targetPriceKind.code\n\n if (parsed.currencyCode !== undefined) record.currencyCode = parsed.currencyCode\n if (parsed.minQuantity !== undefined) record.minQuantity = parsed.minQuantity ?? 1\n if (parsed.maxQuantity !== undefined) record.maxQuantity = parsed.maxQuantity ?? null\n if (taxCalculationResult) {\n record.unitPriceNet = toNumericString(taxCalculationResult.netAmount)\n record.unitPriceGross = toNumericString(taxCalculationResult.grossAmount)\n record.taxRate = toNumericString(taxCalculationResult.taxRate)\n record.taxAmount = toNumericString(taxCalculationResult.taxAmount)\n } else {\n if (hasNetInput) {\n record.unitPriceNet = toNumericString(parsed.unitPriceNet)\n }\n if (hasGrossInput) {\n record.unitPriceGross = toNumericString(parsed.unitPriceGross)\n }\n if (hasTaxRateInput) {\n record.taxRate = toNumericString(parsed.taxRate)\n if (parsed.taxRate == null) {\n record.taxAmount = null\n }\n } else if (hasTaxRateIdInput && parsed.taxRateId === null) {\n record.taxRate = null\n record.taxAmount = null\n }\n }\n if (parsed.channelId !== undefined) {\n record.channelId = parsed.channelId ?? null\n } else if (parsed.offerId !== undefined && targetOffer) {\n record.channelId = targetOffer.channelId\n }\n if (parsed.userId !== undefined) record.userId = parsed.userId ?? null\n if (parsed.userGroupId !== undefined) record.userGroupId = parsed.userGroupId ?? null\n if (parsed.customerId !== undefined) record.customerId = parsed.customerId ?? null\n if (parsed.customerGroupId !== undefined) record.customerGroupId = parsed.customerGroupId ?? null\n if (parsed.metadata !== undefined) {\n record.metadata = parsed.metadata ? cloneJson(parsed.metadata) : null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'startsAt')) {\n record.startsAt = parsed.startsAt ?? null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'endsAt')) {\n record.endsAt = parsed.endsAt ?? null\n }\n await em.flush()\n if (custom && Object.keys(custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n }\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: priceCrudEvents,\n })\n const historyAfter = priceHistoryInputFromRecord(record)\n if (hasPriceHistoryRelevantChange(historyBefore, historyAfter)) {\n await capturePriceHistoryEntry(em, historyAfter, 'update', {\n cache: resolveOmnibusCache(ctx.container),\n invalidatePrices: [historyBefore],\n previous: historyBefore,\n })\n }\n return { priceId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadPriceSnapshot(em, result.priceId)\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as PriceSnapshot | undefined\n const after = snapshots.after as PriceSnapshot | undefined\n if (!before || !after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.prices.update', 'Update product price'),\n resourceKind: 'catalog.price',\n resourceId: before.id,\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 PRICE_CHANGE_KEYS\n ),\n payload: {\n undo: {\n before,\n after,\n } satisfies PriceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PriceUndoPayload>(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(CatalogProductPrice, { id: before.id })\n if (!record) {\n const { variant, product, offer } = await resolveSnapshotAssociations(em, before)\n record = em.create(CatalogProductPrice, {\n id: before.id,\n variant,\n product,\n offer,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n currencyCode: before.currencyCode,\n priceKind: em.getReference(CatalogPriceKind, before.priceKindId),\n kind: before.priceKindCode || before.kind,\n minQuantity: before.minQuantity,\n maxQuantity: before.maxQuantity ?? null,\n unitPriceNet: before.unitPriceNet ?? null,\n unitPriceGross: before.unitPriceGross ?? null,\n taxRate: before.taxRate ?? null,\n taxAmount: before.taxAmount ?? null,\n channelId: before.channelId ?? null,\n userId: before.userId ?? null,\n userGroupId: before.userGroupId ?? null,\n customerId: before.customerId ?? null,\n customerGroupId: before.customerGroupId ?? null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n startsAt: before.startsAt ? new Date(before.startsAt) : null,\n endsAt: before.endsAt ? new Date(before.endsAt) : 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 applyPriceSnapshot(em, record, before)\n await em.flush()\n await capturePriceHistoryEntry(em, before, 'undo', {\n metadata: { undoneCommand: 'catalog.prices.update' },\n cache: resolveOmnibusCache(ctx.container),\n invalidatePrices: [after],\n previous: after,\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_price,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: resetValues,\n })\n }\n },\n}\n\nconst deletePriceCommand: CommandHandler<\n { body?: Record<string, unknown>; query?: Record<string, unknown> },\n { priceId: string }\n> = {\n id: 'catalog.prices.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Price id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPriceSnapshot(em, id, commandScopeWhere(ctx))\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, 'Price id is required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(em, CatalogProductPrice, { id, ...commandScopeWhere(ctx) })\n if (!record) throw new CrudHttpError(404, { error: 'Catalog price not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const { product } = await resolvePriceRecordAssociations(em, record)\n\n const baseEm = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPriceSnapshot(baseEm, id)\n\n const deletedPrice = snapshot ?? priceHistoryInputFromRecord(record)\n em.remove(record)\n await em.flush()\n await capturePriceHistoryEntry(em, deletedPrice, 'delete', { cache: resolveOmnibusCache(ctx.container) })\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: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n values: resetValues,\n })\n }\n }\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\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: priceCrudEvents,\n })\n return { priceId: id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as PriceSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.prices.delete', 'Delete product price'),\n resourceKind: 'catalog.price',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies PriceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PriceUndoPayload>(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(CatalogProductPrice, { id: before.id })\n if (!record) {\n const { variant, product, offer } = await resolveSnapshotAssociations(em, before)\n record = em.create(CatalogProductPrice, {\n id: before.id,\n variant,\n product,\n offer,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n currencyCode: before.currencyCode,\n priceKind: em.getReference(CatalogPriceKind, before.priceKindId),\n kind: before.priceKindCode || before.kind,\n minQuantity: before.minQuantity,\n maxQuantity: before.maxQuantity ?? null,\n unitPriceNet: before.unitPriceNet ?? null,\n unitPriceGross: before.unitPriceGross ?? null,\n taxRate: before.taxRate ?? null,\n taxAmount: before.taxAmount ?? null,\n channelId: before.channelId ?? null,\n userId: before.userId ?? null,\n userGroupId: before.userGroupId ?? null,\n customerId: before.customerId ?? null,\n customerGroupId: before.customerGroupId ?? null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n startsAt: before.startsAt ? new Date(before.startsAt) : null,\n endsAt: before.endsAt ? new Date(before.endsAt) : 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 applyPriceSnapshot(em, record, before)\n await em.flush()\n await capturePriceHistoryEntry(em, before, 'undo', {\n metadata: { undoneCommand: 'catalog.prices.delete' },\n cache: resolveOmnibusCache(ctx.container),\n })\n if (before.custom && Object.keys(before.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: before.custom,\n })\n }\n },\n}\n\nregisterCommand(createPriceCommand)\nregisterCommand(updatePriceCommand)\nregisterCommand(deletePriceCommand)\n\nasync function resolvePriceRecordAssociations(\n em: EntityManager,\n record: CatalogProductPrice,\n): Promise<{ product: CatalogProduct; variant: CatalogProductVariant | null }> {\n const scope = { tenantId: record.tenantId, organizationId: record.organizationId }\n const variant = record.variant\n ? (typeof record.variant === 'string'\n ? await requireVariant(em, record.variant, scope)\n : record.variant)\n : null\n if (record.product) {\n const product =\n typeof record.product === 'string'\n ? await requireProduct(em, record.product, scope)\n : record.product\n return { product, variant }\n }\n if (variant?.product) {\n const productRef = variant.product\n const product =\n typeof productRef === 'string'\n ? await requireProduct(em, productRef, scope)\n : productRef\n return { product, variant }\n }\n if (record.offer) {\n const offer =\n typeof record.offer === 'string'\n ? await requireOffer(em, record.offer, scope)\n : record.offer\n const productRef = offer?.product ?? null\n if (productRef) {\n const product =\n typeof productRef === 'string'\n ? await requireProduct(em, productRef, scope)\n : productRef\n return { product, variant }\n }\n }\n throw new CrudHttpError(400, { error: 'Catalog price is not linked to a product.' })\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,uBAAuB;AAEhC,SAAS,cAAc,WAAW,uBAAuB,sBAAsB,2BAA2B;AAE1G,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAuC,qBAA4C,wBAAwB;AAC3G,SAAS,yBAAyB,gCAAgC;AAClE,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP;AAAA,EACE;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,OACK;AACP,SAAS,6BAA6B;AACtC,SAAS,sBAAsB;AAG/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AAEpC,MAAM,kBAAoC;AAAA,EACxC,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;AAqCA,MAAM,oBAAoB;AAAA,EACxB;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;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,eAAe,4BACb,IACA,UAKC;AACD,QAAM,QAAQ,EAAE,UAAU,SAAS,UAAU,gBAAgB,SAAS,eAAe;AACrF,MAAI,UAAwC;AAC5C,MAAI,SAAS,WAAW;AACtB,cAAU,MAAM,eAAe,IAAI,SAAS,WAAW,KAAK;AAAA,EAC9D;AACA,MAAI,UAAiC;AACrC,MAAI,SAAS,WAAW;AACtB,cAAU,MAAM,eAAe,IAAI,SAAS,WAAW,KAAK;AAAA,EAC9D,WAAW,SAAS;AAClB,cACE,OAAO,QAAQ,YAAY,WACvB,MAAM,eAAe,IAAI,QAAQ,SAAS,KAAK,IAC/C,QAAQ;AAAA,EAChB;AACA,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,8CAA8C,CAAC;AAAA,EACvF;AACA,MAAI,QAA6B;AACjC,MAAI,SAAS,SAAS;AACpB,YAAQ,MAAM,aAAa,IAAI,SAAS,SAAS,KAAK;AAAA,EACxD;AACA,SAAO,EAAE,SAAS,SAAS,MAAM;AACnC;AAEA,eAAe,kBACb,IACA,IACA,aAAsC,CAAC,GACR;AAC/B,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA,EAAE,IAAI,GAAG,WAAW;AAAA,IACpB,EAAE,UAAU,CAAC,aAAa,WAAW,WAAW,OAAO,EAAE;AAAA,EAC3D;AACA,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,YACJ,OAAO,OAAO,YAAY,WACtB,OAAO,UACP,OAAO,UACL,OAAO,QAAQ,KACf;AACR,QAAM,aAAa,OAAO,UACtB,OAAO,UACP,OAAO,OAAO,YAAY,YAAY,OAAO,UAC3C,OAAO,QAAQ,UACf;AACN,QAAM,YACJ,OAAO,eAAe,WAClB,aACA,aACE,WAAW,KACX;AACR,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;AACzB,QAAM,cACJ,OAAO,cAAc,WACjB,YACA,YACE,UAAU,KACV;AACR,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,wCAAwC,CAAC;AAAA,EACjF;AACA,QAAM,gBACJ,OAAO,cAAc,YAAY,YAAY,UAAU,OAAO,OAAO;AACvE,SAAO;AAAA,IACL,IAAI,OAAO;AAAA,IACX;AAAA,IACA;AAAA,IACA,SAAS,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,OAAO,QAAQ,OAAO,MAAM,KAAK;AAAA,IAC5F,gBAAgB,OAAO;AAAA,IACvB,UAAU,OAAO;AAAA,IACjB,cAAc,OAAO;AAAA,IACrB;AAAA,IACA;AAAA,IACA,MAAM,OAAO;AAAA,IACb,aAAa,OAAO;AAAA,IACpB,aAAa,OAAO,eAAe;AAAA,IACnC,cAAc,OAAO,gBAAgB;AAAA,IACrC,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,SAAS,OAAO,WAAW;AAAA,IAC3B,WAAW,OAAO,aAAa;AAAA,IAC/B,WAAW,OAAO,aAAa;AAAA,IAC/B,QAAQ,OAAO,UAAU;AAAA,IACzB,aAAa,OAAO,eAAe;AAAA,IACnC,YAAY,OAAO,cAAc;AAAA,IACjC,iBAAiB,OAAO,mBAAmB;AAAA,IAC3C,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,IACzD,UAAU,OAAO,WAAW,OAAO,SAAS,YAAY,IAAI;AAAA,IAC5D,QAAQ,OAAO,SAAS,OAAO,OAAO,YAAY,IAAI;AAAA,IACtD,WAAW,OAAO,UAAU,YAAY;AAAA,IACxC,WAAW,OAAO,UAAU,YAAY;AAAA,IACxC,QAAQ,OAAO,KAAK,MAAM,EAAE,SAAS,SAAS;AAAA,EAChD;AACF;AAEA,SAAS,mBAAmB,IAAmB,QAA6B,UAA+B;AACzG,SAAO,iBAAiB,SAAS;AACjC,SAAO,WAAW,SAAS;AAC3B,SAAO,eAAe,SAAS;AAC/B,SAAO,YAAY,GAAG,aAAa,kBAAkB,SAAS,WAAW;AACzE,SAAO,OAAO,SAAS,iBAAiB,SAAS;AACjD,SAAO,cAAc,SAAS;AAC9B,SAAO,cAAc,SAAS,eAAe;AAC7C,SAAO,eAAe,SAAS,gBAAgB;AAC/C,SAAO,iBAAiB,SAAS,kBAAkB;AACnD,SAAO,UAAU,SAAS,WAAW;AACrC,SAAO,YAAY,SAAS,aAAa;AACzC,SAAO,YAAY,SAAS,aAAa;AACzC,SAAO,SAAS,SAAS,UAAU;AACnC,SAAO,cAAc,SAAS,eAAe;AAC7C,SAAO,aAAa,SAAS,cAAc;AAC3C,SAAO,kBAAkB,SAAS,mBAAmB;AACrD,SAAO,WAAW,SAAS,WAAW,UAAU,SAAS,QAAQ,IAAI;AACrE,SAAO,WAAW,SAAS,WAAW,IAAI,KAAK,SAAS,QAAQ,IAAI;AACpE,SAAO,SAAS,SAAS,SAAS,IAAI,KAAK,SAAS,MAAM,IAAI;AAC9D,SAAO,YAAY,IAAI,KAAK,SAAS,SAAS;AAC9C,SAAO,YAAY,IAAI,KAAK,SAAS,SAAS;AAChD;AAEA,SAAS,sBAAsB,UAAkD;AAC/E,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,SAAS,SAAS,aAAa;AAAA,IAC/B,SAAS,SAAS,aAAa;AAAA,IAC/B,OAAO,SAAS,WAAW;AAAA,IAC3B,gBAAgB,SAAS;AAAA,IACzB,UAAU,SAAS;AAAA,IACnB,WAAW,SAAS;AAAA,IACpB,cAAc,SAAS;AAAA,IACvB,MAAM,SAAS,iBAAiB,SAAS;AAAA,IACzC,aAAa,SAAS;AAAA,IACtB,aAAa,SAAS,eAAe;AAAA,IACrC,cAAc,SAAS,gBAAgB;AAAA,IACvC,gBAAgB,SAAS,kBAAkB;AAAA,IAC3C,SAAS,SAAS,WAAW;AAAA,IAC7B,WAAW,SAAS,aAAa;AAAA,IACjC,WAAW,SAAS,aAAa;AAAA,IACjC,QAAQ,SAAS,UAAU;AAAA,IAC3B,aAAa,SAAS,eAAe;AAAA,IACrC,YAAY,SAAS,cAAc;AAAA,IACnC,iBAAiB,SAAS,mBAAmB;AAAA,IAC7C,UAAU,SAAS,WAAW,UAAU,SAAS,QAAQ,IAAI;AAAA,IAC7D,UAAU,SAAS,WAAW,IAAI,KAAK,SAAS,QAAQ,IAAI;AAAA,IAC5D,QAAQ,SAAS,SAAS,IAAI,KAAK,SAAS,MAAM,IAAI;AAAA,IACtD,WAAW,IAAI,KAAK,SAAS,SAAS;AAAA,IACtC,WAAW,IAAI,KAAK,SAAS,SAAS;AAAA,EACxC;AACF;AAOA,SAAS,6BACP,QACyB;AACzB,MAAI,OAAO,OAAO,iBAAiB,YAAY,OAAO,SAAS,OAAO,YAAY,GAAG;AACnF,WAAO,EAAE,QAAQ,OAAO,cAAc,MAAM,MAAM;AAAA,EACpD;AACA,MAAI,OAAO,OAAO,mBAAmB,YAAY,OAAO,SAAS,OAAO,cAAc,GAAG;AACvF,WAAO,EAAE,QAAQ,OAAO,gBAAgB,MAAM,QAAQ;AAAA,EACxD;AACA,SAAO;AACT;AAEA,SAAS,6BAA6B,QAAsD;AAC1F,QAAM,MAAM,sBAAsB,OAAO,YAAY;AACrD,MAAI,QAAQ,KAAM,QAAO,EAAE,QAAQ,KAAK,MAAM,MAAM;AACpD,QAAM,QAAQ,sBAAsB,OAAO,cAAc;AACzD,MAAI,UAAU,KAAM,QAAO,EAAE,QAAQ,OAAO,MAAM,QAAQ;AAC1D,SAAO;AACT;AAEA,SAAS,sBAAsB,OAAiD;AAC9E,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,QAAM,UAAU,OAAO,KAAK;AAC5B,SAAO,OAAO,SAAS,OAAO,IAAI,UAAU;AAC9C;AAEA,MAAM,qBAA4E;AAAA,EAChF,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,OAAO,IAAI,sBAAsB,mBAAmB,QAAQ;AAC5E,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,aAAa,kBAAkB,GAAG;AACxC,QAAI,UAAwC;AAC5C,QAAI,UAAiC;AACrC,QAAI,OAAO,WAAW;AACpB,gBAAU,MAAM,eAAe,IAAI,OAAO,WAAW,UAAU;AAC/D,gBACE,OAAO,QAAQ,YAAY,WACvB,MAAM,eAAe,IAAI,QAAQ,SAAS;AAAA,QACxC,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B,CAAC,IACD,QAAQ;AAAA,IAChB;AACA,QAAI,OAAO,WAAW;AACpB,YAAM,kBAAkB,MAAM,eAAe,IAAI,OAAO,WAAW,UAAU;AAC7E,UAAI,WAAW,gBAAgB,OAAO,QAAQ,IAAI;AAChD,cAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mDAAmD,CAAC;AAAA,MAC5F;AACA,gBAAU;AAAA,IACZ;AACA,QAAI,CAAC,WAAW,CAAC,SAAS;AACxB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,uDAAuD,CAAC;AAAA,IAChG;AACA,UAAM,cAAc,WAAW;AAC/B,sBAAkB,KAAK,YAAY,QAAQ;AAC3C,4BAAwB,KAAK,YAAY,cAAc;AACvD,UAAM,mBAAmB;AAAA,MACvB,UAAU,YAAY;AAAA,MACtB,gBAAgB,YAAY;AAAA,IAC9B;AAEA,UAAM,YAAY,MAAM,iBAAiB,IAAI,OAAO,aAAa,gBAAgB;AACjF,qBAAiB,WAAW,YAAY,QAAQ;AAEhD,QAAI,QAA6B;AACjC,QAAI,OAAO,SAAS;AAClB,cAAQ,MAAM,aAAa,IAAI,OAAO,SAAS,gBAAgB;AAC/D,sBAAgB,OAAO,YAAY,gBAAgB,YAAY,QAAQ;AACvE,YAAM,eACJ,OAAO,MAAM,YAAY,WACrB,MAAM,eAAe,IAAI,MAAM,SAAS;AAAA,QACtC,UAAU,MAAM;AAAA,QAChB,gBAAgB,MAAM;AAAA,MACxB,CAAC,IACD,MAAM;AACZ,UAAI,WAAW,aAAa,OAAO,QAAQ,IAAI;AAC7C,cAAM,IAAI,cAAc,KAAK,EAAE,OAAO,iDAAiD,CAAC;AAAA,MAC1F;AACA,gBAAU;AAAA,IACZ;AACA,UAAM,gBAAgB;AACtB,UAAM,YAAY,OAAO,cAAc,QAAQ,MAAM,YAAY;AACjE,UAAM,wBAAwB,IAAI,UAAU,QAA+B,uBAAuB;AAClG,UAAM,cAAc,6BAA6B,MAAM;AACvD,QAAI,oBAAoB,gBAAgB,OAAO,YAAY;AAC3D,QAAI,sBAAsB,gBAAgB,OAAO,cAAc;AAC/D,QAAI,eAAe,gBAAgB,OAAO,OAAO;AACjD,QAAI,iBAAgC;AACpC,QAAI,aAAa;AACf,YAAM,cAAc,MAAM,sBAAsB,qBAAqB;AAAA,QACnE,QAAQ,YAAY;AAAA,QACpB,MAAM,YAAY;AAAA,QAClB,gBAAgB,YAAY;AAAA,QAC5B,UAAU,YAAY;AAAA,QACtB,WAAW,OAAO,aAAa;AAAA,QAC/B,SAAS,OAAO,WAAW;AAAA,MAC7B,CAAC;AACD,0BAAoB,gBAAgB,YAAY,SAAS;AACzD,4BAAsB,gBAAgB,YAAY,WAAW;AAC7D,uBAAiB,gBAAgB,YAAY,SAAS;AACtD,qBAAe,gBAAgB,YAAY,OAAO;AAAA,IACpD;AAEA,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,SAAS,GAAG,OAAO,qBAAqB;AAAA,MAC5C,gBAAgB,YAAY;AAAA,MAC5B,UAAU,YAAY;AAAA,MACtB;AAAA,MACA,SAAS,iBAAiB;AAAA,MAC1B,OAAO,SAAS;AAAA,MAChB;AAAA,MACA,cAAc,OAAO;AAAA,MACrB,MAAM,UAAU;AAAA,MAChB,aAAa,OAAO,eAAe;AAAA,MACnC,aAAa,OAAO,eAAe;AAAA,MACnC,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB,SAAS;AAAA,MACT,WAAW;AAAA,MACX;AAAA,MACA,QAAQ,OAAO,UAAU;AAAA,MACzB,aAAa,OAAO,eAAe;AAAA,MACnC,YAAY,OAAO,cAAc;AAAA,MACjC,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,MACzD,UAAU,OAAO,YAAY;AAAA,MAC7B,QAAQ,OAAO,UAAU;AAAA,MACzB,WAAW;AAAA,MACX,WAAW;AAAA,IACb,CAAC;AACD,OAAG,QAAQ,MAAM;AACjB,UAAM,GAAG,MAAM;AACf,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,KAAK,IAAI,UAAU,QAAQ,YAAY;AAC7C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,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,UAAM,yBAAyB,IAAI,4BAA4B,MAAM,GAAG,UAAU;AAAA,MAChF,OAAO,oBAAoB,IAAI,SAAS;AAAA,IAC1C,CAAC;AACD,WAAO,EAAE,SAAS,OAAO,GAAG;AAAA,EAC9B;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,kBAAkB,IAAI,OAAO,OAAO;AAAA,EAC7C;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,+BAA+B,sBAAsB;AAAA,MAC5E,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,MACtB,eAAe;AAAA,MACf,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,mBAAqC,QAAQ;AAC7D,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO;AACZ,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,SAAS,MAAM,GAAG,QAAQ,qBAAqB,EAAE,IAAI,MAAM,GAAG,CAAC;AACrE,QAAI,CAAC,OAAQ;AACb,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,OAAG,OAAO,MAAM;AAChB,UAAM,GAAG,MAAM;AACf,UAAM,yBAAyB,IAAI,OAAO,QAAQ;AAAA,MAChD,UAAU,EAAE,eAAe,wBAAwB;AAAA,MACnD,OAAO,oBAAoB,IAAI,SAAS;AAAA,IAC1C,CAAC;AACD,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;AAAA,EACA,MAAM,eAA0F;AAAA,IAC9F,aAAa;AAAA,IACb,eAAe,CAAC,aAAa,SAAS;AAAA,IACtC,kBAAkB;AAAA,IAClB,aAAa,CAAC,YAAY,EAAE,SAAS,OAAO,GAAG;AAAA,IAC/C,QAAQ;AAAA,IACR,cAAc,OAAO,EAAE,IAAI,KAAK,QAAQ,SAAS,MAAM;AACrD,UAAI,SAAS,UAAU,OAAO,KAAK,SAAS,MAAM,EAAE,QAAQ;AAC1D,cAAM,qBAAqB;AAAA,UACzB,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,UAC9C,UAAU,EAAE,QAAQ;AAAA,UACpB,UAAU,OAAO;AAAA,UACjB,gBAAgB,OAAO;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB,QAAQ,SAAS;AAAA,QACnB,CAAC;AAAA,MACH;AACA,YAAM,yBAAyB,IAAI,UAAU,UAAU;AAAA,QACrD,UAAU,EAAE,eAAe,wBAAwB;AAAA,QACnD,OAAO,oBAAoB,IAAI,SAAS;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;AAEA,MAAM,qBAA4E;AAAA,EAChF,IAAI;AAAA,EACJ,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,sBAAsB;AAClD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI;AACtC,UAAM,WAAW,MAAM,kBAAkB,IAAI,IAAI,kBAAkB,GAAG,CAAC;AACvE,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,mBAAmB,QAAQ;AAC5E,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA,EAAE,IAAI,OAAO,IAAI,GAAG,kBAAkB,GAAG,EAAE;AAAA,MAC3C,EAAE,UAAU,CAAC,WAAW,EAAE;AAAA,MAC1B,EAAE,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe;AAAA,IACrE;AACA,QAAI,CAAC,OAAQ,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAC9E,UAAM,cAAc,EAAE,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe;AACvF,UAAM,oBAAoB,OAAO;AACjC,QAAI,gBAA8C;AAClD,QAAI,OAAO,sBAAsB,UAAU;AACzC,sBAAgB,MAAM,eAAe,IAAI,mBAAmB,WAAW;AAAA,IACzE,WAAW,mBAAmB;AAC5B,sBAAgB;AAAA,IAClB;AACA,UAAM,oBAAoB,OAAO,YAAY,gBAAgB,cAAc,UAAU;AACrF,QAAI,gBAAuC;AAC3C,QAAI,OAAO,sBAAsB,UAAU;AACzC,sBAAgB,MAAM,eAAe,IAAI,mBAAmB,WAAW;AAAA,IACzE,WAAW,mBAAmB;AAC5B,sBAAgB;AAAA,IAClB;AACA,UAAM,qBAAqB,4BAA4B,MAAM;AAC7D,UAAM,gBAAgB;AAAA,MACpB,GAAG;AAAA,MACH,WAAW,mBAAmB,aAAa,eAAe,MAAM;AAAA,IAClE;AAEA,QAAI,OAAO,cAAc,QAAW;AAClC,UAAI,CAAC,OAAO,WAAW;AACrB,wBAAgB;AAAA,MAClB,OAAO;AACL,wBAAgB,MAAM,eAAe,IAAI,OAAO,WAAW,WAAW;AACtE,wBACE,OAAO,cAAc,YAAY,WAC7B,MAAM,eAAe,IAAI,cAAc,SAAS,WAAW,IAC3D,cAAc;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,iBAAkB,eAAgD,YAAY,QAAW;AAC3F,sBAAgB,MAAM,eAAe,IAAI,cAAc,IAAI,WAAW;AAAA,IACxE;AAEA,QAAI,OAAO,cAAc,QAAW;AAClC,UAAI,CAAC,OAAO,WAAW;AACrB,wBAAgB;AAAA,MAClB,OAAO;AACL,cAAM,kBAAkB,MAAM,eAAe,IAAI,OAAO,WAAW,WAAW;AAC9E,YAAI,eAAe;AACjB,gBAAM,mBACJ,OAAO,cAAc,YAAY,WAC7B,cAAc,UACd,cAAc,QAAQ;AAC5B,cAAI,qBAAqB,gBAAgB,IAAI;AAC3C,kBAAM,IAAI,cAAc,KAAK,EAAE,OAAO,mDAAmD,CAAC;AAAA,UAC5F;AAAA,QACF;AACA,wBAAgB;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB,CAAC,eAAe;AACpC,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0DAA0D,CAAC;AAAA,IACnG;AACA,QAAI,CAAC,iBAAiB,eAAe;AACnC,sBACE,OAAO,cAAc,YAAY,WAC7B,MAAM,eAAe,IAAI,cAAc,SAAS,WAAW,IAC3D,cAAc;AAAA,IACtB;AACA,QAAI,CAAC,eAAe;AAClB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,uCAAuC,CAAC;AAAA,IAChF;AAEA,QAAI,cAAmC;AACvC,QAAI,OAAO,OAAO;AAChB,oBACE,OAAO,OAAO,UAAU,WACpB,MAAM,aAAa,IAAI,OAAO,OAAO,WAAW,IAChD,OAAO;AAAA,IACf;AACA,QAAI,OAAO,YAAY,QAAW;AAChC,UAAI,CAAC,OAAO,SAAS;AACnB,sBAAc;AAAA,MAChB,OAAO;AACL,cAAM,gBAAgB,MAAM,aAAa,IAAI,OAAO,SAAS,WAAW;AACxE,wBAAgB,eAAe,cAAc,gBAAgB,cAAc,QAAQ;AACnF,cAAM,iBACJ,OAAO,cAAc,YAAY,WAC7B,cAAc,UACd,cAAc,QAAQ;AAC5B,YAAI,mBAAmB,cAAc,IAAI;AACvC,gBAAM,IAAI,cAAc,KAAK,EAAE,OAAO,iDAAiD,CAAC;AAAA,QAC1F;AACA,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,sBAAkB,KAAK,cAAc,QAAQ;AAC7C,4BAAwB,KAAK,cAAc,cAAc;AAEzD,QAAI,kBAA2C;AAC/C,QAAI,OAAO,WAAW;AACpB,wBACE,OAAO,OAAO,cAAc,WACxB,MAAM,iBAAiB,IAAI,OAAO,WAAW,WAAW,IACxD,OAAO;AAAA,IACf;AACA,QAAI,OAAO,gBAAgB,QAAW;AACpC,UAAI,CAAC,OAAO,aAAa;AACvB,cAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAAA,MACnE;AACA,wBAAkB,MAAM,iBAAiB,IAAI,OAAO,aAAa,WAAW;AAAA,IAC9E;AACA,QAAI,CAAC,iBAAiB;AACpB,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAAA,IACnE;AACA,qBAAiB,iBAAiB,cAAc,QAAQ;AAExD,UAAM,wBAAwB,IAAI,UAAU,QAA+B,uBAAuB;AAClG,UAAM,cAAc,6BAA6B,MAAM;AACvD,UAAM,cAAc,OAAO,UAAU,eAAe,KAAK,QAAQ,cAAc;AAC/E,UAAM,gBAAgB,OAAO,UAAU,eAAe,KAAK,QAAQ,gBAAgB;AACnF,UAAM,kBAAkB,OAAO,UAAU,eAAe,KAAK,QAAQ,SAAS;AAC9E,UAAM,oBAAoB,OAAO,UAAU,eAAe,KAAK,QAAQ,WAAW;AAClF,QAAI,uBAAkG;AACtG,QAAI,kBAAkB;AACtB,QAAI,CAAC,oBAAoB,mBAAmB,oBAAoB;AAC9D,wBAAkB,6BAA6B,MAAM;AAAA,IACvD;AACA,QAAI,iBAAiB;AACnB,YAAM,0BAA0B,oBAAoB,OAAO,aAAa,OAAO;AAC/E,YAAM,wBAAwB,kBAC1B,OAAO,WAAW,OAClB,4BAA4B,OAC1B,OACA,OAAO,WAAW;AACxB,6BAAuB,MAAM,sBAAsB,qBAAqB;AAAA,QACtE,QAAQ,gBAAgB;AAAA,QACxB,MAAM,gBAAgB;AAAA,QACtB,gBAAgB,cAAc;AAAA,QAC9B,UAAU,cAAc;AAAA,QACxB,WAAW;AAAA,QACX,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,WAAO,UAAU;AACjB,WAAO,UAAU;AACjB,WAAO,QAAQ;AACf,WAAO,iBAAiB,cAAc;AACtC,WAAO,WAAW,cAAc;AAChC,WAAO,YAAY;AACnB,WAAO,OAAO,gBAAgB;AAE9B,QAAI,OAAO,iBAAiB,OAAW,QAAO,eAAe,OAAO;AACpE,QAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO,eAAe;AACjF,QAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO,eAAe;AACjF,QAAI,sBAAsB;AACxB,aAAO,eAAe,gBAAgB,qBAAqB,SAAS;AACpE,aAAO,iBAAiB,gBAAgB,qBAAqB,WAAW;AACxE,aAAO,UAAU,gBAAgB,qBAAqB,OAAO;AAC7D,aAAO,YAAY,gBAAgB,qBAAqB,SAAS;AAAA,IACnE,OAAO;AACL,UAAI,aAAa;AACf,eAAO,eAAe,gBAAgB,OAAO,YAAY;AAAA,MAC3D;AACA,UAAI,eAAe;AACjB,eAAO,iBAAiB,gBAAgB,OAAO,cAAc;AAAA,MAC/D;AACA,UAAI,iBAAiB;AACnB,eAAO,UAAU,gBAAgB,OAAO,OAAO;AAC/C,YAAI,OAAO,WAAW,MAAM;AAC1B,iBAAO,YAAY;AAAA,QACrB;AAAA,MACF,WAAW,qBAAqB,OAAO,cAAc,MAAM;AACzD,eAAO,UAAU;AACjB,eAAO,YAAY;AAAA,MACrB;AAAA,IACF;AACA,QAAI,OAAO,cAAc,QAAW;AAClC,aAAO,YAAY,OAAO,aAAa;AAAA,IACzC,WAAW,OAAO,YAAY,UAAa,aAAa;AACtD,aAAO,YAAY,YAAY;AAAA,IACjC;AACA,QAAI,OAAO,WAAW,OAAW,QAAO,SAAS,OAAO,UAAU;AAClE,QAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO,eAAe;AACjF,QAAI,OAAO,eAAe,OAAW,QAAO,aAAa,OAAO,cAAc;AAC9E,QAAI,OAAO,oBAAoB,OAAW,QAAO,kBAAkB,OAAO,mBAAmB;AAC7F,QAAI,OAAO,aAAa,QAAW;AACjC,aAAO,WAAW,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,IACnE;AACA,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,UAAU,GAAG;AAC5D,aAAO,WAAW,OAAO,YAAY;AAAA,IACvC;AACA,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,QAAQ,GAAG;AAC1D,aAAO,SAAS,OAAO,UAAU;AAAA,IACnC;AACA,UAAM,GAAG,MAAM;AACf,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,KAAK,IAAI,UAAU,QAAQ,YAAY;AAC7C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,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,UAAM,eAAe,4BAA4B,MAAM;AACvD,QAAI,8BAA8B,eAAe,YAAY,GAAG;AAC9D,YAAM,yBAAyB,IAAI,cAAc,UAAU;AAAA,QACzD,OAAO,oBAAoB,IAAI,SAAS;AAAA,QACxC,kBAAkB,CAAC,aAAa;AAAA,QAChC,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,WAAO,EAAE,SAAS,OAAO,GAAG;AAAA,EAC9B;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,kBAAkB,IAAI,OAAO,OAAO;AAAA,EAC7C;AAAA,EACA,UAAU,OAAO,EAAE,UAAU,MAAM;AACjC,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,+BAA+B,sBAAsB;AAAA,MAC5E,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,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,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAqC,QAAQ;AAC7D,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,qBAAqB,EAAE,IAAI,OAAO,GAAG,CAAC;AACpE,QAAI,CAAC,QAAQ;AACX,YAAM,EAAE,SAAS,SAAS,MAAM,IAAI,MAAM,4BAA4B,IAAI,MAAM;AAChF,eAAS,GAAG,OAAO,qBAAqB;AAAA,QACtC,IAAI,OAAO;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,cAAc,OAAO;AAAA,QACrB,WAAW,GAAG,aAAa,kBAAkB,OAAO,WAAW;AAAA,QAC/D,MAAM,OAAO,iBAAiB,OAAO;AAAA,QACrC,aAAa,OAAO;AAAA,QACpB,aAAa,OAAO,eAAe;AAAA,QACnC,cAAc,OAAO,gBAAgB;AAAA,QACrC,gBAAgB,OAAO,kBAAkB;AAAA,QACzC,SAAS,OAAO,WAAW;AAAA,QAC3B,WAAW,OAAO,aAAa;AAAA,QAC/B,WAAW,OAAO,aAAa;AAAA,QAC/B,QAAQ,OAAO,UAAU;AAAA,QACzB,aAAa,OAAO,eAAe;AAAA,QACnC,YAAY,OAAO,cAAc;AAAA,QACjC,iBAAiB,OAAO,mBAAmB;AAAA,QAC3C,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,QACzD,UAAU,OAAO,WAAW,IAAI,KAAK,OAAO,QAAQ,IAAI;AAAA,QACxD,QAAQ,OAAO,SAAS,IAAI,KAAK,OAAO,MAAM,IAAI;AAAA,QAClD,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,uBAAmB,IAAI,QAAQ,MAAM;AACrC,UAAM,GAAG,MAAM;AACf,UAAM,yBAAyB,IAAI,QAAQ,QAAQ;AAAA,MACjD,UAAU,EAAE,eAAe,wBAAwB;AAAA,MACnD,OAAO,oBAAoB,IAAI,SAAS;AAAA,MACxC,kBAAkB,CAAC,KAAK;AAAA,MACxB,UAAU;AAAA,IACZ,CAAC;AACD,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,qBAGF;AAAA,EACF,IAAI;AAAA,EACJ,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,sBAAsB;AAClD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI;AACtC,UAAM,WAAW,MAAM,kBAAkB,IAAI,IAAI,kBAAkB,GAAG,CAAC;AACvE,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,sBAAsB;AAClD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,SAAS,MAAM,sBAAsB,IAAI,qBAAqB,EAAE,IAAI,GAAG,kBAAkB,GAAG,EAAE,CAAC;AACrG,QAAI,CAAC,OAAQ,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,0BAA0B,CAAC;AAC9E,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,UAAM,EAAE,QAAQ,IAAI,MAAM,+BAA+B,IAAI,MAAM;AAEnE,UAAM,SAAU,IAAI,UAAU,QAAQ,IAAI;AAC1C,UAAM,WAAW,MAAM,kBAAkB,QAAQ,EAAE;AAEnD,UAAM,eAAe,YAAY,4BAA4B,MAAM;AACnE,OAAG,OAAO,MAAM;AAChB,UAAM,GAAG,MAAM;AACf,UAAM,yBAAyB,IAAI,cAAc,UAAU,EAAE,OAAO,oBAAoB,IAAI,SAAS,EAAE,CAAC;AACxG,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,YAAY,IAAI,UAAU,QAAQ,YAAY;AAAA,UAC9C,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,KAAK,IAAI,UAAU,QAAQ,YAAY;AAC7C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,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,SAAS,GAAG;AAAA,EACvB;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,+BAA+B,sBAAsB;AAAA,MAC5E,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,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,mBAAqC,QAAQ;AAC7D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,SAAS,MAAM,GAAG,QAAQ,qBAAqB,EAAE,IAAI,OAAO,GAAG,CAAC;AACpE,QAAI,CAAC,QAAQ;AACX,YAAM,EAAE,SAAS,SAAS,MAAM,IAAI,MAAM,4BAA4B,IAAI,MAAM;AAChF,eAAS,GAAG,OAAO,qBAAqB;AAAA,QACtC,IAAI,OAAO;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,QACjB,cAAc,OAAO;AAAA,QACrB,WAAW,GAAG,aAAa,kBAAkB,OAAO,WAAW;AAAA,QAC/D,MAAM,OAAO,iBAAiB,OAAO;AAAA,QACrC,aAAa,OAAO;AAAA,QACpB,aAAa,OAAO,eAAe;AAAA,QACnC,cAAc,OAAO,gBAAgB;AAAA,QACrC,gBAAgB,OAAO,kBAAkB;AAAA,QACzC,SAAS,OAAO,WAAW;AAAA,QAC3B,WAAW,OAAO,aAAa;AAAA,QAC/B,WAAW,OAAO,aAAa;AAAA,QAC/B,QAAQ,OAAO,UAAU;AAAA,QACzB,aAAa,OAAO,eAAe;AAAA,QACnC,YAAY,OAAO,cAAc;AAAA,QACjC,iBAAiB,OAAO,mBAAmB;AAAA,QAC3C,UAAU,OAAO,WAAW,UAAU,OAAO,QAAQ,IAAI;AAAA,QACzD,UAAU,OAAO,WAAW,IAAI,KAAK,OAAO,QAAQ,IAAI;AAAA,QACxD,QAAQ,OAAO,SAAS,IAAI,KAAK,OAAO,MAAM,IAAI;AAAA,QAClD,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,uBAAmB,IAAI,QAAQ,MAAM;AACrC,UAAM,GAAG,MAAM;AACf,UAAM,yBAAyB,IAAI,QAAQ,QAAQ;AAAA,MACjD,UAAU,EAAE,eAAe,wBAAwB;AAAA,MACnD,OAAO,oBAAoB,IAAI,SAAS;AAAA,IAC1C,CAAC;AACD,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,gBAAgB,kBAAkB;AAClC,gBAAgB,kBAAkB;AAClC,gBAAgB,kBAAkB;AAElC,eAAe,+BACb,IACA,QAC6E;AAC7E,QAAM,QAAQ,EAAE,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe;AACjF,QAAM,UAAU,OAAO,UAClB,OAAO,OAAO,YAAY,WACvB,MAAM,eAAe,IAAI,OAAO,SAAS,KAAK,IAC9C,OAAO,UACX;AACJ,MAAI,OAAO,SAAS;AAClB,UAAM,UACJ,OAAO,OAAO,YAAY,WACtB,MAAM,eAAe,IAAI,OAAO,SAAS,KAAK,IAC9C,OAAO;AACb,WAAO,EAAE,SAAS,QAAQ;AAAA,EAC5B;AACA,MAAI,SAAS,SAAS;AACpB,UAAM,aAAa,QAAQ;AAC3B,UAAM,UACJ,OAAO,eAAe,WAClB,MAAM,eAAe,IAAI,YAAY,KAAK,IAC1C;AACN,WAAO,EAAE,SAAS,QAAQ;AAAA,EAC5B;AACA,MAAI,OAAO,OAAO;AAChB,UAAM,QACJ,OAAO,OAAO,UAAU,WACpB,MAAM,aAAa,IAAI,OAAO,OAAO,KAAK,IAC1C,OAAO;AACb,UAAM,aAAa,OAAO,WAAW;AACrC,QAAI,YAAY;AACd,YAAM,UACJ,OAAO,eAAe,WAClB,MAAM,eAAe,IAAI,YAAY,KAAK,IAC1C;AACN,aAAO,EAAE,SAAS,QAAQ;AAAA,IAC5B;AAAA,EACF;AACA,QAAM,IAAI,cAAc,KAAK,EAAE,OAAO,4CAA4C,CAAC;AACrF;",
|
|
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 { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CatalogOffer, CatalogProduct, CatalogProductPrice, CatalogProductVariant, CatalogPriceKind } from '../data/entities'\nimport { loadCustomFieldSnapshot, buildCustomFieldResetMap } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n priceCreateSchema,\n priceUpdateSchema,\n type PriceCreateInput,\n type PriceUpdateInput,\n} from '../data/validators'\nimport type { TaxCalculationService } from '@open-mercato/core/modules/sales/services/taxCalculationService'\nimport {\n cloneJson,\n commandActorScope,\n commandScopeWhere,\n ensureOrganizationScope,\n ensureSameScope,\n ensureSameTenant,\n ensureTenantScope,\n extractUndoPayload,\n requireVariant,\n requireProduct,\n requireOffer,\n requirePriceKind,\n toNumericString,\n} from './shared'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport {\n capturePriceHistoryEntry,\n hasPriceHistoryRelevantChange,\n priceHistoryInputFromRecord,\n} from '../lib/omnibus'\nimport { resolveOmnibusCache } from '../lib/omnibusCache'\n\nconst priceCrudEvents: CrudEventsConfig = {\n module: 'catalog',\n entity: 'price',\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 PriceSnapshot = {\n id: string\n variantId: string | null\n productId: string | null\n offerId: string | null\n organizationId: string\n tenantId: string\n currencyCode: string\n priceKindId: string\n priceKindCode: 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\ntype PriceUndoPayload = {\n before?: PriceSnapshot | null\n after?: PriceSnapshot | null\n}\n\nconst PRICE_CHANGE_KEYS = [\n 'currencyCode',\n 'priceKindId',\n 'kind',\n 'minQuantity',\n 'maxQuantity',\n 'unitPriceNet',\n 'unitPriceGross',\n 'taxRate',\n 'taxAmount',\n 'channelId',\n 'userId',\n 'userGroupId',\n 'customerId',\n 'customerGroupId',\n 'metadata',\n 'startsAt',\n 'endsAt',\n] as const satisfies readonly string[]\n\nasync function resolveSnapshotAssociations(\n em: EntityManager,\n snapshot: PriceSnapshot\n): Promise<{\n variant: CatalogProductVariant | null\n product: CatalogProduct\n offer: CatalogOffer | null\n}> {\n const scope = { tenantId: snapshot.tenantId, organizationId: snapshot.organizationId }\n let variant: CatalogProductVariant | null = null\n if (snapshot.variantId) {\n variant = await requireVariant(em, snapshot.variantId, scope)\n }\n let product: CatalogProduct | null = null\n if (snapshot.productId) {\n product = await requireProduct(em, snapshot.productId, scope)\n } else if (variant) {\n product =\n typeof variant.product === 'string'\n ? await requireProduct(em, variant.product, scope)\n : variant.product\n }\n if (!product) {\n throw new CrudHttpError(400, { error: 'Price snapshot missing product association.' })\n }\n let offer: CatalogOffer | null = null\n if (snapshot.offerId) {\n offer = await requireOffer(em, snapshot.offerId, scope)\n }\n return { variant, product, offer }\n}\n\nasync function loadPriceSnapshot(\n em: EntityManager,\n id: string,\n scopeWhere: Record<string, unknown> = {},\n): Promise<PriceSnapshot | null> {\n const record = await findOneWithDecryption(\n em,\n CatalogProductPrice,\n { id, ...scopeWhere },\n { populate: ['priceKind', 'product', 'variant', 'offer'] },\n )\n if (!record) return null\n const variantId =\n typeof record.variant === 'string'\n ? record.variant\n : record.variant\n ? record.variant.id\n : null\n const productRef = record.product\n ? record.product\n : typeof record.variant === 'object' && record.variant\n ? record.variant.product\n : null\n const productId =\n typeof productRef === 'string'\n ? productRef\n : productRef\n ? productRef.id\n : null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.catalog.catalog_product_price,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n const priceKind = record.priceKind\n const priceKindId =\n typeof priceKind === 'string'\n ? priceKind\n : priceKind\n ? priceKind.id\n : null\n if (!priceKindId) {\n throw new CrudHttpError(400, { error: 'Price is missing price kind metadata.' })\n }\n const priceKindCode =\n typeof priceKind === 'object' && priceKind ? priceKind.code : record.kind\n return {\n id: record.id,\n variantId,\n productId,\n offerId: typeof record.offer === 'string' ? record.offer : record.offer ? record.offer.id : null,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n currencyCode: record.currencyCode,\n priceKindId,\n priceKindCode,\n kind: record.kind,\n minQuantity: record.minQuantity,\n maxQuantity: record.maxQuantity ?? null,\n unitPriceNet: record.unitPriceNet ?? null,\n unitPriceGross: record.unitPriceGross ?? null,\n taxRate: record.taxRate ?? null,\n taxAmount: record.taxAmount ?? null,\n channelId: record.channelId ?? null,\n userId: record.userId ?? null,\n userGroupId: record.userGroupId ?? null,\n customerId: record.customerId ?? null,\n customerGroupId: record.customerGroupId ?? null,\n metadata: record.metadata ? cloneJson(record.metadata) : null,\n startsAt: record.startsAt ? record.startsAt.toISOString() : null,\n endsAt: record.endsAt ? record.endsAt.toISOString() : null,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n custom: Object.keys(custom).length ? custom : null,\n }\n}\n\nfunction applyPriceSnapshot(em: EntityManager, record: CatalogProductPrice, snapshot: PriceSnapshot): void {\n record.organizationId = snapshot.organizationId\n record.tenantId = snapshot.tenantId\n record.currencyCode = snapshot.currencyCode\n record.priceKind = em.getReference(CatalogPriceKind, snapshot.priceKindId)\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\nfunction priceSeedFromSnapshot(snapshot: PriceSnapshot): Record<string, unknown> {\n return {\n id: snapshot.id,\n variant: snapshot.variantId ?? null,\n product: snapshot.productId ?? null,\n offer: snapshot.offerId ?? null,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n priceKind: snapshot.priceKindId,\n currencyCode: snapshot.currencyCode,\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}\n\ntype PriceAmountInput = {\n amount: number\n mode: 'net' | 'gross'\n}\n\nfunction resolveAmountInputFromParsed(\n parsed: Partial<Pick<PriceCreateInput, 'unitPriceNet' | 'unitPriceGross'>>\n): PriceAmountInput | null {\n if (typeof parsed.unitPriceNet === 'number' && Number.isFinite(parsed.unitPriceNet)) {\n return { amount: parsed.unitPriceNet, mode: 'net' }\n }\n if (typeof parsed.unitPriceGross === 'number' && Number.isFinite(parsed.unitPriceGross)) {\n return { amount: parsed.unitPriceGross, mode: 'gross' }\n }\n return null\n}\n\nfunction hasAmountChanged(incoming: unknown, current: string | null | undefined): incoming is number {\n if (typeof incoming !== 'number' || !Number.isFinite(incoming)) return false\n return numericStringToNumber(current) !== incoming\n}\n\nfunction resolveAmountInputForUpdate(\n parsed: Partial<Pick<PriceCreateInput, 'unitPriceNet' | 'unitPriceGross'>>,\n record: CatalogProductPrice\n): PriceAmountInput | null {\n if (hasAmountChanged(parsed.unitPriceNet, record.unitPriceNet)) {\n return { amount: parsed.unitPriceNet, mode: 'net' }\n }\n if (hasAmountChanged(parsed.unitPriceGross, record.unitPriceGross)) {\n return { amount: parsed.unitPriceGross, mode: 'gross' }\n }\n return resolveAmountInputFromParsed(parsed)\n}\n\nfunction resolveAmountInputFromRecord(record: CatalogProductPrice): PriceAmountInput | null {\n const net = numericStringToNumber(record.unitPriceNet)\n if (net !== null) return { amount: net, mode: 'net' }\n const gross = numericStringToNumber(record.unitPriceGross)\n if (gross !== null) return { amount: gross, mode: 'gross' }\n return null\n}\n\nfunction numericStringToNumber(value: string | null | undefined): number | null {\n if (value === undefined || value === null) return null\n const numeric = Number(value)\n return Number.isFinite(numeric) ? numeric : null\n}\n\nconst createPriceCommand: CommandHandler<PriceCreateInput, { priceId: string }> = {\n id: 'catalog.prices.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(priceCreateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const actorScope = commandActorScope(ctx)\n let variant: CatalogProductVariant | null = null\n let product: CatalogProduct | null = null\n if (parsed.variantId) {\n variant = await requireVariant(em, parsed.variantId, actorScope)\n product =\n typeof variant.product === 'string'\n ? await requireProduct(em, variant.product, {\n tenantId: variant.tenantId,\n organizationId: variant.organizationId,\n })\n : variant.product\n }\n if (parsed.productId) {\n const explicitProduct = await requireProduct(em, parsed.productId, actorScope)\n if (product && explicitProduct.id !== product.id) {\n throw new CrudHttpError(400, { error: 'Variant does not belong to the provided product.' })\n }\n product = explicitProduct\n }\n if (!variant && !product) {\n throw new CrudHttpError(400, { error: 'Provide either a variantId or productId for pricing.' })\n }\n const scopeSource = variant ?? product!\n ensureTenantScope(ctx, scopeSource.tenantId)\n ensureOrganizationScope(ctx, scopeSource.organizationId)\n const scopeSourceScope = {\n tenantId: scopeSource.tenantId,\n organizationId: scopeSource.organizationId,\n }\n\n const priceKind = await requirePriceKind(em, parsed.priceKindId, scopeSourceScope)\n ensureSameTenant(priceKind, scopeSource.tenantId)\n\n let offer: CatalogOffer | null = null\n if (parsed.offerId) {\n offer = await requireOffer(em, parsed.offerId, scopeSourceScope)\n ensureSameScope(offer, scopeSource.organizationId, scopeSource.tenantId)\n const offerProduct =\n typeof offer.product === 'string'\n ? await requireProduct(em, offer.product, {\n tenantId: offer.tenantId,\n organizationId: offer.organizationId,\n })\n : offer.product\n if (product && offerProduct.id !== product.id) {\n throw new CrudHttpError(400, { error: 'Offer does not belong to the selected product.' })\n }\n product = offerProduct\n }\n const productEntity = product\n const channelId = parsed.channelId ?? (offer ? offer.channelId : null)\n const taxCalculationService = ctx.container.resolve<TaxCalculationService>('taxCalculationService')\n const amountInput = resolveAmountInputFromParsed(parsed)\n let unitPriceNetValue = toNumericString(parsed.unitPriceNet)\n let unitPriceGrossValue = toNumericString(parsed.unitPriceGross)\n let taxRateValue = toNumericString(parsed.taxRate)\n let taxAmountValue: string | null = null\n if (amountInput) {\n const calculation = await taxCalculationService.calculateUnitAmounts({\n amount: amountInput.amount,\n mode: amountInput.mode,\n organizationId: scopeSource.organizationId,\n tenantId: scopeSource.tenantId,\n taxRateId: parsed.taxRateId ?? null,\n taxRate: parsed.taxRate ?? null,\n })\n unitPriceNetValue = toNumericString(calculation.netAmount)\n unitPriceGrossValue = toNumericString(calculation.grossAmount)\n taxAmountValue = toNumericString(calculation.taxAmount)\n taxRateValue = toNumericString(calculation.taxRate)\n }\n\n const now = new Date()\n const record = em.create(CatalogProductPrice, {\n organizationId: scopeSource.organizationId,\n tenantId: scopeSource.tenantId,\n variant,\n product: productEntity ?? undefined,\n offer: offer ?? undefined,\n priceKind,\n currencyCode: parsed.currencyCode,\n kind: priceKind.code,\n minQuantity: parsed.minQuantity ?? 1,\n maxQuantity: parsed.maxQuantity ?? null,\n unitPriceNet: unitPriceNetValue,\n unitPriceGross: unitPriceGrossValue,\n taxRate: taxRateValue,\n taxAmount: taxAmountValue,\n channelId,\n userId: parsed.userId ?? null,\n userGroupId: parsed.userGroupId ?? null,\n customerId: parsed.customerId ?? null,\n customerGroupId: parsed.customerGroupId ?? null,\n metadata: parsed.metadata ? cloneJson(parsed.metadata) : null,\n startsAt: parsed.startsAt ?? null,\n endsAt: parsed.endsAt ?? null,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: priceCrudEvents,\n })\n await capturePriceHistoryEntry(em, priceHistoryInputFromRecord(record), 'create', {\n cache: resolveOmnibusCache(ctx.container),\n })\n return { priceId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadPriceSnapshot(em, result.priceId)\n },\n buildLog: async ({ result, snapshots }) => {\n const after = snapshots.after as PriceSnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.prices.create', 'Create product price'),\n resourceKind: 'catalog.price',\n resourceId: result.priceId,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: {\n undo: {\n after,\n } satisfies PriceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PriceUndoPayload>(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(CatalogProductPrice, { 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 await capturePriceHistoryEntry(em, after, 'undo', {\n metadata: { undoneCommand: 'catalog.prices.create' },\n cache: resolveOmnibusCache(ctx.container),\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_price,\n recordId: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n values: resetValues,\n })\n }\n },\n redo: makeCreateRedo<CatalogProductPrice, PriceSnapshot, PriceCreateInput, { priceId: string }>({\n entityClass: CatalogProductPrice,\n getSnapshotId: (snapshot) => snapshot.id,\n seedFromSnapshot: priceSeedFromSnapshot,\n buildResult: (entity) => ({ priceId: entity.id }),\n events: priceCrudEvents,\n afterRestore: async ({ em, ctx, entity, snapshot }) => {\n if (snapshot.custom && Object.keys(snapshot.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: entity.id,\n organizationId: entity.organizationId,\n tenantId: entity.tenantId,\n values: snapshot.custom,\n })\n }\n await capturePriceHistoryEntry(em, snapshot, 'create', {\n metadata: { redoneCommand: 'catalog.prices.create' },\n cache: resolveOmnibusCache(ctx.container),\n })\n },\n }),\n}\n\nconst updatePriceCommand: CommandHandler<PriceUpdateInput, { priceId: string }> = {\n id: 'catalog.prices.update',\n async prepare(input, ctx) {\n const id = requireId(input, 'Price id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPriceSnapshot(em, id, commandScopeWhere(ctx))\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(priceUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(\n em,\n CatalogProductPrice,\n { id: parsed.id, ...commandScopeWhere(ctx) },\n { populate: ['priceKind'] },\n { tenantId: parsed.tenantId, organizationId: parsed.organizationId },\n )\n if (!record) throw new CrudHttpError(404, { error: 'Catalog price not found' })\n const recordScope = { tenantId: record.tenantId, organizationId: record.organizationId }\n const currentVariantRef = record.variant\n let targetVariant: CatalogProductVariant | null = null\n if (typeof currentVariantRef === 'string') {\n targetVariant = await requireVariant(em, currentVariantRef, recordScope)\n } else if (currentVariantRef) {\n targetVariant = currentVariantRef\n }\n const currentProductRef = record.product ?? (targetVariant ? targetVariant.product : null)\n let targetProduct: CatalogProduct | null = null\n if (typeof currentProductRef === 'string') {\n targetProduct = await requireProduct(em, currentProductRef, recordScope)\n } else if (currentProductRef) {\n targetProduct = currentProductRef\n }\n const recordHistoryInput = priceHistoryInputFromRecord(record)\n const historyBefore = {\n ...recordHistoryInput,\n productId: recordHistoryInput.productId ?? targetProduct?.id ?? null,\n }\n\n if (parsed.variantId !== undefined) {\n if (!parsed.variantId) {\n targetVariant = null\n } else {\n targetVariant = await requireVariant(em, parsed.variantId, recordScope)\n targetProduct =\n typeof targetVariant.product === 'string'\n ? await requireProduct(em, targetVariant.product, recordScope)\n : targetVariant.product\n }\n }\n\n if (targetVariant && (targetVariant as CatalogProductVariant | null)?.product === undefined) {\n targetVariant = await requireVariant(em, targetVariant.id, recordScope)\n }\n\n if (parsed.productId !== undefined) {\n if (!parsed.productId) {\n targetProduct = null\n } else {\n const explicitProduct = await requireProduct(em, parsed.productId, recordScope)\n if (targetVariant) {\n const variantProductId =\n typeof targetVariant.product === 'string'\n ? targetVariant.product\n : targetVariant.product.id\n if (variantProductId !== explicitProduct.id) {\n throw new CrudHttpError(400, { error: 'Variant does not belong to the provided product.' })\n }\n }\n targetProduct = explicitProduct\n }\n }\n\n if (!targetVariant && !targetProduct) {\n throw new CrudHttpError(400, { error: 'Price must remain associated with a product or variant.' })\n }\n if (!targetProduct && targetVariant) {\n targetProduct =\n typeof targetVariant.product === 'string'\n ? await requireProduct(em, targetVariant.product, recordScope)\n : targetVariant.product\n }\n if (!targetProduct) {\n throw new CrudHttpError(400, { error: 'Unable to resolve product for price.' })\n }\n\n let targetOffer: CatalogOffer | null = null\n if (record.offer) {\n targetOffer =\n typeof record.offer === 'string'\n ? await requireOffer(em, record.offer, recordScope)\n : record.offer\n }\n if (parsed.offerId !== undefined) {\n if (!parsed.offerId) {\n targetOffer = null\n } else {\n const explicitOffer = await requireOffer(em, parsed.offerId, recordScope)\n ensureSameScope(explicitOffer, targetProduct.organizationId, targetProduct.tenantId)\n const offerProductId =\n typeof explicitOffer.product === 'string'\n ? explicitOffer.product\n : explicitOffer.product.id\n if (offerProductId !== targetProduct.id) {\n throw new CrudHttpError(400, { error: 'Offer does not belong to the selected product.' })\n }\n targetOffer = explicitOffer\n }\n }\n\n ensureTenantScope(ctx, targetProduct.tenantId)\n ensureOrganizationScope(ctx, targetProduct.organizationId)\n\n let targetPriceKind: CatalogPriceKind | null = null\n if (record.priceKind) {\n targetPriceKind =\n typeof record.priceKind === 'string'\n ? await requirePriceKind(em, record.priceKind, recordScope)\n : record.priceKind\n }\n if (parsed.priceKindId !== undefined) {\n if (!parsed.priceKindId) {\n throw new CrudHttpError(400, { error: 'Price kind is required.' })\n }\n targetPriceKind = await requirePriceKind(em, parsed.priceKindId, recordScope)\n }\n if (!targetPriceKind) {\n throw new CrudHttpError(400, { error: 'Price kind is required.' })\n }\n ensureSameTenant(targetPriceKind, targetProduct.tenantId)\n\n const taxCalculationService = ctx.container.resolve<TaxCalculationService>('taxCalculationService')\n const amountInput = resolveAmountInputForUpdate(parsed, record)\n const hasNetInput = Object.prototype.hasOwnProperty.call(parsed, 'unitPriceNet')\n const hasGrossInput = Object.prototype.hasOwnProperty.call(parsed, 'unitPriceGross')\n const hasTaxRateInput = Object.prototype.hasOwnProperty.call(parsed, 'taxRate')\n const hasTaxRateIdInput = Object.prototype.hasOwnProperty.call(parsed, 'taxRateId')\n let taxCalculationResult: Awaited<ReturnType<TaxCalculationService['calculateUnitAmounts']>> | null = null\n let calculationBase = amountInput\n if (!calculationBase && (hasTaxRateInput || hasTaxRateIdInput)) {\n calculationBase = resolveAmountInputFromRecord(record)\n }\n if (calculationBase) {\n const taxRateIdForCalculation = hasTaxRateIdInput ? parsed.taxRateId ?? null : undefined\n const taxRateForCalculation = hasTaxRateInput\n ? parsed.taxRate ?? null\n : taxRateIdForCalculation === null\n ? null\n : record.taxRate ?? null\n taxCalculationResult = await taxCalculationService.calculateUnitAmounts({\n amount: calculationBase.amount,\n mode: calculationBase.mode,\n organizationId: targetProduct.organizationId,\n tenantId: targetProduct.tenantId,\n taxRateId: taxRateIdForCalculation,\n taxRate: taxRateForCalculation,\n })\n }\n\n record.variant = targetVariant\n record.product = targetProduct\n record.offer = targetOffer\n record.organizationId = targetProduct.organizationId\n record.tenantId = targetProduct.tenantId\n record.priceKind = targetPriceKind\n record.kind = targetPriceKind.code\n\n if (parsed.currencyCode !== undefined) record.currencyCode = parsed.currencyCode\n if (parsed.minQuantity !== undefined) record.minQuantity = parsed.minQuantity ?? 1\n if (parsed.maxQuantity !== undefined) record.maxQuantity = parsed.maxQuantity ?? null\n if (taxCalculationResult) {\n record.unitPriceNet = toNumericString(taxCalculationResult.netAmount)\n record.unitPriceGross = toNumericString(taxCalculationResult.grossAmount)\n record.taxRate = toNumericString(taxCalculationResult.taxRate)\n record.taxAmount = toNumericString(taxCalculationResult.taxAmount)\n } else {\n if (hasNetInput) {\n record.unitPriceNet = toNumericString(parsed.unitPriceNet)\n }\n if (hasGrossInput) {\n record.unitPriceGross = toNumericString(parsed.unitPriceGross)\n }\n if (hasTaxRateInput) {\n record.taxRate = toNumericString(parsed.taxRate)\n if (parsed.taxRate == null) {\n record.taxAmount = null\n }\n } else if (hasTaxRateIdInput && parsed.taxRateId === null) {\n record.taxRate = null\n record.taxAmount = null\n }\n }\n if (parsed.channelId !== undefined) {\n record.channelId = parsed.channelId ?? null\n } else if (parsed.offerId !== undefined && targetOffer) {\n record.channelId = targetOffer.channelId\n }\n if (parsed.userId !== undefined) record.userId = parsed.userId ?? null\n if (parsed.userGroupId !== undefined) record.userGroupId = parsed.userGroupId ?? null\n if (parsed.customerId !== undefined) record.customerId = parsed.customerId ?? null\n if (parsed.customerGroupId !== undefined) record.customerGroupId = parsed.customerGroupId ?? null\n if (parsed.metadata !== undefined) {\n record.metadata = parsed.metadata ? cloneJson(parsed.metadata) : null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'startsAt')) {\n record.startsAt = parsed.startsAt ?? null\n }\n if (Object.prototype.hasOwnProperty.call(parsed, 'endsAt')) {\n record.endsAt = parsed.endsAt ?? null\n }\n await em.flush()\n if (custom && Object.keys(custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n values: custom,\n })\n }\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: priceCrudEvents,\n })\n const historyAfter = priceHistoryInputFromRecord(record)\n if (hasPriceHistoryRelevantChange(historyBefore, historyAfter)) {\n await capturePriceHistoryEntry(em, historyAfter, 'update', {\n cache: resolveOmnibusCache(ctx.container),\n invalidatePrices: [historyBefore],\n previous: historyBefore,\n })\n }\n return { priceId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadPriceSnapshot(em, result.priceId)\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as PriceSnapshot | undefined\n const after = snapshots.after as PriceSnapshot | undefined\n if (!before || !after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.prices.update', 'Update product price'),\n resourceKind: 'catalog.price',\n resourceId: before.id,\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 PRICE_CHANGE_KEYS\n ),\n payload: {\n undo: {\n before,\n after,\n } satisfies PriceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PriceUndoPayload>(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(CatalogProductPrice, { id: before.id })\n if (!record) {\n const { variant, product, offer } = await resolveSnapshotAssociations(em, before)\n record = em.create(CatalogProductPrice, {\n id: before.id,\n variant,\n product,\n offer,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n currencyCode: before.currencyCode,\n priceKind: em.getReference(CatalogPriceKind, before.priceKindId),\n kind: before.priceKindCode || before.kind,\n minQuantity: before.minQuantity,\n maxQuantity: before.maxQuantity ?? null,\n unitPriceNet: before.unitPriceNet ?? null,\n unitPriceGross: before.unitPriceGross ?? null,\n taxRate: before.taxRate ?? null,\n taxAmount: before.taxAmount ?? null,\n channelId: before.channelId ?? null,\n userId: before.userId ?? null,\n userGroupId: before.userGroupId ?? null,\n customerId: before.customerId ?? null,\n customerGroupId: before.customerGroupId ?? null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n startsAt: before.startsAt ? new Date(before.startsAt) : null,\n endsAt: before.endsAt ? new Date(before.endsAt) : 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 applyPriceSnapshot(em, record, before)\n await em.flush()\n await capturePriceHistoryEntry(em, before, 'undo', {\n metadata: { undoneCommand: 'catalog.prices.update' },\n cache: resolveOmnibusCache(ctx.container),\n invalidatePrices: [after],\n previous: after,\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_price,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: resetValues,\n })\n }\n },\n}\n\nconst deletePriceCommand: CommandHandler<\n { body?: Record<string, unknown>; query?: Record<string, unknown> },\n { priceId: string }\n> = {\n id: 'catalog.prices.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Price id is required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPriceSnapshot(em, id, commandScopeWhere(ctx))\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, 'Price id is required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(em, CatalogProductPrice, { id, ...commandScopeWhere(ctx) })\n if (!record) throw new CrudHttpError(404, { error: 'Catalog price not found' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n const { product } = await resolvePriceRecordAssociations(em, record)\n\n const baseEm = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadPriceSnapshot(baseEm, id)\n\n const deletedPrice = snapshot ?? priceHistoryInputFromRecord(record)\n em.remove(record)\n await em.flush()\n await capturePriceHistoryEntry(em, deletedPrice, 'delete', { cache: resolveOmnibusCache(ctx.container) })\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: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: id,\n organizationId: snapshot.organizationId,\n tenantId: snapshot.tenantId,\n values: resetValues,\n })\n }\n }\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\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: priceCrudEvents,\n })\n return { priceId: id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as PriceSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('catalog.audit.prices.delete', 'Delete product price'),\n resourceKind: 'catalog.price',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies PriceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<PriceUndoPayload>(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(CatalogProductPrice, { id: before.id })\n if (!record) {\n const { variant, product, offer } = await resolveSnapshotAssociations(em, before)\n record = em.create(CatalogProductPrice, {\n id: before.id,\n variant,\n product,\n offer,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n currencyCode: before.currencyCode,\n priceKind: em.getReference(CatalogPriceKind, before.priceKindId),\n kind: before.priceKindCode || before.kind,\n minQuantity: before.minQuantity,\n maxQuantity: before.maxQuantity ?? null,\n unitPriceNet: before.unitPriceNet ?? null,\n unitPriceGross: before.unitPriceGross ?? null,\n taxRate: before.taxRate ?? null,\n taxAmount: before.taxAmount ?? null,\n channelId: before.channelId ?? null,\n userId: before.userId ?? null,\n userGroupId: before.userGroupId ?? null,\n customerId: before.customerId ?? null,\n customerGroupId: before.customerGroupId ?? null,\n metadata: before.metadata ? cloneJson(before.metadata) : null,\n startsAt: before.startsAt ? new Date(before.startsAt) : null,\n endsAt: before.endsAt ? new Date(before.endsAt) : 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 applyPriceSnapshot(em, record, before)\n await em.flush()\n await capturePriceHistoryEntry(em, before, 'undo', {\n metadata: { undoneCommand: 'catalog.prices.delete' },\n cache: resolveOmnibusCache(ctx.container),\n })\n if (before.custom && Object.keys(before.custom).length) {\n await setCustomFieldsIfAny({\n dataEngine: ctx.container.resolve('dataEngine'),\n entityId: E.catalog.catalog_product_price,\n recordId: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n values: before.custom,\n })\n }\n },\n}\n\nregisterCommand(createPriceCommand)\nregisterCommand(updatePriceCommand)\nregisterCommand(deletePriceCommand)\n\nasync function resolvePriceRecordAssociations(\n em: EntityManager,\n record: CatalogProductPrice,\n): Promise<{ product: CatalogProduct; variant: CatalogProductVariant | null }> {\n const scope = { tenantId: record.tenantId, organizationId: record.organizationId }\n const variant = record.variant\n ? (typeof record.variant === 'string'\n ? await requireVariant(em, record.variant, scope)\n : record.variant)\n : null\n if (record.product) {\n const product =\n typeof record.product === 'string'\n ? await requireProduct(em, record.product, scope)\n : record.product\n return { product, variant }\n }\n if (variant?.product) {\n const productRef = variant.product\n const product =\n typeof productRef === 'string'\n ? await requireProduct(em, productRef, scope)\n : productRef\n return { product, variant }\n }\n if (record.offer) {\n const offer =\n typeof record.offer === 'string'\n ? await requireOffer(em, record.offer, scope)\n : record.offer\n const productRef = offer?.product ?? null\n if (productRef) {\n const product =\n typeof productRef === 'string'\n ? await requireProduct(em, productRef, scope)\n : productRef\n return { product, variant }\n }\n }\n throw new CrudHttpError(400, { error: 'Catalog price is not linked to a product.' })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.10.1-develop.
|
|
3
|
+
"version": "0.10.1-develop.7782.1.91d78919ba",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -266,16 +266,16 @@
|
|
|
266
266
|
"zod": "^4.4.3"
|
|
267
267
|
},
|
|
268
268
|
"peerDependencies": {
|
|
269
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
270
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
271
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
269
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7782.1.91d78919ba",
|
|
270
|
+
"@open-mercato/shared": "0.10.1-develop.7782.1.91d78919ba",
|
|
271
|
+
"@open-mercato/ui": "0.10.1-develop.7782.1.91d78919ba",
|
|
272
272
|
"react": "^19.0.0",
|
|
273
273
|
"react-dom": "^19.0.0"
|
|
274
274
|
},
|
|
275
275
|
"devDependencies": {
|
|
276
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
277
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
278
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
276
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7782.1.91d78919ba",
|
|
277
|
+
"@open-mercato/shared": "0.10.1-develop.7782.1.91d78919ba",
|
|
278
|
+
"@open-mercato/ui": "0.10.1-develop.7782.1.91d78919ba",
|
|
279
279
|
"@testing-library/dom": "^10.4.1",
|
|
280
280
|
"@testing-library/jest-dom": "^7.0.1",
|
|
281
281
|
"@testing-library/react": "^16.3.3",
|
|
@@ -287,6 +287,24 @@ function resolveAmountInputFromParsed(
|
|
|
287
287
|
return null
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
function hasAmountChanged(incoming: unknown, current: string | null | undefined): incoming is number {
|
|
291
|
+
if (typeof incoming !== 'number' || !Number.isFinite(incoming)) return false
|
|
292
|
+
return numericStringToNumber(current) !== incoming
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function resolveAmountInputForUpdate(
|
|
296
|
+
parsed: Partial<Pick<PriceCreateInput, 'unitPriceNet' | 'unitPriceGross'>>,
|
|
297
|
+
record: CatalogProductPrice
|
|
298
|
+
): PriceAmountInput | null {
|
|
299
|
+
if (hasAmountChanged(parsed.unitPriceNet, record.unitPriceNet)) {
|
|
300
|
+
return { amount: parsed.unitPriceNet, mode: 'net' }
|
|
301
|
+
}
|
|
302
|
+
if (hasAmountChanged(parsed.unitPriceGross, record.unitPriceGross)) {
|
|
303
|
+
return { amount: parsed.unitPriceGross, mode: 'gross' }
|
|
304
|
+
}
|
|
305
|
+
return resolveAmountInputFromParsed(parsed)
|
|
306
|
+
}
|
|
307
|
+
|
|
290
308
|
function resolveAmountInputFromRecord(record: CatalogProductPrice): PriceAmountInput | null {
|
|
291
309
|
const net = numericStringToNumber(record.unitPriceNet)
|
|
292
310
|
if (net !== null) return { amount: net, mode: 'net' }
|
|
@@ -644,7 +662,7 @@ const updatePriceCommand: CommandHandler<PriceUpdateInput, { priceId: string }>
|
|
|
644
662
|
ensureSameTenant(targetPriceKind, targetProduct.tenantId)
|
|
645
663
|
|
|
646
664
|
const taxCalculationService = ctx.container.resolve<TaxCalculationService>('taxCalculationService')
|
|
647
|
-
const amountInput =
|
|
665
|
+
const amountInput = resolveAmountInputForUpdate(parsed, record)
|
|
648
666
|
const hasNetInput = Object.prototype.hasOwnProperty.call(parsed, 'unitPriceNet')
|
|
649
667
|
const hasGrossInput = Object.prototype.hasOwnProperty.call(parsed, 'unitPriceGross')
|
|
650
668
|
const hasTaxRateInput = Object.prototype.hasOwnProperty.call(parsed, 'taxRate')
|