@open-mercato/sync-akeneo 0.5.1-develop.2683.4878a05b8e → 0.5.1-develop.2694.732417c5ec
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -1
- package/build.mjs +4 -65
- package/dist/modules/sync_akeneo/lib/catalog-importer.js +2 -2
- package/dist/modules/sync_akeneo/lib/catalog-importer.js.map +2 -2
- package/dist/modules/sync_akeneo/lib/preset.js +1 -1
- package/dist/modules/sync_akeneo/lib/preset.js.map +2 -2
- package/jest.config.cjs +4 -2
- package/package.json +6 -6
- package/src/modules/sync_akeneo/lib/catalog-importer.ts +2 -2
- package/src/modules/sync_akeneo/lib/preset.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
sync-akeneo
|
|
1
|
+
[build:sync-akeneo] found 29 entry points
|
|
2
|
+
[build:sync-akeneo] built successfully
|
package/build.mjs
CHANGED
|
@@ -1,68 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { glob } from 'glob'
|
|
3
|
-
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
4
|
-
import { dirname, join } from 'node:path'
|
|
1
|
+
import { dirname } from 'node:path'
|
|
5
2
|
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { buildPackage } from '../../scripts/build-package.mjs'
|
|
6
4
|
|
|
7
|
-
const
|
|
5
|
+
const packageDir = dirname(fileURLToPath(import.meta.url))
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
cwd: __dirname,
|
|
11
|
-
ignore: ['**/__tests__/**', '**/*.test.ts', '**/*.test.tsx'],
|
|
12
|
-
absolute: true,
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
if (entryPoints.length === 0) {
|
|
16
|
-
console.error('No entry points found!')
|
|
17
|
-
process.exit(1)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const addJsExtension = {
|
|
21
|
-
name: 'add-js-extension',
|
|
22
|
-
setup(build) {
|
|
23
|
-
build.onEnd(async (result) => {
|
|
24
|
-
if (result.errors.length > 0) return
|
|
25
|
-
const outputFiles = await glob('dist/**/*.js', { cwd: __dirname, absolute: true })
|
|
26
|
-
for (const file of outputFiles) {
|
|
27
|
-
const fileDir = dirname(file)
|
|
28
|
-
let content = readFileSync(file, 'utf-8')
|
|
29
|
-
content = content.replace(
|
|
30
|
-
/from\s+["'](\.[^"']+)["']/g,
|
|
31
|
-
(match, path) => {
|
|
32
|
-
if (path.endsWith('.js') || path.endsWith('.json')) return match
|
|
33
|
-
const resolvedPath = join(fileDir, path)
|
|
34
|
-
if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
|
|
35
|
-
return `from "${path}/index.js"`
|
|
36
|
-
}
|
|
37
|
-
return `from "${path}.js"`
|
|
38
|
-
},
|
|
39
|
-
)
|
|
40
|
-
content = content.replace(
|
|
41
|
-
/import\s*\(\s*["'](\.[^"']+)["']\s*\)/g,
|
|
42
|
-
(match, path) => {
|
|
43
|
-
if (path.endsWith('.js') || path.endsWith('.json')) return match
|
|
44
|
-
const resolvedPath = join(fileDir, path)
|
|
45
|
-
if (existsSync(resolvedPath) && existsSync(join(resolvedPath, 'index.js'))) {
|
|
46
|
-
return `import("${path}/index.js")`
|
|
47
|
-
}
|
|
48
|
-
return `import("${path}.js")`
|
|
49
|
-
},
|
|
50
|
-
)
|
|
51
|
-
writeFileSync(file, content)
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
},
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
await esbuild.build({
|
|
58
|
-
entryPoints,
|
|
59
|
-
outdir: 'dist',
|
|
60
|
-
format: 'esm',
|
|
61
|
-
platform: 'node',
|
|
62
|
-
target: 'node18',
|
|
63
|
-
sourcemap: true,
|
|
64
|
-
jsx: 'automatic',
|
|
65
|
-
plugins: [addJsExtension],
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
console.log('sync-akeneo built successfully')
|
|
7
|
+
await buildPackage(packageDir, { name: 'sync-akeneo' })
|
|
@@ -1782,7 +1782,7 @@ async function createAkeneoImporter(client, scope) {
|
|
|
1782
1782
|
const shouldDelete = kind === "image" ? params.reconciliation.deleteMissingMedia : params.reconciliation.deleteMissingAttachments;
|
|
1783
1783
|
if (!shouldDelete || desiredExternalIds.has(externalId)) continue;
|
|
1784
1784
|
await deletePartitionFile(attachment.partitionCode, attachment.storagePath, attachment.storageDriver);
|
|
1785
|
-
await em.
|
|
1785
|
+
await em.remove(attachment).flush();
|
|
1786
1786
|
await emitAttachmentCrudChange("deleted", attachment);
|
|
1787
1787
|
}
|
|
1788
1788
|
return {
|
|
@@ -1877,7 +1877,7 @@ async function createAkeneoImporter(client, scope) {
|
|
|
1877
1877
|
const childProductId = typeof relation.childProduct === "string" ? relation.childProduct : relation.childProduct?.id ?? null;
|
|
1878
1878
|
const key = `${relation.relationType}:${childVariantId ?? childProductId}`;
|
|
1879
1879
|
if (!desiredKeys.has(key)) {
|
|
1880
|
-
await em.
|
|
1880
|
+
await em.remove(relation).flush();
|
|
1881
1881
|
}
|
|
1882
1882
|
}
|
|
1883
1883
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/sync_akeneo/lib/catalog-importer.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { DataMapping } from '@open-mercato/core/modules/data_sync/lib/adapter'\nimport type { ExternalIdMappingService } from '@open-mercato/core/modules/data_sync/lib/id-mapping'\nimport { SyncExternalIdMapping } from '@open-mercato/core/modules/integrations/data/entities'\nimport {\n CatalogOffer,\n CatalogOptionSchemaTemplate,\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductPrice,\n CatalogProductVariant,\n CatalogProductVariantRelation,\n} from '@open-mercato/core/modules/catalog/data/entities'\nimport { ensureCustomFieldDefinitions } from '@open-mercato/core/modules/entities/lib/field-definitions'\nimport { CustomFieldDef, CustomFieldEntityConfig } from '@open-mercato/core/modules/entities/data/entities'\nimport { normalizeEntityFieldsetConfig, type CustomFieldsetDefinition } from '@open-mercato/core/modules/entities/lib/fieldsets'\nimport { invalidateDefinitionsCache } from '@open-mercato/core/modules/entities/api/definitions.cache'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport { buildAttachmentFileUrl, buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { deletePartitionFile, storePartitionFile } from '@open-mercato/core/modules/attachments/lib/storage'\nimport { ensureDefaultPartitions, resolveDefaultPartitionCode } from '@open-mercato/core/modules/attachments/lib/partitions'\nimport { mergeAttachmentMetadata } from '@open-mercato/core/modules/attachments/lib/metadata'\nimport { attachmentCrudEvents, attachmentCrudIndexer } from '@open-mercato/core/modules/attachments/lib/crud'\nimport { emitCatalogQueryIndexEvent } from '@open-mercato/core/modules/catalog/commands/shared'\nimport { SalesChannel } from '@open-mercato/core/modules/sales/data/entities'\nimport type { CustomFieldDefinition } from '@open-mercato/shared/modules/entities'\nimport {\n buildAkeneoFieldsetCode,\n buildProductFieldMappings,\n dedupeStrings,\n labelFromLocalizedRecord,\n safeRecord,\n slugifyAkeneoCode,\n type AkeneoAttribute,\n type AkeneoCategory,\n type AkeneoCustomFieldKind,\n type AkeneoDataMapping,\n type AkeneoFamily,\n type AkeneoFamilyVariant,\n type AkeneoFieldsetMapping,\n type AkeneoProduct,\n type AkeneoProductMappingSettings,\n type AkeneoReconciliationSettings,\n type AkeneoValues,\n buildDefaultAkeneoMapping,\n} from './shared'\nimport type { AkeneoClient } from './client'\nimport { inferAkeneoProductMapping } from './inference'\nimport { normalizeMarkdownText } from './markdown'\n\ntype ImportScope = {\n organizationId: string\n tenantId: string\n}\n\ntype UpsertResult = {\n localId: string\n action: 'create' | 'update' | 'skip'\n}\n\ntype CustomFieldSyncItem = {\n externalId: string\n action: 'create' | 'update' | 'skip'\n data: Record<string, unknown>\n}\n\ntype ResolvedHierarchy = {\n rootExternalId: string\n family: string | null\n familyVariantCode: string | null\n rootValues: AkeneoValues\n leafValues: AkeneoValues\n mergedValues: AkeneoValues\n categories: string[]\n parentChain: string[]\n associationSource: AkeneoProduct\n axisCodes: string[]\n}\n\ntype DesiredOffer = {\n externalId: string\n channelCode: string\n channelId: string\n akeneoChannel: string | null\n title: string\n description: string | null\n prices: DesiredPrice[]\n}\n\ntype DesiredPrice = {\n externalId: string\n priceKindCode: string\n priceKindId: string\n channelId: string\n currencyCode: string\n amount: number\n variantId: string\n}\n\ntype MediaReference = {\n codeOrUrl: string\n fileNameHint: string | null\n mimeTypeHint: string | null\n}\n\ntype DesiredAsset = {\n externalId: string\n entityId: string\n recordId: string\n kind: 'image' | 'file'\n remote: MediaReference\n}\n\ntype AkeneoFieldsetPlan = {\n product: CustomFieldsetDefinition | null\n variant: CustomFieldsetDefinition | null\n}\n\nconst PRODUCT_ENTITY_ID = 'catalog:catalog_product'\nconst VARIANT_ENTITY_ID = 'catalog:catalog_product_variant'\n\nexport function readPreferredAkeneoValue(\n values: AkeneoValues | undefined | null,\n attributeCode: string,\n locale: string,\n channel: string | null,\n): unknown {\n const entries = Array.isArray(values?.[attributeCode]) ? values?.[attributeCode] ?? [] : []\n if (entries.length === 0) return null\n\n const normalize = (value: string | null | undefined) => (typeof value === 'string' && value.trim().length > 0 ? value.trim() : null)\n const wantedLocale = normalize(locale)\n const wantedChannel = normalize(channel)\n\n const eligibleEntries = entries.filter((entry) => {\n const entryLocale = normalize(entry.locale)\n const entryChannel = normalize(entry.scope)\n const localeMatches = wantedLocale ? entryLocale === wantedLocale || entryLocale === null : true\n const channelMatches = wantedChannel ? entryChannel === wantedChannel || entryChannel === null : true\n return localeMatches && channelMatches\n })\n\n const scored = eligibleEntries\n .map((entry) => {\n const entryLocale = normalize(entry.locale)\n const entryChannel = normalize(entry.scope)\n let score = 0\n if (wantedLocale && entryLocale === wantedLocale) score += 4\n else if (!wantedLocale && !entryLocale) score += 2\n else if (!entryLocale) score += 1\n if (wantedChannel && entryChannel === wantedChannel) score += 4\n else if (!wantedChannel && !entryChannel) score += 2\n else if (!entryChannel) score += 1\n return { score, entry }\n })\n .sort((left, right) => right.score - left.score)\n\n return scored[0]?.entry?.data ?? null\n}\n\nexport function readLayeredAkeneoValue(\n layers: AkeneoValues[],\n attributeCode: string,\n locale: string,\n channel: string | null,\n): unknown {\n for (const layer of layers) {\n const value = readPreferredAkeneoValue(layer, attributeCode, locale, channel)\n if (value !== null && value !== undefined && !(typeof value === 'string' && value.trim().length === 0)) {\n return value\n }\n }\n return null\n}\n\nfunction coerceString(value: unknown): string | null {\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n if (typeof value === 'number' && Number.isFinite(value)) return String(value)\n return null\n}\n\nexport function normalizeAkeneoSelectValue(\n value: unknown,\n optionLabels: Map<string, string>,\n): string | null {\n if (Array.isArray(value)) {\n const labels = value\n .map((entry) => normalizeAkeneoSelectValue(entry, optionLabels))\n .filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n return labels.length > 0 ? labels.join(', ') : null\n }\n\n const raw = coerceString(value)\n if (!raw) return null\n return optionLabels.get(raw) ?? raw\n}\n\nexport function filterAkeneoAttributeMappingsByAvailableAttributes<T extends { attributeCode: string }>(\n mappings: T[],\n availableAttributeCodes: string[],\n): T[] {\n const allowed = new Set(\n availableAttributeCodes\n .map((code) => code.trim())\n .filter((code) => code.length > 0),\n )\n if (allowed.size === 0) return []\n return mappings.filter((mapping) => allowed.has(mapping.attributeCode))\n}\n\ntype ExistingFieldsetDefinition = {\n key: string\n description: string | null\n fieldset: string | null\n fieldsets: string[]\n}\n\ntype DesiredFieldsetAssignment = {\n key: string\n fieldsets: string[]\n}\n\ntype EntityFieldsetAssignments = {\n fieldsets: CustomFieldsetDefinition[]\n fieldsetsByKey: Map<string, string[]>\n}\n\ntype ResolvedGlobalFieldsetAssignments = {\n product: EntityFieldsetAssignments\n variant: EntityFieldsetAssignments\n}\n\ntype AkeneoOptionSchemaMetadata = {\n familyCode: string | null\n familyVariantCode: string | null\n attributeCodes: string[]\n richAttributes: Record<string, Record<string, unknown>>\n}\n\nexport function resolveAkeneoFieldKeysToDetach(\n definitions: ExistingFieldsetDefinition[],\n desiredFieldKeys: string[],\n fieldsetCode: string | null,\n): string[] {\n if (!fieldsetCode) return []\n const desired = new Set(\n desiredFieldKeys\n .map((key) => normalizeFieldKey(key))\n .filter((key) => key.length > 0),\n )\n\n return definitions\n .filter((definition) => definition.fieldset === fieldsetCode || definition.fieldsets.includes(fieldsetCode))\n .filter((definition) => typeof definition.description === 'string' && definition.description.startsWith('Akeneo attribute '))\n .filter((definition) => !desired.has(normalizeFieldKey(definition.key)))\n .map((definition) => definition.key)\n}\n\nexport function resolveAkeneoFieldsetMemberships(\n currentFieldsets: string[],\n fieldsetCode: string | null,\n): string[] {\n return dedupeStrings([\n ...currentFieldsets\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n ...(fieldsetCode ? [fieldsetCode] : []),\n ])\n}\n\nfunction readConfiguredFieldsets(config: Record<string, unknown> | null | undefined): string[] {\n const configured = Array.isArray(config?.fieldsets)\n ? config.fieldsets.filter((entry): entry is string => typeof entry === 'string')\n : []\n const normalized = dedupeStrings(\n configured\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n )\n if (normalized.length > 0) return normalized\n const legacy = typeof config?.fieldset === 'string' ? config.fieldset.trim() : ''\n return legacy.length > 0 ? [legacy] : []\n}\n\nfunction clampString(value: string | null, maxLength: number): string | null {\n if (!value) return null\n return value.length > maxLength ? value.slice(0, maxLength).trim() : value\n}\n\nfunction coerceMetricAmount(value: unknown): number | null {\n const record = safeRecord(value)\n const amount = record?.amount\n if (typeof amount === 'string' && amount.trim().length > 0) {\n const numeric = Number(amount)\n return Number.isFinite(numeric) ? numeric : null\n }\n if (typeof amount === 'number' && Number.isFinite(amount)) return amount\n if (typeof value === 'number' && Number.isFinite(value)) return value\n return null\n}\n\nfunction coerceNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length > 0) {\n const numeric = Number(value)\n return Number.isFinite(numeric) ? numeric : null\n }\n return null\n}\n\nfunction coerceBoolean(value: unknown): boolean | null {\n if (typeof value === 'boolean') return value\n if (typeof value === 'string') {\n const lowered = value.trim().toLowerCase()\n if (lowered === 'true' || lowered === '1' || lowered === 'yes') return true\n if (lowered === 'false' || lowered === '0' || lowered === 'no') return false\n }\n return null\n}\n\nfunction mergeValueLayers(...layers: Array<AkeneoValues | undefined | null>): AkeneoValues {\n const merged: AkeneoValues = {}\n for (const layer of layers) {\n if (!layer) continue\n for (const [key, value] of Object.entries(layer)) {\n merged[key] = Array.isArray(value) ? value : []\n }\n }\n return merged\n}\n\nfunction normalizeFieldKey(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 100)\n}\n\nfunction readAkeneoOptionSchemaMetadata(value: unknown): AkeneoOptionSchemaMetadata | null {\n const parsedValue = typeof value === 'string'\n ? (() => {\n try {\n return JSON.parse(value) as unknown\n } catch {\n return null\n }\n })()\n : value\n const metadata = safeRecord(parsedValue)\n if (!metadata) return null\n\n const familyCode = typeof metadata.familyCode === 'string' && metadata.familyCode.trim().length > 0\n ? metadata.familyCode.trim()\n : null\n const familyVariantCode = typeof metadata.familyVariantCode === 'string' && metadata.familyVariantCode.trim().length > 0\n ? metadata.familyVariantCode.trim()\n : null\n const attributeCodes = Array.isArray(metadata.attributeCodes)\n ? dedupeStrings(metadata.attributeCodes.filter((entry): entry is string => typeof entry === 'string'))\n : []\n const richAttributes = safeRecord(metadata.richAttributes) ?? {}\n\n if (!familyCode && !familyVariantCode) return null\n if (attributeCodes.length === 0) return null\n\n return {\n familyCode,\n familyVariantCode,\n attributeCodes,\n richAttributes: Object.fromEntries(\n Object.entries(richAttributes)\n .filter(([, entry]) => Boolean(safeRecord(entry))),\n ) as Record<string, Record<string, unknown>>,\n }\n}\n\nfunction mapAkeneoAttributeInputType(attributeType: string): 'select' | 'text' | 'textarea' | 'number' | null {\n if (attributeType === 'pim_catalog_simpleselect' || attributeType === 'akeneo_reference_entity' || attributeType === 'akeneo_reference_entity_collection') {\n return 'select'\n }\n if (attributeType === 'pim_catalog_multiselect') return 'select'\n if (attributeType === 'pim_catalog_text') return 'text'\n if (attributeType === 'pim_catalog_textarea') return 'textarea'\n if (\n attributeType === 'pim_catalog_number'\n || attributeType === 'pim_catalog_metric'\n || attributeType === 'pim_catalog_price_collection'\n ) {\n return 'number'\n }\n return null\n}\n\nfunction mapAkeneoAttributeToCustomFieldKind(attribute: AkeneoAttribute, preferredKind?: AkeneoCustomFieldKind | null): AkeneoCustomFieldKind | null {\n if (preferredKind) return preferredKind\n if (attribute.type === 'pim_catalog_boolean') return 'boolean'\n if (attribute.type === 'pim_catalog_number') {\n return attribute.decimals_allowed === false ? 'integer' : 'float'\n }\n if (attribute.type === 'pim_catalog_metric') return 'float'\n if (\n attribute.type === 'pim_catalog_simpleselect'\n || attribute.type === 'pim_catalog_multiselect'\n || attribute.type === 'akeneo_reference_entity'\n || attribute.type === 'akeneo_reference_entity_collection'\n ) {\n return 'select'\n }\n if (attribute.type === 'pim_catalog_textarea') return 'multiline'\n if (attribute.type === 'pim_catalog_text') return 'text'\n if (attribute.type === 'pim_catalog_date') return 'text'\n return null\n}\n\nfunction buildValidationRules(attribute: AkeneoAttribute): Array<{ rule: string; param?: unknown }> {\n const rules: Array<{ rule: string; param?: unknown }> = []\n if (attribute.is_required_for_completeness) rules.push({ rule: 'required' })\n if (typeof attribute.max_characters === 'number' && Number.isFinite(attribute.max_characters)) {\n rules.push({ rule: 'maxLength', param: attribute.max_characters })\n }\n if (attribute.validation_rule === 'regexp' && typeof attribute.validation_regexp === 'string' && attribute.validation_regexp.trim().length > 0) {\n rules.push({ rule: 'pattern', param: attribute.validation_regexp.trim() })\n }\n const minimumValue = coerceNumber(attribute.minimum_value)\n if (minimumValue !== null) rules.push({ rule: 'min', param: minimumValue })\n const maximumValue = coerceNumber(attribute.maximum_value)\n if (maximumValue !== null) rules.push({ rule: 'max', param: maximumValue })\n return rules\n}\n\nfunction buildAttributeMetadata(attribute: AkeneoAttribute, locale: string): Record<string, unknown> {\n return {\n provider: 'akeneo',\n attributeCode: attribute.code,\n type: attribute.type,\n label: labelFromLocalizedRecord(attribute.labels ?? null, locale, attribute.code),\n groupCode: attribute.group ?? null,\n groupLabel: attribute.group_labels ? labelFromLocalizedRecord(attribute.group_labels, locale, attribute.group ?? 'Akeneo') : null,\n localizable: Boolean(attribute.localizable),\n scopable: Boolean(attribute.scopable),\n isRequiredForCompleteness: Boolean(attribute.is_required_for_completeness),\n unique: Boolean(attribute.unique),\n useableAsGridFilter: Boolean(attribute.useable_as_grid_filter),\n validationRule: attribute.validation_rule ?? null,\n validationRegexp: attribute.validation_regexp ?? null,\n decimalsAllowed: attribute.decimals_allowed ?? null,\n negativeAllowed: attribute.negative_allowed ?? null,\n minimumValue: attribute.minimum_value ?? null,\n maximumValue: attribute.maximum_value ?? null,\n metricFamily: attribute.metric_family ?? null,\n defaultMetricUnit: attribute.default_metric_unit ?? null,\n referenceDataName: attribute.reference_data_name ?? null,\n }\n}\n\nfunction familyRequiresAttribute(family: AkeneoFamily, attributeCode: string): boolean {\n const requirements = family.attribute_requirements\n if (!requirements || typeof requirements !== 'object') return false\n return Object.values(requirements).some((codes) => Array.isArray(codes) && codes.includes(attributeCode))\n}\n\nfunction parsePriceCollection(value: unknown): Array<{ currencyCode: string; amount: number }> {\n if (!Array.isArray(value)) return []\n return value\n .map((entry) => {\n const record = safeRecord(entry)\n const currencyCode = typeof record?.currency === 'string' ? record.currency.trim().toUpperCase() : ''\n const amount = coerceNumber(record?.amount)\n if (!currencyCode || amount === null) return null\n return { currencyCode, amount }\n })\n .filter((entry): entry is { currencyCode: string; amount: number } => Boolean(entry))\n}\n\nfunction collectMediaReferences(value: unknown): MediaReference[] {\n const values = Array.isArray(value) ? value : value === null || value === undefined ? [] : [value]\n return values\n .map((entry) => {\n if (typeof entry === 'string' && entry.trim().length > 0) {\n return {\n codeOrUrl: entry.trim(),\n fileNameHint: null,\n mimeTypeHint: null,\n }\n }\n const record = safeRecord(entry)\n if (!record) return null\n const linkRecord = safeRecord(record._links)\n const downloadRecord = safeRecord(linkRecord?.download)\n const codeOrUrl = coerceString(record.code)\n ?? coerceString(record.download_link)\n ?? coerceString(record.href)\n ?? coerceString(downloadRecord?.href)\n if (!codeOrUrl) return null\n return {\n codeOrUrl,\n fileNameHint: coerceString(record.original_filename) ?? coerceString(record.file_path),\n mimeTypeHint: coerceString(record.mime_type),\n }\n })\n .filter((entry): entry is MediaReference => Boolean(entry))\n}\n\nexport function resolveAkeneoMediaTarget(params: {\n mappingTarget: 'product' | 'variant'\n attributeCode: string\n variantAttributeCodes: string[]\n productScopedValue: unknown\n variantScopedValue: unknown\n}): 'product' | 'variant' {\n const hasProductValue = params.productScopedValue !== null && params.productScopedValue !== undefined\n const hasVariantValue = params.variantScopedValue !== null && params.variantScopedValue !== undefined\n\n if (params.variantAttributeCodes.includes(params.attributeCode)) {\n return 'variant'\n }\n if (hasProductValue) {\n return 'product'\n }\n if (hasVariantValue) {\n return 'variant'\n }\n return params.mappingTarget\n}\n\nfunction resolveCustomFieldValue(value: unknown, attribute: AkeneoAttribute, kind: AkeneoCustomFieldKind): unknown {\n if (kind === 'boolean') return coerceBoolean(value)\n if (kind === 'integer') return coerceNumber(value) === null ? null : Math.trunc(Number(value))\n if (kind === 'float') return attribute.type === 'pim_catalog_metric' ? coerceMetricAmount(value) : coerceNumber(value)\n if (kind === 'multiline') return normalizeMarkdownText(coerceString(value))\n if (kind === 'text') {\n if (typeof value === 'string') return normalizeMarkdownText(value)\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return value ? JSON.stringify(value) : null\n }\n if (kind === 'select') {\n if (Array.isArray(value)) {\n const items = value.map((entry) => coerceString(entry)).filter((entry): entry is string => Boolean(entry))\n return items.length > 0 ? items : null\n }\n return coerceString(value)\n }\n return null\n}\n\nfunction relationTypeFromAssociation(associationType: string): 'bundle' | 'grouped' {\n const normalized = associationType.trim().toLowerCase()\n return normalized.includes('pack') || normalized.includes('bundle') ? 'bundle' : 'grouped'\n}\n\nfunction titleizeCode(value: string): string {\n return value\n .trim()\n .replace(/[_-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .replace(/\\b\\w/g, (char) => char.toUpperCase())\n}\n\nfunction findFieldsetMapping(\n mappings: AkeneoFieldsetMapping[],\n target: 'product' | 'variant',\n sourceType: 'family' | 'familyVariant',\n sourceCode: string | null,\n): AkeneoFieldsetMapping | null {\n if (!sourceCode) return null\n return mappings.find((entry) => (\n entry.target === target\n && entry.sourceType === sourceType\n && entry.sourceCode === sourceCode\n )) ?? null\n}\n\nfunction applyFieldsetOverride(\n fallback: CustomFieldsetDefinition | null,\n override: AkeneoFieldsetMapping | null,\n): CustomFieldsetDefinition | null {\n if (!fallback || !override) return fallback\n return {\n ...fallback,\n code: override.fieldsetCode,\n label: override.fieldsetLabel,\n description: override.description ?? fallback.description,\n }\n}\n\nfunction collectFieldsetGroups(attributes: AkeneoAttribute[], locale: string): NonNullable<CustomFieldsetDefinition['groups']> | undefined {\n const groups = dedupeStrings(attributes.map((attribute) => attribute.group))\n .map((groupCode) => {\n const attribute = attributes.find((entry) => entry.group === groupCode)\n return {\n code: normalizeFieldKey(groupCode),\n title: attribute?.group_labels\n ? labelFromLocalizedRecord(attribute.group_labels, locale, groupCode)\n : titleizeCode(groupCode),\n }\n })\n .filter((group) => group.code.length > 0)\n return groups.length > 0 ? groups : undefined\n}\n\nfunction collectFieldsetGroupsFromSchemaMetadata(\n metadata: AkeneoOptionSchemaMetadata,\n): NonNullable<CustomFieldsetDefinition['groups']> | undefined {\n const groups = new Map<string, { code: string; title: string }>()\n for (const attributeCode of metadata.attributeCodes) {\n const attribute = safeRecord(metadata.richAttributes[attributeCode])\n const groupCode = typeof attribute?.groupCode === 'string' && attribute.groupCode.trim().length > 0\n ? attribute.groupCode.trim()\n : null\n if (!groupCode) continue\n const normalizedCode = normalizeFieldKey(groupCode)\n if (!normalizedCode || groups.has(normalizedCode)) continue\n const title = typeof attribute?.groupLabel === 'string' && attribute.groupLabel.trim().length > 0\n ? attribute.groupLabel.trim()\n : titleizeCode(groupCode)\n groups.set(normalizedCode, { code: normalizedCode, title })\n }\n return groups.size > 0 ? Array.from(groups.values()) : undefined\n}\n\nfunction buildFieldsetPlanFromOptionSchema(params: {\n schema: Pick<CatalogOptionSchemaTemplate, 'code' | 'name' | 'description'>\n metadata: AkeneoOptionSchemaMetadata\n locale: string\n fieldsetMappings: AkeneoFieldsetMapping[]\n}): { target: 'product' | 'variant'; fieldset: CustomFieldsetDefinition | null } {\n const target = params.metadata.familyVariantCode ? 'variant' : 'product'\n const sourceType = params.metadata.familyVariantCode ? 'familyVariant' : 'family'\n const sourceCode = params.metadata.familyVariantCode ?? params.metadata.familyCode\n const fallbackCode = buildAkeneoFieldsetCode(target, sourceCode)\n const override = findFieldsetMapping(params.fieldsetMappings, target, sourceType, sourceCode)\n const fallbackLabel = params.schema.name?.trim().length\n ? params.schema.name.trim()\n : titleizeCode(sourceCode ?? `Akeneo ${target}`)\n const fallbackDescription = params.schema.description?.trim().length\n ? params.schema.description.trim()\n : sourceType === 'familyVariant' && params.metadata.familyVariantCode\n ? `Akeneo family variant ${params.metadata.familyVariantCode}`\n : params.metadata.familyCode\n ? `Akeneo family ${params.metadata.familyCode}`\n : `Akeneo ${target} attributes`\n const fieldsetCode = override?.fieldsetCode ?? fallbackCode\n if (!fieldsetCode) {\n return { target, fieldset: null }\n }\n\n return {\n target,\n fieldset: {\n code: fieldsetCode,\n label: override?.fieldsetLabel ?? fallbackLabel,\n description: override?.description ?? fallbackDescription,\n groups: collectFieldsetGroupsFromSchemaMetadata(params.metadata),\n },\n }\n}\n\nfunction buildFieldsetPlan(params: {\n family: AkeneoFamily | null\n familyVariant: AkeneoFamilyVariant | null\n productAttributes: AkeneoAttribute[]\n variantAttributes: AkeneoAttribute[]\n locale: string\n fieldsetMappings: AkeneoFieldsetMapping[]\n}): AkeneoFieldsetPlan {\n const productFallbackCode = buildAkeneoFieldsetCode('product', params.family?.code ?? null)\n const variantFallbackCode = buildAkeneoFieldsetCode('variant', params.familyVariant?.code ?? params.family?.code ?? null)\n\n const productFallback = productFallbackCode && params.productAttributes.length > 0\n ? {\n code: productFallbackCode,\n label: labelFromLocalizedRecord(params.family?.labels ?? null, params.locale, params.family?.code ?? 'Akeneo product'),\n description: params.family\n ? `Akeneo family ${params.family.code}`\n : 'Akeneo-imported product attributes',\n groups: collectFieldsetGroups(params.productAttributes, params.locale),\n }\n : null\n const variantFallback = variantFallbackCode && params.variantAttributes.length > 0\n ? {\n code: variantFallbackCode,\n label: labelFromLocalizedRecord(\n params.familyVariant?.labels ?? params.family?.labels ?? null,\n params.locale,\n params.familyVariant?.code ?? params.family?.code ?? 'Akeneo variant',\n ),\n description: params.familyVariant?.code\n ? `Akeneo family variant ${params.familyVariant.code}`\n : params.family?.code\n ? `Akeneo variant attributes for family ${params.family.code}`\n : 'Akeneo-imported variant attributes',\n groups: collectFieldsetGroups(params.variantAttributes, params.locale),\n }\n : null\n\n return {\n product: applyFieldsetOverride(\n productFallback,\n findFieldsetMapping(params.fieldsetMappings, 'product', 'family', params.family?.code ?? null),\n ),\n variant: applyFieldsetOverride(\n variantFallback,\n findFieldsetMapping(params.fieldsetMappings, 'variant', 'familyVariant', params.familyVariant?.code ?? null)\n ?? findFieldsetMapping(params.fieldsetMappings, 'variant', 'family', params.family?.code ?? null),\n ),\n }\n}\n\nfunction dedupeCustomFieldMappings(items: Array<{ attributeCode: string; fieldKey: string; target: 'product' | 'variant'; kind?: AkeneoCustomFieldKind | null; skip?: boolean }>) {\n const seen = new Set<string>()\n return items.filter((item) => {\n const key = `${item.target}:${item.attributeCode}:${item.fieldKey}:${item.skip === true ? 'skip' : 'import'}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nfunction dedupeMediaMappings(items: Array<{ attributeCode: string; target: 'product' | 'variant'; kind: 'image' | 'file' }>) {\n const seen = new Set<string>()\n return items.filter((item) => {\n const key = `${item.target}:${item.kind}:${item.attributeCode}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nfunction collectValueScopes(layers: AkeneoValues[], attributeCode: string): Array<string | null> {\n const seen = new Set<string>()\n const scopes: Array<string | null> = []\n for (const layer of layers) {\n const entries = Array.isArray(layer?.[attributeCode]) ? layer[attributeCode] : []\n for (const entry of entries) {\n const scope = coerceString(entry?.scope)\n const key = scope ?? '__null__'\n if (seen.has(key)) continue\n seen.add(key)\n scopes.push(scope)\n }\n }\n return scopes\n}\n\nfunction resolveImportedAkeneoChannels(settings: AkeneoProductMappingSettings): string[] {\n return dedupeStrings([\n ...(settings.channels ?? []),\n settings.channel,\n ])\n}\n\nfunction shouldImportAkeneoChannel(settings: AkeneoProductMappingSettings, akeneoChannel: string | null): boolean {\n if (!akeneoChannel) return true\n if (settings.importAllChannels) return true\n const selectedChannels = resolveImportedAkeneoChannels(settings)\n if (selectedChannels.length === 0) return true\n return selectedChannels.includes(akeneoChannel)\n}\n\nexport async function createAkeneoImporter(client: AkeneoClient, scope: ImportScope) {\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const commandBus = container.resolve('commandBus') as CommandBus\n const dataEngine = container.resolve('dataEngine') as DataEngine\n const externalIdMappingService = container.resolve('externalIdMappingService') as ExternalIdMappingService\n let cacheService: { deleteByTags?: (tags: string[]) => Promise<void> } | null = null\n try {\n cacheService = container.resolve('cache') as { deleteByTags?: (tags: string[]) => Promise<void> }\n } catch {\n cacheService = null\n }\n const categoryCache = new Map<string, Promise<string | null>>()\n const optionSchemaCache = new Map<string, Promise<UpsertResult | null>>()\n const channelCache = new Map<string, Promise<{ id: string; code: string } | null>>()\n const priceKindCache = new Map<string, Promise<{ id: string; code: string; displayMode: string } | null>>()\n const customFieldSyncCache = new Map<string, Promise<CustomFieldSyncItem[]>>()\n const globalFieldsetAssignmentCache = new Map<string, Promise<ResolvedGlobalFieldsetAssignments>>()\n const preferredChannelCodeCache = new Map<string, Promise<string | null>>()\n const preferredPriceKindCodeCache = new Map<string, Promise<string | null>>()\n const attributeOptionLabelCache = new Map<string, Promise<Map<string, string>>>()\n const defaultProductSettings = buildDefaultAkeneoMapping('products').settings?.products\n\n function buildCommandContext(): CommandRuntimeContext {\n return {\n container,\n auth: null,\n organizationScope: {\n selectedId: scope.organizationId,\n filterIds: [scope.organizationId],\n allowedIds: [scope.organizationId],\n tenantId: scope.tenantId,\n },\n selectedOrganizationId: scope.organizationId,\n organizationIds: [scope.organizationId],\n }\n }\n\n async function emitAttachmentCrudChange(\n action: 'created' | 'updated' | 'deleted',\n attachment: Attachment,\n ): Promise<void> {\n await emitCrudSideEffects({\n dataEngine,\n action,\n entity: attachment,\n identifiers: {\n id: attachment.id,\n organizationId: attachment.organizationId ?? null,\n tenantId: attachment.tenantId ?? null,\n },\n events: attachmentCrudEvents,\n indexer: attachmentCrudIndexer,\n })\n await dataEngine.flushOrmEntityChanges()\n }\n\n async function executeCommand<TResult>(commandId: string, input: Record<string, unknown>): Promise<TResult> {\n try {\n const executed = await commandBus.execute<Record<string, unknown>, TResult>(commandId, {\n input,\n ctx: buildCommandContext(),\n })\n return executed.result\n } catch (error) {\n const message = error instanceof Error ? error.message : JSON.stringify(error)\n throw new Error(`${commandId} failed: ${message}`)\n }\n }\n\n async function lookupProductBySku(sku: string | null): Promise<string | null> {\n if (!sku) return null\n const product = await findOneWithDecryption(\n em,\n CatalogProduct,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n sku,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n return product?.id ?? null\n }\n\n async function lookupVariantBySku(sku: string | null, productId?: string | null): Promise<string | null> {\n if (!sku) return null\n const variant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n ...(productId ? { product: productId } : {}),\n sku,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n return variant?.id ?? null\n }\n\n async function resolveExistingProductId(productExternalId: string, sku: string | null): Promise<string | null> {\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product', productExternalId, scope)\n if (mappedId) {\n const mappedProduct = await findOneWithDecryption(\n em,\n CatalogProduct,\n {\n id: mappedId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (mappedProduct) return mappedProduct.id\n }\n\n return lookupProductBySku(sku)\n }\n\n async function resolveExistingVariantId(\n variantExternalId: string,\n sku: string | null,\n productId: string,\n ): Promise<string | null> {\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_variant', variantExternalId, scope)\n if (mappedId) {\n const mappedVariant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n {\n id: mappedId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product: productId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (mappedVariant) return mappedVariant.id\n }\n\n return lookupVariantBySku(sku, productId)\n }\n\n async function resolveCategoryId(code: string | null | undefined, locale: string): Promise<string | null> {\n if (!code) return null\n if (!categoryCache.has(code)) {\n categoryCache.set(code, (async () => {\n const mapped = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_category', code, scope)\n if (mapped) return mapped\n\n const existing = await findOneWithDecryption(\n em,\n CatalogProductCategory,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n slug: slugifyAkeneoCode(code),\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (existing) {\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_category', existing.id, code, scope)\n return existing.id\n }\n\n const remote = await client.getCategory(code)\n if (!remote) return null\n const result = await upsertCategory(remote, locale)\n return result.localId\n })())\n }\n return categoryCache.get(code) ?? null\n }\n\n async function resolveChannel(code: string, options?: { createIfMissing?: boolean; label?: string | null }): Promise<{ id: string; code: string } | null> {\n const normalizedCode = code.trim().toLowerCase()\n if (!normalizedCode) return null\n const cacheKey = `${normalizedCode}:${options?.createIfMissing ? 'create' : 'read'}:${options?.label ?? ''}`\n if (!channelCache.has(cacheKey)) {\n channelCache.set(cacheKey, (async () => {\n const channel = await findOneWithDecryption(em, SalesChannel, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: normalizedCode,\n deletedAt: null,\n isActive: true,\n }, undefined, scope)\n if (channel) {\n return { id: channel.id, code: channel.code ?? normalizedCode }\n }\n if (!options?.createIfMissing) return null\n\n const created = await executeCommand<{ channelId: string }>('sales.channels.create', {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: options.label?.trim() || titleizeCode(normalizedCode),\n code: normalizedCode,\n metadata: {\n source: 'akeneo',\n autoCreatedBy: 'sync_akeneo',\n },\n isActive: true,\n })\n return {\n id: created.channelId,\n code: normalizedCode,\n }\n })())\n }\n return channelCache.get(cacheKey) ?? null\n }\n\n async function resolvePriceKind(code: string): Promise<{ id: string; code: string; displayMode: string } | null> {\n const normalizedCode = code.trim().toLowerCase()\n if (!normalizedCode) return null\n if (!priceKindCache.has(normalizedCode)) {\n priceKindCache.set(normalizedCode, (async () => {\n const priceKind = await findOneWithDecryption(\n em,\n CatalogPriceKind,\n {\n tenantId: scope.tenantId,\n code: normalizedCode,\n deletedAt: null,\n isActive: true,\n },\n undefined,\n scope,\n )\n return priceKind ? { id: priceKind.id, code: priceKind.code, displayMode: priceKind.displayMode } : null\n })())\n }\n return priceKindCache.get(normalizedCode) ?? null\n }\n\n async function resolvePreferredLocalChannelCode(): Promise<string | null> {\n const cacheKey = 'preferred'\n if (!preferredChannelCodeCache.has(cacheKey)) {\n preferredChannelCodeCache.set(cacheKey, (async () => {\n const channels = await findWithDecryption(em, SalesChannel, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n orderBy: { createdAt: 'asc' },\n }, scope)\n const preferredCodes = ['web', 'online', 'ecommerce', 'default']\n for (const preferredCode of preferredCodes) {\n const match = channels.find((channel) => (channel.code ?? '').trim().toLowerCase() === preferredCode)\n if (match?.code) return match.code\n }\n return channels.find((channel) => typeof channel.code === 'string' && channel.code.trim().length > 0)?.code ?? null\n })())\n }\n return preferredChannelCodeCache.get(cacheKey) ?? null\n }\n\n async function resolvePreferredPriceKindCode(): Promise<string | null> {\n const cacheKey = 'preferred'\n if (!preferredPriceKindCodeCache.has(cacheKey)) {\n preferredPriceKindCodeCache.set(cacheKey, (async () => {\n const priceKinds = await findWithDecryption(em, CatalogPriceKind, {\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n orderBy: { createdAt: 'asc' },\n }, scope)\n const preferredCodes = ['regular', 'sale', 'base', 'default']\n for (const preferredCode of preferredCodes) {\n const match = priceKinds.find((priceKind) => priceKind.code.trim().toLowerCase() === preferredCode)\n if (match) return match.code\n }\n return priceKinds[0]?.code ?? null\n })())\n }\n return preferredPriceKindCodeCache.get(cacheKey) ?? null\n }\n\n async function ensureEntityFieldsetConfig(entityId: string, fieldset: CustomFieldsetDefinition | null): Promise<void> {\n if (!fieldset) return\n let config = await findOneWithDecryption(em, CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!config) {\n config = em.create(CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n }\n\n const existing = normalizeEntityFieldsetConfig(config.configJson ?? {})\n const remaining = existing.fieldsets.filter((entry) => entry.code !== fieldset.code)\n config.configJson = {\n fieldsets: [...remaining, fieldset],\n singleFieldsetPerRecord: true,\n }\n config.isActive = true\n config.deletedAt = null\n config.updatedAt = new Date()\n em.persist(config)\n await em.flush()\n }\n\n async function upsertCategory(category: AkeneoCategory, locale: string): Promise<UpsertResult> {\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_category', category.code, scope)\n const existingId = mappedId\n ?? (await findOneWithDecryption(\n em,\n CatalogProductCategory,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n slug: slugifyAkeneoCode(category.code),\n deletedAt: null,\n },\n undefined,\n scope,\n ))?.id\n ?? null\n\n const parentId = category.parent ? await resolveCategoryId(category.parent, locale) : null\n const input = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: labelFromLocalizedRecord(category.labels ?? null, locale, category.code),\n slug: slugifyAkeneoCode(category.code),\n description: undefined,\n parentId,\n isActive: true,\n }\n\n if (existingId) {\n await executeCommand('catalog.categories.update', {\n id: existingId,\n ...input,\n })\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_category', existingId, category.code, scope)\n return { localId: existingId, action: 'update' }\n }\n\n const created = await executeCommand<{ categoryId: string }>('catalog.categories.create', input)\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_category', created.categoryId, category.code, scope)\n return { localId: created.categoryId, action: 'create' }\n }\n\n async function buildOptionSchemaDefinition(attribute: AkeneoAttribute, family: AkeneoFamily, locale: string) {\n const inputType = mapAkeneoAttributeInputType(attribute.type)\n if (!inputType) return null\n\n const definition: Record<string, unknown> = {\n code: slugifyAkeneoCode(attribute.code),\n label: labelFromLocalizedRecord(attribute.labels ?? null, locale, attribute.code),\n description: typeof attribute.group === 'string' ? `Akeneo group: ${attribute.group}` : undefined,\n inputType,\n isRequired: familyRequiresAttribute(family, attribute.code),\n }\n\n if (attribute.type === 'pim_catalog_multiselect') {\n definition.isMultiple = true\n }\n\n if (inputType === 'select' && (attribute.type === 'pim_catalog_simpleselect' || attribute.type === 'pim_catalog_multiselect')) {\n const options = await client.listAttributeOptions(attribute.code).catch(() => [])\n definition.choices = options.map((option) => ({\n code: slugifyAkeneoCode(option.code),\n label: labelFromLocalizedRecord(option.labels ?? null, locale, option.code),\n }))\n }\n\n return definition\n }\n\n async function getAttributeOptionLabels(attributeCode: string, locale: string): Promise<Map<string, string>> {\n const cacheKey = `${attributeCode}:${locale}`\n if (!attributeOptionLabelCache.has(cacheKey)) {\n attributeOptionLabelCache.set(cacheKey, (async () => {\n const options = await client.listAttributeOptions(attributeCode).catch(() => [])\n return new Map(\n options.map((option) => [\n option.code,\n labelFromLocalizedRecord(option.labels ?? null, locale, option.code),\n ]),\n )\n })())\n }\n return attributeOptionLabelCache.get(cacheKey) ?? new Map<string, string>()\n }\n\n async function ensureOptionSchemaForFamily(\n family: AkeneoFamily,\n familyVariant: AkeneoFamilyVariant | null,\n includeTextAttributes: boolean,\n includeNumericAttributes: boolean,\n locale: string,\n attributeCodesOverride?: string[] | null,\n ): Promise<UpsertResult | null> {\n const requestedAttributeCodes = Array.isArray(attributeCodesOverride)\n ? dedupeStrings(attributeCodesOverride)\n : null\n const cacheKey = `${family.code}:${familyVariant?.code ?? 'family'}:${locale}:${includeTextAttributes}:${includeNumericAttributes}:${requestedAttributeCodes ? requestedAttributeCodes.join('|') : 'all'}`\n if (!optionSchemaCache.has(cacheKey)) {\n optionSchemaCache.set(cacheKey, (async () => {\n if (requestedAttributeCodes && requestedAttributeCodes.length === 0) {\n return null\n }\n const externalId = familyVariant?.code ?? family.code\n const schemaCode = slugifyAkeneoCode(`akeneo-${externalId}`)\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_option_schema', externalId, scope)\n const existing = mappedId\n ? await findOneWithDecryption(em, CatalogOptionSchemaTemplate, { id: mappedId, deletedAt: null }, undefined, scope)\n : await findOneWithDecryption(\n em,\n CatalogOptionSchemaTemplate,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: schemaCode,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n const familyAttributes = Array.isArray(family.attributes) ? family.attributes : []\n const familyVariantAttributes = familyVariant?.variant_attribute_sets?.flatMap((set) => [\n ...(Array.isArray(set.attributes) ? set.attributes : []),\n ...(Array.isArray(set.axes) ? set.axes : []),\n ]) ?? []\n const attributeCodes = requestedAttributeCodes ?? dedupeStrings([...familyAttributes, ...familyVariantAttributes])\n const definitions: Record<string, unknown>[] = []\n const richAttributes: Record<string, unknown> = {}\n for (const code of attributeCodes) {\n const attribute = await client.getAttribute(code)\n if (!attribute) continue\n const inputType = mapAkeneoAttributeInputType(attribute.type)\n if (!inputType) continue\n if ((inputType === 'text' || inputType === 'textarea') && !includeTextAttributes) continue\n if (inputType === 'number' && !includeNumericAttributes) continue\n const definition = await buildOptionSchemaDefinition(attribute, family, locale)\n if (!definition) continue\n definitions.push(definition)\n richAttributes[code] = {\n ...buildAttributeMetadata(attribute, locale),\n validation: buildValidationRules(attribute),\n }\n if (definitions.length >= 64) break\n }\n\n const schemaInput = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: labelFromLocalizedRecord(family.labels ?? null, locale, family.code),\n code: schemaCode,\n description: familyVariant?.code ? `Akeneo family variant ${familyVariant.code}` : `Akeneo family ${family.code}`,\n schema: {\n version: 1,\n name: labelFromLocalizedRecord(family.labels ?? null, locale, family.code),\n description: familyVariant?.code ? `Akeneo family variant ${familyVariant.code}` : `Akeneo family ${family.code}`,\n options: definitions,\n },\n metadata: {\n source: 'akeneo',\n familyCode: family.code,\n familyVariantCode: familyVariant?.code ?? null,\n attributeCodes,\n richAttributes,\n attributeAsLabel: family.attribute_as_label ?? null,\n attributeAsImage: family.attribute_as_image ?? null,\n variantAxes: familyVariant?.variant_attribute_sets?.map((set) => ({\n level: set.level ?? null,\n axes: Array.isArray(set.axes) ? set.axes : [],\n attributes: Array.isArray(set.attributes) ? set.attributes : [],\n })) ?? [],\n },\n isActive: true,\n }\n\n if (existing) {\n await executeCommand('catalog.optionSchemas.update', {\n id: existing.id,\n ...schemaInput,\n })\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_option_schema', existing.id, externalId, scope)\n return { localId: existing.id, action: 'update' }\n }\n\n const created = await executeCommand<{ schemaId: string }>('catalog.optionSchemas.create', schemaInput)\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_option_schema', created.schemaId, externalId, scope)\n return { localId: created.schemaId, action: 'create' }\n })())\n }\n\n return optionSchemaCache.get(cacheKey) ?? null\n }\n\n async function syncMappedCustomFields(\n mapping: AkeneoDataMapping,\n locale: string,\n fieldsetPlan?: AkeneoFieldsetPlan | null,\n options?: { forceRefresh?: boolean },\n ): Promise<CustomFieldSyncItem[]> {\n const settings = mapping.settings?.products\n if (!settings || settings.customFieldMappings.length === 0) return []\n const cacheKey = JSON.stringify({\n customFieldMappings: settings.customFieldMappings.filter((mapping) => !mapping.skip),\n fieldsetPlan,\n locale,\n })\n if (options?.forceRefresh) {\n customFieldSyncCache.delete(cacheKey)\n globalFieldsetAssignmentCache.delete(JSON.stringify({\n customFieldMappings: settings.customFieldMappings.filter((entry) => !entry.skip),\n fieldsetMappings: settings.fieldsetMappings,\n }))\n }\n if (!customFieldSyncCache.has(cacheKey)) {\n customFieldSyncCache.set(cacheKey, (async () => {\n const productFields: Array<CustomFieldDefinition & { sourceMetadata?: Record<string, unknown> }> = []\n const variantFields: Array<CustomFieldDefinition & { sourceMetadata?: Record<string, unknown> }> = []\n const items: CustomFieldSyncItem[] = []\n const globalAssignments = await resolveGlobalFieldsetAssignments(settings)\n const existingDefinitions = await findWithDecryption(em, CustomFieldDef, {\n entityId: { $in: [PRODUCT_ENTITY_ID, VARIANT_ENTITY_ID] } as never,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n const existingFieldsetsByEntityAndKey = new Map<string, string[]>()\n for (const definition of existingDefinitions) {\n const config = safeRecord(definition.configJson)\n existingFieldsetsByEntityAndKey.set(\n `${definition.entityId}:${definition.key}`,\n readConfiguredFieldsets(config),\n )\n }\n\n for (const fieldMapping of settings.customFieldMappings) {\n if (fieldMapping.skip) continue\n const attribute = await client.getAttribute(fieldMapping.attributeCode)\n if (!attribute) continue\n const kind = mapAkeneoAttributeToCustomFieldKind(attribute, fieldMapping.kind)\n if (!kind) continue\n const entityId = fieldMapping.target === 'product' ? PRODUCT_ENTITY_ID : VARIANT_ENTITY_ID\n const normalizedKey = normalizeFieldKey(fieldMapping.fieldKey)\n const currentFieldsetCode = fieldMapping.target === 'product'\n ? fieldsetPlan?.product?.code ?? null\n : fieldsetPlan?.variant?.code ?? null\n const globalFieldsets = fieldMapping.target === 'product'\n ? globalAssignments.product.fieldsetsByKey.get(normalizedKey) ?? []\n : globalAssignments.variant.fieldsetsByKey.get(normalizedKey) ?? []\n const inheritedFieldsets = existingFieldsetsByEntityAndKey.get(`${entityId}:${normalizedKey}`) ?? []\n const effectiveFieldsets = dedupeStrings([\n ...globalFieldsets,\n ...inheritedFieldsets,\n ...(currentFieldsetCode ? [currentFieldsetCode] : []),\n ])\n const options = kind === 'select' && (attribute.type === 'pim_catalog_simpleselect' || attribute.type === 'pim_catalog_multiselect')\n ? await client.listAttributeOptions(attribute.code).catch(() => [])\n : []\n const field: CustomFieldDefinition & { sourceMetadata?: Record<string, unknown> } = {\n key: normalizedKey,\n kind,\n label: labelFromLocalizedRecord(attribute.labels ?? null, locale, fieldMapping.fieldKey),\n description: `Akeneo attribute ${fieldMapping.attributeCode}`,\n fieldset: effectiveFieldsets.length === 1 ? effectiveFieldsets[0] : undefined,\n fieldsets: effectiveFieldsets.length > 0 ? effectiveFieldsets : undefined,\n multi: attribute.type === 'pim_catalog_multiselect' || attribute.type === 'akeneo_reference_entity_collection',\n options: options.map((option) => ({\n value: option.code,\n label: labelFromLocalizedRecord(option.labels ?? null, locale, option.code),\n })),\n filterable: Boolean(attribute.useable_as_grid_filter),\n listVisible: false,\n editor: kind === 'multiline' ? 'markdown' : undefined,\n validation: buildValidationRules(attribute),\n group: attribute.group ? {\n code: normalizeFieldKey(attribute.group),\n title: attribute.group_labels ? labelFromLocalizedRecord(attribute.group_labels, locale, attribute.group) : attribute.group,\n } : undefined,\n sourceMetadata: buildAttributeMetadata(attribute, locale),\n }\n if (fieldMapping.target === 'product') productFields.push(field)\n else variantFields.push(field)\n items.push({\n externalId: `${fieldMapping.target}:${fieldMapping.attributeCode}`,\n action: 'update',\n data: {\n key: field.key,\n target: fieldMapping.target,\n attributeCode: fieldMapping.attributeCode,\n },\n })\n }\n\n const sets = []\n if (productFields.length > 0) {\n sets.push({\n entity: PRODUCT_ENTITY_ID,\n fields: productFields,\n source: 'akeneo',\n })\n }\n if (variantFields.length > 0) {\n sets.push({\n entity: VARIANT_ENTITY_ID,\n fields: variantFields,\n source: 'akeneo',\n })\n }\n\n if (sets.length > 0) {\n const productFieldAssignments = productFields.map((field) => ({\n key: field.key,\n fieldsets: resolveAkeneoFieldsetMemberships(\n existingFieldsetsByEntityAndKey.get(`${PRODUCT_ENTITY_ID}:${field.key}`) ?? [],\n fieldsetPlan?.product?.code ?? null,\n ),\n }))\n const variantFieldAssignments = variantFields.map((field) => ({\n key: field.key,\n fieldsets: resolveAkeneoFieldsetMemberships(\n existingFieldsetsByEntityAndKey.get(`${VARIANT_ENTITY_ID}:${field.key}`) ?? [],\n fieldsetPlan?.variant?.code ?? null,\n ),\n }))\n\n await ensureCustomFieldDefinitions(em, sets, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n await Promise.all([\n ensureEntityFieldsetConfig(PRODUCT_ENTITY_ID, fieldsetPlan?.product ?? null),\n ensureEntityFieldsetConfig(VARIANT_ENTITY_ID, fieldsetPlan?.variant ?? null),\n ])\n await Promise.all([\n ensureAkeneoFieldsetAssignments(PRODUCT_ENTITY_ID, productFieldAssignments),\n ensureAkeneoFieldsetAssignments(VARIANT_ENTITY_ID, variantFieldAssignments),\n ])\n await Promise.all([\n reconcileAkeneoFieldsetAssignments(PRODUCT_ENTITY_ID, fieldsetPlan?.product?.code ?? null, productFields.map((field) => field.key)),\n reconcileAkeneoFieldsetAssignments(VARIANT_ENTITY_ID, fieldsetPlan?.variant?.code ?? null, variantFields.map((field) => field.key)),\n ])\n await invalidateDefinitionsCache(cacheService as never, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n entityIds: [PRODUCT_ENTITY_ID, VARIANT_ENTITY_ID],\n })\n }\n\n return items\n })())\n }\n return customFieldSyncCache.get(cacheKey) ?? []\n }\n\n async function reconcileAkeneoFieldsetAssignments(\n entityId: string,\n fieldsetCode: string | null,\n desiredFieldKeys: string[],\n ): Promise<void> {\n if (!fieldsetCode) return\n\n const existingDefinitions = await findWithDecryption(em, CustomFieldDef, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n\n const keysToDetach = resolveAkeneoFieldKeysToDetach(\n existingDefinitions.map((definition) => {\n const config = safeRecord(definition.configJson)\n return {\n key: definition.key,\n description: typeof config?.description === 'string' ? config.description : null,\n fieldset: typeof config?.fieldset === 'string' ? config.fieldset : null,\n fieldsets: readConfiguredFieldsets(config),\n }\n }),\n desiredFieldKeys,\n fieldsetCode,\n )\n\n if (keysToDetach.length === 0) return\n\n for (const definition of existingDefinitions) {\n if (!keysToDetach.includes(definition.key)) continue\n const nextConfig = {\n ...(safeRecord(definition.configJson) ?? {}),\n }\n const remainingFieldsets = readConfiguredFieldsets(nextConfig).filter((entry) => entry !== fieldsetCode)\n if (remainingFieldsets.length === 0) {\n delete nextConfig.fieldset\n delete nextConfig.fieldsets\n } else if (remainingFieldsets.length === 1) {\n nextConfig.fieldset = remainingFieldsets[0]\n nextConfig.fieldsets = remainingFieldsets\n } else {\n delete nextConfig.fieldset\n nextConfig.fieldsets = remainingFieldsets\n }\n definition.configJson = nextConfig\n definition.updatedAt = new Date()\n }\n\n await em.flush()\n }\n\n async function ensureAkeneoFieldsetAssignments(\n entityId: string,\n assignments: DesiredFieldsetAssignment[],\n ): Promise<void> {\n const normalizedAssignments = assignments\n .map((assignment) => ({\n key: normalizeFieldKey(assignment.key),\n fieldsets: dedupeStrings(\n assignment.fieldsets\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n ),\n }))\n .filter((assignment) => assignment.key.length > 0 && assignment.fieldsets.length > 0)\n\n const normalizedKeys = normalizedAssignments.map((assignment) => assignment.key)\n if (normalizedKeys.length === 0) return\n\n const fieldsetsByKey = new Map(normalizedAssignments.map((assignment) => [assignment.key, assignment.fieldsets]))\n\n const existingDefinitions = await findWithDecryption(em, CustomFieldDef, {\n entityId,\n key: { $in: normalizedKeys } as never,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n\n let changed = false\n for (const definition of existingDefinitions) {\n const nextConfig = {\n ...(safeRecord(definition.configJson) ?? {}),\n }\n const nextFieldsets = fieldsetsByKey.get(definition.key) ?? []\n if (nextFieldsets.length === 0) continue\n\n const currentFieldsets = readConfiguredFieldsets(nextConfig)\n const currentPrimary = typeof nextConfig.fieldset === 'string' ? nextConfig.fieldset.trim() : ''\n const nextPrimary = nextFieldsets.length === 1 ? nextFieldsets[0] : ''\n const sameMemberships = currentFieldsets.length === nextFieldsets.length\n && currentFieldsets.every((entry, index) => entry === nextFieldsets[index])\n if (sameMemberships && currentPrimary === nextPrimary) continue\n\n if (nextFieldsets.length === 1) {\n nextConfig.fieldset = nextFieldsets[0]\n delete nextConfig.fieldsets\n } else {\n delete nextConfig.fieldset\n nextConfig.fieldsets = nextFieldsets\n }\n definition.configJson = nextConfig\n definition.updatedAt = new Date()\n changed = true\n }\n\n if (changed) {\n await em.flush()\n }\n }\n\n async function applyAkeneoManagedFieldsetAssignments(\n entityId: string,\n assignments: EntityFieldsetAssignments,\n ): Promise<void> {\n const dedupedFieldsets = new Map(assignments.fieldsets.map((fieldset) => [fieldset.code, fieldset]))\n await Promise.all(\n Array.from(dedupedFieldsets.values()).map((fieldset) => ensureEntityFieldsetConfig(entityId, fieldset)),\n )\n\n const definitions = await findWithDecryption(em, CustomFieldDef, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n\n let changed = false\n for (const definition of definitions) {\n const config = safeRecord(definition.configJson)\n const sourceMetadata = safeRecord(config?.sourceMetadata)\n const isAkeneoManaged = sourceMetadata?.provider === 'akeneo'\n || (typeof config?.description === 'string' && config.description.startsWith('Akeneo attribute '))\n if (!isAkeneoManaged) continue\n\n const nextConfig = {\n ...(config ?? {}),\n }\n const nextFieldsets = assignments.fieldsetsByKey.get(definition.key) ?? []\n const currentFieldsets = readConfiguredFieldsets(nextConfig)\n const currentPrimary = typeof nextConfig.fieldset === 'string' ? nextConfig.fieldset.trim() : ''\n const nextPrimary = nextFieldsets.length === 1 ? nextFieldsets[0] : ''\n const sameMemberships = currentFieldsets.length === nextFieldsets.length\n && currentFieldsets.every((entry, index) => entry === nextFieldsets[index])\n if (sameMemberships && currentPrimary === nextPrimary) continue\n\n if (nextFieldsets.length === 0) {\n delete nextConfig.fieldset\n delete nextConfig.fieldsets\n } else if (nextFieldsets.length === 1) {\n nextConfig.fieldset = nextFieldsets[0]\n delete nextConfig.fieldsets\n } else {\n delete nextConfig.fieldset\n nextConfig.fieldsets = nextFieldsets\n }\n\n definition.configJson = nextConfig\n definition.updatedAt = new Date()\n changed = true\n }\n\n if (changed) {\n await em.flush()\n await invalidateDefinitionsCache(cacheService as never, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n entityIds: [entityId],\n })\n }\n }\n\n async function reconcileMappedCustomFieldFieldsets(mapping: AkeneoDataMapping): Promise<void> {\n const settings = mapping.settings?.products\n if (!settings || settings.customFieldMappings.length === 0) return\n\n const activeMappings = settings.customFieldMappings.filter((entry) => !entry.skip)\n if (activeMappings.length === 0) return\n\n globalFieldsetAssignmentCache.delete(JSON.stringify({\n customFieldMappings: settings.customFieldMappings.filter((entry) => !entry.skip),\n fieldsetMappings: settings.fieldsetMappings,\n }))\n em.clear()\n const globalAssignments = await resolveGlobalFieldsetAssignments(settings)\n const productAssignments = globalAssignments.product\n const variantAssignments = globalAssignments.variant\n\n if (productAssignments.fieldsets.length > 0 || productAssignments.fieldsetsByKey.size > 0) {\n await applyAkeneoManagedFieldsetAssignments(PRODUCT_ENTITY_ID, productAssignments)\n }\n if (variantAssignments.fieldsets.length > 0 || variantAssignments.fieldsetsByKey.size > 0) {\n await applyAkeneoManagedFieldsetAssignments(VARIANT_ENTITY_ID, variantAssignments)\n }\n }\n\n async function resolveGlobalFieldsetAssignments(\n settings: AkeneoProductMappingSettings,\n ): Promise<ResolvedGlobalFieldsetAssignments> {\n const activeMappings = settings.customFieldMappings.filter((entry) => !entry.skip)\n const cacheKey = JSON.stringify({\n customFieldMappings: activeMappings,\n fieldsetMappings: settings.fieldsetMappings,\n })\n if (!globalFieldsetAssignmentCache.has(cacheKey)) {\n globalFieldsetAssignmentCache.set(cacheKey, (async () => {\n const optionSchemas = await em.getConnection().execute<Array<{\n code: string\n name: string\n description: string | null\n metadata: unknown\n }>>(\n `\n select code, name, description, metadata\n from catalog_product_option_schemas\n where organization_id = ?\n and tenant_id = ?\n and deleted_at is null\n `,\n [scope.organizationId, scope.tenantId],\n )\n const akeneoSchemas: Array<{\n schema: {\n code: string\n name: string\n description: string | null\n }\n metadata: AkeneoOptionSchemaMetadata\n }> = []\n for (const schema of optionSchemas) {\n const metadata = readAkeneoOptionSchemaMetadata(schema.metadata)\n if (!metadata) continue\n akeneoSchemas.push({\n schema: {\n code: schema.code,\n name: schema.name,\n description: schema.description,\n },\n metadata,\n })\n }\n\n const productAssignments: EntityFieldsetAssignments = {\n fieldsets: [],\n fieldsetsByKey: new Map(),\n }\n const variantAssignments: EntityFieldsetAssignments = {\n fieldsets: [],\n fieldsetsByKey: new Map(),\n }\n\n const addFieldsetAssignment = (\n bucket: EntityFieldsetAssignments,\n fieldKey: string,\n fieldset: CustomFieldsetDefinition | null,\n ) => {\n if (!fieldset) return\n const normalizedKey = normalizeFieldKey(fieldKey)\n if (!normalizedKey) return\n const existing = bucket.fieldsetsByKey.get(normalizedKey) ?? []\n bucket.fieldsetsByKey.set(\n normalizedKey,\n resolveAkeneoFieldsetMemberships(existing, fieldset.code),\n )\n if (!bucket.fieldsets.some((entry) => entry.code === fieldset.code)) {\n bucket.fieldsets.push(fieldset)\n }\n }\n\n for (const { schema, metadata } of akeneoSchemas) {\n const fieldsetPlan = buildFieldsetPlanFromOptionSchema({\n schema,\n metadata,\n locale: settings.locale,\n fieldsetMappings: settings.fieldsetMappings,\n })\n if (!fieldsetPlan.fieldset) continue\n\n const schemaMappings = activeMappings.filter((entry) => (\n entry.target === fieldsetPlan.target\n && metadata.attributeCodes.includes(entry.attributeCode)\n ))\n if (schemaMappings.length === 0) continue\n\n const bucket = fieldsetPlan.target === 'product' ? productAssignments : variantAssignments\n for (const fieldMapping of schemaMappings) {\n addFieldsetAssignment(bucket, fieldMapping.fieldKey, fieldsetPlan.fieldset)\n }\n }\n\n return {\n product: productAssignments,\n variant: variantAssignments,\n }\n })())\n }\n\n return globalFieldsetAssignmentCache.get(cacheKey) ?? {\n product: { fieldsets: [], fieldsetsByKey: new Map() },\n variant: { fieldsets: [], fieldsetsByKey: new Map() },\n }\n }\n\n async function upsertAttributeFamily(\n family: AkeneoFamily,\n locale: string,\n includeTextAttributes: boolean,\n includeNumericAttributes: boolean,\n ): Promise<UpsertResult | null> {\n return ensureOptionSchemaForFamily(family, null, includeTextAttributes, includeNumericAttributes, locale)\n }\n\n async function resolveAutoLocalChannelCode(\n akeneoChannel: string | null,\n fallbackChannelCode: string | null,\n createIfMissing: boolean,\n ): Promise<string | null> {\n if (akeneoChannel) {\n const exact = await resolveChannel(akeneoChannel, {\n createIfMissing,\n label: titleizeCode(akeneoChannel),\n })\n if (exact) return exact.code\n\n const aliases = akeneoChannel.trim().toLowerCase() === 'ecommerce'\n ? ['web', 'online', 'default']\n : akeneoChannel.trim().toLowerCase() === 'web'\n ? ['ecommerce', 'online', 'default']\n : []\n for (const alias of aliases) {\n const match = await resolveChannel(alias)\n if (match) return match.code\n }\n }\n return fallbackChannelCode\n }\n\n async function resolveAutoPriceKindCode(attributeCode: string): Promise<string | null> {\n const normalizedCode = attributeCode.trim().toLowerCase()\n const preferredCode = normalizedCode.includes('sale')\n || normalizedCode.includes('promo')\n || normalizedCode.includes('special')\n || normalizedCode.includes('discount')\n ? 'sale'\n : 'regular'\n const preferred = await resolvePriceKind(preferredCode)\n if (preferred) return preferred.code\n return resolvePreferredPriceKindCode()\n }\n\n async function buildAutomaticPriceMappings(params: {\n hierarchy: ResolvedHierarchy\n settings: AkeneoProductMappingSettings\n priceAttributeCodes: string[]\n }): Promise<AkeneoProductMappingSettings['priceMappings']> {\n const fallbackChannelCode = await resolvePreferredLocalChannelCode()\n\n const mappings: AkeneoProductMappingSettings['priceMappings'] = []\n const selectedChannels = resolveImportedAkeneoChannels(params.settings)\n for (const attributeCode of dedupeStrings(params.priceAttributeCodes)) {\n const priceKindCode = await resolveAutoPriceKindCode(attributeCode)\n if (!priceKindCode) continue\n const scopes = collectValueScopes(\n [params.hierarchy.leafValues, params.hierarchy.mergedValues],\n attributeCode,\n )\n const effectiveScopes = scopes.length > 0\n ? scopes\n : [\n ...(selectedChannels.length > 0\n ? selectedChannels\n : [params.settings.channel ?? (params.settings.createMissingChannels ? 'default' : null)]),\n ]\n for (const akeneoChannel of effectiveScopes) {\n if (!shouldImportAkeneoChannel(params.settings, akeneoChannel)) continue\n const localChannelCode = await resolveAutoLocalChannelCode(\n akeneoChannel,\n fallbackChannelCode,\n params.settings.createMissingChannels,\n )\n if (!localChannelCode) continue\n mappings.push({\n attributeCode,\n priceKindCode,\n akeneoChannel,\n localChannelCode,\n })\n }\n }\n\n const seen = new Set<string>()\n return mappings.filter((mapping) => {\n const key = `${mapping.attributeCode}:${mapping.priceKindCode}:${mapping.akeneoChannel ?? ''}:${mapping.localChannelCode}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n }\n\n async function resolveProductSettings(params: {\n mapping: AkeneoDataMapping\n hierarchy: ResolvedHierarchy\n family: AkeneoFamily | null\n familyVariant: AkeneoFamilyVariant | null\n }): Promise<{\n settings: AkeneoProductMappingSettings\n axisCodes: string[]\n variantAttributeCodes: string[]\n optionSchemaAttributeCodes: string[]\n fieldsetPlan: AkeneoFieldsetPlan\n }> {\n if (!defaultProductSettings) {\n throw new Error('Default Akeneo product mapping is not available')\n }\n\n const baseSettings = params.mapping.settings?.products ?? defaultProductSettings\n const attributeCodes = dedupeStrings([\n ...Object.keys(params.hierarchy.rootValues),\n ...Object.keys(params.hierarchy.leafValues),\n ...Object.keys(params.hierarchy.mergedValues),\n ...(Array.isArray(params.family?.attributes) ? params.family.attributes : []),\n ...(params.familyVariant?.variant_attribute_sets?.flatMap((set) => [\n ...(Array.isArray(set.axes) ? set.axes : []),\n ...(Array.isArray(set.attributes) ? set.attributes : []),\n ]) ?? []),\n ])\n const attributes = (\n await Promise.all(attributeCodes.map((code) => client.getAttribute(code)))\n ).filter((attribute): attribute is AkeneoAttribute => Boolean(attribute))\n\n const inferred = inferAkeneoProductMapping({\n attributes,\n family: params.family,\n familyVariant: params.familyVariant,\n fieldMap: baseSettings.fieldMap,\n explicitCustomFieldMappings: baseSettings.customFieldMappings,\n explicitMediaMappings: baseSettings.mediaMappings,\n })\n\n const priceMappings = baseSettings.priceMappings.length > 0\n ? baseSettings.priceMappings\n : await buildAutomaticPriceMappings({\n hierarchy: params.hierarchy,\n settings: baseSettings,\n priceAttributeCodes: inferred.autoPriceAttributeCodes,\n })\n\n const explicitCustomAttributeCodes = new Set(baseSettings.customFieldMappings.map((entry) => entry.attributeCode))\n const inferredCustomAttributeCodes = new Set(inferred.autoCustomFieldMappings.map((entry) => entry.attributeCode))\n const productAttributes = attributes.filter((attribute) => {\n if (!explicitCustomAttributeCodes.has(attribute.code) && !inferredCustomAttributeCodes.has(attribute.code)) return false\n return params.familyVariant\n ? !inferred.variantAttributeCodes.includes(attribute.code)\n : true\n })\n const variantAttributes = attributes.filter((attribute) => {\n if (!explicitCustomAttributeCodes.has(attribute.code) && !inferredCustomAttributeCodes.has(attribute.code)) return false\n return inferred.variantAttributeCodes.includes(attribute.code)\n })\n const fieldsetPlan = buildFieldsetPlan({\n family: params.family,\n familyVariant: params.familyVariant,\n productAttributes,\n variantAttributes,\n locale: baseSettings.locale,\n fieldsetMappings: baseSettings.fieldsetMappings,\n })\n const availableAttributeCodes = attributes.map((attribute) => attribute.code)\n\n return {\n settings: {\n ...baseSettings,\n fieldMap: inferred.fieldMap,\n customFieldMappings: filterAkeneoAttributeMappingsByAvailableAttributes(\n dedupeCustomFieldMappings([\n ...baseSettings.customFieldMappings,\n ...inferred.autoCustomFieldMappings,\n ]),\n availableAttributeCodes,\n ),\n mediaMappings: filterAkeneoAttributeMappingsByAvailableAttributes(\n dedupeMediaMappings([\n ...baseSettings.mediaMappings,\n ...inferred.autoMediaMappings,\n ]),\n availableAttributeCodes,\n ),\n fieldsetMappings: baseSettings.fieldsetMappings,\n priceMappings,\n },\n axisCodes: inferred.axisCodes,\n variantAttributeCodes: inferred.variantAttributeCodes,\n optionSchemaAttributeCodes: inferred.optionSchemaAttributeCodes,\n fieldsetPlan,\n }\n }\n\n async function resolveProductHierarchy(product: AkeneoProduct): Promise<ResolvedHierarchy> {\n if (!product.parent) {\n return {\n rootExternalId: product.uuid,\n family: product.family ?? null,\n familyVariantCode: null,\n rootValues: mergeValueLayers(product.values),\n leafValues: mergeValueLayers(product.values),\n mergedValues: mergeValueLayers(product.values),\n categories: Array.isArray(product.categories) ? product.categories : [],\n parentChain: [],\n associationSource: product,\n axisCodes: [],\n }\n }\n\n const chain: Array<{ code: string; values: AkeneoValues; categories: string[]; family?: string | null; familyVariant?: string | null }> = []\n let nextCode: string | null = product.parent\n while (nextCode) {\n const model = await client.getProductModel(nextCode)\n if (!model) break\n chain.unshift({\n code: model.code,\n values: mergeValueLayers(model.values),\n categories: Array.isArray(model.categories) ? model.categories : [],\n family: model.family ?? null,\n familyVariant: model.family_variant ?? null,\n })\n nextCode = model.parent ?? null\n }\n\n const root = chain[0]\n return {\n rootExternalId: root?.code ?? product.uuid,\n family: product.family ?? root?.family ?? null,\n familyVariantCode: chain[chain.length - 1]?.familyVariant ?? root?.familyVariant ?? null,\n rootValues: root?.values ?? mergeValueLayers(product.values),\n leafValues: mergeValueLayers(product.values),\n mergedValues: mergeValueLayers(\n ...chain.map((model) => model.values),\n product.values,\n ),\n categories: Array.from(new Set([\n ...chain.flatMap((model) => model.categories),\n ...(product.categories ?? []),\n ])),\n parentChain: chain.map((model) => model.code),\n associationSource: product,\n axisCodes: [],\n }\n }\n\n async function applyCustomFieldMappings(params: {\n mapping: AkeneoDataMapping\n hierarchy: ResolvedHierarchy\n product: AkeneoProduct\n localProductId: string\n localVariantId: string\n fieldsetPlan?: AkeneoFieldsetPlan | null\n }): Promise<void> {\n const settings = params.mapping.settings?.products\n if (!settings || settings.customFieldMappings.length === 0) return\n\n await syncMappedCustomFields(params.mapping, settings.locale, params.fieldsetPlan)\n\n const productCustomFields: Record<string, unknown> = {}\n const variantCustomFields: Record<string, unknown> = {}\n\n for (const fieldMapping of settings.customFieldMappings) {\n if (fieldMapping.skip) continue\n const attribute = await client.getAttribute(fieldMapping.attributeCode)\n if (!attribute) continue\n const kind = mapAkeneoAttributeToCustomFieldKind(attribute, fieldMapping.kind)\n if (!kind) continue\n const sourceLayers = fieldMapping.target === 'product'\n ? [params.hierarchy.rootValues, params.hierarchy.mergedValues]\n : [params.product.values ?? {}, params.hierarchy.mergedValues]\n const rawValue = readLayeredAkeneoValue(sourceLayers, fieldMapping.attributeCode, settings.locale, settings.channel ?? null)\n const value = resolveCustomFieldValue(rawValue, attribute, kind)\n if (value === null || value === undefined || (Array.isArray(value) && value.length === 0)) continue\n if (fieldMapping.target === 'product') {\n productCustomFields[normalizeFieldKey(fieldMapping.fieldKey)] = value\n } else {\n variantCustomFields[normalizeFieldKey(fieldMapping.fieldKey)] = value\n }\n }\n\n await Promise.all([\n setCustomFieldsIfAny({\n dataEngine,\n entityId: PRODUCT_ENTITY_ID,\n recordId: params.localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: productCustomFields,\n }),\n setCustomFieldsIfAny({\n dataEngine,\n entityId: VARIANT_ENTITY_ID,\n recordId: params.localVariantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: variantCustomFields,\n }),\n ])\n\n await Promise.all([\n params.fieldsetPlan?.product?.code\n ? executeCommand('catalog.products.update', {\n id: params.localProductId,\n customFieldsetCode: params.fieldsetPlan.product.code,\n })\n : Promise.resolve(),\n params.fieldsetPlan?.variant?.code\n ? executeCommand('catalog.variants.update', {\n id: params.localVariantId,\n customFieldsetCode: params.fieldsetPlan.variant.code,\n })\n : Promise.resolve(),\n ])\n\n if (Object.keys(productCustomFields).length > 0) {\n await emitCatalogQueryIndexEvent(buildCommandContext(), {\n entityType: PRODUCT_ENTITY_ID,\n recordId: params.localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n action: 'updated',\n })\n }\n\n if (Object.keys(variantCustomFields).length > 0) {\n await emitCatalogQueryIndexEvent(buildCommandContext(), {\n entityType: VARIANT_ENTITY_ID,\n recordId: params.localVariantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n action: 'updated',\n })\n }\n }\n\n async function upsertOffersAndPrices(params: {\n mapping: AkeneoDataMapping\n settings: AkeneoProductMappingSettings\n hierarchy: ResolvedHierarchy\n localProductId: string\n localVariantId: string\n resolvedProductTitle: string\n resolvedProductDescription: string | null\n variantExternalId: string\n }): Promise<void> {\n const desiredOffers = new Map<string, DesiredOffer>()\n for (const priceMapping of params.settings.priceMappings) {\n const channel = await resolveChannel(priceMapping.localChannelCode, {\n createIfMissing: params.settings.createMissingChannels,\n label: titleizeCode(priceMapping.localChannelCode),\n })\n const priceKind = await resolvePriceKind(priceMapping.priceKindCode)\n if (!channel || !priceKind) continue\n const akeneoChannel = priceMapping.akeneoChannel ?? params.settings.channel ?? null\n if (!shouldImportAkeneoChannel(params.settings, akeneoChannel)) continue\n const rawPrices = readLayeredAkeneoValue(\n [params.hierarchy.leafValues, params.hierarchy.mergedValues],\n priceMapping.attributeCode,\n params.settings.locale,\n akeneoChannel,\n )\n const entries = parsePriceCollection(rawPrices)\n if (entries.length === 0) continue\n const offerExternalId = `${params.hierarchy.rootExternalId}:offer:${channel.code}`\n const existingOffer = desiredOffers.get(offerExternalId)\n const title = coerceString(readLayeredAkeneoValue(\n [params.hierarchy.rootValues, params.hierarchy.mergedValues],\n params.settings.fieldMap.title,\n params.settings.locale,\n akeneoChannel,\n )) ?? params.resolvedProductTitle\n const description = clampString(\n normalizeMarkdownText(\n coerceString(readLayeredAkeneoValue(\n [params.hierarchy.rootValues, params.hierarchy.mergedValues],\n params.settings.fieldMap.description,\n params.settings.locale,\n akeneoChannel,\n )) ?? params.resolvedProductDescription,\n ),\n 4000,\n )\n const bucket = existingOffer ?? {\n externalId: offerExternalId,\n channelCode: channel.code,\n channelId: channel.id,\n akeneoChannel,\n title,\n description,\n prices: [],\n }\n for (const entry of entries) {\n bucket.prices.push({\n externalId: `${params.variantExternalId}:price:${priceKind.code}:${channel.code}:${entry.currencyCode}`,\n priceKindCode: priceKind.code,\n priceKindId: priceKind.id,\n channelId: channel.id,\n currencyCode: entry.currencyCode,\n amount: entry.amount,\n variantId: params.localVariantId,\n })\n }\n desiredOffers.set(offerExternalId, bucket)\n }\n\n const existingOffers = await findWithDecryption(\n em,\n CatalogOffer,\n {\n product: params.localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n const existingOfferByChannelId = new Map(existingOffers.map((offer) => [offer.channelId, offer]))\n const desiredOfferExternalIds = new Set(desiredOffers.keys())\n\n for (const offer of desiredOffers.values()) {\n const mappedOfferId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_offer', offer.externalId, scope)\n const existingOffer = mappedOfferId\n ? existingOffers.find((entry) => entry.id === mappedOfferId) ?? null\n : existingOfferByChannelId.get(offer.channelId) ?? null\n const input = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n productId: params.localProductId,\n channelId: offer.channelId,\n title: offer.title,\n description: offer.description ?? undefined,\n metadata: {\n source: 'akeneo',\n externalId: offer.externalId,\n channelCode: offer.channelCode,\n akeneoChannel: offer.akeneoChannel,\n },\n isActive: true,\n }\n const offerId = existingOffer\n ? (await executeCommand<{ offerId: string }>('catalog.offers.update', { id: existingOffer.id, ...input })).offerId\n : (await executeCommand<{ offerId: string }>('catalog.offers.create', input)).offerId\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_offer', offerId, offer.externalId, scope)\n\n const existingPrices = await findWithDecryption(\n em,\n CatalogProductPrice,\n {\n offer: offerId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n },\n undefined,\n scope,\n )\n const desiredPriceExternalIds = new Set(offer.prices.map((price) => price.externalId))\n for (const price of offer.prices) {\n const mappedPriceId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_price', price.externalId, scope)\n const existingPrice = mappedPriceId\n ? existingPrices.find((entry) => entry.id === mappedPriceId) ?? null\n : existingPrices.find((entry) => (\n (typeof entry.variant === 'string' ? entry.variant : entry.variant?.id ?? null) === price.variantId\n && entry.channelId === price.channelId\n && entry.currencyCode === price.currencyCode\n && entry.kind === price.priceKindCode\n )) ?? null\n const input = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n productId: params.localProductId,\n variantId: price.variantId,\n offerId,\n priceKindId: price.priceKindId,\n currencyCode: price.currencyCode,\n unitPriceNet: price.amount,\n unitPriceGross: price.amount,\n minQuantity: 1,\n channelId: price.channelId,\n metadata: {\n source: 'akeneo',\n externalId: price.externalId,\n priceKindCode: price.priceKindCode,\n },\n }\n const priceId = existingPrice\n ? (await executeCommand<{ priceId: string }>('catalog.prices.update', { id: existingPrice.id, ...input })).priceId\n : (await executeCommand<{ priceId: string }>('catalog.prices.create', input)).priceId\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_price', priceId, price.externalId, scope)\n }\n\n if (params.settings.reconciliation.deleteMissingPrices) {\n for (const existingPrice of existingPrices) {\n const externalId = await externalIdMappingService.lookupExternalId('sync_akeneo', 'catalog_product_price', existingPrice.id, scope)\n if (externalId && !desiredPriceExternalIds.has(externalId)) {\n await executeCommand('catalog.prices.delete', { id: existingPrice.id })\n }\n }\n }\n }\n\n if (params.settings.reconciliation.deleteMissingOffers) {\n for (const existingOffer of existingOffers) {\n const externalId = await externalIdMappingService.lookupExternalId('sync_akeneo', 'catalog_offer', existingOffer.id, scope)\n if (externalId && !desiredOfferExternalIds.has(externalId)) {\n const offerPrices = await findWithDecryption(\n em,\n CatalogProductPrice,\n { offer: existingOffer.id, organizationId: scope.organizationId, tenantId: scope.tenantId },\n undefined,\n scope,\n )\n for (const price of offerPrices) {\n await executeCommand('catalog.prices.delete', { id: price.id })\n }\n await executeCommand('catalog.offers.delete', { id: existingOffer.id })\n }\n }\n }\n }\n\n async function upsertAsset(asset: DesiredAsset): Promise<string> {\n const existingAttachmentId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'attachment', asset.externalId, scope)\n if (existingAttachmentId) return existingAttachmentId\n\n await ensureDefaultPartitions(em)\n const binary = await client.downloadMediaFile(asset.remote.codeOrUrl)\n const fileName = asset.remote.fileNameHint ?? binary.fileName ?? `akeneo-${randomUUID().slice(0, 8)}`\n const partitionCode = resolveDefaultPartitionCode(asset.entityId)\n const stored = await storePartitionFile({\n partitionCode,\n orgId: scope.organizationId,\n tenantId: scope.tenantId,\n fileName,\n buffer: binary.buffer,\n })\n const attachment = em.create(Attachment, {\n entityId: asset.entityId,\n recordId: asset.recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n partitionCode,\n fileName,\n mimeType: asset.remote.mimeTypeHint ?? binary.contentType ?? 'application/octet-stream',\n fileSize: binary.contentLength ?? binary.buffer.byteLength,\n storageDriver: 'local',\n storagePath: stored.storagePath,\n storageMetadata: mergeAttachmentMetadata(null, {\n assignments: [{ type: asset.entityId, id: asset.recordId }],\n }),\n url: buildAttachmentFileUrl('pending'),\n content: null,\n })\n em.persist(attachment)\n await em.flush()\n attachment.url = asset.kind === 'image'\n ? buildAttachmentImageUrl(attachment.id, { slug: slugifyAttachmentFileName(fileName) })\n : buildAttachmentFileUrl(attachment.id)\n attachment.storageMetadata = {\n ...(attachment.storageMetadata ?? {}),\n source: 'akeneo',\n externalId: asset.externalId,\n kind: asset.kind,\n remoteCode: asset.remote.codeOrUrl,\n }\n await em.flush()\n await emitAttachmentCrudChange('created', attachment)\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'attachment', attachment.id, asset.externalId, scope)\n return attachment.id\n }\n\n async function reconcileAttachments(params: {\n entityId: string\n recordId: string\n desiredAssets: DesiredAsset[]\n reconciliation: AkeneoReconciliationSettings\n }): Promise<{ heroAttachmentId: string | null; heroAttachmentUrl: string | null }> {\n const desiredExternalIds = new Set(params.desiredAssets.map((asset) => asset.externalId))\n const desiredImages = params.desiredAssets.filter((asset) => asset.kind === 'image')\n const desiredFiles = params.desiredAssets.filter((asset) => asset.kind === 'file')\n const desiredAttachmentIds = await Promise.all(params.desiredAssets.map((asset) => upsertAsset(asset)))\n const heroAttachmentId = desiredImages.length > 0\n ? desiredAttachmentIds[params.desiredAssets.findIndex((asset) => asset.externalId === desiredImages[0]?.externalId)]\n : null\n const heroAttachmentUrl = heroAttachmentId ? buildAttachmentImageUrl(heroAttachmentId) : null\n\n const existing = await findWithDecryption(em, Attachment, {\n entityId: params.entityId,\n recordId: params.recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, undefined, scope)\n for (const attachment of existing) {\n const metadata = safeRecord(attachment.storageMetadata)\n const externalId = typeof metadata?.externalId === 'string' ? metadata.externalId : null\n const kind = metadata?.kind === 'image' || metadata?.kind === 'file' ? metadata.kind : null\n if (!externalId || !kind) continue\n const shouldDelete = kind === 'image'\n ? params.reconciliation.deleteMissingMedia\n : params.reconciliation.deleteMissingAttachments\n if (!shouldDelete || desiredExternalIds.has(externalId)) continue\n await deletePartitionFile(attachment.partitionCode, attachment.storagePath, attachment.storageDriver)\n await em.removeAndFlush(attachment)\n await emitAttachmentCrudChange('deleted', attachment)\n }\n\n return {\n heroAttachmentId,\n heroAttachmentUrl,\n }\n }\n\n async function syncAssociations(params: {\n product: AkeneoProduct\n localVariantId: string\n localProductId: string\n settings: AkeneoProductMappingSettings\n }): Promise<void> {\n if (!params.settings.syncAssociations) return\n const existing = await findWithDecryption(em, CatalogProductVariantRelation, {\n parentVariant: params.localVariantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, undefined, scope)\n\n const desired = new Map<string, {\n relationType: 'bundle' | 'grouped'\n childVariantId: string | null\n childProductId: string | null\n associationType: string\n minQuantity: number | null\n }>()\n\n const addDesired = async (associationType: string, externalCandidate: string | null, quantity: number | null, mode: 'product' | 'productModel') => {\n if (!externalCandidate) return\n let childVariantId: string | null = null\n let childProductId: string | null = null\n if (mode === 'product') {\n childVariantId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_variant', externalCandidate, scope)\n ?? await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_variant', `${externalCandidate}:default`, scope)\n ?? await lookupVariantBySku(externalCandidate)\n childProductId = childVariantId\n ? null\n : await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product', externalCandidate, scope)\n ?? await lookupProductBySku(externalCandidate)\n } else {\n childProductId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product', externalCandidate, scope)\n }\n if (!childVariantId && !childProductId) return\n const relationType = relationTypeFromAssociation(associationType)\n const key = `${relationType}:${childVariantId ?? childProductId}`\n desired.set(key, {\n relationType,\n childVariantId,\n childProductId,\n associationType,\n minQuantity: quantity,\n })\n }\n\n for (const [associationType, payload] of Object.entries(params.product.associations ?? {})) {\n for (const productIdentifier of payload.products ?? []) {\n await addDesired(associationType, productIdentifier, null, 'product')\n }\n for (const productModelCode of payload.product_models ?? []) {\n await addDesired(associationType, productModelCode, null, 'productModel')\n }\n }\n\n for (const [associationType, payload] of Object.entries(params.product.quantified_associations ?? {})) {\n for (const productEntry of payload.products ?? []) {\n await addDesired(associationType, coerceString(productEntry.uuid) ?? coerceString(productEntry.identifier), coerceNumber(productEntry.quantity), 'product')\n }\n for (const productModelEntry of payload.product_models ?? []) {\n await addDesired(associationType, coerceString(productModelEntry.code) ?? coerceString(productModelEntry.identifier), coerceNumber(productModelEntry.quantity), 'productModel')\n }\n }\n\n const desiredKeys = new Set(desired.keys())\n for (const entry of desired.values()) {\n const existingRelation = existing.find((relation) => {\n const childVariantId = typeof relation.childVariant === 'string' ? relation.childVariant : relation.childVariant?.id ?? null\n const childProductId = typeof relation.childProduct === 'string' ? relation.childProduct : relation.childProduct?.id ?? null\n return relation.relationType === entry.relationType\n && childVariantId === entry.childVariantId\n && childProductId === entry.childProductId\n })\n if (existingRelation) {\n existingRelation.minQuantity = entry.minQuantity\n existingRelation.metadata = {\n source: 'akeneo',\n associationType: entry.associationType,\n }\n await em.flush()\n continue\n }\n const relation = em.create(CatalogProductVariantRelation, {\n parentVariant: em.getReference(CatalogProductVariant, params.localVariantId),\n childVariant: entry.childVariantId ? em.getReference(CatalogProductVariant, entry.childVariantId) : null,\n childProduct: entry.childProductId ? em.getReference(CatalogProduct, entry.childProductId) : null,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n relationType: entry.relationType,\n isRequired: false,\n minQuantity: entry.minQuantity,\n maxQuantity: null,\n position: 0,\n metadata: {\n source: 'akeneo',\n associationType: entry.associationType,\n },\n })\n em.persist(relation)\n await em.flush()\n }\n\n for (const relation of existing) {\n const metadata = safeRecord(relation.metadata)\n if (metadata?.source !== 'akeneo') continue\n const childVariantId = typeof relation.childVariant === 'string' ? relation.childVariant : relation.childVariant?.id ?? null\n const childProductId = typeof relation.childProduct === 'string' ? relation.childProduct : relation.childProduct?.id ?? null\n const key = `${relation.relationType}:${childVariantId ?? childProductId}`\n if (!desiredKeys.has(key)) {\n await em.removeAndFlush(relation)\n }\n }\n }\n\n async function upsertProduct(product: AkeneoProduct, mapping: AkeneoDataMapping): Promise<Array<{ externalId: string; action: 'create' | 'update' | 'skip'; data: Record<string, unknown> }>> {\n const family = product.family ? await client.getFamily(product.family) : null\n const hierarchy = await resolveProductHierarchy(product)\n const resolvedFamily = hierarchy.family ? await client.getFamily(hierarchy.family) : family\n const resolvedFamilyVariant = hierarchy.family && hierarchy.familyVariantCode\n ? await client.getFamilyVariant(hierarchy.family, hierarchy.familyVariantCode)\n : null\n const resolvedProductSettings = await resolveProductSettings({\n mapping,\n hierarchy,\n family: resolvedFamily,\n familyVariant: resolvedFamilyVariant,\n })\n const settings = resolvedProductSettings.settings\n const locale = settings.locale\n const channel = settings.channel ?? null\n hierarchy.axisCodes = resolvedProductSettings.axisCodes\n const productFieldsetCode = resolvedProductSettings.fieldsetPlan.product?.code ?? null\n const variantFieldsetCode = resolvedProductSettings.fieldsetPlan.variant?.code ?? null\n\n let optionSchemaId: string | null = null\n if (resolvedFamily && hierarchy.axisCodes.length > 0) {\n optionSchemaId = (await ensureOptionSchemaForFamily(\n resolvedFamily,\n resolvedFamilyVariant ?? null,\n true,\n true,\n locale,\n resolvedProductSettings.optionSchemaAttributeCodes,\n ))?.localId ?? null\n }\n const fieldMap = settings.fieldMap\n const derivedMapping: AkeneoDataMapping = {\n ...mapping,\n fields: buildProductFieldMappings(settings),\n settings: {\n ...(mapping.settings ?? {}),\n products: settings,\n },\n }\n\n const resolvedTitle = coerceString(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.title, locale, channel))\n ?? coerceString(product.identifier)\n ?? hierarchy.rootExternalId\n const resolvedSubtitle = coerceString(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.subtitle, locale, channel))\n const resolvedDescription = clampString(\n normalizeMarkdownText(\n coerceString(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.description, locale, channel)),\n ),\n 4000,\n )\n const resolvedSku = coerceString(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.sku, locale, channel))\n ?? coerceString(product.identifier)\n ?? product.uuid\n const resolvedBarcode = coerceString(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.barcode, locale, channel))\n const resolvedWeight = coerceMetricAmount(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.weight, locale, channel))\n ?? coerceMetricAmount(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.weight, locale, channel))\n const categoryIds = (\n await Promise.all(hierarchy.categories.map((code) => resolveCategoryId(code, locale)))\n ).filter((value): value is string => typeof value === 'string' && value.length > 0)\n\n const productExternalId = hierarchy.rootExternalId\n const existingProductId = await resolveExistingProductId(\n productExternalId,\n product.parent ? null : resolvedSku,\n )\n\n const productInput = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: resolvedTitle,\n subtitle: resolvedSubtitle ?? undefined,\n description: resolvedDescription ?? undefined,\n sku: product.parent ? undefined : resolvedSku,\n productType: product.parent ? 'configurable' : 'simple',\n optionSchemaId,\n isConfigurable: Boolean(product.parent),\n isActive: product.enabled !== false,\n weightValue: resolvedWeight ?? undefined,\n categoryIds,\n metadata: {\n source: 'akeneo',\n externalId: productExternalId,\n sourceProductUuid: product.uuid,\n family: hierarchy.family,\n familyVariant: hierarchy.familyVariantCode,\n parentChain: hierarchy.parentChain,\n associations: product.associations ?? {},\n quantifiedAssociations: product.quantified_associations ?? {},\n updatedAt: product.updated ?? null,\n },\n customFieldsetCode: productFieldsetCode,\n }\n\n let localProductId: string\n let productAction: 'create' | 'update'\n if (existingProductId) {\n await executeCommand('catalog.products.update', {\n id: existingProductId,\n ...productInput,\n })\n localProductId = existingProductId\n productAction = 'update'\n } else {\n const created = await executeCommand<{ productId?: string; id?: string }>('catalog.products.create', productInput)\n localProductId = created.productId ?? created.id ?? ''\n if (!localProductId) {\n throw new Error(`Akeneo product ${product.uuid} did not return a local product id`)\n }\n productAction = 'create'\n }\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product', localProductId, productExternalId, scope)\n\n const variantExternalId = product.parent ? product.uuid : `${product.uuid}:default`\n const existingVariantId = await resolveExistingVariantId(variantExternalId, resolvedSku, localProductId)\n\n const optionValues =\n hierarchy.axisCodes.length > 0\n ? await (async () => {\n const values: Record<string, string> = {}\n for (const axis of hierarchy.axisCodes) {\n const rawValue = readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], axis, locale, channel)\n const optionLabels = await getAttributeOptionLabels(axis, locale)\n const normalizedValue = normalizeAkeneoSelectValue(rawValue, optionLabels)\n if (normalizedValue) {\n values[slugifyAkeneoCode(axis)] = normalizedValue\n }\n }\n return Object.keys(values).length > 0 ? values : undefined\n })()\n : undefined\n\n const existingDefaultVariant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n {\n product: localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isDefault: true,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n const variantName = coerceString(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.variantName, locale, channel))\n ?? (optionValues && Object.values(optionValues).length > 0 ? Object.values(optionValues).join(' / ') : resolvedTitle)\n\n const variantInput = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n productId: localProductId,\n name: variantName,\n sku: resolvedSku,\n barcode: resolvedBarcode ?? undefined,\n isDefault: existingVariantId ? existingVariantId === existingDefaultVariant?.id : !existingDefaultVariant,\n isActive: product.enabled !== false,\n weightValue: resolvedWeight ?? undefined,\n optionValues: optionValues && Object.keys(optionValues).length > 0 ? optionValues : undefined,\n metadata: {\n source: 'akeneo',\n externalId: variantExternalId,\n sourceProductUuid: product.uuid,\n sourceParentCode: product.parent ?? null,\n associations: product.associations ?? {},\n quantifiedAssociations: product.quantified_associations ?? {},\n updatedAt: product.updated ?? null,\n },\n customFieldsetCode: variantFieldsetCode,\n }\n\n let localVariantId: string\n let variantAction: 'create' | 'update'\n if (existingVariantId) {\n await executeCommand('catalog.variants.update', {\n id: existingVariantId,\n ...variantInput,\n })\n localVariantId = existingVariantId\n variantAction = 'update'\n } else {\n const created = await executeCommand<{ variantId?: string; id?: string }>('catalog.variants.create', variantInput)\n localVariantId = created.variantId ?? created.id ?? ''\n if (!localVariantId) {\n throw new Error(`Akeneo variant ${variantExternalId} did not return a local variant id`)\n }\n variantAction = 'create'\n }\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_variant', localVariantId, variantExternalId, scope)\n\n await applyCustomFieldMappings({\n mapping: derivedMapping,\n hierarchy,\n product,\n localProductId,\n localVariantId,\n fieldsetPlan: resolvedProductSettings.fieldsetPlan,\n })\n await upsertOffersAndPrices({\n mapping: derivedMapping,\n settings,\n hierarchy,\n localProductId,\n localVariantId,\n resolvedProductTitle: resolvedTitle,\n resolvedProductDescription: resolvedDescription,\n variantExternalId,\n })\n\n const desiredAssets: DesiredAsset[] = []\n for (const mediaMapping of settings.mediaMappings) {\n const productScopedValue = readPreferredAkeneoValue(\n hierarchy.rootValues,\n mediaMapping.attributeCode,\n locale,\n channel,\n )\n const variantScopedValue = readPreferredAkeneoValue(\n hierarchy.leafValues,\n mediaMapping.attributeCode,\n locale,\n channel,\n )\n const effectiveTarget = resolveAkeneoMediaTarget({\n mappingTarget: mediaMapping.target,\n attributeCode: mediaMapping.attributeCode,\n variantAttributeCodes: resolvedProductSettings.variantAttributeCodes,\n productScopedValue,\n variantScopedValue,\n })\n const sourceLayers = effectiveTarget === 'product'\n ? [hierarchy.rootValues, hierarchy.mergedValues]\n : [hierarchy.leafValues, hierarchy.mergedValues]\n const rawValue = readLayeredAkeneoValue(sourceLayers, mediaMapping.attributeCode, locale, channel)\n const refs = collectMediaReferences(rawValue)\n refs.forEach((ref, index) => {\n desiredAssets.push({\n externalId: `${effectiveTarget}:${mediaMapping.kind}:${mediaMapping.attributeCode}:${ref.codeOrUrl}:${index}`,\n entityId: effectiveTarget === 'product' ? PRODUCT_ENTITY_ID : VARIANT_ENTITY_ID,\n recordId: effectiveTarget === 'product' ? localProductId : localVariantId,\n kind: mediaMapping.kind,\n remote: ref,\n })\n })\n }\n\n const assetsByTarget = new Map<string, DesiredAsset[]>()\n const pendingVariantHeroUpdates: Array<{\n variantId: string\n defaultMediaId: string | null\n defaultMediaUrl: string | null\n }> = []\n const shouldMirrorVariantHeroToProduct = !product.parent && !hierarchy.familyVariantCode\n let mirroredProductHeroFromVariant: {\n defaultMediaId: string | null\n defaultMediaUrl: string | null\n } | null = null\n for (const asset of desiredAssets) {\n const key = `${asset.entityId}:${asset.recordId}`\n const bucket = assetsByTarget.get(key) ?? []\n bucket.push(asset)\n assetsByTarget.set(key, bucket)\n }\n\n for (const assets of assetsByTarget.values()) {\n const firstAsset = assets[0]\n if (!firstAsset) continue\n const hero = await reconcileAttachments({\n entityId: firstAsset.entityId,\n recordId: firstAsset.recordId,\n desiredAssets: assets,\n reconciliation: settings.reconciliation,\n })\n if (firstAsset.entityId === PRODUCT_ENTITY_ID) {\n await executeCommand('catalog.products.update', {\n id: localProductId,\n defaultMediaId: hero.heroAttachmentId,\n defaultMediaUrl: hero.heroAttachmentUrl,\n })\n } else {\n pendingVariantHeroUpdates.push({\n variantId: localVariantId,\n defaultMediaId: hero.heroAttachmentId,\n defaultMediaUrl: hero.heroAttachmentUrl,\n })\n if (\n shouldMirrorVariantHeroToProduct\n && firstAsset.recordId === localVariantId\n && hero.heroAttachmentId\n && !mirroredProductHeroFromVariant\n ) {\n mirroredProductHeroFromVariant = {\n defaultMediaId: hero.heroAttachmentId,\n defaultMediaUrl: hero.heroAttachmentUrl,\n }\n }\n }\n }\n\n await syncAssociations({\n product,\n localVariantId,\n localProductId,\n settings,\n })\n\n for (const heroUpdate of pendingVariantHeroUpdates) {\n await em.getConnection().execute(\n `\n update catalog_product_variants\n set default_media_id = ?, default_media_url = ?, updated_at = now()\n where id = ? and organization_id = ? and tenant_id = ?\n `,\n [\n heroUpdate.defaultMediaId,\n heroUpdate.defaultMediaUrl,\n heroUpdate.variantId,\n scope.organizationId,\n scope.tenantId,\n ],\n )\n await emitCatalogQueryIndexEvent(buildCommandContext(), {\n entityType: VARIANT_ENTITY_ID,\n recordId: heroUpdate.variantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n action: 'updated',\n })\n }\n\n if (mirroredProductHeroFromVariant) {\n await executeCommand('catalog.products.update', {\n id: localProductId,\n defaultMediaId: mirroredProductHeroFromVariant.defaultMediaId,\n defaultMediaUrl: mirroredProductHeroFromVariant.defaultMediaUrl,\n })\n }\n\n return [\n {\n externalId: productExternalId,\n action: productAction,\n data: {\n localProductId,\n sku: resolvedSku,\n family: hierarchy.family,\n },\n },\n {\n externalId: variantExternalId,\n action: variantAction,\n data: {\n localVariantId,\n productId: localProductId,\n sku: resolvedSku,\n },\n },\n ]\n }\n\n async function deactivateMappedEntities(entityType: string, seenExternalIds: Set<string>, commandId: string): Promise<void> {\n const mappings = await findWithDecryption(em, SyncExternalIdMapping, {\n integrationId: 'sync_akeneo',\n internalEntityType: entityType,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n for (const mapping of mappings) {\n if (seenExternalIds.has(mapping.externalId)) continue\n await executeCommand(commandId, {\n id: mapping.internalEntityId,\n isActive: false,\n })\n }\n }\n\n async function reconcileCategories(seenExternalIds: Set<string>, locale: string, reconciliation: AkeneoReconciliationSettings): Promise<void> {\n if (!reconciliation.deactivateMissingCategories || seenExternalIds.size === 0) return\n await deactivateMappedEntities('catalog_product_category', seenExternalIds, 'catalog.categories.update')\n }\n\n async function reconcileAttributes(params: {\n seenFamilyExternalIds: Set<string>\n currentCustomFieldKeys: Set<string>\n reconciliation: AkeneoReconciliationSettings\n }): Promise<void> {\n if (!params.reconciliation.deactivateMissingAttributes) return\n if (params.seenFamilyExternalIds.size > 0) {\n await deactivateMappedEntities('catalog_option_schema', params.seenFamilyExternalIds, 'catalog.optionSchemas.update')\n }\n const defs = await findWithDecryption(em, CustomFieldDef, {\n entityId: { $in: [PRODUCT_ENTITY_ID, VARIANT_ENTITY_ID] },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n for (const def of defs) {\n const sourceMetadata = safeRecord(def.configJson?.sourceMetadata)\n if (sourceMetadata?.provider !== 'akeneo') continue\n if (params.currentCustomFieldKeys.has(`${def.entityId}:${def.key}`)) continue\n def.isActive = false\n }\n await em.flush()\n }\n\n async function reconcileProducts(seenProductExternalIds: Set<string>, seenVariantExternalIds: Set<string>, reconciliation: AkeneoReconciliationSettings): Promise<void> {\n if (!reconciliation.deactivateMissingProducts) return\n if (seenProductExternalIds.size > 0) {\n await deactivateMappedEntities('catalog_product', seenProductExternalIds, 'catalog.products.update')\n }\n if (seenVariantExternalIds.size > 0) {\n await deactivateMappedEntities('catalog_product_variant', seenVariantExternalIds, 'catalog.variants.update')\n }\n }\n\n return {\n upsertCategory,\n upsertAttributeFamily,\n upsertProduct,\n syncMappedCustomFields,\n reconcileMappedCustomFieldFieldsets,\n reconcileCategories,\n reconcileAttributes,\n reconcileProducts,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from 'crypto'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { DataMapping } from '@open-mercato/core/modules/data_sync/lib/adapter'\nimport type { ExternalIdMappingService } from '@open-mercato/core/modules/data_sync/lib/id-mapping'\nimport { SyncExternalIdMapping } from '@open-mercato/core/modules/integrations/data/entities'\nimport {\n CatalogOffer,\n CatalogOptionSchemaTemplate,\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductPrice,\n CatalogProductVariant,\n CatalogProductVariantRelation,\n} from '@open-mercato/core/modules/catalog/data/entities'\nimport { ensureCustomFieldDefinitions } from '@open-mercato/core/modules/entities/lib/field-definitions'\nimport { CustomFieldDef, CustomFieldEntityConfig } from '@open-mercato/core/modules/entities/data/entities'\nimport { normalizeEntityFieldsetConfig, type CustomFieldsetDefinition } from '@open-mercato/core/modules/entities/lib/fieldsets'\nimport { invalidateDefinitionsCache } from '@open-mercato/core/modules/entities/api/definitions.cache'\nimport { Attachment } from '@open-mercato/core/modules/attachments/data/entities'\nimport { buildAttachmentFileUrl, buildAttachmentImageUrl, slugifyAttachmentFileName } from '@open-mercato/core/modules/attachments/lib/imageUrls'\nimport { deletePartitionFile, storePartitionFile } from '@open-mercato/core/modules/attachments/lib/storage'\nimport { ensureDefaultPartitions, resolveDefaultPartitionCode } from '@open-mercato/core/modules/attachments/lib/partitions'\nimport { mergeAttachmentMetadata } from '@open-mercato/core/modules/attachments/lib/metadata'\nimport { attachmentCrudEvents, attachmentCrudIndexer } from '@open-mercato/core/modules/attachments/lib/crud'\nimport { emitCatalogQueryIndexEvent } from '@open-mercato/core/modules/catalog/commands/shared'\nimport { SalesChannel } from '@open-mercato/core/modules/sales/data/entities'\nimport type { CustomFieldDefinition } from '@open-mercato/shared/modules/entities'\nimport {\n buildAkeneoFieldsetCode,\n buildProductFieldMappings,\n dedupeStrings,\n labelFromLocalizedRecord,\n safeRecord,\n slugifyAkeneoCode,\n type AkeneoAttribute,\n type AkeneoCategory,\n type AkeneoCustomFieldKind,\n type AkeneoDataMapping,\n type AkeneoFamily,\n type AkeneoFamilyVariant,\n type AkeneoFieldsetMapping,\n type AkeneoProduct,\n type AkeneoProductMappingSettings,\n type AkeneoReconciliationSettings,\n type AkeneoValues,\n buildDefaultAkeneoMapping,\n} from './shared'\nimport type { AkeneoClient } from './client'\nimport { inferAkeneoProductMapping } from './inference'\nimport { normalizeMarkdownText } from './markdown'\n\ntype ImportScope = {\n organizationId: string\n tenantId: string\n}\n\ntype UpsertResult = {\n localId: string\n action: 'create' | 'update' | 'skip'\n}\n\ntype CustomFieldSyncItem = {\n externalId: string\n action: 'create' | 'update' | 'skip'\n data: Record<string, unknown>\n}\n\ntype ResolvedHierarchy = {\n rootExternalId: string\n family: string | null\n familyVariantCode: string | null\n rootValues: AkeneoValues\n leafValues: AkeneoValues\n mergedValues: AkeneoValues\n categories: string[]\n parentChain: string[]\n associationSource: AkeneoProduct\n axisCodes: string[]\n}\n\ntype DesiredOffer = {\n externalId: string\n channelCode: string\n channelId: string\n akeneoChannel: string | null\n title: string\n description: string | null\n prices: DesiredPrice[]\n}\n\ntype DesiredPrice = {\n externalId: string\n priceKindCode: string\n priceKindId: string\n channelId: string\n currencyCode: string\n amount: number\n variantId: string\n}\n\ntype MediaReference = {\n codeOrUrl: string\n fileNameHint: string | null\n mimeTypeHint: string | null\n}\n\ntype DesiredAsset = {\n externalId: string\n entityId: string\n recordId: string\n kind: 'image' | 'file'\n remote: MediaReference\n}\n\ntype AkeneoFieldsetPlan = {\n product: CustomFieldsetDefinition | null\n variant: CustomFieldsetDefinition | null\n}\n\nconst PRODUCT_ENTITY_ID = 'catalog:catalog_product'\nconst VARIANT_ENTITY_ID = 'catalog:catalog_product_variant'\n\nexport function readPreferredAkeneoValue(\n values: AkeneoValues | undefined | null,\n attributeCode: string,\n locale: string,\n channel: string | null,\n): unknown {\n const entries = Array.isArray(values?.[attributeCode]) ? values?.[attributeCode] ?? [] : []\n if (entries.length === 0) return null\n\n const normalize = (value: string | null | undefined) => (typeof value === 'string' && value.trim().length > 0 ? value.trim() : null)\n const wantedLocale = normalize(locale)\n const wantedChannel = normalize(channel)\n\n const eligibleEntries = entries.filter((entry) => {\n const entryLocale = normalize(entry.locale)\n const entryChannel = normalize(entry.scope)\n const localeMatches = wantedLocale ? entryLocale === wantedLocale || entryLocale === null : true\n const channelMatches = wantedChannel ? entryChannel === wantedChannel || entryChannel === null : true\n return localeMatches && channelMatches\n })\n\n const scored = eligibleEntries\n .map((entry) => {\n const entryLocale = normalize(entry.locale)\n const entryChannel = normalize(entry.scope)\n let score = 0\n if (wantedLocale && entryLocale === wantedLocale) score += 4\n else if (!wantedLocale && !entryLocale) score += 2\n else if (!entryLocale) score += 1\n if (wantedChannel && entryChannel === wantedChannel) score += 4\n else if (!wantedChannel && !entryChannel) score += 2\n else if (!entryChannel) score += 1\n return { score, entry }\n })\n .sort((left, right) => right.score - left.score)\n\n return scored[0]?.entry?.data ?? null\n}\n\nexport function readLayeredAkeneoValue(\n layers: AkeneoValues[],\n attributeCode: string,\n locale: string,\n channel: string | null,\n): unknown {\n for (const layer of layers) {\n const value = readPreferredAkeneoValue(layer, attributeCode, locale, channel)\n if (value !== null && value !== undefined && !(typeof value === 'string' && value.trim().length === 0)) {\n return value\n }\n }\n return null\n}\n\nfunction coerceString(value: unknown): string | null {\n if (typeof value === 'string' && value.trim().length > 0) return value.trim()\n if (typeof value === 'number' && Number.isFinite(value)) return String(value)\n return null\n}\n\nexport function normalizeAkeneoSelectValue(\n value: unknown,\n optionLabels: Map<string, string>,\n): string | null {\n if (Array.isArray(value)) {\n const labels = value\n .map((entry) => normalizeAkeneoSelectValue(entry, optionLabels))\n .filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n return labels.length > 0 ? labels.join(', ') : null\n }\n\n const raw = coerceString(value)\n if (!raw) return null\n return optionLabels.get(raw) ?? raw\n}\n\nexport function filterAkeneoAttributeMappingsByAvailableAttributes<T extends { attributeCode: string }>(\n mappings: T[],\n availableAttributeCodes: string[],\n): T[] {\n const allowed = new Set(\n availableAttributeCodes\n .map((code) => code.trim())\n .filter((code) => code.length > 0),\n )\n if (allowed.size === 0) return []\n return mappings.filter((mapping) => allowed.has(mapping.attributeCode))\n}\n\ntype ExistingFieldsetDefinition = {\n key: string\n description: string | null\n fieldset: string | null\n fieldsets: string[]\n}\n\ntype DesiredFieldsetAssignment = {\n key: string\n fieldsets: string[]\n}\n\ntype EntityFieldsetAssignments = {\n fieldsets: CustomFieldsetDefinition[]\n fieldsetsByKey: Map<string, string[]>\n}\n\ntype ResolvedGlobalFieldsetAssignments = {\n product: EntityFieldsetAssignments\n variant: EntityFieldsetAssignments\n}\n\ntype AkeneoOptionSchemaMetadata = {\n familyCode: string | null\n familyVariantCode: string | null\n attributeCodes: string[]\n richAttributes: Record<string, Record<string, unknown>>\n}\n\nexport function resolveAkeneoFieldKeysToDetach(\n definitions: ExistingFieldsetDefinition[],\n desiredFieldKeys: string[],\n fieldsetCode: string | null,\n): string[] {\n if (!fieldsetCode) return []\n const desired = new Set(\n desiredFieldKeys\n .map((key) => normalizeFieldKey(key))\n .filter((key) => key.length > 0),\n )\n\n return definitions\n .filter((definition) => definition.fieldset === fieldsetCode || definition.fieldsets.includes(fieldsetCode))\n .filter((definition) => typeof definition.description === 'string' && definition.description.startsWith('Akeneo attribute '))\n .filter((definition) => !desired.has(normalizeFieldKey(definition.key)))\n .map((definition) => definition.key)\n}\n\nexport function resolveAkeneoFieldsetMemberships(\n currentFieldsets: string[],\n fieldsetCode: string | null,\n): string[] {\n return dedupeStrings([\n ...currentFieldsets\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n ...(fieldsetCode ? [fieldsetCode] : []),\n ])\n}\n\nfunction readConfiguredFieldsets(config: Record<string, unknown> | null | undefined): string[] {\n const configured = Array.isArray(config?.fieldsets)\n ? config.fieldsets.filter((entry): entry is string => typeof entry === 'string')\n : []\n const normalized = dedupeStrings(\n configured\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n )\n if (normalized.length > 0) return normalized\n const legacy = typeof config?.fieldset === 'string' ? config.fieldset.trim() : ''\n return legacy.length > 0 ? [legacy] : []\n}\n\nfunction clampString(value: string | null, maxLength: number): string | null {\n if (!value) return null\n return value.length > maxLength ? value.slice(0, maxLength).trim() : value\n}\n\nfunction coerceMetricAmount(value: unknown): number | null {\n const record = safeRecord(value)\n const amount = record?.amount\n if (typeof amount === 'string' && amount.trim().length > 0) {\n const numeric = Number(amount)\n return Number.isFinite(numeric) ? numeric : null\n }\n if (typeof amount === 'number' && Number.isFinite(amount)) return amount\n if (typeof value === 'number' && Number.isFinite(value)) return value\n return null\n}\n\nfunction coerceNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length > 0) {\n const numeric = Number(value)\n return Number.isFinite(numeric) ? numeric : null\n }\n return null\n}\n\nfunction coerceBoolean(value: unknown): boolean | null {\n if (typeof value === 'boolean') return value\n if (typeof value === 'string') {\n const lowered = value.trim().toLowerCase()\n if (lowered === 'true' || lowered === '1' || lowered === 'yes') return true\n if (lowered === 'false' || lowered === '0' || lowered === 'no') return false\n }\n return null\n}\n\nfunction mergeValueLayers(...layers: Array<AkeneoValues | undefined | null>): AkeneoValues {\n const merged: AkeneoValues = {}\n for (const layer of layers) {\n if (!layer) continue\n for (const [key, value] of Object.entries(layer)) {\n merged[key] = Array.isArray(value) ? value : []\n }\n }\n return merged\n}\n\nfunction normalizeFieldKey(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 100)\n}\n\nfunction readAkeneoOptionSchemaMetadata(value: unknown): AkeneoOptionSchemaMetadata | null {\n const parsedValue = typeof value === 'string'\n ? (() => {\n try {\n return JSON.parse(value) as unknown\n } catch {\n return null\n }\n })()\n : value\n const metadata = safeRecord(parsedValue)\n if (!metadata) return null\n\n const familyCode = typeof metadata.familyCode === 'string' && metadata.familyCode.trim().length > 0\n ? metadata.familyCode.trim()\n : null\n const familyVariantCode = typeof metadata.familyVariantCode === 'string' && metadata.familyVariantCode.trim().length > 0\n ? metadata.familyVariantCode.trim()\n : null\n const attributeCodes = Array.isArray(metadata.attributeCodes)\n ? dedupeStrings(metadata.attributeCodes.filter((entry): entry is string => typeof entry === 'string'))\n : []\n const richAttributes = safeRecord(metadata.richAttributes) ?? {}\n\n if (!familyCode && !familyVariantCode) return null\n if (attributeCodes.length === 0) return null\n\n return {\n familyCode,\n familyVariantCode,\n attributeCodes,\n richAttributes: Object.fromEntries(\n Object.entries(richAttributes)\n .filter(([, entry]) => Boolean(safeRecord(entry))),\n ) as Record<string, Record<string, unknown>>,\n }\n}\n\nfunction mapAkeneoAttributeInputType(attributeType: string): 'select' | 'text' | 'textarea' | 'number' | null {\n if (attributeType === 'pim_catalog_simpleselect' || attributeType === 'akeneo_reference_entity' || attributeType === 'akeneo_reference_entity_collection') {\n return 'select'\n }\n if (attributeType === 'pim_catalog_multiselect') return 'select'\n if (attributeType === 'pim_catalog_text') return 'text'\n if (attributeType === 'pim_catalog_textarea') return 'textarea'\n if (\n attributeType === 'pim_catalog_number'\n || attributeType === 'pim_catalog_metric'\n || attributeType === 'pim_catalog_price_collection'\n ) {\n return 'number'\n }\n return null\n}\n\nfunction mapAkeneoAttributeToCustomFieldKind(attribute: AkeneoAttribute, preferredKind?: AkeneoCustomFieldKind | null): AkeneoCustomFieldKind | null {\n if (preferredKind) return preferredKind\n if (attribute.type === 'pim_catalog_boolean') return 'boolean'\n if (attribute.type === 'pim_catalog_number') {\n return attribute.decimals_allowed === false ? 'integer' : 'float'\n }\n if (attribute.type === 'pim_catalog_metric') return 'float'\n if (\n attribute.type === 'pim_catalog_simpleselect'\n || attribute.type === 'pim_catalog_multiselect'\n || attribute.type === 'akeneo_reference_entity'\n || attribute.type === 'akeneo_reference_entity_collection'\n ) {\n return 'select'\n }\n if (attribute.type === 'pim_catalog_textarea') return 'multiline'\n if (attribute.type === 'pim_catalog_text') return 'text'\n if (attribute.type === 'pim_catalog_date') return 'text'\n return null\n}\n\nfunction buildValidationRules(attribute: AkeneoAttribute): Array<{ rule: string; param?: unknown }> {\n const rules: Array<{ rule: string; param?: unknown }> = []\n if (attribute.is_required_for_completeness) rules.push({ rule: 'required' })\n if (typeof attribute.max_characters === 'number' && Number.isFinite(attribute.max_characters)) {\n rules.push({ rule: 'maxLength', param: attribute.max_characters })\n }\n if (attribute.validation_rule === 'regexp' && typeof attribute.validation_regexp === 'string' && attribute.validation_regexp.trim().length > 0) {\n rules.push({ rule: 'pattern', param: attribute.validation_regexp.trim() })\n }\n const minimumValue = coerceNumber(attribute.minimum_value)\n if (minimumValue !== null) rules.push({ rule: 'min', param: minimumValue })\n const maximumValue = coerceNumber(attribute.maximum_value)\n if (maximumValue !== null) rules.push({ rule: 'max', param: maximumValue })\n return rules\n}\n\nfunction buildAttributeMetadata(attribute: AkeneoAttribute, locale: string): Record<string, unknown> {\n return {\n provider: 'akeneo',\n attributeCode: attribute.code,\n type: attribute.type,\n label: labelFromLocalizedRecord(attribute.labels ?? null, locale, attribute.code),\n groupCode: attribute.group ?? null,\n groupLabel: attribute.group_labels ? labelFromLocalizedRecord(attribute.group_labels, locale, attribute.group ?? 'Akeneo') : null,\n localizable: Boolean(attribute.localizable),\n scopable: Boolean(attribute.scopable),\n isRequiredForCompleteness: Boolean(attribute.is_required_for_completeness),\n unique: Boolean(attribute.unique),\n useableAsGridFilter: Boolean(attribute.useable_as_grid_filter),\n validationRule: attribute.validation_rule ?? null,\n validationRegexp: attribute.validation_regexp ?? null,\n decimalsAllowed: attribute.decimals_allowed ?? null,\n negativeAllowed: attribute.negative_allowed ?? null,\n minimumValue: attribute.minimum_value ?? null,\n maximumValue: attribute.maximum_value ?? null,\n metricFamily: attribute.metric_family ?? null,\n defaultMetricUnit: attribute.default_metric_unit ?? null,\n referenceDataName: attribute.reference_data_name ?? null,\n }\n}\n\nfunction familyRequiresAttribute(family: AkeneoFamily, attributeCode: string): boolean {\n const requirements = family.attribute_requirements\n if (!requirements || typeof requirements !== 'object') return false\n return Object.values(requirements).some((codes) => Array.isArray(codes) && codes.includes(attributeCode))\n}\n\nfunction parsePriceCollection(value: unknown): Array<{ currencyCode: string; amount: number }> {\n if (!Array.isArray(value)) return []\n return value\n .map((entry) => {\n const record = safeRecord(entry)\n const currencyCode = typeof record?.currency === 'string' ? record.currency.trim().toUpperCase() : ''\n const amount = coerceNumber(record?.amount)\n if (!currencyCode || amount === null) return null\n return { currencyCode, amount }\n })\n .filter((entry): entry is { currencyCode: string; amount: number } => Boolean(entry))\n}\n\nfunction collectMediaReferences(value: unknown): MediaReference[] {\n const values = Array.isArray(value) ? value : value === null || value === undefined ? [] : [value]\n return values\n .map((entry) => {\n if (typeof entry === 'string' && entry.trim().length > 0) {\n return {\n codeOrUrl: entry.trim(),\n fileNameHint: null,\n mimeTypeHint: null,\n }\n }\n const record = safeRecord(entry)\n if (!record) return null\n const linkRecord = safeRecord(record._links)\n const downloadRecord = safeRecord(linkRecord?.download)\n const codeOrUrl = coerceString(record.code)\n ?? coerceString(record.download_link)\n ?? coerceString(record.href)\n ?? coerceString(downloadRecord?.href)\n if (!codeOrUrl) return null\n return {\n codeOrUrl,\n fileNameHint: coerceString(record.original_filename) ?? coerceString(record.file_path),\n mimeTypeHint: coerceString(record.mime_type),\n }\n })\n .filter((entry): entry is MediaReference => Boolean(entry))\n}\n\nexport function resolveAkeneoMediaTarget(params: {\n mappingTarget: 'product' | 'variant'\n attributeCode: string\n variantAttributeCodes: string[]\n productScopedValue: unknown\n variantScopedValue: unknown\n}): 'product' | 'variant' {\n const hasProductValue = params.productScopedValue !== null && params.productScopedValue !== undefined\n const hasVariantValue = params.variantScopedValue !== null && params.variantScopedValue !== undefined\n\n if (params.variantAttributeCodes.includes(params.attributeCode)) {\n return 'variant'\n }\n if (hasProductValue) {\n return 'product'\n }\n if (hasVariantValue) {\n return 'variant'\n }\n return params.mappingTarget\n}\n\nfunction resolveCustomFieldValue(value: unknown, attribute: AkeneoAttribute, kind: AkeneoCustomFieldKind): unknown {\n if (kind === 'boolean') return coerceBoolean(value)\n if (kind === 'integer') return coerceNumber(value) === null ? null : Math.trunc(Number(value))\n if (kind === 'float') return attribute.type === 'pim_catalog_metric' ? coerceMetricAmount(value) : coerceNumber(value)\n if (kind === 'multiline') return normalizeMarkdownText(coerceString(value))\n if (kind === 'text') {\n if (typeof value === 'string') return normalizeMarkdownText(value)\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n return value ? JSON.stringify(value) : null\n }\n if (kind === 'select') {\n if (Array.isArray(value)) {\n const items = value.map((entry) => coerceString(entry)).filter((entry): entry is string => Boolean(entry))\n return items.length > 0 ? items : null\n }\n return coerceString(value)\n }\n return null\n}\n\nfunction relationTypeFromAssociation(associationType: string): 'bundle' | 'grouped' {\n const normalized = associationType.trim().toLowerCase()\n return normalized.includes('pack') || normalized.includes('bundle') ? 'bundle' : 'grouped'\n}\n\nfunction titleizeCode(value: string): string {\n return value\n .trim()\n .replace(/[_-]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .replace(/\\b\\w/g, (char) => char.toUpperCase())\n}\n\nfunction findFieldsetMapping(\n mappings: AkeneoFieldsetMapping[],\n target: 'product' | 'variant',\n sourceType: 'family' | 'familyVariant',\n sourceCode: string | null,\n): AkeneoFieldsetMapping | null {\n if (!sourceCode) return null\n return mappings.find((entry) => (\n entry.target === target\n && entry.sourceType === sourceType\n && entry.sourceCode === sourceCode\n )) ?? null\n}\n\nfunction applyFieldsetOverride(\n fallback: CustomFieldsetDefinition | null,\n override: AkeneoFieldsetMapping | null,\n): CustomFieldsetDefinition | null {\n if (!fallback || !override) return fallback\n return {\n ...fallback,\n code: override.fieldsetCode,\n label: override.fieldsetLabel,\n description: override.description ?? fallback.description,\n }\n}\n\nfunction collectFieldsetGroups(attributes: AkeneoAttribute[], locale: string): NonNullable<CustomFieldsetDefinition['groups']> | undefined {\n const groups = dedupeStrings(attributes.map((attribute) => attribute.group))\n .map((groupCode) => {\n const attribute = attributes.find((entry) => entry.group === groupCode)\n return {\n code: normalizeFieldKey(groupCode),\n title: attribute?.group_labels\n ? labelFromLocalizedRecord(attribute.group_labels, locale, groupCode)\n : titleizeCode(groupCode),\n }\n })\n .filter((group) => group.code.length > 0)\n return groups.length > 0 ? groups : undefined\n}\n\nfunction collectFieldsetGroupsFromSchemaMetadata(\n metadata: AkeneoOptionSchemaMetadata,\n): NonNullable<CustomFieldsetDefinition['groups']> | undefined {\n const groups = new Map<string, { code: string; title: string }>()\n for (const attributeCode of metadata.attributeCodes) {\n const attribute = safeRecord(metadata.richAttributes[attributeCode])\n const groupCode = typeof attribute?.groupCode === 'string' && attribute.groupCode.trim().length > 0\n ? attribute.groupCode.trim()\n : null\n if (!groupCode) continue\n const normalizedCode = normalizeFieldKey(groupCode)\n if (!normalizedCode || groups.has(normalizedCode)) continue\n const title = typeof attribute?.groupLabel === 'string' && attribute.groupLabel.trim().length > 0\n ? attribute.groupLabel.trim()\n : titleizeCode(groupCode)\n groups.set(normalizedCode, { code: normalizedCode, title })\n }\n return groups.size > 0 ? Array.from(groups.values()) : undefined\n}\n\nfunction buildFieldsetPlanFromOptionSchema(params: {\n schema: Pick<CatalogOptionSchemaTemplate, 'code' | 'name' | 'description'>\n metadata: AkeneoOptionSchemaMetadata\n locale: string\n fieldsetMappings: AkeneoFieldsetMapping[]\n}): { target: 'product' | 'variant'; fieldset: CustomFieldsetDefinition | null } {\n const target = params.metadata.familyVariantCode ? 'variant' : 'product'\n const sourceType = params.metadata.familyVariantCode ? 'familyVariant' : 'family'\n const sourceCode = params.metadata.familyVariantCode ?? params.metadata.familyCode\n const fallbackCode = buildAkeneoFieldsetCode(target, sourceCode)\n const override = findFieldsetMapping(params.fieldsetMappings, target, sourceType, sourceCode)\n const fallbackLabel = params.schema.name?.trim().length\n ? params.schema.name.trim()\n : titleizeCode(sourceCode ?? `Akeneo ${target}`)\n const fallbackDescription = params.schema.description?.trim().length\n ? params.schema.description.trim()\n : sourceType === 'familyVariant' && params.metadata.familyVariantCode\n ? `Akeneo family variant ${params.metadata.familyVariantCode}`\n : params.metadata.familyCode\n ? `Akeneo family ${params.metadata.familyCode}`\n : `Akeneo ${target} attributes`\n const fieldsetCode = override?.fieldsetCode ?? fallbackCode\n if (!fieldsetCode) {\n return { target, fieldset: null }\n }\n\n return {\n target,\n fieldset: {\n code: fieldsetCode,\n label: override?.fieldsetLabel ?? fallbackLabel,\n description: override?.description ?? fallbackDescription,\n groups: collectFieldsetGroupsFromSchemaMetadata(params.metadata),\n },\n }\n}\n\nfunction buildFieldsetPlan(params: {\n family: AkeneoFamily | null\n familyVariant: AkeneoFamilyVariant | null\n productAttributes: AkeneoAttribute[]\n variantAttributes: AkeneoAttribute[]\n locale: string\n fieldsetMappings: AkeneoFieldsetMapping[]\n}): AkeneoFieldsetPlan {\n const productFallbackCode = buildAkeneoFieldsetCode('product', params.family?.code ?? null)\n const variantFallbackCode = buildAkeneoFieldsetCode('variant', params.familyVariant?.code ?? params.family?.code ?? null)\n\n const productFallback = productFallbackCode && params.productAttributes.length > 0\n ? {\n code: productFallbackCode,\n label: labelFromLocalizedRecord(params.family?.labels ?? null, params.locale, params.family?.code ?? 'Akeneo product'),\n description: params.family\n ? `Akeneo family ${params.family.code}`\n : 'Akeneo-imported product attributes',\n groups: collectFieldsetGroups(params.productAttributes, params.locale),\n }\n : null\n const variantFallback = variantFallbackCode && params.variantAttributes.length > 0\n ? {\n code: variantFallbackCode,\n label: labelFromLocalizedRecord(\n params.familyVariant?.labels ?? params.family?.labels ?? null,\n params.locale,\n params.familyVariant?.code ?? params.family?.code ?? 'Akeneo variant',\n ),\n description: params.familyVariant?.code\n ? `Akeneo family variant ${params.familyVariant.code}`\n : params.family?.code\n ? `Akeneo variant attributes for family ${params.family.code}`\n : 'Akeneo-imported variant attributes',\n groups: collectFieldsetGroups(params.variantAttributes, params.locale),\n }\n : null\n\n return {\n product: applyFieldsetOverride(\n productFallback,\n findFieldsetMapping(params.fieldsetMappings, 'product', 'family', params.family?.code ?? null),\n ),\n variant: applyFieldsetOverride(\n variantFallback,\n findFieldsetMapping(params.fieldsetMappings, 'variant', 'familyVariant', params.familyVariant?.code ?? null)\n ?? findFieldsetMapping(params.fieldsetMappings, 'variant', 'family', params.family?.code ?? null),\n ),\n }\n}\n\nfunction dedupeCustomFieldMappings(items: Array<{ attributeCode: string; fieldKey: string; target: 'product' | 'variant'; kind?: AkeneoCustomFieldKind | null; skip?: boolean }>) {\n const seen = new Set<string>()\n return items.filter((item) => {\n const key = `${item.target}:${item.attributeCode}:${item.fieldKey}:${item.skip === true ? 'skip' : 'import'}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nfunction dedupeMediaMappings(items: Array<{ attributeCode: string; target: 'product' | 'variant'; kind: 'image' | 'file' }>) {\n const seen = new Set<string>()\n return items.filter((item) => {\n const key = `${item.target}:${item.kind}:${item.attributeCode}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n}\n\nfunction collectValueScopes(layers: AkeneoValues[], attributeCode: string): Array<string | null> {\n const seen = new Set<string>()\n const scopes: Array<string | null> = []\n for (const layer of layers) {\n const entries = Array.isArray(layer?.[attributeCode]) ? layer[attributeCode] : []\n for (const entry of entries) {\n const scope = coerceString(entry?.scope)\n const key = scope ?? '__null__'\n if (seen.has(key)) continue\n seen.add(key)\n scopes.push(scope)\n }\n }\n return scopes\n}\n\nfunction resolveImportedAkeneoChannels(settings: AkeneoProductMappingSettings): string[] {\n return dedupeStrings([\n ...(settings.channels ?? []),\n settings.channel,\n ])\n}\n\nfunction shouldImportAkeneoChannel(settings: AkeneoProductMappingSettings, akeneoChannel: string | null): boolean {\n if (!akeneoChannel) return true\n if (settings.importAllChannels) return true\n const selectedChannels = resolveImportedAkeneoChannels(settings)\n if (selectedChannels.length === 0) return true\n return selectedChannels.includes(akeneoChannel)\n}\n\nexport async function createAkeneoImporter(client: AkeneoClient, scope: ImportScope) {\n const container = await createRequestContainer()\n const em = container.resolve('em') as EntityManager\n const commandBus = container.resolve('commandBus') as CommandBus\n const dataEngine = container.resolve('dataEngine') as DataEngine\n const externalIdMappingService = container.resolve('externalIdMappingService') as ExternalIdMappingService\n let cacheService: { deleteByTags?: (tags: string[]) => Promise<void> } | null = null\n try {\n cacheService = container.resolve('cache') as { deleteByTags?: (tags: string[]) => Promise<void> }\n } catch {\n cacheService = null\n }\n const categoryCache = new Map<string, Promise<string | null>>()\n const optionSchemaCache = new Map<string, Promise<UpsertResult | null>>()\n const channelCache = new Map<string, Promise<{ id: string; code: string } | null>>()\n const priceKindCache = new Map<string, Promise<{ id: string; code: string; displayMode: string } | null>>()\n const customFieldSyncCache = new Map<string, Promise<CustomFieldSyncItem[]>>()\n const globalFieldsetAssignmentCache = new Map<string, Promise<ResolvedGlobalFieldsetAssignments>>()\n const preferredChannelCodeCache = new Map<string, Promise<string | null>>()\n const preferredPriceKindCodeCache = new Map<string, Promise<string | null>>()\n const attributeOptionLabelCache = new Map<string, Promise<Map<string, string>>>()\n const defaultProductSettings = buildDefaultAkeneoMapping('products').settings?.products\n\n function buildCommandContext(): CommandRuntimeContext {\n return {\n container,\n auth: null,\n organizationScope: {\n selectedId: scope.organizationId,\n filterIds: [scope.organizationId],\n allowedIds: [scope.organizationId],\n tenantId: scope.tenantId,\n },\n selectedOrganizationId: scope.organizationId,\n organizationIds: [scope.organizationId],\n }\n }\n\n async function emitAttachmentCrudChange(\n action: 'created' | 'updated' | 'deleted',\n attachment: Attachment,\n ): Promise<void> {\n await emitCrudSideEffects({\n dataEngine,\n action,\n entity: attachment,\n identifiers: {\n id: attachment.id,\n organizationId: attachment.organizationId ?? null,\n tenantId: attachment.tenantId ?? null,\n },\n events: attachmentCrudEvents,\n indexer: attachmentCrudIndexer,\n })\n await dataEngine.flushOrmEntityChanges()\n }\n\n async function executeCommand<TResult>(commandId: string, input: Record<string, unknown>): Promise<TResult> {\n try {\n const executed = await commandBus.execute<Record<string, unknown>, TResult>(commandId, {\n input,\n ctx: buildCommandContext(),\n })\n return executed.result\n } catch (error) {\n const message = error instanceof Error ? error.message : JSON.stringify(error)\n throw new Error(`${commandId} failed: ${message}`)\n }\n }\n\n async function lookupProductBySku(sku: string | null): Promise<string | null> {\n if (!sku) return null\n const product = await findOneWithDecryption(\n em,\n CatalogProduct,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n sku,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n return product?.id ?? null\n }\n\n async function lookupVariantBySku(sku: string | null, productId?: string | null): Promise<string | null> {\n if (!sku) return null\n const variant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n ...(productId ? { product: productId } : {}),\n sku,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n return variant?.id ?? null\n }\n\n async function resolveExistingProductId(productExternalId: string, sku: string | null): Promise<string | null> {\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product', productExternalId, scope)\n if (mappedId) {\n const mappedProduct = await findOneWithDecryption(\n em,\n CatalogProduct,\n {\n id: mappedId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (mappedProduct) return mappedProduct.id\n }\n\n return lookupProductBySku(sku)\n }\n\n async function resolveExistingVariantId(\n variantExternalId: string,\n sku: string | null,\n productId: string,\n ): Promise<string | null> {\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_variant', variantExternalId, scope)\n if (mappedId) {\n const mappedVariant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n {\n id: mappedId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product: productId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (mappedVariant) return mappedVariant.id\n }\n\n return lookupVariantBySku(sku, productId)\n }\n\n async function resolveCategoryId(code: string | null | undefined, locale: string): Promise<string | null> {\n if (!code) return null\n if (!categoryCache.has(code)) {\n categoryCache.set(code, (async () => {\n const mapped = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_category', code, scope)\n if (mapped) return mapped\n\n const existing = await findOneWithDecryption(\n em,\n CatalogProductCategory,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n slug: slugifyAkeneoCode(code),\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (existing) {\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_category', existing.id, code, scope)\n return existing.id\n }\n\n const remote = await client.getCategory(code)\n if (!remote) return null\n const result = await upsertCategory(remote, locale)\n return result.localId\n })())\n }\n return categoryCache.get(code) ?? null\n }\n\n async function resolveChannel(code: string, options?: { createIfMissing?: boolean; label?: string | null }): Promise<{ id: string; code: string } | null> {\n const normalizedCode = code.trim().toLowerCase()\n if (!normalizedCode) return null\n const cacheKey = `${normalizedCode}:${options?.createIfMissing ? 'create' : 'read'}:${options?.label ?? ''}`\n if (!channelCache.has(cacheKey)) {\n channelCache.set(cacheKey, (async () => {\n const channel = await findOneWithDecryption(em, SalesChannel, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: normalizedCode,\n deletedAt: null,\n isActive: true,\n }, undefined, scope)\n if (channel) {\n return { id: channel.id, code: channel.code ?? normalizedCode }\n }\n if (!options?.createIfMissing) return null\n\n const created = await executeCommand<{ channelId: string }>('sales.channels.create', {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: options.label?.trim() || titleizeCode(normalizedCode),\n code: normalizedCode,\n metadata: {\n source: 'akeneo',\n autoCreatedBy: 'sync_akeneo',\n },\n isActive: true,\n })\n return {\n id: created.channelId,\n code: normalizedCode,\n }\n })())\n }\n return channelCache.get(cacheKey) ?? null\n }\n\n async function resolvePriceKind(code: string): Promise<{ id: string; code: string; displayMode: string } | null> {\n const normalizedCode = code.trim().toLowerCase()\n if (!normalizedCode) return null\n if (!priceKindCache.has(normalizedCode)) {\n priceKindCache.set(normalizedCode, (async () => {\n const priceKind = await findOneWithDecryption(\n em,\n CatalogPriceKind,\n {\n tenantId: scope.tenantId,\n code: normalizedCode,\n deletedAt: null,\n isActive: true,\n },\n undefined,\n scope,\n )\n return priceKind ? { id: priceKind.id, code: priceKind.code, displayMode: priceKind.displayMode } : null\n })())\n }\n return priceKindCache.get(normalizedCode) ?? null\n }\n\n async function resolvePreferredLocalChannelCode(): Promise<string | null> {\n const cacheKey = 'preferred'\n if (!preferredChannelCodeCache.has(cacheKey)) {\n preferredChannelCodeCache.set(cacheKey, (async () => {\n const channels = await findWithDecryption(em, SalesChannel, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n orderBy: { createdAt: 'asc' },\n }, scope)\n const preferredCodes = ['web', 'online', 'ecommerce', 'default']\n for (const preferredCode of preferredCodes) {\n const match = channels.find((channel) => (channel.code ?? '').trim().toLowerCase() === preferredCode)\n if (match?.code) return match.code\n }\n return channels.find((channel) => typeof channel.code === 'string' && channel.code.trim().length > 0)?.code ?? null\n })())\n }\n return preferredChannelCodeCache.get(cacheKey) ?? null\n }\n\n async function resolvePreferredPriceKindCode(): Promise<string | null> {\n const cacheKey = 'preferred'\n if (!preferredPriceKindCodeCache.has(cacheKey)) {\n preferredPriceKindCodeCache.set(cacheKey, (async () => {\n const priceKinds = await findWithDecryption(em, CatalogPriceKind, {\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n orderBy: { createdAt: 'asc' },\n }, scope)\n const preferredCodes = ['regular', 'sale', 'base', 'default']\n for (const preferredCode of preferredCodes) {\n const match = priceKinds.find((priceKind) => priceKind.code.trim().toLowerCase() === preferredCode)\n if (match) return match.code\n }\n return priceKinds[0]?.code ?? null\n })())\n }\n return preferredPriceKindCodeCache.get(cacheKey) ?? null\n }\n\n async function ensureEntityFieldsetConfig(entityId: string, fieldset: CustomFieldsetDefinition | null): Promise<void> {\n if (!fieldset) return\n let config = await findOneWithDecryption(em, CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!config) {\n config = em.create(CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n }\n\n const existing = normalizeEntityFieldsetConfig(config.configJson ?? {})\n const remaining = existing.fieldsets.filter((entry) => entry.code !== fieldset.code)\n config.configJson = {\n fieldsets: [...remaining, fieldset],\n singleFieldsetPerRecord: true,\n }\n config.isActive = true\n config.deletedAt = null\n config.updatedAt = new Date()\n em.persist(config)\n await em.flush()\n }\n\n async function upsertCategory(category: AkeneoCategory, locale: string): Promise<UpsertResult> {\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_category', category.code, scope)\n const existingId = mappedId\n ?? (await findOneWithDecryption(\n em,\n CatalogProductCategory,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n slug: slugifyAkeneoCode(category.code),\n deletedAt: null,\n },\n undefined,\n scope,\n ))?.id\n ?? null\n\n const parentId = category.parent ? await resolveCategoryId(category.parent, locale) : null\n const input = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: labelFromLocalizedRecord(category.labels ?? null, locale, category.code),\n slug: slugifyAkeneoCode(category.code),\n description: undefined,\n parentId,\n isActive: true,\n }\n\n if (existingId) {\n await executeCommand('catalog.categories.update', {\n id: existingId,\n ...input,\n })\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_category', existingId, category.code, scope)\n return { localId: existingId, action: 'update' }\n }\n\n const created = await executeCommand<{ categoryId: string }>('catalog.categories.create', input)\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_category', created.categoryId, category.code, scope)\n return { localId: created.categoryId, action: 'create' }\n }\n\n async function buildOptionSchemaDefinition(attribute: AkeneoAttribute, family: AkeneoFamily, locale: string) {\n const inputType = mapAkeneoAttributeInputType(attribute.type)\n if (!inputType) return null\n\n const definition: Record<string, unknown> = {\n code: slugifyAkeneoCode(attribute.code),\n label: labelFromLocalizedRecord(attribute.labels ?? null, locale, attribute.code),\n description: typeof attribute.group === 'string' ? `Akeneo group: ${attribute.group}` : undefined,\n inputType,\n isRequired: familyRequiresAttribute(family, attribute.code),\n }\n\n if (attribute.type === 'pim_catalog_multiselect') {\n definition.isMultiple = true\n }\n\n if (inputType === 'select' && (attribute.type === 'pim_catalog_simpleselect' || attribute.type === 'pim_catalog_multiselect')) {\n const options = await client.listAttributeOptions(attribute.code).catch(() => [])\n definition.choices = options.map((option) => ({\n code: slugifyAkeneoCode(option.code),\n label: labelFromLocalizedRecord(option.labels ?? null, locale, option.code),\n }))\n }\n\n return definition\n }\n\n async function getAttributeOptionLabels(attributeCode: string, locale: string): Promise<Map<string, string>> {\n const cacheKey = `${attributeCode}:${locale}`\n if (!attributeOptionLabelCache.has(cacheKey)) {\n attributeOptionLabelCache.set(cacheKey, (async () => {\n const options = await client.listAttributeOptions(attributeCode).catch(() => [])\n return new Map(\n options.map((option) => [\n option.code,\n labelFromLocalizedRecord(option.labels ?? null, locale, option.code),\n ]),\n )\n })())\n }\n return attributeOptionLabelCache.get(cacheKey) ?? new Map<string, string>()\n }\n\n async function ensureOptionSchemaForFamily(\n family: AkeneoFamily,\n familyVariant: AkeneoFamilyVariant | null,\n includeTextAttributes: boolean,\n includeNumericAttributes: boolean,\n locale: string,\n attributeCodesOverride?: string[] | null,\n ): Promise<UpsertResult | null> {\n const requestedAttributeCodes = Array.isArray(attributeCodesOverride)\n ? dedupeStrings(attributeCodesOverride)\n : null\n const cacheKey = `${family.code}:${familyVariant?.code ?? 'family'}:${locale}:${includeTextAttributes}:${includeNumericAttributes}:${requestedAttributeCodes ? requestedAttributeCodes.join('|') : 'all'}`\n if (!optionSchemaCache.has(cacheKey)) {\n optionSchemaCache.set(cacheKey, (async () => {\n if (requestedAttributeCodes && requestedAttributeCodes.length === 0) {\n return null\n }\n const externalId = familyVariant?.code ?? family.code\n const schemaCode = slugifyAkeneoCode(`akeneo-${externalId}`)\n const mappedId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_option_schema', externalId, scope)\n const existing = mappedId\n ? await findOneWithDecryption(em, CatalogOptionSchemaTemplate, { id: mappedId, deletedAt: null }, undefined, scope)\n : await findOneWithDecryption(\n em,\n CatalogOptionSchemaTemplate,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: schemaCode,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n const familyAttributes = Array.isArray(family.attributes) ? family.attributes : []\n const familyVariantAttributes = familyVariant?.variant_attribute_sets?.flatMap((set) => [\n ...(Array.isArray(set.attributes) ? set.attributes : []),\n ...(Array.isArray(set.axes) ? set.axes : []),\n ]) ?? []\n const attributeCodes = requestedAttributeCodes ?? dedupeStrings([...familyAttributes, ...familyVariantAttributes])\n const definitions: Record<string, unknown>[] = []\n const richAttributes: Record<string, unknown> = {}\n for (const code of attributeCodes) {\n const attribute = await client.getAttribute(code)\n if (!attribute) continue\n const inputType = mapAkeneoAttributeInputType(attribute.type)\n if (!inputType) continue\n if ((inputType === 'text' || inputType === 'textarea') && !includeTextAttributes) continue\n if (inputType === 'number' && !includeNumericAttributes) continue\n const definition = await buildOptionSchemaDefinition(attribute, family, locale)\n if (!definition) continue\n definitions.push(definition)\n richAttributes[code] = {\n ...buildAttributeMetadata(attribute, locale),\n validation: buildValidationRules(attribute),\n }\n if (definitions.length >= 64) break\n }\n\n const schemaInput = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: labelFromLocalizedRecord(family.labels ?? null, locale, family.code),\n code: schemaCode,\n description: familyVariant?.code ? `Akeneo family variant ${familyVariant.code}` : `Akeneo family ${family.code}`,\n schema: {\n version: 1,\n name: labelFromLocalizedRecord(family.labels ?? null, locale, family.code),\n description: familyVariant?.code ? `Akeneo family variant ${familyVariant.code}` : `Akeneo family ${family.code}`,\n options: definitions,\n },\n metadata: {\n source: 'akeneo',\n familyCode: family.code,\n familyVariantCode: familyVariant?.code ?? null,\n attributeCodes,\n richAttributes,\n attributeAsLabel: family.attribute_as_label ?? null,\n attributeAsImage: family.attribute_as_image ?? null,\n variantAxes: familyVariant?.variant_attribute_sets?.map((set) => ({\n level: set.level ?? null,\n axes: Array.isArray(set.axes) ? set.axes : [],\n attributes: Array.isArray(set.attributes) ? set.attributes : [],\n })) ?? [],\n },\n isActive: true,\n }\n\n if (existing) {\n await executeCommand('catalog.optionSchemas.update', {\n id: existing.id,\n ...schemaInput,\n })\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_option_schema', existing.id, externalId, scope)\n return { localId: existing.id, action: 'update' }\n }\n\n const created = await executeCommand<{ schemaId: string }>('catalog.optionSchemas.create', schemaInput)\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_option_schema', created.schemaId, externalId, scope)\n return { localId: created.schemaId, action: 'create' }\n })())\n }\n\n return optionSchemaCache.get(cacheKey) ?? null\n }\n\n async function syncMappedCustomFields(\n mapping: AkeneoDataMapping,\n locale: string,\n fieldsetPlan?: AkeneoFieldsetPlan | null,\n options?: { forceRefresh?: boolean },\n ): Promise<CustomFieldSyncItem[]> {\n const settings = mapping.settings?.products\n if (!settings || settings.customFieldMappings.length === 0) return []\n const cacheKey = JSON.stringify({\n customFieldMappings: settings.customFieldMappings.filter((mapping) => !mapping.skip),\n fieldsetPlan,\n locale,\n })\n if (options?.forceRefresh) {\n customFieldSyncCache.delete(cacheKey)\n globalFieldsetAssignmentCache.delete(JSON.stringify({\n customFieldMappings: settings.customFieldMappings.filter((entry) => !entry.skip),\n fieldsetMappings: settings.fieldsetMappings,\n }))\n }\n if (!customFieldSyncCache.has(cacheKey)) {\n customFieldSyncCache.set(cacheKey, (async () => {\n const productFields: Array<CustomFieldDefinition & { sourceMetadata?: Record<string, unknown> }> = []\n const variantFields: Array<CustomFieldDefinition & { sourceMetadata?: Record<string, unknown> }> = []\n const items: CustomFieldSyncItem[] = []\n const globalAssignments = await resolveGlobalFieldsetAssignments(settings)\n const existingDefinitions = await findWithDecryption(em, CustomFieldDef, {\n entityId: { $in: [PRODUCT_ENTITY_ID, VARIANT_ENTITY_ID] } as never,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n const existingFieldsetsByEntityAndKey = new Map<string, string[]>()\n for (const definition of existingDefinitions) {\n const config = safeRecord(definition.configJson)\n existingFieldsetsByEntityAndKey.set(\n `${definition.entityId}:${definition.key}`,\n readConfiguredFieldsets(config),\n )\n }\n\n for (const fieldMapping of settings.customFieldMappings) {\n if (fieldMapping.skip) continue\n const attribute = await client.getAttribute(fieldMapping.attributeCode)\n if (!attribute) continue\n const kind = mapAkeneoAttributeToCustomFieldKind(attribute, fieldMapping.kind)\n if (!kind) continue\n const entityId = fieldMapping.target === 'product' ? PRODUCT_ENTITY_ID : VARIANT_ENTITY_ID\n const normalizedKey = normalizeFieldKey(fieldMapping.fieldKey)\n const currentFieldsetCode = fieldMapping.target === 'product'\n ? fieldsetPlan?.product?.code ?? null\n : fieldsetPlan?.variant?.code ?? null\n const globalFieldsets = fieldMapping.target === 'product'\n ? globalAssignments.product.fieldsetsByKey.get(normalizedKey) ?? []\n : globalAssignments.variant.fieldsetsByKey.get(normalizedKey) ?? []\n const inheritedFieldsets = existingFieldsetsByEntityAndKey.get(`${entityId}:${normalizedKey}`) ?? []\n const effectiveFieldsets = dedupeStrings([\n ...globalFieldsets,\n ...inheritedFieldsets,\n ...(currentFieldsetCode ? [currentFieldsetCode] : []),\n ])\n const options = kind === 'select' && (attribute.type === 'pim_catalog_simpleselect' || attribute.type === 'pim_catalog_multiselect')\n ? await client.listAttributeOptions(attribute.code).catch(() => [])\n : []\n const field: CustomFieldDefinition & { sourceMetadata?: Record<string, unknown> } = {\n key: normalizedKey,\n kind,\n label: labelFromLocalizedRecord(attribute.labels ?? null, locale, fieldMapping.fieldKey),\n description: `Akeneo attribute ${fieldMapping.attributeCode}`,\n fieldset: effectiveFieldsets.length === 1 ? effectiveFieldsets[0] : undefined,\n fieldsets: effectiveFieldsets.length > 0 ? effectiveFieldsets : undefined,\n multi: attribute.type === 'pim_catalog_multiselect' || attribute.type === 'akeneo_reference_entity_collection',\n options: options.map((option) => ({\n value: option.code,\n label: labelFromLocalizedRecord(option.labels ?? null, locale, option.code),\n })),\n filterable: Boolean(attribute.useable_as_grid_filter),\n listVisible: false,\n editor: kind === 'multiline' ? 'markdown' : undefined,\n validation: buildValidationRules(attribute),\n group: attribute.group ? {\n code: normalizeFieldKey(attribute.group),\n title: attribute.group_labels ? labelFromLocalizedRecord(attribute.group_labels, locale, attribute.group) : attribute.group,\n } : undefined,\n sourceMetadata: buildAttributeMetadata(attribute, locale),\n }\n if (fieldMapping.target === 'product') productFields.push(field)\n else variantFields.push(field)\n items.push({\n externalId: `${fieldMapping.target}:${fieldMapping.attributeCode}`,\n action: 'update',\n data: {\n key: field.key,\n target: fieldMapping.target,\n attributeCode: fieldMapping.attributeCode,\n },\n })\n }\n\n const sets = []\n if (productFields.length > 0) {\n sets.push({\n entity: PRODUCT_ENTITY_ID,\n fields: productFields,\n source: 'akeneo',\n })\n }\n if (variantFields.length > 0) {\n sets.push({\n entity: VARIANT_ENTITY_ID,\n fields: variantFields,\n source: 'akeneo',\n })\n }\n\n if (sets.length > 0) {\n const productFieldAssignments = productFields.map((field) => ({\n key: field.key,\n fieldsets: resolveAkeneoFieldsetMemberships(\n existingFieldsetsByEntityAndKey.get(`${PRODUCT_ENTITY_ID}:${field.key}`) ?? [],\n fieldsetPlan?.product?.code ?? null,\n ),\n }))\n const variantFieldAssignments = variantFields.map((field) => ({\n key: field.key,\n fieldsets: resolveAkeneoFieldsetMemberships(\n existingFieldsetsByEntityAndKey.get(`${VARIANT_ENTITY_ID}:${field.key}`) ?? [],\n fieldsetPlan?.variant?.code ?? null,\n ),\n }))\n\n await ensureCustomFieldDefinitions(em, sets, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n await Promise.all([\n ensureEntityFieldsetConfig(PRODUCT_ENTITY_ID, fieldsetPlan?.product ?? null),\n ensureEntityFieldsetConfig(VARIANT_ENTITY_ID, fieldsetPlan?.variant ?? null),\n ])\n await Promise.all([\n ensureAkeneoFieldsetAssignments(PRODUCT_ENTITY_ID, productFieldAssignments),\n ensureAkeneoFieldsetAssignments(VARIANT_ENTITY_ID, variantFieldAssignments),\n ])\n await Promise.all([\n reconcileAkeneoFieldsetAssignments(PRODUCT_ENTITY_ID, fieldsetPlan?.product?.code ?? null, productFields.map((field) => field.key)),\n reconcileAkeneoFieldsetAssignments(VARIANT_ENTITY_ID, fieldsetPlan?.variant?.code ?? null, variantFields.map((field) => field.key)),\n ])\n await invalidateDefinitionsCache(cacheService as never, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n entityIds: [PRODUCT_ENTITY_ID, VARIANT_ENTITY_ID],\n })\n }\n\n return items\n })())\n }\n return customFieldSyncCache.get(cacheKey) ?? []\n }\n\n async function reconcileAkeneoFieldsetAssignments(\n entityId: string,\n fieldsetCode: string | null,\n desiredFieldKeys: string[],\n ): Promise<void> {\n if (!fieldsetCode) return\n\n const existingDefinitions = await findWithDecryption(em, CustomFieldDef, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n\n const keysToDetach = resolveAkeneoFieldKeysToDetach(\n existingDefinitions.map((definition) => {\n const config = safeRecord(definition.configJson)\n return {\n key: definition.key,\n description: typeof config?.description === 'string' ? config.description : null,\n fieldset: typeof config?.fieldset === 'string' ? config.fieldset : null,\n fieldsets: readConfiguredFieldsets(config),\n }\n }),\n desiredFieldKeys,\n fieldsetCode,\n )\n\n if (keysToDetach.length === 0) return\n\n for (const definition of existingDefinitions) {\n if (!keysToDetach.includes(definition.key)) continue\n const nextConfig = {\n ...(safeRecord(definition.configJson) ?? {}),\n }\n const remainingFieldsets = readConfiguredFieldsets(nextConfig).filter((entry) => entry !== fieldsetCode)\n if (remainingFieldsets.length === 0) {\n delete nextConfig.fieldset\n delete nextConfig.fieldsets\n } else if (remainingFieldsets.length === 1) {\n nextConfig.fieldset = remainingFieldsets[0]\n nextConfig.fieldsets = remainingFieldsets\n } else {\n delete nextConfig.fieldset\n nextConfig.fieldsets = remainingFieldsets\n }\n definition.configJson = nextConfig\n definition.updatedAt = new Date()\n }\n\n await em.flush()\n }\n\n async function ensureAkeneoFieldsetAssignments(\n entityId: string,\n assignments: DesiredFieldsetAssignment[],\n ): Promise<void> {\n const normalizedAssignments = assignments\n .map((assignment) => ({\n key: normalizeFieldKey(assignment.key),\n fieldsets: dedupeStrings(\n assignment.fieldsets\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0),\n ),\n }))\n .filter((assignment) => assignment.key.length > 0 && assignment.fieldsets.length > 0)\n\n const normalizedKeys = normalizedAssignments.map((assignment) => assignment.key)\n if (normalizedKeys.length === 0) return\n\n const fieldsetsByKey = new Map(normalizedAssignments.map((assignment) => [assignment.key, assignment.fieldsets]))\n\n const existingDefinitions = await findWithDecryption(em, CustomFieldDef, {\n entityId,\n key: { $in: normalizedKeys } as never,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n\n let changed = false\n for (const definition of existingDefinitions) {\n const nextConfig = {\n ...(safeRecord(definition.configJson) ?? {}),\n }\n const nextFieldsets = fieldsetsByKey.get(definition.key) ?? []\n if (nextFieldsets.length === 0) continue\n\n const currentFieldsets = readConfiguredFieldsets(nextConfig)\n const currentPrimary = typeof nextConfig.fieldset === 'string' ? nextConfig.fieldset.trim() : ''\n const nextPrimary = nextFieldsets.length === 1 ? nextFieldsets[0] : ''\n const sameMemberships = currentFieldsets.length === nextFieldsets.length\n && currentFieldsets.every((entry, index) => entry === nextFieldsets[index])\n if (sameMemberships && currentPrimary === nextPrimary) continue\n\n if (nextFieldsets.length === 1) {\n nextConfig.fieldset = nextFieldsets[0]\n delete nextConfig.fieldsets\n } else {\n delete nextConfig.fieldset\n nextConfig.fieldsets = nextFieldsets\n }\n definition.configJson = nextConfig\n definition.updatedAt = new Date()\n changed = true\n }\n\n if (changed) {\n await em.flush()\n }\n }\n\n async function applyAkeneoManagedFieldsetAssignments(\n entityId: string,\n assignments: EntityFieldsetAssignments,\n ): Promise<void> {\n const dedupedFieldsets = new Map(assignments.fieldsets.map((fieldset) => [fieldset.code, fieldset]))\n await Promise.all(\n Array.from(dedupedFieldsets.values()).map((fieldset) => ensureEntityFieldsetConfig(entityId, fieldset)),\n )\n\n const definitions = await findWithDecryption(em, CustomFieldDef, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n\n let changed = false\n for (const definition of definitions) {\n const config = safeRecord(definition.configJson)\n const sourceMetadata = safeRecord(config?.sourceMetadata)\n const isAkeneoManaged = sourceMetadata?.provider === 'akeneo'\n || (typeof config?.description === 'string' && config.description.startsWith('Akeneo attribute '))\n if (!isAkeneoManaged) continue\n\n const nextConfig = {\n ...(config ?? {}),\n }\n const nextFieldsets = assignments.fieldsetsByKey.get(definition.key) ?? []\n const currentFieldsets = readConfiguredFieldsets(nextConfig)\n const currentPrimary = typeof nextConfig.fieldset === 'string' ? nextConfig.fieldset.trim() : ''\n const nextPrimary = nextFieldsets.length === 1 ? nextFieldsets[0] : ''\n const sameMemberships = currentFieldsets.length === nextFieldsets.length\n && currentFieldsets.every((entry, index) => entry === nextFieldsets[index])\n if (sameMemberships && currentPrimary === nextPrimary) continue\n\n if (nextFieldsets.length === 0) {\n delete nextConfig.fieldset\n delete nextConfig.fieldsets\n } else if (nextFieldsets.length === 1) {\n nextConfig.fieldset = nextFieldsets[0]\n delete nextConfig.fieldsets\n } else {\n delete nextConfig.fieldset\n nextConfig.fieldsets = nextFieldsets\n }\n\n definition.configJson = nextConfig\n definition.updatedAt = new Date()\n changed = true\n }\n\n if (changed) {\n await em.flush()\n await invalidateDefinitionsCache(cacheService as never, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n entityIds: [entityId],\n })\n }\n }\n\n async function reconcileMappedCustomFieldFieldsets(mapping: AkeneoDataMapping): Promise<void> {\n const settings = mapping.settings?.products\n if (!settings || settings.customFieldMappings.length === 0) return\n\n const activeMappings = settings.customFieldMappings.filter((entry) => !entry.skip)\n if (activeMappings.length === 0) return\n\n globalFieldsetAssignmentCache.delete(JSON.stringify({\n customFieldMappings: settings.customFieldMappings.filter((entry) => !entry.skip),\n fieldsetMappings: settings.fieldsetMappings,\n }))\n em.clear()\n const globalAssignments = await resolveGlobalFieldsetAssignments(settings)\n const productAssignments = globalAssignments.product\n const variantAssignments = globalAssignments.variant\n\n if (productAssignments.fieldsets.length > 0 || productAssignments.fieldsetsByKey.size > 0) {\n await applyAkeneoManagedFieldsetAssignments(PRODUCT_ENTITY_ID, productAssignments)\n }\n if (variantAssignments.fieldsets.length > 0 || variantAssignments.fieldsetsByKey.size > 0) {\n await applyAkeneoManagedFieldsetAssignments(VARIANT_ENTITY_ID, variantAssignments)\n }\n }\n\n async function resolveGlobalFieldsetAssignments(\n settings: AkeneoProductMappingSettings,\n ): Promise<ResolvedGlobalFieldsetAssignments> {\n const activeMappings = settings.customFieldMappings.filter((entry) => !entry.skip)\n const cacheKey = JSON.stringify({\n customFieldMappings: activeMappings,\n fieldsetMappings: settings.fieldsetMappings,\n })\n if (!globalFieldsetAssignmentCache.has(cacheKey)) {\n globalFieldsetAssignmentCache.set(cacheKey, (async () => {\n const optionSchemas = await em.getConnection().execute<Array<{\n code: string\n name: string\n description: string | null\n metadata: unknown\n }>>(\n `\n select code, name, description, metadata\n from catalog_product_option_schemas\n where organization_id = ?\n and tenant_id = ?\n and deleted_at is null\n `,\n [scope.organizationId, scope.tenantId],\n )\n const akeneoSchemas: Array<{\n schema: {\n code: string\n name: string\n description: string | null\n }\n metadata: AkeneoOptionSchemaMetadata\n }> = []\n for (const schema of optionSchemas) {\n const metadata = readAkeneoOptionSchemaMetadata(schema.metadata)\n if (!metadata) continue\n akeneoSchemas.push({\n schema: {\n code: schema.code,\n name: schema.name,\n description: schema.description,\n },\n metadata,\n })\n }\n\n const productAssignments: EntityFieldsetAssignments = {\n fieldsets: [],\n fieldsetsByKey: new Map(),\n }\n const variantAssignments: EntityFieldsetAssignments = {\n fieldsets: [],\n fieldsetsByKey: new Map(),\n }\n\n const addFieldsetAssignment = (\n bucket: EntityFieldsetAssignments,\n fieldKey: string,\n fieldset: CustomFieldsetDefinition | null,\n ) => {\n if (!fieldset) return\n const normalizedKey = normalizeFieldKey(fieldKey)\n if (!normalizedKey) return\n const existing = bucket.fieldsetsByKey.get(normalizedKey) ?? []\n bucket.fieldsetsByKey.set(\n normalizedKey,\n resolveAkeneoFieldsetMemberships(existing, fieldset.code),\n )\n if (!bucket.fieldsets.some((entry) => entry.code === fieldset.code)) {\n bucket.fieldsets.push(fieldset)\n }\n }\n\n for (const { schema, metadata } of akeneoSchemas) {\n const fieldsetPlan = buildFieldsetPlanFromOptionSchema({\n schema,\n metadata,\n locale: settings.locale,\n fieldsetMappings: settings.fieldsetMappings,\n })\n if (!fieldsetPlan.fieldset) continue\n\n const schemaMappings = activeMappings.filter((entry) => (\n entry.target === fieldsetPlan.target\n && metadata.attributeCodes.includes(entry.attributeCode)\n ))\n if (schemaMappings.length === 0) continue\n\n const bucket = fieldsetPlan.target === 'product' ? productAssignments : variantAssignments\n for (const fieldMapping of schemaMappings) {\n addFieldsetAssignment(bucket, fieldMapping.fieldKey, fieldsetPlan.fieldset)\n }\n }\n\n return {\n product: productAssignments,\n variant: variantAssignments,\n }\n })())\n }\n\n return globalFieldsetAssignmentCache.get(cacheKey) ?? {\n product: { fieldsets: [], fieldsetsByKey: new Map() },\n variant: { fieldsets: [], fieldsetsByKey: new Map() },\n }\n }\n\n async function upsertAttributeFamily(\n family: AkeneoFamily,\n locale: string,\n includeTextAttributes: boolean,\n includeNumericAttributes: boolean,\n ): Promise<UpsertResult | null> {\n return ensureOptionSchemaForFamily(family, null, includeTextAttributes, includeNumericAttributes, locale)\n }\n\n async function resolveAutoLocalChannelCode(\n akeneoChannel: string | null,\n fallbackChannelCode: string | null,\n createIfMissing: boolean,\n ): Promise<string | null> {\n if (akeneoChannel) {\n const exact = await resolveChannel(akeneoChannel, {\n createIfMissing,\n label: titleizeCode(akeneoChannel),\n })\n if (exact) return exact.code\n\n const aliases = akeneoChannel.trim().toLowerCase() === 'ecommerce'\n ? ['web', 'online', 'default']\n : akeneoChannel.trim().toLowerCase() === 'web'\n ? ['ecommerce', 'online', 'default']\n : []\n for (const alias of aliases) {\n const match = await resolveChannel(alias)\n if (match) return match.code\n }\n }\n return fallbackChannelCode\n }\n\n async function resolveAutoPriceKindCode(attributeCode: string): Promise<string | null> {\n const normalizedCode = attributeCode.trim().toLowerCase()\n const preferredCode = normalizedCode.includes('sale')\n || normalizedCode.includes('promo')\n || normalizedCode.includes('special')\n || normalizedCode.includes('discount')\n ? 'sale'\n : 'regular'\n const preferred = await resolvePriceKind(preferredCode)\n if (preferred) return preferred.code\n return resolvePreferredPriceKindCode()\n }\n\n async function buildAutomaticPriceMappings(params: {\n hierarchy: ResolvedHierarchy\n settings: AkeneoProductMappingSettings\n priceAttributeCodes: string[]\n }): Promise<AkeneoProductMappingSettings['priceMappings']> {\n const fallbackChannelCode = await resolvePreferredLocalChannelCode()\n\n const mappings: AkeneoProductMappingSettings['priceMappings'] = []\n const selectedChannels = resolveImportedAkeneoChannels(params.settings)\n for (const attributeCode of dedupeStrings(params.priceAttributeCodes)) {\n const priceKindCode = await resolveAutoPriceKindCode(attributeCode)\n if (!priceKindCode) continue\n const scopes = collectValueScopes(\n [params.hierarchy.leafValues, params.hierarchy.mergedValues],\n attributeCode,\n )\n const effectiveScopes = scopes.length > 0\n ? scopes\n : [\n ...(selectedChannels.length > 0\n ? selectedChannels\n : [params.settings.channel ?? (params.settings.createMissingChannels ? 'default' : null)]),\n ]\n for (const akeneoChannel of effectiveScopes) {\n if (!shouldImportAkeneoChannel(params.settings, akeneoChannel)) continue\n const localChannelCode = await resolveAutoLocalChannelCode(\n akeneoChannel,\n fallbackChannelCode,\n params.settings.createMissingChannels,\n )\n if (!localChannelCode) continue\n mappings.push({\n attributeCode,\n priceKindCode,\n akeneoChannel,\n localChannelCode,\n })\n }\n }\n\n const seen = new Set<string>()\n return mappings.filter((mapping) => {\n const key = `${mapping.attributeCode}:${mapping.priceKindCode}:${mapping.akeneoChannel ?? ''}:${mapping.localChannelCode}`\n if (seen.has(key)) return false\n seen.add(key)\n return true\n })\n }\n\n async function resolveProductSettings(params: {\n mapping: AkeneoDataMapping\n hierarchy: ResolvedHierarchy\n family: AkeneoFamily | null\n familyVariant: AkeneoFamilyVariant | null\n }): Promise<{\n settings: AkeneoProductMappingSettings\n axisCodes: string[]\n variantAttributeCodes: string[]\n optionSchemaAttributeCodes: string[]\n fieldsetPlan: AkeneoFieldsetPlan\n }> {\n if (!defaultProductSettings) {\n throw new Error('Default Akeneo product mapping is not available')\n }\n\n const baseSettings = params.mapping.settings?.products ?? defaultProductSettings\n const attributeCodes = dedupeStrings([\n ...Object.keys(params.hierarchy.rootValues),\n ...Object.keys(params.hierarchy.leafValues),\n ...Object.keys(params.hierarchy.mergedValues),\n ...(Array.isArray(params.family?.attributes) ? params.family.attributes : []),\n ...(params.familyVariant?.variant_attribute_sets?.flatMap((set) => [\n ...(Array.isArray(set.axes) ? set.axes : []),\n ...(Array.isArray(set.attributes) ? set.attributes : []),\n ]) ?? []),\n ])\n const attributes = (\n await Promise.all(attributeCodes.map((code) => client.getAttribute(code)))\n ).filter((attribute): attribute is AkeneoAttribute => Boolean(attribute))\n\n const inferred = inferAkeneoProductMapping({\n attributes,\n family: params.family,\n familyVariant: params.familyVariant,\n fieldMap: baseSettings.fieldMap,\n explicitCustomFieldMappings: baseSettings.customFieldMappings,\n explicitMediaMappings: baseSettings.mediaMappings,\n })\n\n const priceMappings = baseSettings.priceMappings.length > 0\n ? baseSettings.priceMappings\n : await buildAutomaticPriceMappings({\n hierarchy: params.hierarchy,\n settings: baseSettings,\n priceAttributeCodes: inferred.autoPriceAttributeCodes,\n })\n\n const explicitCustomAttributeCodes = new Set(baseSettings.customFieldMappings.map((entry) => entry.attributeCode))\n const inferredCustomAttributeCodes = new Set(inferred.autoCustomFieldMappings.map((entry) => entry.attributeCode))\n const productAttributes = attributes.filter((attribute) => {\n if (!explicitCustomAttributeCodes.has(attribute.code) && !inferredCustomAttributeCodes.has(attribute.code)) return false\n return params.familyVariant\n ? !inferred.variantAttributeCodes.includes(attribute.code)\n : true\n })\n const variantAttributes = attributes.filter((attribute) => {\n if (!explicitCustomAttributeCodes.has(attribute.code) && !inferredCustomAttributeCodes.has(attribute.code)) return false\n return inferred.variantAttributeCodes.includes(attribute.code)\n })\n const fieldsetPlan = buildFieldsetPlan({\n family: params.family,\n familyVariant: params.familyVariant,\n productAttributes,\n variantAttributes,\n locale: baseSettings.locale,\n fieldsetMappings: baseSettings.fieldsetMappings,\n })\n const availableAttributeCodes = attributes.map((attribute) => attribute.code)\n\n return {\n settings: {\n ...baseSettings,\n fieldMap: inferred.fieldMap,\n customFieldMappings: filterAkeneoAttributeMappingsByAvailableAttributes(\n dedupeCustomFieldMappings([\n ...baseSettings.customFieldMappings,\n ...inferred.autoCustomFieldMappings,\n ]),\n availableAttributeCodes,\n ),\n mediaMappings: filterAkeneoAttributeMappingsByAvailableAttributes(\n dedupeMediaMappings([\n ...baseSettings.mediaMappings,\n ...inferred.autoMediaMappings,\n ]),\n availableAttributeCodes,\n ),\n fieldsetMappings: baseSettings.fieldsetMappings,\n priceMappings,\n },\n axisCodes: inferred.axisCodes,\n variantAttributeCodes: inferred.variantAttributeCodes,\n optionSchemaAttributeCodes: inferred.optionSchemaAttributeCodes,\n fieldsetPlan,\n }\n }\n\n async function resolveProductHierarchy(product: AkeneoProduct): Promise<ResolvedHierarchy> {\n if (!product.parent) {\n return {\n rootExternalId: product.uuid,\n family: product.family ?? null,\n familyVariantCode: null,\n rootValues: mergeValueLayers(product.values),\n leafValues: mergeValueLayers(product.values),\n mergedValues: mergeValueLayers(product.values),\n categories: Array.isArray(product.categories) ? product.categories : [],\n parentChain: [],\n associationSource: product,\n axisCodes: [],\n }\n }\n\n const chain: Array<{ code: string; values: AkeneoValues; categories: string[]; family?: string | null; familyVariant?: string | null }> = []\n let nextCode: string | null = product.parent\n while (nextCode) {\n const model = await client.getProductModel(nextCode)\n if (!model) break\n chain.unshift({\n code: model.code,\n values: mergeValueLayers(model.values),\n categories: Array.isArray(model.categories) ? model.categories : [],\n family: model.family ?? null,\n familyVariant: model.family_variant ?? null,\n })\n nextCode = model.parent ?? null\n }\n\n const root = chain[0]\n return {\n rootExternalId: root?.code ?? product.uuid,\n family: product.family ?? root?.family ?? null,\n familyVariantCode: chain[chain.length - 1]?.familyVariant ?? root?.familyVariant ?? null,\n rootValues: root?.values ?? mergeValueLayers(product.values),\n leafValues: mergeValueLayers(product.values),\n mergedValues: mergeValueLayers(\n ...chain.map((model) => model.values),\n product.values,\n ),\n categories: Array.from(new Set([\n ...chain.flatMap((model) => model.categories),\n ...(product.categories ?? []),\n ])),\n parentChain: chain.map((model) => model.code),\n associationSource: product,\n axisCodes: [],\n }\n }\n\n async function applyCustomFieldMappings(params: {\n mapping: AkeneoDataMapping\n hierarchy: ResolvedHierarchy\n product: AkeneoProduct\n localProductId: string\n localVariantId: string\n fieldsetPlan?: AkeneoFieldsetPlan | null\n }): Promise<void> {\n const settings = params.mapping.settings?.products\n if (!settings || settings.customFieldMappings.length === 0) return\n\n await syncMappedCustomFields(params.mapping, settings.locale, params.fieldsetPlan)\n\n const productCustomFields: Record<string, unknown> = {}\n const variantCustomFields: Record<string, unknown> = {}\n\n for (const fieldMapping of settings.customFieldMappings) {\n if (fieldMapping.skip) continue\n const attribute = await client.getAttribute(fieldMapping.attributeCode)\n if (!attribute) continue\n const kind = mapAkeneoAttributeToCustomFieldKind(attribute, fieldMapping.kind)\n if (!kind) continue\n const sourceLayers = fieldMapping.target === 'product'\n ? [params.hierarchy.rootValues, params.hierarchy.mergedValues]\n : [params.product.values ?? {}, params.hierarchy.mergedValues]\n const rawValue = readLayeredAkeneoValue(sourceLayers, fieldMapping.attributeCode, settings.locale, settings.channel ?? null)\n const value = resolveCustomFieldValue(rawValue, attribute, kind)\n if (value === null || value === undefined || (Array.isArray(value) && value.length === 0)) continue\n if (fieldMapping.target === 'product') {\n productCustomFields[normalizeFieldKey(fieldMapping.fieldKey)] = value\n } else {\n variantCustomFields[normalizeFieldKey(fieldMapping.fieldKey)] = value\n }\n }\n\n await Promise.all([\n setCustomFieldsIfAny({\n dataEngine,\n entityId: PRODUCT_ENTITY_ID,\n recordId: params.localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: productCustomFields,\n }),\n setCustomFieldsIfAny({\n dataEngine,\n entityId: VARIANT_ENTITY_ID,\n recordId: params.localVariantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: variantCustomFields,\n }),\n ])\n\n await Promise.all([\n params.fieldsetPlan?.product?.code\n ? executeCommand('catalog.products.update', {\n id: params.localProductId,\n customFieldsetCode: params.fieldsetPlan.product.code,\n })\n : Promise.resolve(),\n params.fieldsetPlan?.variant?.code\n ? executeCommand('catalog.variants.update', {\n id: params.localVariantId,\n customFieldsetCode: params.fieldsetPlan.variant.code,\n })\n : Promise.resolve(),\n ])\n\n if (Object.keys(productCustomFields).length > 0) {\n await emitCatalogQueryIndexEvent(buildCommandContext(), {\n entityType: PRODUCT_ENTITY_ID,\n recordId: params.localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n action: 'updated',\n })\n }\n\n if (Object.keys(variantCustomFields).length > 0) {\n await emitCatalogQueryIndexEvent(buildCommandContext(), {\n entityType: VARIANT_ENTITY_ID,\n recordId: params.localVariantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n action: 'updated',\n })\n }\n }\n\n async function upsertOffersAndPrices(params: {\n mapping: AkeneoDataMapping\n settings: AkeneoProductMappingSettings\n hierarchy: ResolvedHierarchy\n localProductId: string\n localVariantId: string\n resolvedProductTitle: string\n resolvedProductDescription: string | null\n variantExternalId: string\n }): Promise<void> {\n const desiredOffers = new Map<string, DesiredOffer>()\n for (const priceMapping of params.settings.priceMappings) {\n const channel = await resolveChannel(priceMapping.localChannelCode, {\n createIfMissing: params.settings.createMissingChannels,\n label: titleizeCode(priceMapping.localChannelCode),\n })\n const priceKind = await resolvePriceKind(priceMapping.priceKindCode)\n if (!channel || !priceKind) continue\n const akeneoChannel = priceMapping.akeneoChannel ?? params.settings.channel ?? null\n if (!shouldImportAkeneoChannel(params.settings, akeneoChannel)) continue\n const rawPrices = readLayeredAkeneoValue(\n [params.hierarchy.leafValues, params.hierarchy.mergedValues],\n priceMapping.attributeCode,\n params.settings.locale,\n akeneoChannel,\n )\n const entries = parsePriceCollection(rawPrices)\n if (entries.length === 0) continue\n const offerExternalId = `${params.hierarchy.rootExternalId}:offer:${channel.code}`\n const existingOffer = desiredOffers.get(offerExternalId)\n const title = coerceString(readLayeredAkeneoValue(\n [params.hierarchy.rootValues, params.hierarchy.mergedValues],\n params.settings.fieldMap.title,\n params.settings.locale,\n akeneoChannel,\n )) ?? params.resolvedProductTitle\n const description = clampString(\n normalizeMarkdownText(\n coerceString(readLayeredAkeneoValue(\n [params.hierarchy.rootValues, params.hierarchy.mergedValues],\n params.settings.fieldMap.description,\n params.settings.locale,\n akeneoChannel,\n )) ?? params.resolvedProductDescription,\n ),\n 4000,\n )\n const bucket = existingOffer ?? {\n externalId: offerExternalId,\n channelCode: channel.code,\n channelId: channel.id,\n akeneoChannel,\n title,\n description,\n prices: [],\n }\n for (const entry of entries) {\n bucket.prices.push({\n externalId: `${params.variantExternalId}:price:${priceKind.code}:${channel.code}:${entry.currencyCode}`,\n priceKindCode: priceKind.code,\n priceKindId: priceKind.id,\n channelId: channel.id,\n currencyCode: entry.currencyCode,\n amount: entry.amount,\n variantId: params.localVariantId,\n })\n }\n desiredOffers.set(offerExternalId, bucket)\n }\n\n const existingOffers = await findWithDecryption(\n em,\n CatalogOffer,\n {\n product: params.localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n const existingOfferByChannelId = new Map(existingOffers.map((offer) => [offer.channelId, offer]))\n const desiredOfferExternalIds = new Set(desiredOffers.keys())\n\n for (const offer of desiredOffers.values()) {\n const mappedOfferId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_offer', offer.externalId, scope)\n const existingOffer = mappedOfferId\n ? existingOffers.find((entry) => entry.id === mappedOfferId) ?? null\n : existingOfferByChannelId.get(offer.channelId) ?? null\n const input = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n productId: params.localProductId,\n channelId: offer.channelId,\n title: offer.title,\n description: offer.description ?? undefined,\n metadata: {\n source: 'akeneo',\n externalId: offer.externalId,\n channelCode: offer.channelCode,\n akeneoChannel: offer.akeneoChannel,\n },\n isActive: true,\n }\n const offerId = existingOffer\n ? (await executeCommand<{ offerId: string }>('catalog.offers.update', { id: existingOffer.id, ...input })).offerId\n : (await executeCommand<{ offerId: string }>('catalog.offers.create', input)).offerId\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_offer', offerId, offer.externalId, scope)\n\n const existingPrices = await findWithDecryption(\n em,\n CatalogProductPrice,\n {\n offer: offerId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n },\n undefined,\n scope,\n )\n const desiredPriceExternalIds = new Set(offer.prices.map((price) => price.externalId))\n for (const price of offer.prices) {\n const mappedPriceId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_price', price.externalId, scope)\n const existingPrice = mappedPriceId\n ? existingPrices.find((entry) => entry.id === mappedPriceId) ?? null\n : existingPrices.find((entry) => (\n (typeof entry.variant === 'string' ? entry.variant : entry.variant?.id ?? null) === price.variantId\n && entry.channelId === price.channelId\n && entry.currencyCode === price.currencyCode\n && entry.kind === price.priceKindCode\n )) ?? null\n const input = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n productId: params.localProductId,\n variantId: price.variantId,\n offerId,\n priceKindId: price.priceKindId,\n currencyCode: price.currencyCode,\n unitPriceNet: price.amount,\n unitPriceGross: price.amount,\n minQuantity: 1,\n channelId: price.channelId,\n metadata: {\n source: 'akeneo',\n externalId: price.externalId,\n priceKindCode: price.priceKindCode,\n },\n }\n const priceId = existingPrice\n ? (await executeCommand<{ priceId: string }>('catalog.prices.update', { id: existingPrice.id, ...input })).priceId\n : (await executeCommand<{ priceId: string }>('catalog.prices.create', input)).priceId\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_price', priceId, price.externalId, scope)\n }\n\n if (params.settings.reconciliation.deleteMissingPrices) {\n for (const existingPrice of existingPrices) {\n const externalId = await externalIdMappingService.lookupExternalId('sync_akeneo', 'catalog_product_price', existingPrice.id, scope)\n if (externalId && !desiredPriceExternalIds.has(externalId)) {\n await executeCommand('catalog.prices.delete', { id: existingPrice.id })\n }\n }\n }\n }\n\n if (params.settings.reconciliation.deleteMissingOffers) {\n for (const existingOffer of existingOffers) {\n const externalId = await externalIdMappingService.lookupExternalId('sync_akeneo', 'catalog_offer', existingOffer.id, scope)\n if (externalId && !desiredOfferExternalIds.has(externalId)) {\n const offerPrices = await findWithDecryption(\n em,\n CatalogProductPrice,\n { offer: existingOffer.id, organizationId: scope.organizationId, tenantId: scope.tenantId },\n undefined,\n scope,\n )\n for (const price of offerPrices) {\n await executeCommand('catalog.prices.delete', { id: price.id })\n }\n await executeCommand('catalog.offers.delete', { id: existingOffer.id })\n }\n }\n }\n }\n\n async function upsertAsset(asset: DesiredAsset): Promise<string> {\n const existingAttachmentId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'attachment', asset.externalId, scope)\n if (existingAttachmentId) return existingAttachmentId\n\n await ensureDefaultPartitions(em)\n const binary = await client.downloadMediaFile(asset.remote.codeOrUrl)\n const fileName = asset.remote.fileNameHint ?? binary.fileName ?? `akeneo-${randomUUID().slice(0, 8)}`\n const partitionCode = resolveDefaultPartitionCode(asset.entityId)\n const stored = await storePartitionFile({\n partitionCode,\n orgId: scope.organizationId,\n tenantId: scope.tenantId,\n fileName,\n buffer: binary.buffer,\n })\n const attachment = em.create(Attachment, {\n entityId: asset.entityId,\n recordId: asset.recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n partitionCode,\n fileName,\n mimeType: asset.remote.mimeTypeHint ?? binary.contentType ?? 'application/octet-stream',\n fileSize: binary.contentLength ?? binary.buffer.byteLength,\n storageDriver: 'local',\n storagePath: stored.storagePath,\n storageMetadata: mergeAttachmentMetadata(null, {\n assignments: [{ type: asset.entityId, id: asset.recordId }],\n }),\n url: buildAttachmentFileUrl('pending'),\n content: null,\n })\n em.persist(attachment)\n await em.flush()\n attachment.url = asset.kind === 'image'\n ? buildAttachmentImageUrl(attachment.id, { slug: slugifyAttachmentFileName(fileName) })\n : buildAttachmentFileUrl(attachment.id)\n attachment.storageMetadata = {\n ...(attachment.storageMetadata ?? {}),\n source: 'akeneo',\n externalId: asset.externalId,\n kind: asset.kind,\n remoteCode: asset.remote.codeOrUrl,\n }\n await em.flush()\n await emitAttachmentCrudChange('created', attachment)\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'attachment', attachment.id, asset.externalId, scope)\n return attachment.id\n }\n\n async function reconcileAttachments(params: {\n entityId: string\n recordId: string\n desiredAssets: DesiredAsset[]\n reconciliation: AkeneoReconciliationSettings\n }): Promise<{ heroAttachmentId: string | null; heroAttachmentUrl: string | null }> {\n const desiredExternalIds = new Set(params.desiredAssets.map((asset) => asset.externalId))\n const desiredImages = params.desiredAssets.filter((asset) => asset.kind === 'image')\n const desiredFiles = params.desiredAssets.filter((asset) => asset.kind === 'file')\n const desiredAttachmentIds = await Promise.all(params.desiredAssets.map((asset) => upsertAsset(asset)))\n const heroAttachmentId = desiredImages.length > 0\n ? desiredAttachmentIds[params.desiredAssets.findIndex((asset) => asset.externalId === desiredImages[0]?.externalId)]\n : null\n const heroAttachmentUrl = heroAttachmentId ? buildAttachmentImageUrl(heroAttachmentId) : null\n\n const existing = await findWithDecryption(em, Attachment, {\n entityId: params.entityId,\n recordId: params.recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, undefined, scope)\n for (const attachment of existing) {\n const metadata = safeRecord(attachment.storageMetadata)\n const externalId = typeof metadata?.externalId === 'string' ? metadata.externalId : null\n const kind = metadata?.kind === 'image' || metadata?.kind === 'file' ? metadata.kind : null\n if (!externalId || !kind) continue\n const shouldDelete = kind === 'image'\n ? params.reconciliation.deleteMissingMedia\n : params.reconciliation.deleteMissingAttachments\n if (!shouldDelete || desiredExternalIds.has(externalId)) continue\n await deletePartitionFile(attachment.partitionCode, attachment.storagePath, attachment.storageDriver)\n await em.remove(attachment).flush()\n await emitAttachmentCrudChange('deleted', attachment)\n }\n\n return {\n heroAttachmentId,\n heroAttachmentUrl,\n }\n }\n\n async function syncAssociations(params: {\n product: AkeneoProduct\n localVariantId: string\n localProductId: string\n settings: AkeneoProductMappingSettings\n }): Promise<void> {\n if (!params.settings.syncAssociations) return\n const existing = await findWithDecryption(em, CatalogProductVariantRelation, {\n parentVariant: params.localVariantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, undefined, scope)\n\n const desired = new Map<string, {\n relationType: 'bundle' | 'grouped'\n childVariantId: string | null\n childProductId: string | null\n associationType: string\n minQuantity: number | null\n }>()\n\n const addDesired = async (associationType: string, externalCandidate: string | null, quantity: number | null, mode: 'product' | 'productModel') => {\n if (!externalCandidate) return\n let childVariantId: string | null = null\n let childProductId: string | null = null\n if (mode === 'product') {\n childVariantId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_variant', externalCandidate, scope)\n ?? await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product_variant', `${externalCandidate}:default`, scope)\n ?? await lookupVariantBySku(externalCandidate)\n childProductId = childVariantId\n ? null\n : await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product', externalCandidate, scope)\n ?? await lookupProductBySku(externalCandidate)\n } else {\n childProductId = await externalIdMappingService.lookupLocalId('sync_akeneo', 'catalog_product', externalCandidate, scope)\n }\n if (!childVariantId && !childProductId) return\n const relationType = relationTypeFromAssociation(associationType)\n const key = `${relationType}:${childVariantId ?? childProductId}`\n desired.set(key, {\n relationType,\n childVariantId,\n childProductId,\n associationType,\n minQuantity: quantity,\n })\n }\n\n for (const [associationType, payload] of Object.entries(params.product.associations ?? {})) {\n for (const productIdentifier of payload.products ?? []) {\n await addDesired(associationType, productIdentifier, null, 'product')\n }\n for (const productModelCode of payload.product_models ?? []) {\n await addDesired(associationType, productModelCode, null, 'productModel')\n }\n }\n\n for (const [associationType, payload] of Object.entries(params.product.quantified_associations ?? {})) {\n for (const productEntry of payload.products ?? []) {\n await addDesired(associationType, coerceString(productEntry.uuid) ?? coerceString(productEntry.identifier), coerceNumber(productEntry.quantity), 'product')\n }\n for (const productModelEntry of payload.product_models ?? []) {\n await addDesired(associationType, coerceString(productModelEntry.code) ?? coerceString(productModelEntry.identifier), coerceNumber(productModelEntry.quantity), 'productModel')\n }\n }\n\n const desiredKeys = new Set(desired.keys())\n for (const entry of desired.values()) {\n const existingRelation = existing.find((relation) => {\n const childVariantId = typeof relation.childVariant === 'string' ? relation.childVariant : relation.childVariant?.id ?? null\n const childProductId = typeof relation.childProduct === 'string' ? relation.childProduct : relation.childProduct?.id ?? null\n return relation.relationType === entry.relationType\n && childVariantId === entry.childVariantId\n && childProductId === entry.childProductId\n })\n if (existingRelation) {\n existingRelation.minQuantity = entry.minQuantity\n existingRelation.metadata = {\n source: 'akeneo',\n associationType: entry.associationType,\n }\n await em.flush()\n continue\n }\n const relation = em.create(CatalogProductVariantRelation, {\n parentVariant: em.getReference(CatalogProductVariant, params.localVariantId),\n childVariant: entry.childVariantId ? em.getReference(CatalogProductVariant, entry.childVariantId) : null,\n childProduct: entry.childProductId ? em.getReference(CatalogProduct, entry.childProductId) : null,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n relationType: entry.relationType,\n isRequired: false,\n minQuantity: entry.minQuantity,\n maxQuantity: null,\n position: 0,\n metadata: {\n source: 'akeneo',\n associationType: entry.associationType,\n },\n })\n em.persist(relation)\n await em.flush()\n }\n\n for (const relation of existing) {\n const metadata = safeRecord(relation.metadata)\n if (metadata?.source !== 'akeneo') continue\n const childVariantId = typeof relation.childVariant === 'string' ? relation.childVariant : relation.childVariant?.id ?? null\n const childProductId = typeof relation.childProduct === 'string' ? relation.childProduct : relation.childProduct?.id ?? null\n const key = `${relation.relationType}:${childVariantId ?? childProductId}`\n if (!desiredKeys.has(key)) {\n await em.remove(relation).flush()\n }\n }\n }\n\n async function upsertProduct(product: AkeneoProduct, mapping: AkeneoDataMapping): Promise<Array<{ externalId: string; action: 'create' | 'update' | 'skip'; data: Record<string, unknown> }>> {\n const family = product.family ? await client.getFamily(product.family) : null\n const hierarchy = await resolveProductHierarchy(product)\n const resolvedFamily = hierarchy.family ? await client.getFamily(hierarchy.family) : family\n const resolvedFamilyVariant = hierarchy.family && hierarchy.familyVariantCode\n ? await client.getFamilyVariant(hierarchy.family, hierarchy.familyVariantCode)\n : null\n const resolvedProductSettings = await resolveProductSettings({\n mapping,\n hierarchy,\n family: resolvedFamily,\n familyVariant: resolvedFamilyVariant,\n })\n const settings = resolvedProductSettings.settings\n const locale = settings.locale\n const channel = settings.channel ?? null\n hierarchy.axisCodes = resolvedProductSettings.axisCodes\n const productFieldsetCode = resolvedProductSettings.fieldsetPlan.product?.code ?? null\n const variantFieldsetCode = resolvedProductSettings.fieldsetPlan.variant?.code ?? null\n\n let optionSchemaId: string | null = null\n if (resolvedFamily && hierarchy.axisCodes.length > 0) {\n optionSchemaId = (await ensureOptionSchemaForFamily(\n resolvedFamily,\n resolvedFamilyVariant ?? null,\n true,\n true,\n locale,\n resolvedProductSettings.optionSchemaAttributeCodes,\n ))?.localId ?? null\n }\n const fieldMap = settings.fieldMap\n const derivedMapping: AkeneoDataMapping = {\n ...mapping,\n fields: buildProductFieldMappings(settings),\n settings: {\n ...(mapping.settings ?? {}),\n products: settings,\n },\n }\n\n const resolvedTitle = coerceString(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.title, locale, channel))\n ?? coerceString(product.identifier)\n ?? hierarchy.rootExternalId\n const resolvedSubtitle = coerceString(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.subtitle, locale, channel))\n const resolvedDescription = clampString(\n normalizeMarkdownText(\n coerceString(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.description, locale, channel)),\n ),\n 4000,\n )\n const resolvedSku = coerceString(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.sku, locale, channel))\n ?? coerceString(product.identifier)\n ?? product.uuid\n const resolvedBarcode = coerceString(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.barcode, locale, channel))\n const resolvedWeight = coerceMetricAmount(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.weight, locale, channel))\n ?? coerceMetricAmount(readLayeredAkeneoValue([hierarchy.rootValues, hierarchy.mergedValues], fieldMap.weight, locale, channel))\n const categoryIds = (\n await Promise.all(hierarchy.categories.map((code) => resolveCategoryId(code, locale)))\n ).filter((value): value is string => typeof value === 'string' && value.length > 0)\n\n const productExternalId = hierarchy.rootExternalId\n const existingProductId = await resolveExistingProductId(\n productExternalId,\n product.parent ? null : resolvedSku,\n )\n\n const productInput = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: resolvedTitle,\n subtitle: resolvedSubtitle ?? undefined,\n description: resolvedDescription ?? undefined,\n sku: product.parent ? undefined : resolvedSku,\n productType: product.parent ? 'configurable' : 'simple',\n optionSchemaId,\n isConfigurable: Boolean(product.parent),\n isActive: product.enabled !== false,\n weightValue: resolvedWeight ?? undefined,\n categoryIds,\n metadata: {\n source: 'akeneo',\n externalId: productExternalId,\n sourceProductUuid: product.uuid,\n family: hierarchy.family,\n familyVariant: hierarchy.familyVariantCode,\n parentChain: hierarchy.parentChain,\n associations: product.associations ?? {},\n quantifiedAssociations: product.quantified_associations ?? {},\n updatedAt: product.updated ?? null,\n },\n customFieldsetCode: productFieldsetCode,\n }\n\n let localProductId: string\n let productAction: 'create' | 'update'\n if (existingProductId) {\n await executeCommand('catalog.products.update', {\n id: existingProductId,\n ...productInput,\n })\n localProductId = existingProductId\n productAction = 'update'\n } else {\n const created = await executeCommand<{ productId?: string; id?: string }>('catalog.products.create', productInput)\n localProductId = created.productId ?? created.id ?? ''\n if (!localProductId) {\n throw new Error(`Akeneo product ${product.uuid} did not return a local product id`)\n }\n productAction = 'create'\n }\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product', localProductId, productExternalId, scope)\n\n const variantExternalId = product.parent ? product.uuid : `${product.uuid}:default`\n const existingVariantId = await resolveExistingVariantId(variantExternalId, resolvedSku, localProductId)\n\n const optionValues =\n hierarchy.axisCodes.length > 0\n ? await (async () => {\n const values: Record<string, string> = {}\n for (const axis of hierarchy.axisCodes) {\n const rawValue = readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], axis, locale, channel)\n const optionLabels = await getAttributeOptionLabels(axis, locale)\n const normalizedValue = normalizeAkeneoSelectValue(rawValue, optionLabels)\n if (normalizedValue) {\n values[slugifyAkeneoCode(axis)] = normalizedValue\n }\n }\n return Object.keys(values).length > 0 ? values : undefined\n })()\n : undefined\n\n const existingDefaultVariant = await findOneWithDecryption(\n em,\n CatalogProductVariant,\n {\n product: localProductId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isDefault: true,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n const variantName = coerceString(readLayeredAkeneoValue([hierarchy.leafValues, hierarchy.mergedValues], fieldMap.variantName, locale, channel))\n ?? (optionValues && Object.values(optionValues).length > 0 ? Object.values(optionValues).join(' / ') : resolvedTitle)\n\n const variantInput = {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n productId: localProductId,\n name: variantName,\n sku: resolvedSku,\n barcode: resolvedBarcode ?? undefined,\n isDefault: existingVariantId ? existingVariantId === existingDefaultVariant?.id : !existingDefaultVariant,\n isActive: product.enabled !== false,\n weightValue: resolvedWeight ?? undefined,\n optionValues: optionValues && Object.keys(optionValues).length > 0 ? optionValues : undefined,\n metadata: {\n source: 'akeneo',\n externalId: variantExternalId,\n sourceProductUuid: product.uuid,\n sourceParentCode: product.parent ?? null,\n associations: product.associations ?? {},\n quantifiedAssociations: product.quantified_associations ?? {},\n updatedAt: product.updated ?? null,\n },\n customFieldsetCode: variantFieldsetCode,\n }\n\n let localVariantId: string\n let variantAction: 'create' | 'update'\n if (existingVariantId) {\n await executeCommand('catalog.variants.update', {\n id: existingVariantId,\n ...variantInput,\n })\n localVariantId = existingVariantId\n variantAction = 'update'\n } else {\n const created = await executeCommand<{ variantId?: string; id?: string }>('catalog.variants.create', variantInput)\n localVariantId = created.variantId ?? created.id ?? ''\n if (!localVariantId) {\n throw new Error(`Akeneo variant ${variantExternalId} did not return a local variant id`)\n }\n variantAction = 'create'\n }\n await externalIdMappingService.storeExternalIdMapping('sync_akeneo', 'catalog_product_variant', localVariantId, variantExternalId, scope)\n\n await applyCustomFieldMappings({\n mapping: derivedMapping,\n hierarchy,\n product,\n localProductId,\n localVariantId,\n fieldsetPlan: resolvedProductSettings.fieldsetPlan,\n })\n await upsertOffersAndPrices({\n mapping: derivedMapping,\n settings,\n hierarchy,\n localProductId,\n localVariantId,\n resolvedProductTitle: resolvedTitle,\n resolvedProductDescription: resolvedDescription,\n variantExternalId,\n })\n\n const desiredAssets: DesiredAsset[] = []\n for (const mediaMapping of settings.mediaMappings) {\n const productScopedValue = readPreferredAkeneoValue(\n hierarchy.rootValues,\n mediaMapping.attributeCode,\n locale,\n channel,\n )\n const variantScopedValue = readPreferredAkeneoValue(\n hierarchy.leafValues,\n mediaMapping.attributeCode,\n locale,\n channel,\n )\n const effectiveTarget = resolveAkeneoMediaTarget({\n mappingTarget: mediaMapping.target,\n attributeCode: mediaMapping.attributeCode,\n variantAttributeCodes: resolvedProductSettings.variantAttributeCodes,\n productScopedValue,\n variantScopedValue,\n })\n const sourceLayers = effectiveTarget === 'product'\n ? [hierarchy.rootValues, hierarchy.mergedValues]\n : [hierarchy.leafValues, hierarchy.mergedValues]\n const rawValue = readLayeredAkeneoValue(sourceLayers, mediaMapping.attributeCode, locale, channel)\n const refs = collectMediaReferences(rawValue)\n refs.forEach((ref, index) => {\n desiredAssets.push({\n externalId: `${effectiveTarget}:${mediaMapping.kind}:${mediaMapping.attributeCode}:${ref.codeOrUrl}:${index}`,\n entityId: effectiveTarget === 'product' ? PRODUCT_ENTITY_ID : VARIANT_ENTITY_ID,\n recordId: effectiveTarget === 'product' ? localProductId : localVariantId,\n kind: mediaMapping.kind,\n remote: ref,\n })\n })\n }\n\n const assetsByTarget = new Map<string, DesiredAsset[]>()\n const pendingVariantHeroUpdates: Array<{\n variantId: string\n defaultMediaId: string | null\n defaultMediaUrl: string | null\n }> = []\n const shouldMirrorVariantHeroToProduct = !product.parent && !hierarchy.familyVariantCode\n let mirroredProductHeroFromVariant: {\n defaultMediaId: string | null\n defaultMediaUrl: string | null\n } | null = null\n for (const asset of desiredAssets) {\n const key = `${asset.entityId}:${asset.recordId}`\n const bucket = assetsByTarget.get(key) ?? []\n bucket.push(asset)\n assetsByTarget.set(key, bucket)\n }\n\n for (const assets of assetsByTarget.values()) {\n const firstAsset = assets[0]\n if (!firstAsset) continue\n const hero = await reconcileAttachments({\n entityId: firstAsset.entityId,\n recordId: firstAsset.recordId,\n desiredAssets: assets,\n reconciliation: settings.reconciliation,\n })\n if (firstAsset.entityId === PRODUCT_ENTITY_ID) {\n await executeCommand('catalog.products.update', {\n id: localProductId,\n defaultMediaId: hero.heroAttachmentId,\n defaultMediaUrl: hero.heroAttachmentUrl,\n })\n } else {\n pendingVariantHeroUpdates.push({\n variantId: localVariantId,\n defaultMediaId: hero.heroAttachmentId,\n defaultMediaUrl: hero.heroAttachmentUrl,\n })\n if (\n shouldMirrorVariantHeroToProduct\n && firstAsset.recordId === localVariantId\n && hero.heroAttachmentId\n && !mirroredProductHeroFromVariant\n ) {\n mirroredProductHeroFromVariant = {\n defaultMediaId: hero.heroAttachmentId,\n defaultMediaUrl: hero.heroAttachmentUrl,\n }\n }\n }\n }\n\n await syncAssociations({\n product,\n localVariantId,\n localProductId,\n settings,\n })\n\n for (const heroUpdate of pendingVariantHeroUpdates) {\n await em.getConnection().execute(\n `\n update catalog_product_variants\n set default_media_id = ?, default_media_url = ?, updated_at = now()\n where id = ? and organization_id = ? and tenant_id = ?\n `,\n [\n heroUpdate.defaultMediaId,\n heroUpdate.defaultMediaUrl,\n heroUpdate.variantId,\n scope.organizationId,\n scope.tenantId,\n ],\n )\n await emitCatalogQueryIndexEvent(buildCommandContext(), {\n entityType: VARIANT_ENTITY_ID,\n recordId: heroUpdate.variantId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n action: 'updated',\n })\n }\n\n if (mirroredProductHeroFromVariant) {\n await executeCommand('catalog.products.update', {\n id: localProductId,\n defaultMediaId: mirroredProductHeroFromVariant.defaultMediaId,\n defaultMediaUrl: mirroredProductHeroFromVariant.defaultMediaUrl,\n })\n }\n\n return [\n {\n externalId: productExternalId,\n action: productAction,\n data: {\n localProductId,\n sku: resolvedSku,\n family: hierarchy.family,\n },\n },\n {\n externalId: variantExternalId,\n action: variantAction,\n data: {\n localVariantId,\n productId: localProductId,\n sku: resolvedSku,\n },\n },\n ]\n }\n\n async function deactivateMappedEntities(entityType: string, seenExternalIds: Set<string>, commandId: string): Promise<void> {\n const mappings = await findWithDecryption(em, SyncExternalIdMapping, {\n integrationId: 'sync_akeneo',\n internalEntityType: entityType,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n for (const mapping of mappings) {\n if (seenExternalIds.has(mapping.externalId)) continue\n await executeCommand(commandId, {\n id: mapping.internalEntityId,\n isActive: false,\n })\n }\n }\n\n async function reconcileCategories(seenExternalIds: Set<string>, locale: string, reconciliation: AkeneoReconciliationSettings): Promise<void> {\n if (!reconciliation.deactivateMissingCategories || seenExternalIds.size === 0) return\n await deactivateMappedEntities('catalog_product_category', seenExternalIds, 'catalog.categories.update')\n }\n\n async function reconcileAttributes(params: {\n seenFamilyExternalIds: Set<string>\n currentCustomFieldKeys: Set<string>\n reconciliation: AkeneoReconciliationSettings\n }): Promise<void> {\n if (!params.reconciliation.deactivateMissingAttributes) return\n if (params.seenFamilyExternalIds.size > 0) {\n await deactivateMappedEntities('catalog_option_schema', params.seenFamilyExternalIds, 'catalog.optionSchemas.update')\n }\n const defs = await findWithDecryption(em, CustomFieldDef, {\n entityId: { $in: [PRODUCT_ENTITY_ID, VARIANT_ENTITY_ID] },\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n for (const def of defs) {\n const sourceMetadata = safeRecord(def.configJson?.sourceMetadata)\n if (sourceMetadata?.provider !== 'akeneo') continue\n if (params.currentCustomFieldKeys.has(`${def.entityId}:${def.key}`)) continue\n def.isActive = false\n }\n await em.flush()\n }\n\n async function reconcileProducts(seenProductExternalIds: Set<string>, seenVariantExternalIds: Set<string>, reconciliation: AkeneoReconciliationSettings): Promise<void> {\n if (!reconciliation.deactivateMissingProducts) return\n if (seenProductExternalIds.size > 0) {\n await deactivateMappedEntities('catalog_product', seenProductExternalIds, 'catalog.products.update')\n }\n if (seenVariantExternalIds.size > 0) {\n await deactivateMappedEntities('catalog_product_variant', seenVariantExternalIds, 'catalog.variants.update')\n }\n }\n\n return {\n upsertCategory,\n upsertAttributeFamily,\n upsertProduct,\n syncMappedCustomFields,\n reconcileMappedCustomFieldFieldsets,\n reconcileCategories,\n reconcileAttributes,\n reconcileProducts,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["mapping", "options", "input", "relation"]
|
|
7
7
|
}
|
|
@@ -303,7 +303,7 @@ async function upsertSyncMapping(em, entityType, mapping, scope) {
|
|
|
303
303
|
organizationId: scope.organizationId,
|
|
304
304
|
tenantId: scope.tenantId
|
|
305
305
|
});
|
|
306
|
-
await em.
|
|
306
|
+
await em.persist(created).flush();
|
|
307
307
|
}
|
|
308
308
|
async function hasExistingAkeneoConfiguration(em, credentialsService, scope) {
|
|
309
309
|
const [credentials, mappings] = await Promise.all([
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/sync_akeneo/lib/preset.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CatalogPriceKind } from '@open-mercato/core/modules/catalog/data/entities'\nimport { SyncMapping } from '@open-mercato/core/modules/data_sync/data/entities'\nimport type { CredentialsService } from '@open-mercato/core/modules/integrations/lib/credentials-service'\nimport type { IntegrationLogService } from '@open-mercato/core/modules/integrations/lib/log-service'\nimport type { IntegrationStateService } from '@open-mercato/core/modules/integrations/lib/state-service'\nimport { SalesChannel } from '@open-mercato/core/modules/sales/data/entities'\nimport { createAkeneoClient } from './client'\nimport { inferAkeneoProductMapping } from './inference'\nimport {\n buildAkeneoFieldsetCode,\n buildDefaultAkeneoMapping,\n buildProductFieldMappings,\n normalizeAkeneoMapping,\n type AkeneoCredentialShape,\n} from './shared'\n\nconst AKENEO_INTEGRATION_ID = 'sync_akeneo'\n\ntype IntegrationScope = {\n organizationId: string\n tenantId: string\n}\n\ntype LocalChannelOption = {\n code: string\n name: string\n}\n\ntype PriceKindOption = {\n code: string\n title: string\n displayMode: string\n}\n\ntype DiscoverySnapshot = {\n locales: Array<{ code: string; label: string; enabled?: boolean }>\n channels: Array<{ code: string; label: string; locales: string[] }>\n attributes: Array<{\n code: string\n type: string\n label: string\n localizable: boolean\n scopable: boolean\n group?: string\n metricFamily?: string\n }>\n families: Array<{ code: string; label: string; attributeCount: number }>\n familyVariants: Array<{ familyCode: string; code: string; label: string; axes: string[]; attributes: string[] }>\n}\n\ntype AkeneoEnvPreset = {\n credentials: AkeneoCredentialShape\n force: boolean\n productLocale?: string\n categoryLocale?: string\n productChannel?: string | null\n productChannels?: string[]\n importAllChannels?: boolean\n createMissingChannels?: boolean\n syncAssociations?: boolean\n familyCodeFilter?: string[]\n productsSettingsOverride?: Record<string, unknown>\n categoriesSettingsOverride?: Record<string, unknown>\n attributesSettingsOverride?: Record<string, unknown>\n}\n\nexport type ApplyAkeneoPresetResult =\n | { status: 'skipped'; reason: string }\n | { status: 'configured'; discoveryApplied: true }\n\nfunction readEnvValue(env: NodeJS.ProcessEnv, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = env[key]?.trim()\n if (value) return value\n }\n return undefined\n}\n\nfunction readCsvEnv(env: NodeJS.ProcessEnv, keys: string[]): string[] | undefined {\n const raw = readEnvValue(env, keys)\n if (!raw) return undefined\n const values = raw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n return values.length > 0 ? Array.from(new Set(values)) : undefined\n}\n\nfunction readBooleanEnv(env: NodeJS.ProcessEnv, keys: string[]): boolean | undefined {\n for (const key of keys) {\n const parsed = parseBooleanToken(env[key])\n if (parsed !== null) return parsed\n }\n return undefined\n}\n\nfunction readJsonEnv(env: NodeJS.ProcessEnv, keys: string[], label: string): Record<string, unknown> | undefined {\n const raw = readEnvValue(env, keys)\n if (!raw) return undefined\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid JSON'\n throw new Error(`[sync_akeneo] ${label} is not valid JSON: ${message}`)\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`[sync_akeneo] ${label} must be a JSON object.`)\n }\n return parsed as Record<string, unknown>\n}\n\nexport function readAkeneoEnvPreset(env: NodeJS.ProcessEnv = process.env): AkeneoEnvPreset | null {\n const credentialKeys = {\n apiUrl: ['OM_INTEGRATION_AKENEO_API_URL', 'OPENMERCATO_AKENEO_API_URL', 'AKENEO_API_URL'],\n clientId: ['OM_INTEGRATION_AKENEO_CLIENT_ID', 'OPENMERCATO_AKENEO_CLIENT_ID', 'AKENEO_CLIENT_ID'],\n clientSecret: ['OM_INTEGRATION_AKENEO_CLIENT_SECRET', 'OPENMERCATO_AKENEO_CLIENT_SECRET', 'AKENEO_CLIENT_SECRET'],\n username: ['OM_INTEGRATION_AKENEO_USERNAME', 'OPENMERCATO_AKENEO_USERNAME', 'AKENEO_USERNAME'],\n password: ['OM_INTEGRATION_AKENEO_PASSWORD', 'OPENMERCATO_AKENEO_PASSWORD', 'AKENEO_PASSWORD'],\n } as const\n\n const anyCredentialProvided = Object.values(credentialKeys).some((keys) => Boolean(readEnvValue(env, [...keys])))\n if (!anyCredentialProvided) {\n return null\n }\n\n const apiUrl = readEnvValue(env, [...credentialKeys.apiUrl])\n const clientId = readEnvValue(env, [...credentialKeys.clientId])\n const clientSecret = readEnvValue(env, [...credentialKeys.clientSecret])\n const username = readEnvValue(env, [...credentialKeys.username])\n const password = readEnvValue(env, [...credentialKeys.password])\n\n if (!apiUrl || !clientId || !clientSecret || !username || !password) {\n throw new Error(\n '[sync_akeneo] Incomplete Akeneo env preset. Set OM_INTEGRATION_AKENEO_API_URL, OM_INTEGRATION_AKENEO_CLIENT_ID, OM_INTEGRATION_AKENEO_CLIENT_SECRET, OM_INTEGRATION_AKENEO_USERNAME, and OM_INTEGRATION_AKENEO_PASSWORD.',\n )\n }\n\n return {\n credentials: {\n apiUrl,\n clientId,\n clientSecret,\n username,\n password,\n },\n force: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_FORCE_PRECONFIGURE', 'OPENMERCATO_AKENEO_FORCE_PRECONFIGURE', 'AKENEO_FORCE_PRECONFIGURE']) ?? false,\n productLocale: readEnvValue(env, ['OM_INTEGRATION_AKENEO_PRODUCT_LOCALE', 'OPENMERCATO_AKENEO_PRODUCT_LOCALE', 'AKENEO_PRODUCT_LOCALE']),\n categoryLocale: readEnvValue(env, ['OM_INTEGRATION_AKENEO_CATEGORY_LOCALE', 'OPENMERCATO_AKENEO_CATEGORY_LOCALE', 'AKENEO_CATEGORY_LOCALE']),\n productChannel: readEnvValue(env, ['OM_INTEGRATION_AKENEO_PRODUCT_CHANNEL', 'OPENMERCATO_AKENEO_PRODUCT_CHANNEL', 'AKENEO_PRODUCT_CHANNEL']) ?? undefined,\n productChannels: readCsvEnv(env, ['OM_INTEGRATION_AKENEO_IMPORT_CHANNELS', 'OPENMERCATO_AKENEO_IMPORT_CHANNELS', 'AKENEO_IMPORT_CHANNELS']),\n importAllChannels: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_IMPORT_ALL_CHANNELS', 'OPENMERCATO_AKENEO_IMPORT_ALL_CHANNELS', 'AKENEO_IMPORT_ALL_CHANNELS']),\n createMissingChannels: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_CREATE_MISSING_CHANNELS', 'OPENMERCATO_AKENEO_CREATE_MISSING_CHANNELS', 'AKENEO_CREATE_MISSING_CHANNELS']),\n syncAssociations: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_SYNC_ASSOCIATIONS', 'OPENMERCATO_AKENEO_SYNC_ASSOCIATIONS', 'AKENEO_SYNC_ASSOCIATIONS']),\n familyCodeFilter: readCsvEnv(env, ['OM_INTEGRATION_AKENEO_ATTRIBUTE_FAMILY_FILTER', 'OPENMERCATO_AKENEO_ATTRIBUTE_FAMILY_FILTER', 'AKENEO_ATTRIBUTE_FAMILY_FILTER']),\n productsSettingsOverride: readJsonEnv(\n env,\n ['OM_INTEGRATION_AKENEO_PRODUCTS_SETTINGS_JSON', 'OPENMERCATO_AKENEO_PRODUCTS_SETTINGS_JSON', 'AKENEO_PRODUCTS_SETTINGS_JSON'],\n 'OM_INTEGRATION_AKENEO_PRODUCTS_SETTINGS_JSON',\n ),\n categoriesSettingsOverride: readJsonEnv(\n env,\n ['OM_INTEGRATION_AKENEO_CATEGORIES_SETTINGS_JSON', 'OPENMERCATO_AKENEO_CATEGORIES_SETTINGS_JSON', 'AKENEO_CATEGORIES_SETTINGS_JSON'],\n 'OM_INTEGRATION_AKENEO_CATEGORIES_SETTINGS_JSON',\n ),\n attributesSettingsOverride: readJsonEnv(\n env,\n ['OM_INTEGRATION_AKENEO_ATTRIBUTES_SETTINGS_JSON', 'OPENMERCATO_AKENEO_ATTRIBUTES_SETTINGS_JSON', 'AKENEO_ATTRIBUTES_SETTINGS_JSON'],\n 'OM_INTEGRATION_AKENEO_ATTRIBUTES_SETTINGS_JSON',\n ),\n }\n}\n\nfunction inferPriceKindCode(attributeCode: string): string {\n const normalized = attributeCode.trim().toLowerCase()\n return normalized.includes('sale')\n || normalized.includes('promo')\n || normalized.includes('special')\n || normalized.includes('discount')\n ? 'sale'\n : 'regular'\n}\n\nfunction buildDiscoveredFieldsetMappings(discovery: DiscoverySnapshot): Array<{\n sourceType: 'family' | 'familyVariant'\n sourceCode: string\n target: 'product' | 'variant'\n fieldsetCode: string\n fieldsetLabel: string\n description: string\n}> {\n const familyRows = discovery.families.flatMap((family) => {\n const fieldsetCode = buildAkeneoFieldsetCode('product', family.code)\n if (!fieldsetCode) return []\n return [{\n sourceType: 'family' as const,\n sourceCode: family.code,\n target: 'product' as const,\n fieldsetCode,\n fieldsetLabel: family.label || family.code,\n description: `Akeneo family ${family.code}`,\n }]\n })\n\n const familyVariantRows = discovery.familyVariants.flatMap((familyVariant) => {\n const fieldsetCode = buildAkeneoFieldsetCode('variant', familyVariant.code)\n if (!fieldsetCode) return []\n return [{\n sourceType: 'familyVariant' as const,\n sourceCode: familyVariant.code,\n target: 'variant' as const,\n fieldsetCode,\n fieldsetLabel: familyVariant.label || familyVariant.code,\n description: `Akeneo family variant ${familyVariant.code} from family ${familyVariant.familyCode}`,\n }]\n })\n\n return [...familyRows, ...familyVariantRows]\n}\n\nexport function buildAkeneoMappingsFromPreset(input: {\n preset: AkeneoEnvPreset\n discovery: DiscoverySnapshot\n localChannels: LocalChannelOption[]\n priceKinds: PriceKindOption[]\n}): {\n productsMapping: ReturnType<typeof buildDefaultAkeneoMapping>\n categoriesMapping: ReturnType<typeof buildDefaultAkeneoMapping>\n attributesMapping: ReturnType<typeof buildDefaultAkeneoMapping>\n} {\n const { preset, discovery, localChannels, priceKinds } = input\n const baseProducts = buildDefaultAkeneoMapping('products')\n const productSettings = baseProducts.settings?.products\n if (!productSettings) {\n throw new Error('[sync_akeneo] Failed to resolve default product mapping settings.')\n }\n\n const discoveredFamilyVariant = discovery.familyVariants.length > 0\n ? {\n code: '__discovery__',\n variant_attribute_sets: discovery.familyVariants.map((familyVariant, index) => ({\n level: index + 1,\n axes: familyVariant.axes,\n attributes: familyVariant.attributes,\n })),\n }\n : null\n\n const inferred = inferAkeneoProductMapping({\n attributes: discovery.attributes.map((attribute) => ({\n code: attribute.code,\n type: attribute.type,\n labels: attribute.label ? { inferred: attribute.label } : undefined,\n localizable: attribute.localizable,\n scopable: attribute.scopable,\n group: attribute.group,\n metric_family: attribute.metricFamily,\n })),\n family: null,\n familyVariant: discoveredFamilyVariant,\n fieldMap: productSettings.fieldMap,\n explicitCustomFieldMappings: [],\n explicitMediaMappings: [],\n })\n\n const preferredLocale = preset.productLocale\n ?? productSettings.locale\n ?? discovery.locales.find((locale) => locale.enabled)?.code\n ?? discovery.locales[0]?.code\n const preferredAkeneoChannel = preset.productChannel\n ?? discovery.channels[0]?.code\n ?? productSettings.channel\n const preferredLocalChannel = localChannels.find((channel) => ['web', 'online', 'ecommerce', 'default'].includes(channel.code.trim().toLowerCase()))\n ?? localChannels[0]\n ?? null\n const selectedChannels = preset.productChannels\n ?? (preferredAkeneoChannel ? [preferredAkeneoChannel] : [])\n\n const discoveredPriceMappings = preferredLocalChannel\n ? inferred.autoPriceAttributeCodes.map((attributeCode) => {\n const inferredKind = inferPriceKindCode(attributeCode)\n const matchedPriceKind = priceKinds.find((priceKind) => priceKind.code === inferredKind)\n return {\n attributeCode,\n priceKindCode: matchedPriceKind?.code ?? inferredKind,\n akeneoChannel: preferredAkeneoChannel ?? null,\n localChannelCode: preferredLocalChannel.code,\n }\n })\n : []\n\n const productsOverride = preset.productsSettingsOverride ?? {}\n const overrideFieldMap = productsOverride.fieldMap && typeof productsOverride.fieldMap === 'object' && !Array.isArray(productsOverride.fieldMap)\n ? productsOverride.fieldMap as Record<string, unknown>\n : null\n const overrideReconciliation = productsOverride.reconciliation && typeof productsOverride.reconciliation === 'object' && !Array.isArray(productsOverride.reconciliation)\n ? productsOverride.reconciliation as Record<string, unknown>\n : null\n const {\n fieldMap: _ignoredFieldMap,\n reconciliation: _ignoredReconciliation,\n ...productsOverrideShallow\n } = productsOverride\n\n const rawProductsMapping = {\n ...baseProducts,\n settings: {\n products: {\n ...productSettings,\n locale: preferredLocale,\n channel: preferredAkeneoChannel ?? null,\n channels: selectedChannels,\n importAllChannels: preset.importAllChannels ?? productSettings.importAllChannels,\n customFieldMappings: inferred.autoCustomFieldMappings.map((mapping) => ({\n attributeCode: mapping.attributeCode,\n target: mapping.target,\n fieldKey: mapping.fieldKey,\n kind: mapping.kind ?? null,\n skip: mapping.skip ?? false,\n })),\n mediaMappings: inferred.autoMediaMappings.map((mapping) => ({\n attributeCode: mapping.attributeCode,\n target: mapping.target,\n kind: mapping.kind,\n })),\n priceMappings: discoveredPriceMappings,\n fieldsetMappings: buildDiscoveredFieldsetMappings(discovery),\n createMissingChannels: preset.createMissingChannels ?? productSettings.createMissingChannels,\n syncAssociations: preset.syncAssociations ?? productSettings.syncAssociations,\n ...productsOverrideShallow,\n fieldMap: {\n ...inferred.fieldMap,\n ...(overrideFieldMap ?? {}),\n },\n reconciliation: {\n ...productSettings.reconciliation,\n ...(overrideReconciliation ?? {}),\n },\n },\n },\n }\n const productsMapping = normalizeAkeneoMapping('products', rawProductsMapping as Record<string, unknown>)\n if (productsMapping.settings?.products) {\n productsMapping.fields = buildProductFieldMappings(productsMapping.settings.products)\n }\n\n const baseCategories = buildDefaultAkeneoMapping('categories')\n const categoriesMapping = normalizeAkeneoMapping('categories', {\n ...baseCategories,\n settings: {\n categories: {\n locale: preset.categoryLocale ?? preferredLocale,\n ...(preset.categoriesSettingsOverride ?? {}),\n },\n },\n })\n\n const baseAttributes = buildDefaultAkeneoMapping('attributes')\n const attributesMapping = normalizeAkeneoMapping('attributes', {\n ...baseAttributes,\n settings: {\n attributes: {\n ...baseAttributes.settings?.attributes,\n familyCodeFilter: preset.familyCodeFilter ?? baseAttributes.settings?.attributes?.familyCodeFilter ?? [],\n ...(preset.attributesSettingsOverride ?? {}),\n },\n },\n })\n\n return {\n productsMapping,\n categoriesMapping,\n attributesMapping,\n }\n}\n\nasync function loadLocalDiscoveryContext(em: EntityManager, scope: IntegrationScope): Promise<{\n localChannels: LocalChannelOption[]\n priceKinds: PriceKindOption[]\n}> {\n const [channels, priceKinds] = await Promise.all([\n findWithDecryption(em, SalesChannel, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n fields: ['code', 'name'],\n orderBy: { name: 'asc' },\n }, scope),\n findWithDecryption(em, CatalogPriceKind, {\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n fields: ['code', 'title', 'displayMode'],\n orderBy: { title: 'asc' },\n }, scope),\n ])\n\n return {\n localChannels: channels\n .filter((channel) => typeof channel.code === 'string' && channel.code.trim().length > 0)\n .map((channel) => ({ code: String(channel.code), name: channel.name })),\n priceKinds: priceKinds.map((priceKind) => ({\n code: priceKind.code,\n title: priceKind.title,\n displayMode: priceKind.displayMode,\n })),\n }\n}\n\nasync function upsertSyncMapping(\n em: EntityManager,\n entityType: 'products' | 'categories' | 'attributes',\n mapping: Record<string, unknown>,\n scope: IntegrationScope,\n): Promise<void> {\n const existing = await findOneWithDecryption(em, SyncMapping, {\n integrationId: AKENEO_INTEGRATION_ID,\n entityType,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, undefined, scope)\n\n if (existing) {\n existing.mapping = mapping\n await em.flush()\n return\n }\n\n const created = em.create(SyncMapping, {\n integrationId: AKENEO_INTEGRATION_ID,\n entityType,\n mapping,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n await em.persistAndFlush(created)\n}\n\nasync function hasExistingAkeneoConfiguration(\n em: EntityManager,\n credentialsService: CredentialsService,\n scope: IntegrationScope,\n): Promise<boolean> {\n const [credentials, mappings] = await Promise.all([\n credentialsService.getRaw(AKENEO_INTEGRATION_ID, scope),\n findOneWithDecryption(em, SyncMapping, {\n integrationId: AKENEO_INTEGRATION_ID,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, {\n fields: ['id'],\n }, scope),\n ])\n return Boolean(credentials) || Boolean(mappings)\n}\n\nexport async function applyAkeneoEnvPreset(params: {\n em: EntityManager\n credentialsService: CredentialsService\n integrationStateService: IntegrationStateService\n integrationLogService?: IntegrationLogService\n scope: IntegrationScope\n force?: boolean\n env?: NodeJS.ProcessEnv\n}): Promise<ApplyAkeneoPresetResult> {\n const preset = readAkeneoEnvPreset(params.env)\n if (!preset) {\n return { status: 'skipped', reason: 'No Akeneo preset env variables were provided.' }\n }\n\n const force = params.force ?? preset.force\n if (!force && await hasExistingAkeneoConfiguration(params.em, params.credentialsService, params.scope)) {\n return { status: 'skipped', reason: 'Akeneo credentials or mappings already exist. Use force to overwrite them.' }\n }\n\n await params.credentialsService.save(AKENEO_INTEGRATION_ID, preset.credentials, params.scope)\n\n const client = createAkeneoClient(preset.credentials)\n const [discovery, localContext] = await Promise.all([\n client.collectDiscoveryData(),\n loadLocalDiscoveryContext(params.em, params.scope),\n ])\n\n const mappings = buildAkeneoMappingsFromPreset({\n preset,\n discovery,\n localChannels: localContext.localChannels,\n priceKinds: localContext.priceKinds,\n })\n\n await upsertSyncMapping(params.em, 'products', mappings.productsMapping as unknown as Record<string, unknown>, params.scope)\n await upsertSyncMapping(params.em, 'categories', mappings.categoriesMapping as unknown as Record<string, unknown>, params.scope)\n await upsertSyncMapping(params.em, 'attributes', mappings.attributesMapping as unknown as Record<string, unknown>, params.scope)\n await params.integrationStateService.upsert(AKENEO_INTEGRATION_ID, { isEnabled: true }, params.scope)\n\n if (params.integrationLogService) {\n await params.integrationLogService.scoped(AKENEO_INTEGRATION_ID, params.scope).info(\n 'Akeneo integration was preconfigured from environment variables.',\n {\n locale: mappings.productsMapping.settings?.products?.locale ?? null,\n channel: mappings.productsMapping.settings?.products?.channel ?? null,\n importAllChannels: mappings.productsMapping.settings?.products?.importAllChannels ?? null,\n },\n )\n }\n\n return { status: 'configured', discoveryApplied: true }\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CatalogPriceKind } from '@open-mercato/core/modules/catalog/data/entities'\nimport { SyncMapping } from '@open-mercato/core/modules/data_sync/data/entities'\nimport type { CredentialsService } from '@open-mercato/core/modules/integrations/lib/credentials-service'\nimport type { IntegrationLogService } from '@open-mercato/core/modules/integrations/lib/log-service'\nimport type { IntegrationStateService } from '@open-mercato/core/modules/integrations/lib/state-service'\nimport { SalesChannel } from '@open-mercato/core/modules/sales/data/entities'\nimport { createAkeneoClient } from './client'\nimport { inferAkeneoProductMapping } from './inference'\nimport {\n buildAkeneoFieldsetCode,\n buildDefaultAkeneoMapping,\n buildProductFieldMappings,\n normalizeAkeneoMapping,\n type AkeneoCredentialShape,\n} from './shared'\n\nconst AKENEO_INTEGRATION_ID = 'sync_akeneo'\n\ntype IntegrationScope = {\n organizationId: string\n tenantId: string\n}\n\ntype LocalChannelOption = {\n code: string\n name: string\n}\n\ntype PriceKindOption = {\n code: string\n title: string\n displayMode: string\n}\n\ntype DiscoverySnapshot = {\n locales: Array<{ code: string; label: string; enabled?: boolean }>\n channels: Array<{ code: string; label: string; locales: string[] }>\n attributes: Array<{\n code: string\n type: string\n label: string\n localizable: boolean\n scopable: boolean\n group?: string\n metricFamily?: string\n }>\n families: Array<{ code: string; label: string; attributeCount: number }>\n familyVariants: Array<{ familyCode: string; code: string; label: string; axes: string[]; attributes: string[] }>\n}\n\ntype AkeneoEnvPreset = {\n credentials: AkeneoCredentialShape\n force: boolean\n productLocale?: string\n categoryLocale?: string\n productChannel?: string | null\n productChannels?: string[]\n importAllChannels?: boolean\n createMissingChannels?: boolean\n syncAssociations?: boolean\n familyCodeFilter?: string[]\n productsSettingsOverride?: Record<string, unknown>\n categoriesSettingsOverride?: Record<string, unknown>\n attributesSettingsOverride?: Record<string, unknown>\n}\n\nexport type ApplyAkeneoPresetResult =\n | { status: 'skipped'; reason: string }\n | { status: 'configured'; discoveryApplied: true }\n\nfunction readEnvValue(env: NodeJS.ProcessEnv, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = env[key]?.trim()\n if (value) return value\n }\n return undefined\n}\n\nfunction readCsvEnv(env: NodeJS.ProcessEnv, keys: string[]): string[] | undefined {\n const raw = readEnvValue(env, keys)\n if (!raw) return undefined\n const values = raw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n return values.length > 0 ? Array.from(new Set(values)) : undefined\n}\n\nfunction readBooleanEnv(env: NodeJS.ProcessEnv, keys: string[]): boolean | undefined {\n for (const key of keys) {\n const parsed = parseBooleanToken(env[key])\n if (parsed !== null) return parsed\n }\n return undefined\n}\n\nfunction readJsonEnv(env: NodeJS.ProcessEnv, keys: string[], label: string): Record<string, unknown> | undefined {\n const raw = readEnvValue(env, keys)\n if (!raw) return undefined\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid JSON'\n throw new Error(`[sync_akeneo] ${label} is not valid JSON: ${message}`)\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error(`[sync_akeneo] ${label} must be a JSON object.`)\n }\n return parsed as Record<string, unknown>\n}\n\nexport function readAkeneoEnvPreset(env: NodeJS.ProcessEnv = process.env): AkeneoEnvPreset | null {\n const credentialKeys = {\n apiUrl: ['OM_INTEGRATION_AKENEO_API_URL', 'OPENMERCATO_AKENEO_API_URL', 'AKENEO_API_URL'],\n clientId: ['OM_INTEGRATION_AKENEO_CLIENT_ID', 'OPENMERCATO_AKENEO_CLIENT_ID', 'AKENEO_CLIENT_ID'],\n clientSecret: ['OM_INTEGRATION_AKENEO_CLIENT_SECRET', 'OPENMERCATO_AKENEO_CLIENT_SECRET', 'AKENEO_CLIENT_SECRET'],\n username: ['OM_INTEGRATION_AKENEO_USERNAME', 'OPENMERCATO_AKENEO_USERNAME', 'AKENEO_USERNAME'],\n password: ['OM_INTEGRATION_AKENEO_PASSWORD', 'OPENMERCATO_AKENEO_PASSWORD', 'AKENEO_PASSWORD'],\n } as const\n\n const anyCredentialProvided = Object.values(credentialKeys).some((keys) => Boolean(readEnvValue(env, [...keys])))\n if (!anyCredentialProvided) {\n return null\n }\n\n const apiUrl = readEnvValue(env, [...credentialKeys.apiUrl])\n const clientId = readEnvValue(env, [...credentialKeys.clientId])\n const clientSecret = readEnvValue(env, [...credentialKeys.clientSecret])\n const username = readEnvValue(env, [...credentialKeys.username])\n const password = readEnvValue(env, [...credentialKeys.password])\n\n if (!apiUrl || !clientId || !clientSecret || !username || !password) {\n throw new Error(\n '[sync_akeneo] Incomplete Akeneo env preset. Set OM_INTEGRATION_AKENEO_API_URL, OM_INTEGRATION_AKENEO_CLIENT_ID, OM_INTEGRATION_AKENEO_CLIENT_SECRET, OM_INTEGRATION_AKENEO_USERNAME, and OM_INTEGRATION_AKENEO_PASSWORD.',\n )\n }\n\n return {\n credentials: {\n apiUrl,\n clientId,\n clientSecret,\n username,\n password,\n },\n force: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_FORCE_PRECONFIGURE', 'OPENMERCATO_AKENEO_FORCE_PRECONFIGURE', 'AKENEO_FORCE_PRECONFIGURE']) ?? false,\n productLocale: readEnvValue(env, ['OM_INTEGRATION_AKENEO_PRODUCT_LOCALE', 'OPENMERCATO_AKENEO_PRODUCT_LOCALE', 'AKENEO_PRODUCT_LOCALE']),\n categoryLocale: readEnvValue(env, ['OM_INTEGRATION_AKENEO_CATEGORY_LOCALE', 'OPENMERCATO_AKENEO_CATEGORY_LOCALE', 'AKENEO_CATEGORY_LOCALE']),\n productChannel: readEnvValue(env, ['OM_INTEGRATION_AKENEO_PRODUCT_CHANNEL', 'OPENMERCATO_AKENEO_PRODUCT_CHANNEL', 'AKENEO_PRODUCT_CHANNEL']) ?? undefined,\n productChannels: readCsvEnv(env, ['OM_INTEGRATION_AKENEO_IMPORT_CHANNELS', 'OPENMERCATO_AKENEO_IMPORT_CHANNELS', 'AKENEO_IMPORT_CHANNELS']),\n importAllChannels: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_IMPORT_ALL_CHANNELS', 'OPENMERCATO_AKENEO_IMPORT_ALL_CHANNELS', 'AKENEO_IMPORT_ALL_CHANNELS']),\n createMissingChannels: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_CREATE_MISSING_CHANNELS', 'OPENMERCATO_AKENEO_CREATE_MISSING_CHANNELS', 'AKENEO_CREATE_MISSING_CHANNELS']),\n syncAssociations: readBooleanEnv(env, ['OM_INTEGRATION_AKENEO_SYNC_ASSOCIATIONS', 'OPENMERCATO_AKENEO_SYNC_ASSOCIATIONS', 'AKENEO_SYNC_ASSOCIATIONS']),\n familyCodeFilter: readCsvEnv(env, ['OM_INTEGRATION_AKENEO_ATTRIBUTE_FAMILY_FILTER', 'OPENMERCATO_AKENEO_ATTRIBUTE_FAMILY_FILTER', 'AKENEO_ATTRIBUTE_FAMILY_FILTER']),\n productsSettingsOverride: readJsonEnv(\n env,\n ['OM_INTEGRATION_AKENEO_PRODUCTS_SETTINGS_JSON', 'OPENMERCATO_AKENEO_PRODUCTS_SETTINGS_JSON', 'AKENEO_PRODUCTS_SETTINGS_JSON'],\n 'OM_INTEGRATION_AKENEO_PRODUCTS_SETTINGS_JSON',\n ),\n categoriesSettingsOverride: readJsonEnv(\n env,\n ['OM_INTEGRATION_AKENEO_CATEGORIES_SETTINGS_JSON', 'OPENMERCATO_AKENEO_CATEGORIES_SETTINGS_JSON', 'AKENEO_CATEGORIES_SETTINGS_JSON'],\n 'OM_INTEGRATION_AKENEO_CATEGORIES_SETTINGS_JSON',\n ),\n attributesSettingsOverride: readJsonEnv(\n env,\n ['OM_INTEGRATION_AKENEO_ATTRIBUTES_SETTINGS_JSON', 'OPENMERCATO_AKENEO_ATTRIBUTES_SETTINGS_JSON', 'AKENEO_ATTRIBUTES_SETTINGS_JSON'],\n 'OM_INTEGRATION_AKENEO_ATTRIBUTES_SETTINGS_JSON',\n ),\n }\n}\n\nfunction inferPriceKindCode(attributeCode: string): string {\n const normalized = attributeCode.trim().toLowerCase()\n return normalized.includes('sale')\n || normalized.includes('promo')\n || normalized.includes('special')\n || normalized.includes('discount')\n ? 'sale'\n : 'regular'\n}\n\nfunction buildDiscoveredFieldsetMappings(discovery: DiscoverySnapshot): Array<{\n sourceType: 'family' | 'familyVariant'\n sourceCode: string\n target: 'product' | 'variant'\n fieldsetCode: string\n fieldsetLabel: string\n description: string\n}> {\n const familyRows = discovery.families.flatMap((family) => {\n const fieldsetCode = buildAkeneoFieldsetCode('product', family.code)\n if (!fieldsetCode) return []\n return [{\n sourceType: 'family' as const,\n sourceCode: family.code,\n target: 'product' as const,\n fieldsetCode,\n fieldsetLabel: family.label || family.code,\n description: `Akeneo family ${family.code}`,\n }]\n })\n\n const familyVariantRows = discovery.familyVariants.flatMap((familyVariant) => {\n const fieldsetCode = buildAkeneoFieldsetCode('variant', familyVariant.code)\n if (!fieldsetCode) return []\n return [{\n sourceType: 'familyVariant' as const,\n sourceCode: familyVariant.code,\n target: 'variant' as const,\n fieldsetCode,\n fieldsetLabel: familyVariant.label || familyVariant.code,\n description: `Akeneo family variant ${familyVariant.code} from family ${familyVariant.familyCode}`,\n }]\n })\n\n return [...familyRows, ...familyVariantRows]\n}\n\nexport function buildAkeneoMappingsFromPreset(input: {\n preset: AkeneoEnvPreset\n discovery: DiscoverySnapshot\n localChannels: LocalChannelOption[]\n priceKinds: PriceKindOption[]\n}): {\n productsMapping: ReturnType<typeof buildDefaultAkeneoMapping>\n categoriesMapping: ReturnType<typeof buildDefaultAkeneoMapping>\n attributesMapping: ReturnType<typeof buildDefaultAkeneoMapping>\n} {\n const { preset, discovery, localChannels, priceKinds } = input\n const baseProducts = buildDefaultAkeneoMapping('products')\n const productSettings = baseProducts.settings?.products\n if (!productSettings) {\n throw new Error('[sync_akeneo] Failed to resolve default product mapping settings.')\n }\n\n const discoveredFamilyVariant = discovery.familyVariants.length > 0\n ? {\n code: '__discovery__',\n variant_attribute_sets: discovery.familyVariants.map((familyVariant, index) => ({\n level: index + 1,\n axes: familyVariant.axes,\n attributes: familyVariant.attributes,\n })),\n }\n : null\n\n const inferred = inferAkeneoProductMapping({\n attributes: discovery.attributes.map((attribute) => ({\n code: attribute.code,\n type: attribute.type,\n labels: attribute.label ? { inferred: attribute.label } : undefined,\n localizable: attribute.localizable,\n scopable: attribute.scopable,\n group: attribute.group,\n metric_family: attribute.metricFamily,\n })),\n family: null,\n familyVariant: discoveredFamilyVariant,\n fieldMap: productSettings.fieldMap,\n explicitCustomFieldMappings: [],\n explicitMediaMappings: [],\n })\n\n const preferredLocale = preset.productLocale\n ?? productSettings.locale\n ?? discovery.locales.find((locale) => locale.enabled)?.code\n ?? discovery.locales[0]?.code\n const preferredAkeneoChannel = preset.productChannel\n ?? discovery.channels[0]?.code\n ?? productSettings.channel\n const preferredLocalChannel = localChannels.find((channel) => ['web', 'online', 'ecommerce', 'default'].includes(channel.code.trim().toLowerCase()))\n ?? localChannels[0]\n ?? null\n const selectedChannels = preset.productChannels\n ?? (preferredAkeneoChannel ? [preferredAkeneoChannel] : [])\n\n const discoveredPriceMappings = preferredLocalChannel\n ? inferred.autoPriceAttributeCodes.map((attributeCode) => {\n const inferredKind = inferPriceKindCode(attributeCode)\n const matchedPriceKind = priceKinds.find((priceKind) => priceKind.code === inferredKind)\n return {\n attributeCode,\n priceKindCode: matchedPriceKind?.code ?? inferredKind,\n akeneoChannel: preferredAkeneoChannel ?? null,\n localChannelCode: preferredLocalChannel.code,\n }\n })\n : []\n\n const productsOverride = preset.productsSettingsOverride ?? {}\n const overrideFieldMap = productsOverride.fieldMap && typeof productsOverride.fieldMap === 'object' && !Array.isArray(productsOverride.fieldMap)\n ? productsOverride.fieldMap as Record<string, unknown>\n : null\n const overrideReconciliation = productsOverride.reconciliation && typeof productsOverride.reconciliation === 'object' && !Array.isArray(productsOverride.reconciliation)\n ? productsOverride.reconciliation as Record<string, unknown>\n : null\n const {\n fieldMap: _ignoredFieldMap,\n reconciliation: _ignoredReconciliation,\n ...productsOverrideShallow\n } = productsOverride\n\n const rawProductsMapping = {\n ...baseProducts,\n settings: {\n products: {\n ...productSettings,\n locale: preferredLocale,\n channel: preferredAkeneoChannel ?? null,\n channels: selectedChannels,\n importAllChannels: preset.importAllChannels ?? productSettings.importAllChannels,\n customFieldMappings: inferred.autoCustomFieldMappings.map((mapping) => ({\n attributeCode: mapping.attributeCode,\n target: mapping.target,\n fieldKey: mapping.fieldKey,\n kind: mapping.kind ?? null,\n skip: mapping.skip ?? false,\n })),\n mediaMappings: inferred.autoMediaMappings.map((mapping) => ({\n attributeCode: mapping.attributeCode,\n target: mapping.target,\n kind: mapping.kind,\n })),\n priceMappings: discoveredPriceMappings,\n fieldsetMappings: buildDiscoveredFieldsetMappings(discovery),\n createMissingChannels: preset.createMissingChannels ?? productSettings.createMissingChannels,\n syncAssociations: preset.syncAssociations ?? productSettings.syncAssociations,\n ...productsOverrideShallow,\n fieldMap: {\n ...inferred.fieldMap,\n ...(overrideFieldMap ?? {}),\n },\n reconciliation: {\n ...productSettings.reconciliation,\n ...(overrideReconciliation ?? {}),\n },\n },\n },\n }\n const productsMapping = normalizeAkeneoMapping('products', rawProductsMapping as Record<string, unknown>)\n if (productsMapping.settings?.products) {\n productsMapping.fields = buildProductFieldMappings(productsMapping.settings.products)\n }\n\n const baseCategories = buildDefaultAkeneoMapping('categories')\n const categoriesMapping = normalizeAkeneoMapping('categories', {\n ...baseCategories,\n settings: {\n categories: {\n locale: preset.categoryLocale ?? preferredLocale,\n ...(preset.categoriesSettingsOverride ?? {}),\n },\n },\n })\n\n const baseAttributes = buildDefaultAkeneoMapping('attributes')\n const attributesMapping = normalizeAkeneoMapping('attributes', {\n ...baseAttributes,\n settings: {\n attributes: {\n ...baseAttributes.settings?.attributes,\n familyCodeFilter: preset.familyCodeFilter ?? baseAttributes.settings?.attributes?.familyCodeFilter ?? [],\n ...(preset.attributesSettingsOverride ?? {}),\n },\n },\n })\n\n return {\n productsMapping,\n categoriesMapping,\n attributesMapping,\n }\n}\n\nasync function loadLocalDiscoveryContext(em: EntityManager, scope: IntegrationScope): Promise<{\n localChannels: LocalChannelOption[]\n priceKinds: PriceKindOption[]\n}> {\n const [channels, priceKinds] = await Promise.all([\n findWithDecryption(em, SalesChannel, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n fields: ['code', 'name'],\n orderBy: { name: 'asc' },\n }, scope),\n findWithDecryption(em, CatalogPriceKind, {\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n }, {\n fields: ['code', 'title', 'displayMode'],\n orderBy: { title: 'asc' },\n }, scope),\n ])\n\n return {\n localChannels: channels\n .filter((channel) => typeof channel.code === 'string' && channel.code.trim().length > 0)\n .map((channel) => ({ code: String(channel.code), name: channel.name })),\n priceKinds: priceKinds.map((priceKind) => ({\n code: priceKind.code,\n title: priceKind.title,\n displayMode: priceKind.displayMode,\n })),\n }\n}\n\nasync function upsertSyncMapping(\n em: EntityManager,\n entityType: 'products' | 'categories' | 'attributes',\n mapping: Record<string, unknown>,\n scope: IntegrationScope,\n): Promise<void> {\n const existing = await findOneWithDecryption(em, SyncMapping, {\n integrationId: AKENEO_INTEGRATION_ID,\n entityType,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, undefined, scope)\n\n if (existing) {\n existing.mapping = mapping\n await em.flush()\n return\n }\n\n const created = em.create(SyncMapping, {\n integrationId: AKENEO_INTEGRATION_ID,\n entityType,\n mapping,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n })\n await em.persist(created).flush()\n}\n\nasync function hasExistingAkeneoConfiguration(\n em: EntityManager,\n credentialsService: CredentialsService,\n scope: IntegrationScope,\n): Promise<boolean> {\n const [credentials, mappings] = await Promise.all([\n credentialsService.getRaw(AKENEO_INTEGRATION_ID, scope),\n findOneWithDecryption(em, SyncMapping, {\n integrationId: AKENEO_INTEGRATION_ID,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n }, {\n fields: ['id'],\n }, scope),\n ])\n return Boolean(credentials) || Boolean(mappings)\n}\n\nexport async function applyAkeneoEnvPreset(params: {\n em: EntityManager\n credentialsService: CredentialsService\n integrationStateService: IntegrationStateService\n integrationLogService?: IntegrationLogService\n scope: IntegrationScope\n force?: boolean\n env?: NodeJS.ProcessEnv\n}): Promise<ApplyAkeneoPresetResult> {\n const preset = readAkeneoEnvPreset(params.env)\n if (!preset) {\n return { status: 'skipped', reason: 'No Akeneo preset env variables were provided.' }\n }\n\n const force = params.force ?? preset.force\n if (!force && await hasExistingAkeneoConfiguration(params.em, params.credentialsService, params.scope)) {\n return { status: 'skipped', reason: 'Akeneo credentials or mappings already exist. Use force to overwrite them.' }\n }\n\n await params.credentialsService.save(AKENEO_INTEGRATION_ID, preset.credentials, params.scope)\n\n const client = createAkeneoClient(preset.credentials)\n const [discovery, localContext] = await Promise.all([\n client.collectDiscoveryData(),\n loadLocalDiscoveryContext(params.em, params.scope),\n ])\n\n const mappings = buildAkeneoMappingsFromPreset({\n preset,\n discovery,\n localChannels: localContext.localChannels,\n priceKinds: localContext.priceKinds,\n })\n\n await upsertSyncMapping(params.em, 'products', mappings.productsMapping as unknown as Record<string, unknown>, params.scope)\n await upsertSyncMapping(params.em, 'categories', mappings.categoriesMapping as unknown as Record<string, unknown>, params.scope)\n await upsertSyncMapping(params.em, 'attributes', mappings.attributesMapping as unknown as Record<string, unknown>, params.scope)\n await params.integrationStateService.upsert(AKENEO_INTEGRATION_ID, { isEnabled: true }, params.scope)\n\n if (params.integrationLogService) {\n await params.integrationLogService.scoped(AKENEO_INTEGRATION_ID, params.scope).info(\n 'Akeneo integration was preconfigured from environment variables.',\n {\n locale: mappings.productsMapping.settings?.products?.locale ?? null,\n channel: mappings.productsMapping.settings?.products?.channel ?? null,\n importAllChannels: mappings.productsMapping.settings?.products?.importAllChannels ?? null,\n },\n )\n }\n\n return { status: 'configured', discoveryApplied: true }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,yBAAyB;AAClC,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAI5B,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,iCAAiC;AAC1C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,MAAM,wBAAwB;AAsD9B,SAAS,aAAa,KAAwB,MAAoC;AAChF,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,IAAI,GAAG,GAAG,KAAK;AAC7B,QAAI,MAAO,QAAO;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,WAAW,KAAwB,MAAsC;AAChF,QAAM,MAAM,aAAa,KAAK,IAAI;AAClC,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,SAAS,IACZ,MAAM,GAAG,EACT,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AACrC,SAAO,OAAO,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI;AAC3D;AAEA,SAAS,eAAe,KAAwB,MAAqC;AACnF,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,kBAAkB,IAAI,GAAG,CAAC;AACzC,QAAI,WAAW,KAAM,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;AAEA,SAAS,YAAY,KAAwB,MAAgB,OAAoD;AAC/G,QAAM,MAAM,aAAa,KAAK,IAAI;AAClC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAM,IAAI,MAAM,iBAAiB,KAAK,uBAAuB,OAAO,EAAE;AAAA,EACxE;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,UAAM,IAAI,MAAM,iBAAiB,KAAK,yBAAyB;AAAA,EACjE;AACA,SAAO;AACT;AAEO,SAAS,oBAAoB,MAAyB,QAAQ,KAA6B;AAChG,QAAM,iBAAiB;AAAA,IACrB,QAAQ,CAAC,iCAAiC,8BAA8B,gBAAgB;AAAA,IACxF,UAAU,CAAC,mCAAmC,gCAAgC,kBAAkB;AAAA,IAChG,cAAc,CAAC,uCAAuC,oCAAoC,sBAAsB;AAAA,IAChH,UAAU,CAAC,kCAAkC,+BAA+B,iBAAiB;AAAA,IAC7F,UAAU,CAAC,kCAAkC,+BAA+B,iBAAiB;AAAA,EAC/F;AAEA,QAAM,wBAAwB,OAAO,OAAO,cAAc,EAAE,KAAK,CAAC,SAAS,QAAQ,aAAa,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAChH,MAAI,CAAC,uBAAuB;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,aAAa,KAAK,CAAC,GAAG,eAAe,MAAM,CAAC;AAC3D,QAAM,WAAW,aAAa,KAAK,CAAC,GAAG,eAAe,QAAQ,CAAC;AAC/D,QAAM,eAAe,aAAa,KAAK,CAAC,GAAG,eAAe,YAAY,CAAC;AACvE,QAAM,WAAW,aAAa,KAAK,CAAC,GAAG,eAAe,QAAQ,CAAC;AAC/D,QAAM,WAAW,aAAa,KAAK,CAAC,GAAG,eAAe,QAAQ,CAAC;AAE/D,MAAI,CAAC,UAAU,CAAC,YAAY,CAAC,gBAAgB,CAAC,YAAY,CAAC,UAAU;AACnE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO,eAAe,KAAK,CAAC,4CAA4C,yCAAyC,2BAA2B,CAAC,KAAK;AAAA,IAClJ,eAAe,aAAa,KAAK,CAAC,wCAAwC,qCAAqC,uBAAuB,CAAC;AAAA,IACvI,gBAAgB,aAAa,KAAK,CAAC,yCAAyC,sCAAsC,wBAAwB,CAAC;AAAA,IAC3I,gBAAgB,aAAa,KAAK,CAAC,yCAAyC,sCAAsC,wBAAwB,CAAC,KAAK;AAAA,IAChJ,iBAAiB,WAAW,KAAK,CAAC,yCAAyC,sCAAsC,wBAAwB,CAAC;AAAA,IAC1I,mBAAmB,eAAe,KAAK,CAAC,6CAA6C,0CAA0C,4BAA4B,CAAC;AAAA,IAC5J,uBAAuB,eAAe,KAAK,CAAC,iDAAiD,8CAA8C,gCAAgC,CAAC;AAAA,IAC5K,kBAAkB,eAAe,KAAK,CAAC,2CAA2C,wCAAwC,0BAA0B,CAAC;AAAA,IACrJ,kBAAkB,WAAW,KAAK,CAAC,iDAAiD,8CAA8C,gCAAgC,CAAC;AAAA,IACnK,0BAA0B;AAAA,MACxB;AAAA,MACA,CAAC,gDAAgD,6CAA6C,+BAA+B;AAAA,MAC7H;AAAA,IACF;AAAA,IACA,4BAA4B;AAAA,MAC1B;AAAA,MACA,CAAC,kDAAkD,+CAA+C,iCAAiC;AAAA,MACnI;AAAA,IACF;AAAA,IACA,4BAA4B;AAAA,MAC1B;AAAA,MACA,CAAC,kDAAkD,+CAA+C,iCAAiC;AAAA,MACnI;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,eAA+B;AACzD,QAAM,aAAa,cAAc,KAAK,EAAE,YAAY;AACpD,SAAO,WAAW,SAAS,MAAM,KAC5B,WAAW,SAAS,OAAO,KAC3B,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,UAAU,IAC/B,SACA;AACN;AAEA,SAAS,gCAAgC,WAOtC;AACD,QAAM,aAAa,UAAU,SAAS,QAAQ,CAAC,WAAW;AACxD,UAAM,eAAe,wBAAwB,WAAW,OAAO,IAAI;AACnE,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,WAAO,CAAC;AAAA,MACN,YAAY;AAAA,MACZ,YAAY,OAAO;AAAA,MACnB,QAAQ;AAAA,MACR;AAAA,MACA,eAAe,OAAO,SAAS,OAAO;AAAA,MACtC,aAAa,iBAAiB,OAAO,IAAI;AAAA,IAC3C,CAAC;AAAA,EACH,CAAC;AAED,QAAM,oBAAoB,UAAU,eAAe,QAAQ,CAAC,kBAAkB;AAC5E,UAAM,eAAe,wBAAwB,WAAW,cAAc,IAAI;AAC1E,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,WAAO,CAAC;AAAA,MACN,YAAY;AAAA,MACZ,YAAY,cAAc;AAAA,MAC1B,QAAQ;AAAA,MACR;AAAA,MACA,eAAe,cAAc,SAAS,cAAc;AAAA,MACpD,aAAa,yBAAyB,cAAc,IAAI,gBAAgB,cAAc,UAAU;AAAA,IAClG,CAAC;AAAA,EACH,CAAC;AAED,SAAO,CAAC,GAAG,YAAY,GAAG,iBAAiB;AAC7C;AAEO,SAAS,8BAA8B,OAS5C;AACA,QAAM,EAAE,QAAQ,WAAW,eAAe,WAAW,IAAI;AACzD,QAAM,eAAe,0BAA0B,UAAU;AACzD,QAAM,kBAAkB,aAAa,UAAU;AAC/C,MAAI,CAAC,iBAAiB;AACpB,UAAM,IAAI,MAAM,mEAAmE;AAAA,EACrF;AAEA,QAAM,0BAA0B,UAAU,eAAe,SAAS,IAC9D;AAAA,IACE,MAAM;AAAA,IACN,wBAAwB,UAAU,eAAe,IAAI,CAAC,eAAe,WAAW;AAAA,MAC9E,OAAO,QAAQ;AAAA,MACf,MAAM,cAAc;AAAA,MACpB,YAAY,cAAc;AAAA,IAC5B,EAAE;AAAA,EACJ,IACA;AAEJ,QAAM,WAAW,0BAA0B;AAAA,IACzC,YAAY,UAAU,WAAW,IAAI,CAAC,eAAe;AAAA,MACnD,MAAM,UAAU;AAAA,MAChB,MAAM,UAAU;AAAA,MAChB,QAAQ,UAAU,QAAQ,EAAE,UAAU,UAAU,MAAM,IAAI;AAAA,MAC1D,aAAa,UAAU;AAAA,MACvB,UAAU,UAAU;AAAA,MACpB,OAAO,UAAU;AAAA,MACjB,eAAe,UAAU;AAAA,IAC3B,EAAE;AAAA,IACF,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,UAAU,gBAAgB;AAAA,IAC1B,6BAA6B,CAAC;AAAA,IAC9B,uBAAuB,CAAC;AAAA,EAC1B,CAAC;AAED,QAAM,kBAAkB,OAAO,iBAC1B,gBAAgB,UAChB,UAAU,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,GAAG,QACpD,UAAU,QAAQ,CAAC,GAAG;AAC3B,QAAM,yBAAyB,OAAO,kBACjC,UAAU,SAAS,CAAC,GAAG,QACvB,gBAAgB;AACrB,QAAM,wBAAwB,cAAc,KAAK,CAAC,YAAY,CAAC,OAAO,UAAU,aAAa,SAAS,EAAE,SAAS,QAAQ,KAAK,KAAK,EAAE,YAAY,CAAC,CAAC,KAC9I,cAAc,CAAC,KACf;AACL,QAAM,mBAAmB,OAAO,oBAC1B,yBAAyB,CAAC,sBAAsB,IAAI,CAAC;AAE3D,QAAM,0BAA0B,wBAC5B,SAAS,wBAAwB,IAAI,CAAC,kBAAkB;AACtD,UAAM,eAAe,mBAAmB,aAAa;AACrD,UAAM,mBAAmB,WAAW,KAAK,CAAC,cAAc,UAAU,SAAS,YAAY;AACvF,WAAO;AAAA,MACL;AAAA,MACA,eAAe,kBAAkB,QAAQ;AAAA,MACzC,eAAe,0BAA0B;AAAA,MACzC,kBAAkB,sBAAsB;AAAA,IAC1C;AAAA,EACF,CAAC,IACD,CAAC;AAEL,QAAM,mBAAmB,OAAO,4BAA4B,CAAC;AAC7D,QAAM,mBAAmB,iBAAiB,YAAY,OAAO,iBAAiB,aAAa,YAAY,CAAC,MAAM,QAAQ,iBAAiB,QAAQ,IAC3I,iBAAiB,WACjB;AACJ,QAAM,yBAAyB,iBAAiB,kBAAkB,OAAO,iBAAiB,mBAAmB,YAAY,CAAC,MAAM,QAAQ,iBAAiB,cAAc,IACnK,iBAAiB,iBACjB;AACJ,QAAM;AAAA,IACJ,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,qBAAqB;AAAA,IACzB,GAAG;AAAA,IACH,UAAU;AAAA,MACR,UAAU;AAAA,QACR,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,SAAS,0BAA0B;AAAA,QACnC,UAAU;AAAA,QACV,mBAAmB,OAAO,qBAAqB,gBAAgB;AAAA,QAC/D,qBAAqB,SAAS,wBAAwB,IAAI,CAAC,aAAa;AAAA,UACtE,eAAe,QAAQ;AAAA,UACvB,QAAQ,QAAQ;AAAA,UAChB,UAAU,QAAQ;AAAA,UAClB,MAAM,QAAQ,QAAQ;AAAA,UACtB,MAAM,QAAQ,QAAQ;AAAA,QACxB,EAAE;AAAA,QACF,eAAe,SAAS,kBAAkB,IAAI,CAAC,aAAa;AAAA,UAC1D,eAAe,QAAQ;AAAA,UACvB,QAAQ,QAAQ;AAAA,UAChB,MAAM,QAAQ;AAAA,QAChB,EAAE;AAAA,QACF,eAAe;AAAA,QACf,kBAAkB,gCAAgC,SAAS;AAAA,QAC3D,uBAAuB,OAAO,yBAAyB,gBAAgB;AAAA,QACvE,kBAAkB,OAAO,oBAAoB,gBAAgB;AAAA,QAC7D,GAAG;AAAA,QACH,UAAU;AAAA,UACR,GAAG,SAAS;AAAA,UACZ,GAAI,oBAAoB,CAAC;AAAA,QAC3B;AAAA,QACA,gBAAgB;AAAA,UACd,GAAG,gBAAgB;AAAA,UACnB,GAAI,0BAA0B,CAAC;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,kBAAkB,uBAAuB,YAAY,kBAA6C;AACxG,MAAI,gBAAgB,UAAU,UAAU;AACtC,oBAAgB,SAAS,0BAA0B,gBAAgB,SAAS,QAAQ;AAAA,EACtF;AAEA,QAAM,iBAAiB,0BAA0B,YAAY;AAC7D,QAAM,oBAAoB,uBAAuB,cAAc;AAAA,IAC7D,GAAG;AAAA,IACH,UAAU;AAAA,MACR,YAAY;AAAA,QACV,QAAQ,OAAO,kBAAkB;AAAA,QACjC,GAAI,OAAO,8BAA8B,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,iBAAiB,0BAA0B,YAAY;AAC7D,QAAM,oBAAoB,uBAAuB,cAAc;AAAA,IAC7D,GAAG;AAAA,IACH,UAAU;AAAA,MACR,YAAY;AAAA,QACV,GAAG,eAAe,UAAU;AAAA,QAC5B,kBAAkB,OAAO,oBAAoB,eAAe,UAAU,YAAY,oBAAoB,CAAC;AAAA,QACvG,GAAI,OAAO,8BAA8B,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,0BAA0B,IAAmB,OAGzD;AACD,QAAM,CAAC,UAAU,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC/C,mBAAmB,IAAI,cAAc;AAAA,MACnC,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,MACX,UAAU;AAAA,IACZ,GAAG;AAAA,MACD,QAAQ,CAAC,QAAQ,MAAM;AAAA,MACvB,SAAS,EAAE,MAAM,MAAM;AAAA,IACzB,GAAG,KAAK;AAAA,IACR,mBAAmB,IAAI,kBAAkB;AAAA,MACvC,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,MACX,UAAU;AAAA,IACZ,GAAG;AAAA,MACD,QAAQ,CAAC,QAAQ,SAAS,aAAa;AAAA,MACvC,SAAS,EAAE,OAAO,MAAM;AAAA,IAC1B,GAAG,KAAK;AAAA,EACV,CAAC;AAED,SAAO;AAAA,IACL,eAAe,SACZ,OAAO,CAAC,YAAY,OAAO,QAAQ,SAAS,YAAY,QAAQ,KAAK,KAAK,EAAE,SAAS,CAAC,EACtF,IAAI,CAAC,aAAa,EAAE,MAAM,OAAO,QAAQ,IAAI,GAAG,MAAM,QAAQ,KAAK,EAAE;AAAA,IACxE,YAAY,WAAW,IAAI,CAAC,eAAe;AAAA,MACzC,MAAM,UAAU;AAAA,MAChB,OAAO,UAAU;AAAA,MACjB,aAAa,UAAU;AAAA,IACzB,EAAE;AAAA,EACJ;AACF;AAEA,eAAe,kBACb,IACA,YACA,SACA,OACe;AACf,QAAM,WAAW,MAAM,sBAAsB,IAAI,aAAa;AAAA,IAC5D,eAAe;AAAA,IACf;AAAA,IACA,gBAAgB,MAAM;AAAA,IACtB,UAAU,MAAM;AAAA,EAClB,GAAG,QAAW,KAAK;AAEnB,MAAI,UAAU;AACZ,aAAS,UAAU;AACnB,UAAM,GAAG,MAAM;AACf;AAAA,EACF;AAEA,QAAM,UAAU,GAAG,OAAO,aAAa;AAAA,IACrC,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,gBAAgB,MAAM;AAAA,IACtB,UAAU,MAAM;AAAA,EAClB,CAAC;AACD,QAAM,GAAG,QAAQ,OAAO,EAAE,MAAM;AAClC;AAEA,eAAe,+BACb,IACA,oBACA,OACkB;AAClB,QAAM,CAAC,aAAa,QAAQ,IAAI,MAAM,QAAQ,IAAI;AAAA,IAChD,mBAAmB,OAAO,uBAAuB,KAAK;AAAA,IACtD,sBAAsB,IAAI,aAAa;AAAA,MACrC,eAAe;AAAA,MACf,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM;AAAA,IAClB,GAAG;AAAA,MACD,QAAQ,CAAC,IAAI;AAAA,IACf,GAAG,KAAK;AAAA,EACV,CAAC;AACD,SAAO,QAAQ,WAAW,KAAK,QAAQ,QAAQ;AACjD;AAEA,eAAsB,qBAAqB,QAQN;AACnC,QAAM,SAAS,oBAAoB,OAAO,GAAG;AAC7C,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,QAAQ,WAAW,QAAQ,gDAAgD;AAAA,EACtF;AAEA,QAAM,QAAQ,OAAO,SAAS,OAAO;AACrC,MAAI,CAAC,SAAS,MAAM,+BAA+B,OAAO,IAAI,OAAO,oBAAoB,OAAO,KAAK,GAAG;AACtG,WAAO,EAAE,QAAQ,WAAW,QAAQ,6EAA6E;AAAA,EACnH;AAEA,QAAM,OAAO,mBAAmB,KAAK,uBAAuB,OAAO,aAAa,OAAO,KAAK;AAE5F,QAAM,SAAS,mBAAmB,OAAO,WAAW;AACpD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,IAClD,OAAO,qBAAqB;AAAA,IAC5B,0BAA0B,OAAO,IAAI,OAAO,KAAK;AAAA,EACnD,CAAC;AAED,QAAM,WAAW,8BAA8B;AAAA,IAC7C;AAAA,IACA;AAAA,IACA,eAAe,aAAa;AAAA,IAC5B,YAAY,aAAa;AAAA,EAC3B,CAAC;AAED,QAAM,kBAAkB,OAAO,IAAI,YAAY,SAAS,iBAAuD,OAAO,KAAK;AAC3H,QAAM,kBAAkB,OAAO,IAAI,cAAc,SAAS,mBAAyD,OAAO,KAAK;AAC/H,QAAM,kBAAkB,OAAO,IAAI,cAAc,SAAS,mBAAyD,OAAO,KAAK;AAC/H,QAAM,OAAO,wBAAwB,OAAO,uBAAuB,EAAE,WAAW,KAAK,GAAG,OAAO,KAAK;AAEpG,MAAI,OAAO,uBAAuB;AAChC,UAAM,OAAO,sBAAsB,OAAO,uBAAuB,OAAO,KAAK,EAAE;AAAA,MAC7E;AAAA,MACA;AAAA,QACE,QAAQ,SAAS,gBAAgB,UAAU,UAAU,UAAU;AAAA,QAC/D,SAAS,SAAS,gBAAgB,UAAU,UAAU,WAAW;AAAA,QACjE,mBAAmB,SAAS,gBAAgB,UAAU,UAAU,qBAAqB;AAAA,MACvF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,cAAc,kBAAkB,KAAK;AACxD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/jest.config.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @type {import('jest').Config} */
|
|
2
2
|
module.exports = {
|
|
3
|
-
preset: 'ts-jest',
|
|
4
3
|
testEnvironment: 'node',
|
|
5
4
|
watchman: false,
|
|
6
5
|
rootDir: '.',
|
|
@@ -15,7 +14,7 @@ module.exports = {
|
|
|
15
14
|
},
|
|
16
15
|
transform: {
|
|
17
16
|
'^.+\\.(t|j)sx?$': [
|
|
18
|
-
'
|
|
17
|
+
'<rootDir>/../../scripts/jest-mikroorm-transformer.cjs',
|
|
19
18
|
{
|
|
20
19
|
tsconfig: {
|
|
21
20
|
jsx: 'react-jsx',
|
|
@@ -23,6 +22,9 @@ module.exports = {
|
|
|
23
22
|
},
|
|
24
23
|
],
|
|
25
24
|
},
|
|
25
|
+
transformIgnorePatterns: [
|
|
26
|
+
'node_modules/(?!(@mikro-orm)/)',
|
|
27
|
+
],
|
|
26
28
|
testMatch: ['<rootDir>/src/**/__tests__/**/*.test.(ts|tsx)'],
|
|
27
29
|
passWithNoTests: true,
|
|
28
30
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/sync-akeneo",
|
|
3
|
-
"version": "0.5.1-develop.
|
|
3
|
+
"version": "0.5.1-develop.2694.732417c5ec",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -52,18 +52,18 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@open-mercato/core": "0.5.1-develop.
|
|
56
|
-
"@open-mercato/ui": "0.5.1-develop.
|
|
55
|
+
"@open-mercato/core": "0.5.1-develop.2694.732417c5ec",
|
|
56
|
+
"@open-mercato/ui": "0.5.1-develop.2694.732417c5ec",
|
|
57
57
|
"node-html-markdown": "^2.0.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@mikro-orm/postgresql": "^
|
|
61
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
60
|
+
"@mikro-orm/postgresql": "^7.0.10",
|
|
61
|
+
"@open-mercato/shared": "0.5.1-develop.2694.732417c5ec",
|
|
62
62
|
"react": "^19.0.0",
|
|
63
63
|
"react-dom": "^19.0.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@open-mercato/shared": "0.5.1-develop.
|
|
66
|
+
"@open-mercato/shared": "0.5.1-develop.2694.732417c5ec",
|
|
67
67
|
"@types/jest": "^30.0.0",
|
|
68
68
|
"esbuild": "^0.28.0",
|
|
69
69
|
"glob": "^13.0.6",
|
|
@@ -2349,7 +2349,7 @@ export async function createAkeneoImporter(client: AkeneoClient, scope: ImportSc
|
|
|
2349
2349
|
: params.reconciliation.deleteMissingAttachments
|
|
2350
2350
|
if (!shouldDelete || desiredExternalIds.has(externalId)) continue
|
|
2351
2351
|
await deletePartitionFile(attachment.partitionCode, attachment.storagePath, attachment.storageDriver)
|
|
2352
|
-
await em.
|
|
2352
|
+
await em.remove(attachment).flush()
|
|
2353
2353
|
await emitAttachmentCrudChange('deleted', attachment)
|
|
2354
2354
|
}
|
|
2355
2355
|
|
|
@@ -2470,7 +2470,7 @@ export async function createAkeneoImporter(client: AkeneoClient, scope: ImportSc
|
|
|
2470
2470
|
const childProductId = typeof relation.childProduct === 'string' ? relation.childProduct : relation.childProduct?.id ?? null
|
|
2471
2471
|
const key = `${relation.relationType}:${childVariantId ?? childProductId}`
|
|
2472
2472
|
if (!desiredKeys.has(key)) {
|
|
2473
|
-
await em.
|
|
2473
|
+
await em.remove(relation).flush()
|
|
2474
2474
|
}
|
|
2475
2475
|
}
|
|
2476
2476
|
}
|