Skip to main content

EAN Secondary (Marketplace Override)

This note frames the addition of a secondary EAN used only for marketplaces. This need is different from a true "second global product EAN".

Summary

The reformulated business need is:

  • mz_product.ean remains the canonical product EAN
  • A secondary EAN (ean bis) can exist only for marketplace exports
  • It must not become the primary EAN used everywhere in Logidav

The safest solution is therefore not to manage "2 equivalent product EANs", but rather:

  1. mz_product.ean = primary / canonical EAN
  2. ean bis = marketplace override EAN
  3. The override must only be read by the relevant marketplace feeds
  4. Magento and Meduse should not necessarily be impacted if their business contract remains based on the primary EAN

What already exists in the code

Storage

  • The main product already has an ean (src/AppBundle/Entity/Product.php:76) field in mz_product.
  • The EanProduct (src/AppBundle/Entity/EanProduct.php:9) entity maps mz_ean_product.
  • Currently, mz_ean_product.sku is declared unique=true, which already prevents more than one row per SKU in this table.

Magento / Meduse synchronization

  • The Magento sync for create/update currently sends a single ean attribute:
    • CreateProductCommand (src/AppBundle/Command/Product/newProduct/CreateProductCommand.php:422)
    • UpdateProductCommand (src/AppBundle/Command/Product/newProduct/UpdateProductCommand.php:439)
    • SynchroniseProductInMagentoCommand (src/AppBundle/Command/Product/newProduct/SynchroniseProductInMagentoCommand.php:589)
  • The Magento-to-Logidav import also writes a single ean in ProductService::saveFromApi() (src/AppBundle/Services/ProductService.php:403) and in generateProductDataMapping() (src/AppBundle/Services/ProductService.php:860).
  • The Meduse update pushes custom_attributes to logidav.api.product.put.queue via ProductMeduseDataUpdateProcessor (src/MeduseBundle/Services/Queue/ProductMeduseDataUpdateProcessor.php:133).

Marketplace feeds that already read the canonical EAN

  • Google Shopping exports gtin from GoogleShoppingService (src/ErpBundle/Services/GoogleShoppingService.php:1531).
  • The Merchant API then transforms this gtin into gtins in MerchantApiService (src/ErpBundle/Services/Merchant/MerchantApiService.php:480).
  • Temu also reads the product EAN directly in TemuProductMapper (src/ErpBundle/Services/Temu/TemuProductMapper.php:105).

Business model

For each SKU, we must now distinguish:

  • mz_product.ean = primary EAN
  • ean bis marketplace = substitute EAN for marketplace channels

Business rules:

  • An EAN can belong to only one SKU
  • ean bis must be distinct from mz_product.ean
  • ean bis must not be used by logistics, stock, order, or ERP flows that expect the primary EAN
  • A product must have at most one marketplace ean bis
  • By default, marketplaces use ean bis if present, otherwise mz_product.ean

Why this need is simpler than a true dual-EAN product

If ean bis is marketplace-only:

  • We avoid redefining the notion of product identity throughout Logidav
  • We avoid breaking EAN searches on the orders and ERP side
  • We can limit the change to marketplace exports
  • We greatly reduce the need to modify Magento and Meduse

In other words, ean bis should not be presented as "a second equivalent EAN". It is rather a commercial distribution override.

Likely bugs / regressions if implemented too quickly

1. Regression if ean bis replaces the canonical EAN instead of overriding it only in marketplace feeds

If we start writing ean bis into mz_product.ean, we change the source data for the entire system.

Impact:

  • Non-marketplace orders/integrations may end up with the wrong EAN
  • Parcels, after-sales, product matching, and other flows may drift
  • The old primary EAN becomes unfindable

References:

  • ProductService::saveFromApi() (src/AppBundle/Services/ProductService.php:403)
  • ProductService::generateProductDataMapping() (src/AppBundle/Services/ProductService.php:860)

2. Regression if marketplace exports keep reading only getEan()

Currently several GTIN exports read the canonical EAN directly.

Impact:

  • ean bis will be stored but never used
  • The client will believe the feature exists while feeds continue publishing the old EAN

References:

  • GoogleShoppingService (src/ErpBundle/Services/GoogleShoppingService.php:1531)
  • MerchantApiService (src/ErpBundle/Services/Merchant/MerchantApiService.php:480)
  • TemuProductMapper (src/ErpBundle/Services/Temu/TemuProductMapper.php:105)

3. Regression if Magento / Meduse are forced to carry ean bis when they don't need it

If ean bis is purely for marketplaces, extending it immediately to Magento / Meduse can add complexity to the contract without clear business benefit.

Impact:

  • More complex contract than necessary
  • Risk of confusion between product EAN and commercial distribution EAN
  • More desynchronization points

Reference:

  • ProductMeduseDataUpdateProcessor (src/MeduseBundle/Services/Queue/ProductMeduseDataUpdateProcessor.php:149)

4. Risk of duplication between primary EAN and ean bis

Even if we only manage a single ean bis, we must prevent:

  • ean bis = primary EAN
  • ean bis already taken by another SKU
  • Multiple ean bis for the same SKU if mz_ean_product is reused without clear rules

Impact:

  • Business ambiguity
  • Feed conflicts
  • Data difficult to clean up

Reference:

  • NewProductService::checkEanConflicts() (src/AppBundle/Services/NewProductService.php:1723)

5. Business searches by EAN should probably continue to see only the primary EAN

Some flows do a findOneByEan() on mz_product.

Impact:

  • This is acceptable if ean bis is never used to identify incoming orders
  • This is not acceptable if a marketplace returns ean bis in its imports

Reference:

  • TatiSynchronizeOrdersCommand (src/ErpBundle/Command/Tati/TatiSynchronizeOrdersCommand.php:128)

6. The current admin EAN interface is not suitable

The current screen displays a message "this SKU already has the following EAN" and is not designed to distinguish primary vs ean bis.

Impact:

  • Confusing behavior for the user
  • Risk of modifying the primary when the intent was only to set ean bis

Reference:

  • ProductController::indexEanProductAction() (src/AppBundle/Controller/Product/ProductController.php:9464)

Edge cases to cover

Duplications

  • ean bis identical to mz_product.ean
  • Same ean bis entered twice for the same SKU
  • Same EAN already used by another SKU in mz_product
  • Same EAN already used by another SKU in mz_ean_product
  • Same EAN used as primary on one SKU and ean bis on another

Cardinality / scope

  • Product with primary EAN only
  • Product with primary EAN + ean bis
  • Attempt to add a second ean bis
  • Deletion of ean bis
  • Replacement of ean bis

Synchronization

  • Marketplace exports ean bis when it exists
  • Marketplace exports the primary EAN when ean bis is empty
  • Magento continues to receive the primary EAN
  • Meduse continues to receive the primary EAN
  • Marketplace order imports: verify whether the return uses SKU, marketplace ID, or EAN

Data quality

  • Empty EAN
  • EAN with spaces
  • Non-numeric EAN
  • EAN with length other than 13
  • Invalid checksum

Database

At minimum:

  • Keep global uniqueness on the stored ean bis value
  • Guarantee at most one ean bis per SKU
  • Forbid ean bis = mz_product.ean

Two clean options:

  1. Add a dedicated column like marketplace_ean_bis on mz_product
  2. Or reuse mz_ean_product, but clearly specialize it as a marketplace override table

The first option is simpler if we know there will only be one ean bis per product.

Application

Create a single business API such as:

  • setMarketplaceEanBis(string $sku, string $ean)
  • removeMarketplaceEanBis(string $sku)
  • getMarketplaceExportEan(Product $product): string

And all marketplace feeds must use getMarketplaceExportEan() instead of getEan() directly.

Magento contract

Recommendation

Magento should continue to receive:

  • ean = primary EAN

Unless there is a contrary business requirement, Magento does not need to carry ean bis.

  • Logidav to Magento:
    • ean = primary only
  • Magento to Logidav:
    • ean feeds into mz_product.ean

Meduse contract

Recommendation

Same logic as Magento:

  • Meduse continues to see the primary EAN as long as there is no explicit business need for ean bis
  • Do not overwrite ean with ean bis
  • Do not add an additional Meduse attribute without a validated use case

Reference:

  • ProductMeduseDataUpdateProcessor (src/MeduseBundle/Services/Queue/ProductMeduseDataUpdateProcessor.php:149)

Proposed rollout

Phase 1

  • Validate that ean bis is strictly marketplace only
  • List the marketplaces / feeds that must use it
  • Confirm whether marketplace order imports ever return an EAN

Phase 2

  • Add dedicated storage for ean bis
  • Add duplicate validations
  • Expose a single helper/service: getMarketplaceExportEan()

Phase 3

  • Connect marketplace exports to ean bis
  • Update the admin UI with 2 distinct fields:
    • Primary EAN
    • Marketplace secondary EAN

Phase 4

  • Audit scripts:
    • ean bis duplicated between SKUs
    • ean bis identical to the primary EAN
    • Marketplaces still reading getEan() directly

Final recommendation

With this new need, the best strategy changes:

  • mz_product.ean must remain the sole canonical EAN
  • ean bis must be modeled as a marketplace override
  • Avoid extending Magento and Meduse until there is a validated business need
  • Audit and adapt only the marketplace exports that currently publish getEan()

In short: this is no longer about a "dual product EAN", but rather a secondary commercial EAN for marketplace distribution.