lumnik. / scénarios Tous les scénarios · English

Le catalogue part chez le partenaire dans son format à lui

Objectif Livrer le catalogue produits à un partenaire dans le format qu'il impose, sans écrire de code de conversion.

Deux CSV d'un ERP, produits et catégories, sont joints dans le hub puis livrés sur S3 au format d'un partenaire.

manifests/10-products.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: import-export-products-b  connector_type: csv-file  scopes: [catalogue]spec:  transport:    kind: local    path: /tmp/lumnik-scenario/import-export/b/m_product.csv  parser:    has_header: true  after_process: none  mapping:    dataset:      - require-headers:          columns: [m_product_id, m_product_category_id, name, description, isactive]      - enrich-context:          record_type: ARTICLE          source_system: COMPIERE          catalogue_version: "1.5"          catalogue_date: "2026-10-15"    cell:      - parse-number: { column: m_product_id, integer: true }      - parse-number: { column: m_product_category_id, integer: true }      - clean:          columns: [name, description]          strip: true          remove-control-chars: true          normalize-unicode: NFC      - strip-invisible: { columns: [name] }      - upper: { columns: [name] }      - replace-smart-quotes: { columns: [description] }      - lookup:          column: isactive          table: { "Y": "1", "N": "0" }          on-missing: null
manifests/20-product-categories.yaml
apiVersion: connectors.lumnik.io/v1kind: Connectormetadata:  name: import-export-product-categories-b  connector_type: csv-file  scopes: [catalogue]spec:  transport:    kind: local    path: /tmp/lumnik-scenario/import-export/b/m_product_category.csv  parser:    has_header: true  after_process: none  mapping:    dataset:      - require-headers:          columns: [m_product_category_id, name, description, isactive]    cell:      - parse-number: { column: m_product_category_id, integer: true }      - clean:          columns: [name, description]          strip: true          remove-control-chars: true          normalize-unicode: NFC      - strip-invisible: { columns: [name] }      - replace-smart-quotes: { columns: [name, description] }      - decode-html-entities: { columns: [name, description] }      - lookup:          column: isactive          table: { "Y": "1", "N": "0" }          on-missing: null
manifests/30-product-with-category.yaml
kind: Entityname: ProductWithCategoryBdescription: Products enriched with their category before delivery to S3.match: [product_id]scopes: [catalogue]sources:  - table: t_import_export_products_b    map:      record_type: record_type      source_system: source_system      catalogue_version: catalogue_version      catalogue_date: catalogue_date      m_product_id: product_id      m_product_category_id: category_id      name: product_name      description: product_description      isactive: product_activejoins:  - table: t_import_export_product_categories_b    from: category_id    to: m_product_category_id    map:      name: category_name      description: category_description      isactive: category_active
manifests/40-product-catalogue-s3.yaml
apiVersion: apps.lumnik.io/v1kind: Exportmetadata:  name: import-export-product-catalogue-bspec:  scope: catalogue  source:    entity: ProductWithCategoryB  columns:    - name: record_type      as: TYPE_ENREGISTRE    - name: source_system      as: SYSTEME_SOURCE    - name: catalogue_version      as: VERSION_FORMAT      format:        - format-number: { decimal-separator: ",", scale: 2 }    - name: catalogue_date      as: DATE_CATALOGUE      format:        - format-date: { pattern: dd/MM/yyyy }    - name: product_id      as: ID_ARTICLE    - name: product_name      as: REFERENCE_ARTICLE    - name: product_description      as: DESCRIPTION_ARTICLE    - name: product_active      as: STATUT_ARTICLE      format:        - lookup: { table: { "1": A, "0": I }, on-missing: error }    - name: category_id      as: REF_CATEGORIE      format:        - mask: { keep-last: 4 }    - name: category_name      as: LIBELLE_CATEGORIE    - name: category_description      as: DESCRIPTION_CATEGORIE  filter:    - column: category_active      equals: "1"  order: [product_id]  format:    kind: csv    delimiter: ";"  destination:    kind: s3    bucket: import-export    prefix: catalogue/b    filename: products.csv    region: us-east-1    endpoint: http://import-export-minio:9000    access_key_env: IMPORT_EXPORT_S3_ACCESS_KEY    secret_key_env: IMPORT_EXPORT_S3_SECRET_KEY  mode: snapshot
header
"TYPE_ENREGISTRE";"SYSTEME_SOURCE";"VERSION_FORMAT";"DATE_CATALOGUE";"ID_ARTICLE";"REFERENCE_ARTICLE";"DESCRIPTION_ARTICLE";"STATUT_ARTICLE";"REF_CATEGORIE";"LIBELLE_CATEGORIE";"DESCRIPTION_CATEGORIE"
first row
"ARTICLE";"COMPIERE";"1,50";"15/10/2026";"218";"294508";"FILTRE A CARTOUCHE MISTRAL 880 Ø 400";"A";"***0018";"Filtration à cartouche";
check
38300 products from active categories exported in the partner's Maximus format; headers are renamed, version and date are formatted, statuses are recoded, internal category ids are masked, and the receipt proves the exact delivered bytes.

preuves: replay.log, delivered-head.csv · transform v1

Limites

  • Masquer un identifiant prévisible est de la pseudonymisation, pas du chiffrement; si le partenaire ne doit pas corréler les catégories, retirez la colonne.
  • Le mode snapshot réécrit l'objet entier à chaque exécution.
  • Données synthétiques.

Catalogue · partenaire

Un partenaire veut le catalogue.

Dans son format, pas dans le nôtre.

Point-virgule, virgule décimale, ses propres en-têtes et codes.

Catalogue synthétique

Le problème

Chaque partenaire, un script de conversion.

  • L'ERP exporte produits et catégories à part.
  • Le partenaire veut une ligne par article, catégorie comprise.
  • Ses statuts et ses dates ne sont pas ceux de l'ERP.

Rien n'est modifié

L'ERP exporte comme avant.

  • Deux fichiers CSV, tels quels.
  • Le hub joint et formate.
  • Aucun script à maintenir.

Ce qu'il a fallu écrire

- name: category_id
  as: REF_CATEGORIE
  format:
    - mask: { keep-last: 4 }

La référence interne est masquée.

Le scénario complet tient en 4 fichiers de déclaration, 149 lignes.

Ce que reçoit le partenaire

38 300 articles, dans son format.

  • En-têtes renommés.
  • Version 1,50 et date 15/10/2026.
  • Statut A ou I, référence ***0018.

La preuve

Le reçu dit les octets livrés.

Le runner relit l'objet sur S3: même taille, même SHA-256.

Rejeu du 3 novembre 2026.

La limite

Masquer n'est pas chiffrer.

  • Un identifiant masqué reste corrélable.
  • Si le partenaire ne doit pas corréler, retirez la colonne.
  • Le mode snapshot réécrit l'objet entier.

Essayer

Le scénario se rejoue de bout en bout.

CSV, entité, export S3: chaque étape est publiée avec sa sortie.

Ce scénario tourne sur lumnik Open, gratuit et open source.

Essayer lumnik Open →