Mettez régulièrement à jour vos produits

La sous-API Products vous permet de mettre à jour partiellement vos produits existants. Cette méthode est idéale pour les données qui changent fréquemment, comme le prix et la disponibilité, car elle évite de devoir renvoyer l'intégralité du produit pour une petite modification. Toutefois, vous devez réinsérer régulièrement les produits pour vous assurer que toutes les données produit sont synchronisées.

Ce guide explique comment utiliser la méthode productinputs.patch pour mettre à jour vos produits.

Prérequis

Pour pouvoir modifier un produit, vous devez disposer des éléments suivants :

Modifier des informations détaillées sur un produit spécifique

Pour modifier quelques détails d'un produit, comme son prix ou sa disponibilité, sans renvoyer toutes ses informations, utilisez la méthode productInputs.patch.

Vous pouvez spécifier les champs que vous modifiez dans le paramètre updateMask. updateMask est une liste de champs à mettre à jour, séparés par une virgule. La méthode patch se comporte comme suit :

  • Champs dans updateMask et corps : ces champs sont mis à jour avec les nouvelles valeurs.
  • Champs dans updateMask, mais pas dans le corps : ces champs sont supprimés de l'entrée du produit.
  • Champs absents de updateMask : ces champs restent inchangés.
  • Paramètre updateMask omis : tous les champs fournis dans le corps de la requête sont mis à jour. Les champs non fournis dans le corps de la requête ne sont pas supprimés de l'entrée du produit.

Voici un exemple de données produit avant une mise à jour :

{
  "name": "accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345",
  "product": "accounts/{ACCOUNT_ID}/products/en~US~SKU12345",
  "offerId": "SKU12345",
  "contentLanguage": "en",
  "feedLabel": "US",
  "productAttributes": {
    "title": "Classic Cotton T-Shirt",
    "description": "A comfortable, durable, and stylish t-shirt made from 100% cotton.",
    "link": "https://www.example.com/p/SKU12345",
    "availability": "IN_STOCK",
    "price": {
      "amountMicros": "15990000",
      "currencyCode": "USD"
    },
    "condition": "NEW",
    "gtins": [
      "9780007350896"
    ],
    "imageLink": "https://www.example.com/image/SKU12345"
  }
}

Cet exemple met à jour les title et availability d'un produit, et supprime son imageLink. Les description et price ne figurent pas dans updateMask et resteront inchangés.

PATCH https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.availability,productAttributes.imageLink&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
 "productAttributes": {
   "title": "Classic Cotton T-Shirt - New Edition",
   "availability": "OUT_OF_STOCK",
    "description": "A comfortable T-shirt from premium cotton, newer edition.",
    "price": {
      "amountMicros": "9990000",
      "currencyCode": "USD"
    }
 }
}

Un appel réussi renvoie la ressource ProductInput mise à jour. Les title et availability sont mis à jour, et le imageLink est supprimé, car il figurait dans le updateMask, mais pas dans le corps de la requête. Les description et price restent inchangés, car ils ne figuraient pas dans updateMask.

{
  "name": "accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345",
  "product": "accounts/{ACCOUNT_ID}/products/en~US~SKU12345",
  "offerId": "SKU12345",
  "contentLanguage": "en",
  "feedLabel": "US",
  "productAttributes": {
    "title": "Classic Cotton T-Shirt - New Edition",
    "description": "A comfortable, durable, and stylish t-shirt made from 100% cotton.",
    "link": "https://www.example.com/p/SKU12345",
    "availability": "OUT_OF_STOCK",
    "price": {
      "amountMicros": "15990000",
      "currencyCode": "USD"
    },
    "condition": "NEW",
    "gtins": [
      "9780007350896"
    ],
  }
}

Les exemples de code suivants montrent comment mettre à jour un produit.

Java

import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.protobuf.FieldMask;
import com.google.shopping.merchant.datasources.v1.DataSourceName;
import com.google.shopping.merchant.products.v1.Availability;
import com.google.shopping.merchant.products.v1.Condition;
import com.google.shopping.merchant.products.v1.ProductAttributes;
import com.google.shopping.merchant.products.v1.ProductInput;
import com.google.shopping.merchant.products.v1.ProductInputName;
import com.google.shopping.merchant.products.v1.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1.UpdateProductInputRequest;
import com.google.shopping.type.CustomAttribute;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;

/** This class demonstrates how to update a product input */
public class UpdateProductInputSample {

  public static void updateProductInput(Config config, String productId, String dataSourceId)
      throws Exception {

    // Obtains OAuth token based on the user's configuration.
    GoogleCredentials credential = new Authenticator().authenticate();

    // Creates service settings using the credentials retrieved above.
    ProductInputsServiceSettings productInputsServiceSettings =
        ProductInputsServiceSettings.newBuilder()
            .setCredentialsProvider(FixedCredentialsProvider.create(credential))
            .build();

    // Creates product name to identify product.
    String name =
        ProductInputName.newBuilder()
            .setAccount(config.getAccountId().toString())
            .setProductinput(productId)
            .build()
            .toString();

    // Just productAttributes and customAttributes can be updated
    FieldMask fieldMask =
        FieldMask.newBuilder()
            .addPaths("product_attributes.title")
            .addPaths("product_attributes.description")
            .addPaths("product_attributes.link")
            .addPaths("product_attributes.image_link")
            .addPaths("product_attributes.availability")
            .addPaths("product_attributes.condition")
            .addPaths("product_attributes.gtins")
            .addPaths("custom_attributes.mycustomattribute")
            .build();

    // Calls the API and catches and prints any network failures/errors.
    try (ProductInputsServiceClient productInputsServiceClient =
        ProductInputsServiceClient.create(productInputsServiceSettings)) {

      ProductAttributes attributes =
          ProductAttributes.newBuilder()
              .setTitle("A Tale of Two Cities")
              .setDescription("A classic novel about the French Revolution")
              .setLink("https://exampleWebsite.com/tale-of-two-cities.html")
              .setImageLink("https://exampleWebsite.com/tale-of-two-cities.jpg")
              .setAvailability(Availability.IN_STOCK)
              .setCondition(Condition.NEW)
              .addGtins("9780007350896")
              .build();

      // The datasource can be either a primary or supplemental datasource.
      String dataSource =
          DataSourceName.newBuilder()
              .setAccount(config.getAccountId().toString())
              .setDatasource(dataSourceId)
              .build()
              .toString();

      UpdateProductInputRequest request =
          UpdateProductInputRequest.newBuilder()
              .setUpdateMask(fieldMask)
              // You can only update product attributes and custom_attributes
              .setDataSource(dataSource)
              .setProductInput(
                  ProductInput.newBuilder()
                      .setName(name)
                      .setProductAttributes(attributes)
                      .addCustomAttributes(
                          CustomAttribute.newBuilder()
                              .setName("mycustomattribute")
                              .setValue("Example value")
                              .build())
                      .build())
              .build();

      System.out.println("Sending update ProductInput request");
      ProductInput response = productInputsServiceClient.updateProductInput(request);
      System.out.println("Updated ProductInput Name below");
      // The last part of the product name will be the product ID assigned to a product by Google.
      // Product ID has the format `contentLanguage~feedLabel~offerId`
      System.out.println(response.getName());
      System.out.println("Updated Product below");
      System.out.println(response);
    } catch (Exception e) {
      System.out.println(e);
    }
  }

  public static void main(String[] args) throws Exception {
    Config config = Config.load();
    // An ID assigned to a product by Google. In the format
    // contentLanguage~feedLabel~offerId
    String productId = "en~label~sku123"; // Replace with your product ID.

    // Identifies the data source that will own the product input.
    String dataSourceId = "{INSERT_DATASOURCE_ID}"; // Replace with your datasource ID.

    updateProductInput(config, productId, dataSourceId);
  }
}

PHP

use Google\ApiCore\ApiException;
use Google\Protobuf\FieldMask;
use Google\Shopping\Merchant\Products\V1\Availability;
use Google\Shopping\Merchant\Products\V1\Condition;
use Google\Shopping\Merchant\Products\V1\ProductAttributes;
use Google\Shopping\Merchant\Products\V1\Client\ProductInputsServiceClient;
use Google\Shopping\Merchant\Products\V1\ProductInput;
use Google\Shopping\Merchant\Products\V1\UpdateProductInputRequest;
use Google\Shopping\Type\CustomAttribute;

/**
 * This class demonstrates how to update a product input.
 */
class UpdateProductInputSample
{
    // An ID assigned to a product by Google. In the format
    // contentLanguage~feedLabel~offerId
    // Please ensure this product ID exists for the update to succeed.
    private const PRODUCT_ID = "online~en~label~sku123";

    // Identifies the data source that will own the product input.
    // Please ensure this data source ID exists.
    private const DATASOURCE_ID = "<INSERT_DATASOURCE_ID>";

    /**
     * Helper function to construct the full product input resource name.
     *
     * @param string $accountId The merchant account ID.
     * @param string $productInputId The product input ID (e.g., "online~en~label~sku123").
     * @return string The full product input resource name.
     */
    private static function getProductInputName(string $accountId, string $productInputId): string
    {
        return sprintf("accounts/%s/productInputs/%s", $accountId, $productInputId);
    }

    /**
     * Helper function to construct the full data source resource name.
     *
     * @param string $accountId The merchant account ID.
     * @param string $dataSourceId The data source ID.
     * @return string The full data source resource name.
     */
    private static function getDataSourceName(string $accountId, string $dataSourceId): string
    {
        return sprintf("accounts/%s/dataSources/%s", $accountId, $dataSourceId);
    }

    /**
     * Updates an existing product input in your Merchant Center account.
     *
     * @param array $config The configuration array containing the account ID.
     * @param string $productId The ID of the product input to update.
     * @param string $dataSourceId The ID of the data source.
     */
    public static function updateProductInput(
        array $config,
        string $productId,
        string $dataSourceId
    ): void {
        // Gets the OAuth credentials to make the request.
        $credentials = Authentication::useServiceAccountOrTokenFile();

        // Creates options config containing credentials for the client to use.
        $options = ['credentials' => $credentials];

        // Creates a ProductInputsServiceClient.
        $productInputsServiceClient = new ProductInputsServiceClient($options);

        // Construct the full resource name of the product input to be updated.
        $name = self::getProductInputName($config['accountId'], $productId);

        // Define the FieldMask to specify which fields to update.
        // Only 'attributes' and 'custom_attributes' can be specified in the
        // FieldMask for product input updates.
        $fieldMask = new FieldMask([
            'paths' => [
                "product_attributes.title",
                "product_attributes.description",
                "product_attributes.link",
                "product_attributes.image_link",
                "product_attributes.availability",
                "product_attributes.condition",
                "product_attributes.gtin",
                "custom_attributes.mycustomattribute" // Path for a specific custom attribute
            ]
        ]);

        // Calls the API and handles any network failures or errors.
        try {
            // Define the new attributes for the product.
            $attributes = new ProductAttributes([
                'title' => 'A Tale of Two Cities 3',
                'description' => 'A classic novel about the French Revolution',
                'link' => 'https://exampleWebsite.com/tale-of-two-cities.html',
                'image_link' => 'https://exampleWebsite.com/tale-of-two-cities.jpg',
                'availability' => Availability::IN_STOCK,
                'condition' => Condition::PBNEW,
                'gtins' => ['9780007350896'] // GTIN is a repeated field.
            ]);

            // Construct the full data source name.
            // This specifies the data source context for the update.
            $dataSource = self::getDataSourceName($config['accountId'], $dataSourceId);

            // Create the ProductInput object with the desired updates.
            // The 'name' field must match the product input being updated.
            $productInput = new ProductInput([
                'name' => $name,
                'product_attributes' => $attributes,
                'custom_attributes' => [ // Provide the list of custom attributes.
                    new CustomAttribute([
                        'name' => 'mycustomattribute',
                        'value' => 'Example value'
                    ])
                ]
            ]);

            // Create the UpdateProductInputRequest.
            $request = new UpdateProductInputRequest([
                'update_mask' => $fieldMask,
                'data_source' => $dataSource,
                'product_input' => $productInput
            ]);

            print "Sending update ProductInput request\n";
            // Make the API call to update the product input.
            $response = $productInputsServiceClient->updateProductInput($request);

            print "Updated ProductInput Name below\n";
            // The name of the updated product input.
            // The last part of the product name is the product ID (e.g., contentLanguage~feedLabel~offerId).
            print $response->getName() . "\n";
            print "Updated Product below\n";
            // Print the full updated product input object.
            print_r($response);

        } catch (ApiException $e) {
            printf("ApiException caught: %s\n", $e->getMessage());
        }
    }

    /**
     * Executes the UpdateProductInput sample.
     */
    public function callSample(): void
    {
        $config = Config::generateConfig();
        $productId = self::PRODUCT_ID;
        $dataSourceId = self::DATASOURCE_ID;

        self::updateProductInput($config, $productId, $dataSourceId);
    }
}

// Run the script.
$sample = new UpdateProductInputSample();
$sample->callSample();

Python

"""A module to update a product input."""

from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.protobuf import field_mask_pb2
from google.shopping.merchant_products_v1 import Availability
from google.shopping.merchant_products_v1 import Condition
from google.shopping.merchant_products_v1 import ProductAttributes
from google.shopping.merchant_products_v1 import ProductInput
from google.shopping.merchant_products_v1 import ProductInputsServiceClient
from google.shopping.merchant_products_v1 import UpdateProductInputRequest
from google.shopping.type import CustomAttribute


# Fetches the Merchant Center account ID from the authentication examples.
# This ID is needed to construct resource names for the API.
_ACCOUNT_ID = configuration.Configuration().read_merchant_info()


def update_product_input(account_id: str, product_id: str, data_source_id: str):
  """Updates an existing product input for a specific account.

  Args:
    account_id: The Merchant Center account ID.
    product_id: The ID of the product input to update. This ID is assigned by
      Google and has the format `contentLanguage~feedLabel~offerId`.
    data_source_id: The ID of the data source that owns the product input.
  """

  # Obtains OAuth credentials for authentication.
  credentials = generate_user_credentials.main()

  # Creates a ProductInputsServiceClient instance.
  client = ProductInputsServiceClient(credentials=credentials)

  # Constructs the full resource name for the product input.
  # Format: accounts/{account}/productInputs/{productinput}
  name = f"accounts/{account_id}/productInputs/{product_id}"

  # Defines the FieldMask to specify which fields of the product input
  # are being updated. Only 'attributes' and 'custom_attributes' can be updated.
  field_mask = field_mask_pb2.FieldMask(
      paths=[
          "product_attributes.title",
          "product_attributes.description",
          "product_attributes.link",
          "product_attributes.image_link",
          "product_attributes.availability",
          "product_attributes.condition",
          "product_attributes.gtins",
          "custom_attributes.mycustomattribute",
      ]
  )

  # Prepares the new attribute values for the product.
  attributes = ProductAttributes(
      title="A Tale of Two Cities updated",
      description="A classic novel about the French Revolution",
      link="https://exampleWebsite.com/tale-of-two-cities.html",
      image_link="https://exampleWebsite.com/tale-of-two-cities.jpg",
      availability=Availability.IN_STOCK,
      condition=Condition.NEW,
      gtins=["9780007350896"],  # GTIN is a repeated field.
  )

  # Constructs the full resource name for the data source.
  # The data source can be primary or supplemental.
  # Format: accounts/{account}/dataSources/{datasource}
  data_source = f"accounts/{account_id}/dataSources/{data_source_id}"

  # Prepares the ProductInput object with the updated information.
  product_input_data = ProductInput(
      name=name,
      product_attributes=attributes,
      custom_attributes=[
          CustomAttribute(
              name="mycustomattribute", value="Example value"
          )
      ],
  )

  # Creates the UpdateProductInputRequest.
  request = UpdateProductInputRequest(
      update_mask=field_mask,
      data_source=data_source,
      product_input=product_input_data,
  )

  # Sends the update request to the API.
  try:
    print("Sending update ProductInput request")
    response = client.update_product_input(request=request)
    print("Updated ProductInput Name below")
    # The response includes the name of the updated product input.
    # The last part of the product name is the product ID assigned by Google.
    print(response.name)
    print("Updated Product below")
    print(response)
  except RuntimeError as e:
    # Catches and prints any errors that occur during the API call.
    print(e)


if __name__ == "__main__":
  # The ID of the product to be updated.
  # This ID is assigned by Google and typically follows the format:
  # contentLanguage~feedLabel~offerId
  # Replace with an actual product ID from your Merchant Center account.
  product_id_to_update = "online~en~label~sku123"

  # The ID of the data source that will own the updated product input.
  # Replace with an actual data source ID from your Merchant Center account.
  data_source_id_for_update = "<INSERT_DATA_SOURCE_ID>"

  update_product_input(
      _ACCOUNT_ID, product_id_to_update, data_source_id_for_update
  )

cURL

curl --location --request PATCH 'https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.description&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}' \
--header 'Authorization: Bearer <API_TOKEN>' \
--header 'Content-Type: application/json' \
--data '{
   "productAttributes": {
       "title": "A Tale of Two Cities",
       "description": "A classic novel about the French Revolution"
   }
}'

Mettre à jour à l'aide d'attributs personnalisés

Vous pouvez mettre à jour les attributs standards et personnalisés en un seul appel. Pour mettre à jour un attribut personnalisé, préfixez son nom avec customAttributes dans updateMask.

Cet exemple effectue plusieurs actions dans une même requête :

  • Met à jour directement l'attribut standard title.
  • Met à jour un attribut personnalisé existant (myCustomAttrToBeUpdated).
  • Insère un attribut personnalisé (myCustomAttrToBeInserted).
  • Supprime un attribut personnalisé existant (myCustomAttrToBeDeleted).
PATCH https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?updateMask=productAttributes.title,customAttributes.myCustomAttrToBeInserted,customAttributes.myCustomAttrToBeUpdated,customAttributes.myCustomAttrToBeDeleted&dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
  "productAttributes": {
    "title": "ProductTitle Updated"
  },
  "customAttributes": [
    {
      "name": "description",
      "value": "A newly updated description."
    },
    {
      "name": "myCustomAttrToBeUpdated",
      "value": "myCustomAttrToBeUpdated updated value"
    },
    {
      "name": "myCustomAttrToBeInserted",
      "value": "new from update"
    }
  ]
}

Une requête réussie renvoie le ProductInput mis à jour, reflétant toutes les modifications spécifiées.

Comprendre les mises à jour des attributs personnalisés

Vous pouvez utiliser le champ customAttributes pour mettre à jour les attributs que vous avez définis vous-même. Ils ne correspondent pas aux spécifications standards et seront stockés en tant qu'attributs personnalisés sur le produit final.

Traitement des mises à jour de produits

Lorsque vous envoyez une requête patch, la mise à jour est appliquée aux données ProductInput spécifiques avant l'application des règles. Cela permet d'obtenir un comportement cohérent entre l'insertion et la mise à jour des produits.

Voici comment votre mise à jour est traitée :

  1. Mettre à jour l'entrée : votre requête patch modifie le ProductInput spécifique associé à la source de données que vous avez fournie.

  2. Traitement et fusion : une fois l'entrée mise à jour, le traitement commence :

    • Règles de flux et sources de données supplémentaires : les règles configurées sur la source principale du produit combinent les ProductInput des sources principales et supplémentaires. Ces règles peuvent modifier des attributs ou en dériver de nouveaux. Pour en savoir plus sur la configuration des règles, consultez l'article https://support.google.com/merchants/answer/14994083.
    • Autres sources de données : les données provenant d'autres sources (par exemple, les améliorations automatiques) sont également fusionnées avec les données d'entrée de la source de données principale.
    • Validation : les données fusionnées sont validées par rapport aux spécifications des données produit et aux règles de Google Shopping.
  3. Produit final : le résultat de ce pipeline est la ressource Product finale traitée qui peut être renvoyée à l'aide de products.get ou products.list. Il s'agit également de la version du produit affichée dans Merchant Center et éligible à la diffusion dans différentes destinations.

En raison de ce processus en plusieurs étapes, il existe un délai, généralement de quelques minutes, entre le moment où vous envoyez une demande de mise à jour et celui où les modifications sont reflétées dans la ressource Product finale que vous pouvez récupérer avec products.get.

Exemple : Mettre à jour un produit avec une seule entrée principale

Il s'agit du cas d'utilisation le plus courant. Un produit existe dans une seule source de données principale et vous souhaitez mettre à jour certains de ses attributs.

  1. État initial : un produit en~US~SKU12345 existe dans votre source de données principale avec title: "Classic T-Shirt" et price: 15.99 USD.
  2. Demande de mise à jour : vous envoyez une requête patch pour mettre à jour price sur 14.99 USD et définir availability sur out of stock.
  3. Traitement :
    • Le ProductInput pour SKU12345 a été modifié.
  4. Produit final : le Product final comporte désormais title: "Classic T-Shirt", price: 14.99 USD et availability: "out of stock".

Exemple : Mettre à jour un produit avec des données et des règles supplémentaires

Cet exemple montre comment les règles de flux peuvent affecter une mise à jour, en appliquant certaines modifications et en en ignorant d'autres.

  1. État initial :
    • Entrée principale : en~US~SKU12345 comporte title: "Great T-Shirt" et description: "A great short-sleeve t-shirt.".
    • Entrée supplémentaire : le même produit figure dans une source de données supplémentaire avec title: "Awesome T-Shirt" et description: "An awesome short-sleeve t-shirt.".
    • Règle de flux : une règle est définie pour extraire title de la source de données supplémentaire. Il n'existe aucune règle pour description.
    • Résultat : le Product final traité comporte title: "Awesome T-Shirt" et description: "A great short-sleeve t-shirt.".
  2. Requête de mise à jour : vous envoyez une requête patch pour mettre à jour la source de données principale, en définissant title sur "Fantastic T-Shirt" et description sur "A fantastic short-sleeve t-shirt.".
  3. Traitement :
    • Le ProductInput de la source de données principale est mis à jour pour inclure title: "Fantastic T-Shirt" et description: "A fantastic short-sleeve t-shirt.".
    • Le pipeline de traitement s'exécute.
    • Pour title, la règle du flux stipule que la valeur de la source de données supplémentaire (Awesome T-Shirt) prévaut sur votre modification.
    • Pour description, comme il n'existe aucune règle de remplacement, la valeur mise à jour de l'entrée principale (A fantastic short-sleeve t-shirt.) est utilisée.
  4. Produit final : le titre de la Product finale reste Awesome T-Shirt (votre modification a été ignorée), mais sa description est désormais A fantastic short-sleeve t-shirt. (votre modification a été appliquée).

Choisir entre les mises à jour et les sources de données supplémentaires

Vous pouvez modifier les données produit à l'aide de productinputs.patch ou en insérant des données dans des sources de données supplémentaires. Le meilleur choix dépend de votre stratégie de gestion des données.

Pour éviter des résultats imprévisibles, nous vous recommandons de ne pas utiliser à la fois productinputs.patch et des sources de données supplémentaires pour gérer les mêmes données produit pour le même produit.

Voici une comparaison détaillée :

Fonctionnalité productinputs.patch (Mises à jour) Sources de données supplémentaires
Recommandée pour Modifications partielles, rapides et fréquentes des données existantes (prix, disponibilité, etc.). Superposition de données logiquement distinctes, gestion de différents attributs par différents systèmes ou remplacements complexes basés sur des règles.
Mécanisme Modifie une valeur ProductInput existante sur place. Crée un ProductInput distinct dans une source de données supplémentaire.
Précision des données Fonctionne sur des champs spécifiques d'un seul ProductInput. Opère sur l'ensemble de l'ProductInput dans la source supplémentaire.
Persistance Les modifications sont conservées jusqu'à ce que le même ProductInput soit remplacé par un insert complet ou un autre patch. La persistance est contrôlée par les règles de flux. Peut remplacer les données principales indéfiniment si les règles le permettent.
Interaction avec les règles Peut être utilisé sans les règles de flux, car il met à jour une source de données existante et ProductInput. Nécessite de configurer explicitement une règle sur la source principale pour associer la source supplémentaire.
Configuration de la source de données Opère sur une source de données existante. Aucune nouvelle source n'est nécessaire. Nécessite de créer et de gérer des sources de données supplémentaires distinctes, puis de les associer à l'aide de règles de flux.