Variants

Summary

Overview

The goal of the variant module is to group similar products to push them as models & children in the PIM. Note that despite this module being exclusively used by Akeneo PIM customers, it is built, like the rest of the app, to be compatible with different systems. That's why SDM don't necessarily make the same assumptions as SDM could if just working with Akeneo.

As of now, this module is entirely manual, the products are not linked together and the user has to create product models themselves.

Note that this module does not assume that a specific "parent" row exists in the input file. The parent will be created automatically when products are grouped.

 

Interface & Use Cases

More info in our dedicated guide

 

The top of the screen is similar to other table-based modules: some clickable stats filters with 4 groups :

  • Rows to add in product model (red): rows that still have to be processed. As for all others, this step can't be finalized if there are still rows to process.
  • Rows added in product model by you (green): rows that the user has manually grouped
  • Independent rows: rows marked by the user as having no parent, will be pushed as simple products in the PIM

⬇️ Then there are two tables, the first one, on the left, shows all products matching the current filter grouped by product model. This table has a "Group" column used to show which products can be grouped inside a product model. The second table, on the right, lists product models created by the user.

Grouping the products

When selecting multiple ungrouped products (in the left table) you can use the "Create a product model" button. This will open the following pop-up allowing you to add the following information :

The id of the product model: this is used internally to know which products belong together and will be stored in an attribute (see product_model_name_column config entry). This will also be used as the id of the product model when pushing to the PIM.

The variant columns: the columns marked as variant are attributes whose values are allowed to change for each product related to the product model.

The parent row: one row must be selected as "parent". What it means is that every attribute not marked as variant, when the step is done, will be set to the same value as for the parent.

When grouping products, there are multiple validations done based on the matching_groups configuration.

  1. If allow_product_model_without_matching_group is disabled SDM checks that all the products being grouped all have a matching group.
  2. SDM checks that the products grouped together belong to the same matching group, otherwise, the creation/update is rejected
  3. Finally, based on the matching group SDM also checks that the set unique_columns all have different values. For instance, SDM can't group two blue, size L, t-shirts if they only unique_columns are "size" and "color".

Configuration

Always be sure to refer to the API docs. The API docs are always up to date and should remain a source of truth. It is recommended to double check the info presented here against it.

 
  • product_model_name_column : this is the attribute (that don't have to be pushed into the PIM) where SDM will store the id of the product model for the product (empty if the product is independent). The content is the name of the attribute and the associated labels.
  • product_model_head_column : this is the attribute (that don't have to be pushed into the PIM) where SDM will store the type of the row (child, parent, independent or ungrouped). The content is the name of the attribute and the associated labels.
  • export_data : this is a list whose elements can be "parent", "child" or "independent". When the step is finalized, the products whose "product_model_head_column" is in the list of columns will be made available in the "export" dataframe.
  • output_data : this is a list whose elements can be "parent", "child" or "independent". When the step is finalized, the products whose "product_model_head_column" is in the list of columns will be made available in the "output" dataframe and continue to the next step.
  • default_id_column : used to automatically fill the group id column based on an attribute value when creating a product model
  • unique_columns: list of attributes used to validate that all products belonging to the same model have distinct values. Mostly used in matching_groups (below) and rarely used here at the root of the config.
  • invariant_columns : list of attributes that will be marked as invariant when creating a product model.
  • variant_columns : list of attributes that will be marked as variants when creating a product model.
  • allow_product_model_without_matching_group : flag to authorize to group products without a matching group together. This is set by default to false by the connector.
  • matching_groups : list of groups used for automation & validation. Each entry has the following arguments :
    • name : id of the group
    • label : mapping of locale => label used for display purposes only
    • conditions : list of rules used to tell if a given product belongs to a matching group. Note that, unlike groups, a product can only belong to a single matching group and will belong to the first one where they match all conditions.
    • unique_columns : list of attributes used to validate that all products belonging to the same model have distinct values. If all the fields in this list are similar then it means that the product is identical and not a variant (see above).
    • variant_columns : list of attributes that will be marked as variants when creating/updating the product model (cannot be changed in the UI).
    • invariant_columns : list of attributes that won't be able to be marked as variants when creating/updating the product model.

How does it work with the Akeneo connector?

For project creation

By default the connector does not leverage variants, this has to be activated. To do that, simply set use_variants it to true. This will do multiple things :

  1. The family hierarchy will be changed from one level (just the families) to two levels (the families and all their variant families as children).
  2. When creating the steps for the project, instead of having the boilerplate Akeneo project:

The project gets more complicated with:

The reason the project is done that way is to reduce the amount of duplicated work:

  1. first, SDM only works on variant attributes for products that have a family variant assigned. That way SDM will work on most products BUT only on a limited set of attributes and SDM makes sure not to fill multiple times an attribute that will have the same value because it belongs to a model and not a child.
  2. Then at the variant step, it is automatically configured to only output "parents" and "independent". That means that the following steps will be only working on simple products or product models.
  3. From that point, SDM works on all attributes.

The Variant step is configured entirely and the matching_groups entry is made to represent variant families. SDM does not make the distinction between variant families with one or two axes of variation. Everything is flattened to just one level and will be reconstructed during the push. Each family variant is configured as a matching group with the following config :

  • name: id of the family variant
  • label: translations of the family variant
  • conditions: rules that check that the "family_variant" attribute is not empty and matches the id of the family variant.
  • unique_columns: list all variation axes from both levels
  • variant_columns: list all variant attributes from both levels
  • invariant columns: empty list

One last thing done when generating the config is making sure that variation axes are marked as required even if a max_requirement_level is set. SDM do that because if a variation axis is empty, the PIM refuses the push so SDM need to force the value to be filled.

 

For project config updates

When a config sync is triggered for a connector, the Variant step config is automatically updated. Specifically, SDM make sure that the matching_groups entry is kept up to date to be able to properly validate created groups.

Note that for now, a config sync, if there is not exactly one Variant step in the project, will trigger an error if the option "use_variants" is active in the connector.

 

For pushing to the PIM

When a job is done, if a connector is linked to said job's project and the push is activated then SDM push products in multiple stages :

  1. SDM pushes simple products directly
  2. SDM identifies all products marked as "parent" and pushes them as product models. The id of the product model is the id of that the user filled in when creating the group.
  3. For variant families with two axes of variations, SDM randomly selects one "parent" for each unique set of values in the first variation axis. 
    From that, SDM creates an intermediary parent who carries the first axis attributes and has for id the id of the parent concatenated with the values of the first axis. So for instance if we have t-shirts varying by color then size and one parent has the id "tshirt-collection-aw25" then the blue t-shirt intermediary parent regrouping the different sizes would have "tshirt-collection-aw25-blue" as the id.
  4. Finally, SDM creates all children as products linked to the appropriate parent (first or second level depending on the family variant).

Configuration exemple

Here is a sample of the Variant step as generated by the Akeneo Connector (with just one matching group for readability).

{
  "export_data": [
    "parent",
    "child",
    "independent"
  ],
  "output_data": [
    "parent",
    "independent"
  ],
  "matching_groups": [
    {
      "name": "fam_bathroom_sink_variant_1",
      "label": {
        "fr-FR": "Vasque - Forme, couleur"
      },
      "conditions": [
        {
          "name": "required",
          "field": "family",
          "negate": false
        },
        {
          "name": "isin",
          "field": "family",
          "negate": false,
          "values": [
            "fam_bathroom_sink"
          ]
        },
        {
          "name": "required",
          "field": "family_variant",
          "negate": false
        },
        {
          "name": "isin",
          "field": "family_variant",
          "negate": false,
          "values": [
            "fam_bathroom_sink_variant_1"
          ]
        }
      ],
      "unique_columns": [
        "product_shape",
        "product_color"
      ],
      "variant_columns": [
        "parcel_send_to_effitrace",
        "product_CBM",
        "product_PVR_TTC_PCS",
        "product_PVR_TTC_PCS-currency",
        "product_color",
        "product_depth",
        "product_depth-unit",
        "product_description_instructions-fr_FR",
        "product_diameter",
        "product_diameter-unit",
        "product_ean",
        "product_from_prestashop",
        "product_height",
        "product_height-unit",
        "product_origin_description",
        "product_origin_image_url",
        "product_origin_informations",
        "product_origin_name",
        "product_supplier_reference",
        "product_suppliers_purchase_price_per_pcs",
        "product_suppliers_purchase_price_per_pcs-currency",
        "product_variant_name-fr_FR",
        "product_weight",
        "product_weight-unit",
      ],
      "invariant_columns": []
    }
  ],
  "variant_columns": [],
  "default_id_column": "code_modele",
  "invariant_columns": [],
  "product_model_head_column": {
    "name": "is_parent",
    "label": {
      "fr": "est un parent"
    }
  },
  "product_model_name_column": {
    "name": "akeneo_parent_id",
    "label": {
      "fr": "Akeneo parent id"
    }
  },
  "allow_product_model_without_matching_group": false
}

Variant family as configured in client's PIM

{
    "code": "fam_bathroom_sink_variant_1",
    "labels": {
        "fr_FR": "Vasque - Forme, couleur"
    },
    "variant_attribute_sets": [
        {
            "axes": [
                "product_shape"
            ],
            "level": 1.0,
            "attributes": [
                "product_name",
                "product_styles",
                "product_summary",
                "product_seo_description",
                "product_height",
                "product_width",
                "product_depth",
                "product_diameter",
                "product_weight",
                "product_shape",
                "product_instruction_file",
                "product_installation_vid",
                "product_schema_pics",
                "product_description",
                "product_main_points",
                "product_long_name",
                "product_description_instructions",
                "product_syphon_diameter"
            ]
        },
        {
            "axes": [
                "product_color"
            ],
            "level": 2.0,
            "attributes": [
                "sku",
                "product_step_of_publication",
                "product_is_dropshipped",
                "parcel_send_to_effitrace",
                "product_color",
                "product_origin_name",
                "product_origin_description",
                "product_supplier_reference",
                "product_CBM",
                "product_suppliers_purchase_price_per_pcs",
                "product_packshot_pics",
                "product_ambience_pics",
                "product_zoom_pics",
                "product_influencers_pics",
                "product_trace_file",
                "product_PVR_TTC_PCS",
                "product_ean",
                "product_variant_full_name",
                "parcel",
                "product_origin_informations",
                "product_origin_image_url",
                "product_from_prestashop",
                "product_reverse_full_name",
                "product_variant_name",
                "product_total_parcel_qty",
                "product_reverse_variant_name_2"
            ]
        }
    ]
}

What you can see is that :

  • SDM output both “parent” and “independent” to make sure SDM fill all necessary attributes
  • The variant family (see in toggle) has two variation axes combined into a single matching group
  • They have in their input file the information of the product model name so default_id_column is filled.

Glossary

  • Parent products: this refers to a product model. It has no variation notion, only “common” attributes. This product is not real: it cannot be bought. One parent product may be linked to many child products.
  • Child products: this refers to products that can be bought. The child product has all of the variation notions (variant columns), which differentiate it from other child products.
  • Independant products: Product that has no product model attached to, no variation notion. Also called “simple products”. All fields composing an independent product are common.