Mise à jour automatique du prix et du prix de référence en cas de modification du coût chez le fournisseur
September 3, 2026
Votre fournisseur augmente le prix d'une variante de 4,00 à 5,20. Rien ne se passe dans «Shopify ». Le prix de vente reste inchangé, et la marge que vous aviez prévue disparaît discrètement jusqu'à ce que quelqu'un s'en aperçoive lors d'un inventaire, quelques semaines plus tard.
Shopify Flow Cela ne suffit pas à lui seul, car Shopify ne dispose d'aucun déclencheur intégré en cas de modification du coût unitaire. Il n'existe pas non plus d'action permettant de recalculer un prix à partir de celui-ci.
Ce guide comble ces deux lacunes. Dès que le coût unitaire d'une variante évolue, un « Flow » se déclenche et une petite fonction enregistre le nouveau prix ainsi que le prix de référence sur Shopify. La mise en place prend environ dix minutes, puis le processus s'exécute à chaque modification du coût, de manière permanente.
Ce que vous allez créer
- Workflow Trigger Extensions détecte la modification du prix et lance un flux, en transmettant la variante, sa référence, ainsi que l'ancien et le nouveau prix.
- Shopify Flow transmet ces valeurs à une fonction sous forme de JSON.
- Workflow Functions exécute quelques lignes de code JavaScript qui calculent les nouveaux prix et les renvoient via l'API d'administration.
La règle de tarification est définie à un seul endroit, dans du code que vous contrôlez ; ainsi, pour la modifier ultérieurement, il suffit de modifier une ligne plutôt que de reconstruire tout un flux de travail.
Étape 1 : Activer le seuil de coût
Dans «Workflow Trigger Extensions », ouvrez la page « Triggers », recherchez le groupe « Inventory », puis activez l'option « Product Variant Cost Changed ».
Ce déclencheur nécessite l'accès aux données d'inventaire, car le coût unitaire est associé à l'article en stock plutôt qu'à la variante elle-même. Si l'autorisation n'a pas encore été accordée, l'activation du déclencheur déclenchera l'affichage d'une boîte de dialogue unique pour la demander. Tant que l'autorisation n'est pas accordée, le déclencheur reste activé mais affiche un indicateur « Autorisation requise » et ne se déclenchera pas.
Ce que vous apporte le déclencheur
Une fois qu'il se déclenche, votre Flow a accès à :
| Champ | Exemple |
|---|---|
variantCostChange.variantId |
gid://shopify/ProductVariant/54589751394579 |
variantCostChange.variantTitle |
Medium / Black |
variantCostChange.sku |
TSHIRT-M-BLK |
variantCostChange.oldCost.amount |
4.00 |
variantCostChange.newCost.amount |
5.20 |
variantCostChange.newCost.currencyCode |
EUR |
Le produit lui-même est également inclus en tant que référence produit ; vous pouvez donc ajouter des conditions Flow basées sur le fournisseur, le type, les balises ou la collection avant même de modifier le prix.
Étape 2 : Créer la fonction
Dans « Workflow Functions », créez une nouvelle fonction et collez le code ci-dessous.
Avant d'enregistrer, activez l'option « Nécessite des données d'Shopify ». C'est cette option qui expose ctx.shopify.graphql(...) à votre code afin qu'il puisse lire et modifier les données du magasin. Ouvrez ensuite la page « Autorisations » à l'adresse Workflow Functions et accordez l'autorisation d'écriture sur les produits, ce qui correspond à la portée dont cette fonction a besoin pour modifier un prix.
Sans ce paramètre, l'objet « ctx.shopify » n'est pas disponible et la fonction échoue dès le premier appel à l'API d'administration.
export default async function (input, ctx) {
const toGid = (value, type) => {
if (value === undefined || value === null) return null;
const str = String(value).trim();
if (!str) return null;
if (str.startsWith('gid://')) return str;
if (/^\d+$/.test(str)) return `gid://shopify/${type}/${str}`;
return str;
};
try {
const variantId = toGid(input.variantId || input.variant_id || input.id, 'ProductVariant');
if (!variantId) throw new Error('Missing "variantId" in input.');
const hasPrice = input.price !== undefined && input.price !== null && String(input.price).trim() !== '';
const hasCompareAt = Object.prototype.hasOwnProperty.call(input, 'compareAtPrice') || Object.prototype.hasOwnProperty.call(input, 'compare_at_price');
const rawCompareAt = input.compareAtPrice !== undefined ? input.compareAtPrice : input.compare_at_price;
if (!hasPrice && !hasCompareAt) throw new Error('Nothing to update: provide "price" and/or "compareAtPrice".');
const asMoney = (value) => {
const num = Number(value);
if (!Number.isFinite(num) || num < 0) throw new Error(`Invalid money value: ${JSON.stringify(value)}`);
return num.toFixed(2);
};
let productId = toGid(input.productId || input.product_id, 'Product');
if (!productId) {
const readQuery = `
query VariantForPriceUpdate($id: ID!) {
productVariant(id: $id) { id product { id } }
}`;
const readRes = await ctx.shopify.graphql(readQuery, { id: variantId });
if (readRes.errors) throw new Error('Failed to read variant: ' + JSON.stringify(readRes.errors));
const variant = readRes.data && readRes.data.productVariant;
if (!variant) throw new Error(`Variant not found: ${variantId}`);
productId = variant.product && variant.product.id;
if (!productId) throw new Error('Could not resolve the parent product id for the variant.');
}
const variantInput = { id: variantId };
if (hasPrice) variantInput.price = asMoney(input.price);
if (hasCompareAt) {
variantInput.compareAtPrice = rawCompareAt === null || String(rawCompareAt).trim() === '' ? null : asMoney(rawCompareAt);
}
ctx.log('Updating variant', variantId, 'on product', productId, variantInput);
const mutation = `
mutation UpdateVariantPrice($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
productVariantsBulkUpdate(productId: $productId, variants: $variants) {
productVariants { id }
userErrors { field message }
}
}`;
const res = await ctx.shopify.graphql(mutation, { productId, variants: [variantInput] });
if (res.errors) throw new Error('GraphQL error updating variant: ' + JSON.stringify(res.errors));
const payload = res.data && res.data.productVariantsBulkUpdate;
if (!payload) throw new Error('Unexpected empty response from productVariantsBulkUpdate.');
if (payload.userErrors && payload.userErrors.length) {
throw new Error('Variant update failed: ' + payload.userErrors.map(e => `${(e.field || []).join('.')}: ${e.message}`).join('; '));
}
return { success: true };
} catch (err) {
ctx.log('Error updating variant price:', err.message);
return { success: false };
}
}Quelques remarques à propos du code :
- Il accepte un identifiant numérique simple ou un GID complet. La fonction «
toGid» normalise les deux, vous n’avez donc pas à vous soucier du format dans lequel Flow vous le fournit. - Elle ne recherche le produit parent que lorsque cela est nécessaire. La fonction
productVariantsBulkUpdatenécessite un identifiant de produit ; si vous n'en fournissez pas, la fonction le récupère. En passantproductIddans le paramètre d'entrée, vous évitez cet aller-retour. - Il vérifie l'
userErrorsité, et pas seulement les erreurs de transport. Un appel GraphQL peut renvoyer un code HTTP 200 tout en refusant l'écriture. C'est la raison la plus courante pour laquelle une mise à jour de prix semble aboutir, mais rien ne change. - La suppression de « compare-at » est intentionnelle. Le fait de passer «
compareAtPrice: null» ou une chaîne vide permet de le supprimer, ce n'est pas considéré comme une erreur.
Étape 3 : Testez la fonction avant de la raccorder
Utilisez l'onglet « Test » en indiquant un identifiant de variante réel provenant de votre boutique. Vous pouvez en choisir un dans l'URL de n'importe quel produit dans l'espace d'administration, ou dans l'historique des événements du déclencheur.
Définissez un prix qui vous soit familier afin de pouvoir vérifier que le message a bien été reçu.
{
"variantId": "gid://shopify/ProductVariant/54589751394579",
"price": "24.99",
"compareAtPrice": "39.99"
}Étape 4 : Câbler le Flow
Créer un workflow dans « Shopify Flow » :
- Déclencheur : modification du coût d'une variante de produit
- Action : Exécuter la fonction depuis « Workflow Functions », puis sélectionnez la fonction que vous venez de créer
Dans le champ de saisie JSON, collez ceci. À chaque exécution, Flow remplace le code Liquid par des valeurs réelles.
{
"variantId": "{{variantCostChange.variantId}}",
"price": "{{variantCostChange.newCost.amount | times: 5}}",
"compareAtPrice": "{{variantCostChange.newCost.amount | times: 7}}"
}Voilà en quoi consiste la règle de tarification : le prix de vente correspond à cinq fois le coût, tandis que le prix de référence correspond à sept fois le coût, ce qui permet au produit d'afficher en permanence une remise constante.
Ces multiplicateurs sont donnés à titre d'exemple et ne constituent pas une recommandation. Remplacez times: 5 par la valeur prise en charge par votre catégorie. Liquid se charge des calculs : ainsi, pour une majoration fixe au lieu d'un multiplicateur, utilisez plus: 12, et pour une marge en pourcentage, utilisez times: 1.6.
Si vous vendez dans plusieurs devises, notez que l'newCost.amounts s'affiche dans la devise de la boutique. Markets se charge de la conversion au moment de l'affichage ; vous n'avez donc pas à vous en occuper.
Vérifiez que cela fonctionne de bout en bout
- Ouvrez n'importe quelle variante de produit dans l'interface d'administration d'Shopify, puis modifiez le coût unitaire.
- Enregistrer
- En quelques secondes, le prix et le prix de référence se mettent à jour automatiquement.
Si rien ne se passe, suivez ces étapes dans cet ordre, car chacune d'entre elles exclut la précédente :
| Vérifier | Où |
|---|---|
| La gâchette s'est-elle actionnée ? | Historique des événements dans l'Workflow Trigger Extensions |
| Est-ce que le Flow a fonctionné ? | Shopify Flow journal d'activité |
| La fonction s'est-elle exécutée, et quels messages a-t-elle affichés dans le journal ? | Historique des exécutions dans l'Workflow Functions |
La cause la plus fréquente d'un cycle signalant un échec est l'absence de portée. La fonction « ctx.shopify » n'est disponible que lorsque l'option « Needs Shopify » est activée, et l'écriture ne réussit qu'une fois que l'autorisation d'écriture a été accordée.
Où aller ensuite ?
Ce même principe s'applique à tout ce qui peut être affecté par une variation de coût. Il suffit de modifier le corps de la fonction pour marquer un produit comme devant faire l'objet d'un réexamen lorsque son coût augmente de plus de 10 %, publier l'ancienne et la nouvelle marge sur Slack, ou enregistrer la modification dans un méta-champ à des fins de reporting.
Le déclencheur est la partie que Shopify ne vous fournit pas. Ce qui suit est du code classique.
Workflow Functions documentation
- Autorisations et accès aux données du magasin - Activer « Nécessite les données de Shopify » et accorder les périmètres d'accès
- Passer des variables à votre fonction : fonctionnement des données d'entrée JSON et de Liquid
- Configurez l'action « Exécuter une fonction » dans Shopify Flow
- Historique d'exécution et dépannage

