@open-mercato/sync-akeneo 0.10.1-develop.8075.1.f2d38008c0 → 0.10.1-develop.8099.1.debd225eaa

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "crypto";
2
2
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
3
3
  import { emitCrudSideEffects, setCustomFieldsIfAny } from "@open-mercato/shared/lib/commands/helpers";
4
+ import { loadCustomFieldSnapshot } from "@open-mercato/shared/lib/commands/customFieldSnapshots";
4
5
  import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
5
6
  import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
6
7
  import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
@@ -319,6 +320,9 @@ function resolveAkeneoMediaTarget(params) {
319
320
  }
320
321
  return params.mappingTarget;
321
322
  }
323
+ function isEmptyCustomFieldValue(value) {
324
+ return value === null || value === void 0 || Array.isArray(value) && value.length === 0;
325
+ }
322
326
  function resolveCustomFieldValue(value, attribute, kind) {
323
327
  if (kind === "boolean") return coerceBoolean(value);
324
328
  if (kind === "integer") return coerceNumber(value) === null ? null : Math.trunc(Number(value));
@@ -1513,6 +1517,18 @@ async function createAkeneoImporter(client, scope) {
1513
1517
  axisCodes: []
1514
1518
  };
1515
1519
  }
1520
+ async function omitClearsOfEmptyFields(entityId, recordId, values) {
1521
+ if (!Object.values(values).some((value) => value === null)) return values;
1522
+ const current = await loadCustomFieldSnapshot(em, {
1523
+ entityId,
1524
+ recordId,
1525
+ tenantId: scope.tenantId,
1526
+ organizationId: scope.organizationId
1527
+ });
1528
+ return Object.fromEntries(
1529
+ Object.entries(values).filter(([key, value]) => value !== null || !isEmptyCustomFieldValue(current[key]))
1530
+ );
1531
+ }
1516
1532
  async function applyCustomFieldMappings(params) {
1517
1533
  const settings = params.mapping.settings?.products;
1518
1534
  if (!settings || settings.customFieldMappings.length === 0) return;
@@ -1527,32 +1543,32 @@ async function createAkeneoImporter(client, scope) {
1527
1543
  if (!kind) continue;
1528
1544
  const sourceLayers = fieldMapping.target === "product" ? [params.hierarchy.rootValues, params.hierarchy.mergedValues] : [params.product.values ?? {}, params.hierarchy.mergedValues];
1529
1545
  const rawValue = readLayeredAkeneoValue(sourceLayers, fieldMapping.attributeCode, settings.locale, settings.channel ?? null);
1530
- const value = resolveCustomFieldValue(rawValue, attribute, kind);
1531
- if (value === null || value === void 0 || Array.isArray(value) && value.length === 0) continue;
1546
+ const resolved = resolveCustomFieldValue(rawValue, attribute, kind);
1547
+ const value = isEmptyCustomFieldValue(resolved) ? null : resolved;
1532
1548
  if (fieldMapping.target === "product") {
1533
1549
  productCustomFields[normalizeFieldKey(fieldMapping.fieldKey)] = value;
1534
1550
  } else {
1535
1551
  variantCustomFields[normalizeFieldKey(fieldMapping.fieldKey)] = value;
1536
1552
  }
1537
1553
  }
1538
- await Promise.all([
1539
- setCustomFieldsIfAny({
1540
- dataEngine,
1541
- entityId: PRODUCT_ENTITY_ID,
1542
- recordId: params.localProductId,
1543
- organizationId: scope.organizationId,
1544
- tenantId: scope.tenantId,
1545
- values: productCustomFields
1546
- }),
1547
- setCustomFieldsIfAny({
1548
- dataEngine,
1549
- entityId: VARIANT_ENTITY_ID,
1550
- recordId: params.localVariantId,
1551
- organizationId: scope.organizationId,
1552
- tenantId: scope.tenantId,
1553
- values: variantCustomFields
1554
- })
1555
- ]);
1554
+ const productValues = await omitClearsOfEmptyFields(PRODUCT_ENTITY_ID, params.localProductId, productCustomFields);
1555
+ await setCustomFieldsIfAny({
1556
+ dataEngine,
1557
+ entityId: PRODUCT_ENTITY_ID,
1558
+ recordId: params.localProductId,
1559
+ organizationId: scope.organizationId,
1560
+ tenantId: scope.tenantId,
1561
+ values: productValues
1562
+ });
1563
+ const variantValues = await omitClearsOfEmptyFields(VARIANT_ENTITY_ID, params.localVariantId, variantCustomFields);
1564
+ await setCustomFieldsIfAny({
1565
+ dataEngine,
1566
+ entityId: VARIANT_ENTITY_ID,
1567
+ recordId: params.localVariantId,
1568
+ organizationId: scope.organizationId,
1569
+ tenantId: scope.tenantId,
1570
+ values: variantValues
1571
+ });
1556
1572
  await Promise.all([
1557
1573
  params.fieldsetPlan?.product?.code ? executeCommand("catalog.products.update", {
1558
1574
  id: params.localProductId,
@@ -1563,7 +1579,7 @@ async function createAkeneoImporter(client, scope) {
1563
1579
  customFieldsetCode: params.fieldsetPlan.variant.code
1564
1580
  }) : Promise.resolve()
1565
1581
  ]);
1566
- if (Object.keys(productCustomFields).length > 0) {
1582
+ if (Object.keys(productValues).length > 0) {
1567
1583
  await emitCatalogQueryIndexEvent(buildCommandContext(), {
1568
1584
  entityType: PRODUCT_ENTITY_ID,
1569
1585
  recordId: params.localProductId,
@@ -1572,7 +1588,7 @@ async function createAkeneoImporter(client, scope) {
1572
1588
  action: "updated"
1573
1589
  });
1574
1590
  }
1575
- if (Object.keys(variantCustomFields).length > 0) {
1591
+ if (Object.keys(variantValues).length > 0) {
1576
1592
  await emitCatalogQueryIndexEvent(buildCommandContext(), {
1577
1593
  entityType: VARIANT_ENTITY_ID,
1578
1594
  recordId: params.localVariantId,