Atualizar automaticamente o preço e o preço de referência quando o custo do fornecedor se alterar

September 3, 2026

O seu fornecedor aumenta o custo de uma variante de 4,00 para 5,20. Nada no Shopify reage a isso. O preço de venda ao público mantém-se inalterado e a margem que planeou desaparece discretamente, até que alguém repara nisso durante um inventário, semanas mais tarde.

Shopify Flow Isso, por si só, não resolve o problema, porque o Shopify não dispõe de um gatilho integrado para uma alteração no custo por unidade. Também não possui nenhuma ação que recalcule o preço a partir desse valor.

Este guia colmata ambas as lacunas. Quando o custo por artigo muda em qualquer variante, é iniciado um «Flow» e uma função curta grava o novo preço e o preço de referência de volta no Shopify. A configuração demora cerca de dez minutos e, depois, é executada sempre que houver uma alteração no custo, de forma contínua.

O que vais construir

  1. Workflow Trigger Extensions deteta a alteração no custo e inicia um Fluxo, incluindo a variante, o seu SKU e tanto o custo antigo como o novo.
  2. Shopify Flow passa esses valores para uma função no formato JSON.
  3. Workflow Functions executa algumas linhas de JavaScript que calculam os novos preços e os enviam de volta através da API de administração.

A regra de preços está definida num único local, no código que controlas, pelo que alterá-la posteriormente implica editar apenas uma linha, em vez de ter de reconstruir um fluxo de trabalho.

Passo 1: Ativar o gatilho de custos

No site Workflow Trigger Extensions, abra a página «Triggers», localize o grupo «Inventário» e ative a opção «Alteração do custo da variante do produto».

Este gatilho requer acesso aos dados de inventário, uma vez que o custo por artigo está associado ao artigo em si e não à própria variante. Se a autorização ainda não tiver sido concedida, ao ativar o gatilho será solicitada essa autorização numa única caixa de diálogo. Até que a autorização seja concedida, o gatilho permanece ativado, mas exibe uma indicação de «Autorização necessária» e não será acionado.

O que o gatilho lhe proporciona

Assim que for acionado, o seu Flow tem acesso a:

Campo Exemplo
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

O próprio produto também está incluído como referência de produto, pelo que pode adicionar condições do Flow com base no fornecedor, tipo, etiquetas ou coleção antes de qualquer preço ser alterado.

Passo 2: Criar a função

Em «Workflow Functions», crie uma nova função e cole o código abaixo.

Antes de guardar, ative a opção «Necessita de dados dShopify». É isso que expõe ctx.shopify.graphql(...) ao seu código, para que este possa ler e modificar os dados da loja. Em seguida, abra a página «Permissões» em Workflow Functions e conceda permissão para escrever em produtos, que é o âmbito de que esta função necessita para alterar um preço.

Sem essa opção, o objeto ctx.shopify não está disponível e a função falha na primeira chamada à API de administração.

update-variant-price.jsjavascript
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 };
  }
}

Algumas observações a destacar sobre o código:

  • Aceita um identificador numérico simples ou um GID completo. O toGid normaliza ambos, pelo que não precisa de se preocupar com o formato que o Flow lhe fornece.
  • A função só procura o produto pai quando é necessário. A função productVariantsBulkUpdate requer um ID de produto; se não for passado nenhum, a função obtém-no. Ao passar productId na entrada, evita-se essa ida e volta.
  • Verifica o código de estado userErrors, e não apenas erros de transporte. Uma chamada GraphQL pode devolver um código HTTP 200 e, mesmo assim, recusar a gravação. Esta é a razão mais comum pela qual uma atualização de preço parece ter sido bem-sucedida, mas nada muda.
  • A remoção do «compare-at» é intencional. Ao passar compareAtPrice: null ou uma cadeia de caracteres vazia, este é removido, em vez de ser considerado um erro.

Passo 3: Testar a função antes de a ligar

Utilize o separador «Teste» com um ID de variante real da sua loja. Escolha um a partir de qualquer URL de produto na área de administração ou do histórico de eventos do gatilho.

Defina um preço que consiga reconhecer, para poder confirmar que a mensagem foi recebida.

test-input.jsonjson
{
  "variantId": "gid://shopify/ProductVariant/54589751394579",
  "price": "24.99",
  "compareAtPrice": "39.99"
}

Passo 4: Ligar o Flow

Criar um fluxo de trabalho no Shopify Flow:

  1. Desencadeador: Alteração do custo de uma variante do produto
  2. Ação: Executar função em Workflow Functions e selecionar a função que acabou de criar

No campo de introdução de dados JSON, cole isto. O Flow substitui o Liquid por valores reais sempre que é executado.

flow-input.jsonjson
{
  "variantId": "{{variantCostChange.variantId}}",
  "price": "{{variantCostChange.newCost.amount | times: 5}}",
  "compareAtPrice": "{{variantCostChange.newCost.amount | times: 7}}"
}

Essa é toda a regra de fixação de preços: cinco vezes o custo como preço de venda e sete vezes o custo como preço de referência, para que o produto apresente sempre um desconto consistente.

Esses multiplicadores são um exemplo, não uma recomendação. Altere times: 5 para o valor que a sua categoria realmente suporta. O Liquid trata dos cálculos, pelo que uma margem fixa, em vez de um multiplicador, é plus: 12, e uma margem percentual é times: 1.6.

Se vender em várias moedas, tenha em atenção que newCost.amount está na moeda da loja. O Markets trata da conversão no momento da visualização, pelo que não precisa de o fazer.

Confirme se funciona de ponta a ponta

  1. Abra qualquer variante de produto no painel de administração dShopify e altere o custo por unidade
  2. Guardar
  3. Em poucos segundos, o preço e o preço de referência atualizam-se automaticamente

Se nada acontecer, siga estes passos por esta ordem, pois cada passo exclui o anterior:

Verificar Onde
O gatilho disparou? Histórico de eventos no Workflow Trigger Extensions
O Flow funcionou? Shopify Flow registo de atividades
A função foi executada e o que foi registado no log? Histórico de execuções no Workflow Functions

A causa mais comum de uma execução que apresenta uma falha é a ausência de um âmbito. A função ctx.shopify só está disponível quando a opção «Needs Shopify data» está ativada, e a gravação só é bem-sucedida depois de ter sido concedida a autorização para gravar produtos.

Para onde ir a seguir

O mesmo padrão aplica-se a qualquer situação em que ocorra uma alteração de custo. Basta trocar o corpo da função e poderá marcar um produto para revisão quando o custo aumentar mais de 10 por cento, publicar a margem antiga e a nova no Slack ou registar a alteração num metacampo para efeitos de relatório.

O gatilho é a parte que o Shopify não te fornece. O que se segue é código normal.

Related articleAutorizações e acesso aos dadosO que o acesso aos dados de inventário permite e como concedê-lo ou revogá-lo.Related articleReferência completa sobre os gatilhosTodos os gatilhos do Workflow Trigger Extensions, com os campos que cada um deles contém.

Workflow Functions documentação