Alertas de código de desconto removido

Quando usar esse fluxo de trabalho

Utilize este fluxo de trabalho quando um código de desconto for removido e você precisar de um registro imediato do que foi afetado. Ele ajuda a registrar o código removido, o número de utilizações, os detalhes da campanha e um resumo que você pode enviar ao departamento financeiro ou de operações pelo Slack.

Isso é especialmente útil no caso de códigos de influenciadores que vazaram, divulgação não planejada de cupons ou em qualquer situação em que seja necessário um relatório documentado do impacto após a remoção de um código.

O que você vai criar

  • Um fluxo de trabalho do Slack que recebe uma variável text de um webhook e publica esse mesmo texto em um canal do Slack.
  • Um fluxo de trabalho Shopify Flow acionado pela remoção do código de desconto.
  • Uma etapa de dados “Obter desconto” que consulta o desconto usando o ID do gatilho.
  • Uma etapa de execução de código que formata um relatório de remoção.
  • Uma etapa de solicitação HTTP que envia o relatório para o Slack.

Antes de começar

  • Verifique se o aplicativo está instalado e visível no painel de administração do Shopify, em Apps > Workflow Trigger Extensions.
  • Certifique-se de ter acesso ao site Shopify Flow.
  • Crie ou escolha um canal do Slack onde os alertas devem aparecer.
  • Crie um fluxo de trabalho no Slack que seja acionado por um webhook e aceite um campo text.

Guia em vídeo

Você também pode assistir ao vídeo completo da implementação.

Primeiro, crie o fluxo de trabalho do Slack

No Slack, crie um fluxo de trabalho com o gatilho “Começa com um webhook”. Adicione uma variável de texto chamada text e, em seguida, adicione a etapa de mensagem que envia uma mensagem para o canal escolhido usando essa mesma variável text.

Fluxo de trabalho do Slack que é acionado por um webhook e envia a variável de texto para um canal do Slack
Fluxo de trabalho do Slack que começa com um webhook e envia a variável de texto para um canal do Slack

Conceder acesso com desconto no Workflow Trigger Extensions

Antes que o gatilho apareça no Shopify Flow, habilite o acesso aos descontos no aplicativo.

No painel de administração do Shopify, acesse Aplicativos > Workflow Trigger Extensions.

No Painel, procure a lista de verificação de configuração.

Ative a opção “Conceder acesso a descontos”. Isso habilita os gatilhos relacionados a descontos, como “Desconto criado”, “Desconto atualizado”, “Desconto excluído”, “Código de desconto adicionado”, “Código de desconto removido” e “Desconto expirado”.

Workflow Trigger Extensions painel mostrando que o acesso com desconto do Grant está ativado
Workflow Trigger Extensions painel de controle indicando que o acesso com desconto do Grant está ativado

Construa o Shopify Flow

Acesse Shopify Flow e crie um novo fluxo de trabalho.

Procure por gatilhos relacionados a descontos e selecione “Código de desconto removido” em “Workflow Trigger Extensions”.

Shopify Flow seletor de gatilho com código de desconto removido (selecionado)
Shopify Flow seletor de gatilho com código de desconto removido (selecionado)

Adicione a ação Shopify para obter os dados de descontos.

Em “Selecione uma consulta para filtrar dados”, escolha “Avançado”. Em “Editar consulta”, use o ID do desconto do gatilho e remova o prefixo GID Shopify:

bash
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Obtenha dados sobre ações relacionadas a descontos por meio de uma consulta avançada com o ID do desconto já limpo
Obtenha dados sobre ações de desconto por meio de uma consulta avançada com o ID de desconto limpo

Adicione uma etapa “Executar código” após “Obter dados de desconto”.

Use a seguinte consulta GraphQL nas entradas “Selecionar” das etapas anteriores:

graphql
query {
  redeemCode {
    code
    usageCount
    bulkRemoval
  }
  getDiscountData {
    discount {
      ... on DiscountCodeBasic {
        title
        startsAt
        endsAt
        asyncUsageCount
        codes {
          code
          asyncUsageCount
        }
        customerGets {
          value {
            ... on DiscountAmount {
              amount { amount currencyCode }
            }
            ... on DiscountPercentage {
              percentage
            }
          }
        }
      }
    }
  }
}

Defina as saídas da seguinte maneira:

typescript
"Output of discount code removal report"
type Output {
  "Discount code that was removed"
  code: String!
  "Discount campaign title"
  title: String!
  "Campaign start date"
  startsAt: String!
  "Campaign end date"
  endsAt: String!
  "Number of times it was redeemed"
  usageCount: Int!
  "Total discount impact as a formatted string"
  totalImpact: String!
  "When it was removed"
  removedAt: String!
  "Full summary for alerts"
  summary: String!
}

Em seguida, cole este código na área “Escrever código”:

javascript
export default function main(input) {
  // ── Trigger: removed code ──
  const removedCode  = input?.redeemCode?.code         ?? "Unknown";
  const usageCount   = input?.redeemCode?.usageCount   ?? null; // null = bulk removal or unknown
  const bulkRemoval  = input?.redeemCode?.bulkRemoval  ?? false;

  const currency = input?.shop?.currencyCode ?? "";
  const shopName = input?.shop?.name         ?? "(not bound)";
  const removedAt = new Date().toISOString();

  // ── Find matching discount ──
  const dataItems = input?.getDiscountData ?? [];
  let matchedDiscount = null;
  for (const item of dataItems) {
    const d = item?.discount?.DiscountCodeBasic ?? item?.discount;
    if (!d) continue;
    const codesArray = Array.isArray(d.codes)
      ? d.codes.map(c => (typeof c === "string" ? c : c?.code ?? ""))
      : [];
    if (codesArray.includes(removedCode)) {
      matchedDiscount = d;
      break;
    }
  }
  // fallback to first entry if removed code already gone from list
  if (!matchedDiscount && dataItems.length > 0) {
    matchedDiscount =
      dataItems[0]?.discount?.DiscountCodeBasic ?? dataItems[0]?.discount ?? null;
  }

  const title              = matchedDiscount?.title            ?? "Untitled";
  const startsAt           = matchedDiscount?.startsAt         ?? "N/A";
  const endsAt             = matchedDiscount?.endsAt           ?? "None (no expiry)";
  const totalUsageCount    = matchedDiscount?.asyncUsageCount  ?? null;

  // ── Discount value ──
  const valueWrapper = matchedDiscount?.customerGets?.value ?? {};
  const pctObj       = valueWrapper?.DiscountPercentage ?? null;
  const amtObj       = valueWrapper?.DiscountAmount ?? valueWrapper?.amount ?? null;

  let discountLabel = "Unknown";
  if (pctObj?.percentage != null) {
    discountLabel = `${(pctObj.percentage * 100).toFixed(0)}% off`;
  } else if (amtObj?.amount != null) {
    const cur = amtObj.currencyCode || currency;
    discountLabel = `${cur} ${parseFloat(amtObj.amount).toFixed(2)} off`;
  }

  // ── This code's impact ──
  let thisCodeImpact;
  if (bulkRemoval) {
    thisCodeImpact = `Not available - removed as part of bulk deletion`;
  } else if (usageCount === null) {
    thisCodeImpact = `Could not be determined`;
  } else if (pctObj?.percentage != null) {
    thisCodeImpact = `${discountLabel} × ${usageCount} use(s)`;
  } else if (amtObj?.amount != null) {
    const perUse = parseFloat(amtObj.amount);
    const cur    = amtObj.currencyCode || currency;
    thisCodeImpact = `${cur} ${(perUse * usageCount).toFixed(2)} (${cur} ${perUse.toFixed(2)} × ${usageCount} uses)`;
  } else {
    thisCodeImpact = "Unknown";
  }

  // ── Campaign-wide impact using asyncUsageCount on the discount ──
  let campaignImpact;
  if (totalUsageCount === null) {
    campaignImpact = "Not available";
  } else if (pctObj?.percentage != null) {
    campaignImpact = `${discountLabel} × ${totalUsageCount} total use(s) across all codes`;
  } else if (amtObj?.amount != null) {
    const perUse = parseFloat(amtObj.amount);
    const cur    = amtObj.currencyCode || currency;
    campaignImpact = `${cur} ${(perUse * totalUsageCount).toFixed(2)} total (${cur} ${perUse.toFixed(2)} × ${totalUsageCount} uses)`;
  } else {
    campaignImpact = "Unknown";
  }

  // ── Per-code breakdown ──
  const codesNodes = Array.isArray(matchedDiscount?.codes)
    ? matchedDiscount.codes
    : [];

  const allCodes = codesNodes
    .map(c => (typeof c === "string" ? c : c?.code ?? ""))
    .filter(Boolean);

  const codesRoster = codesNodes.length
    ? codesNodes.map(c => {
        const code = typeof c === "string" ? c : c?.code ?? "";
        const used = c?.asyncUsageCount ?? "?";
        const flag = code === removedCode ? " ← REMOVED" : "";
        return `${code} (used ${used}×)${flag}`;
      }).join("\n                  ")
    : "N/A";

  const usageCountLabel = bulkRemoval
    ? "N/A (bulk removal)"
    : usageCount !== null
      ? String(usageCount)
      : "Unknown";

  const summary =
    `DISCOUNT CODE REMOVED\n` +
    `─────────────────────\n` +
    `Store:            ${shopName}\n` +
    `Code removed:     ${removedCode}\n` +
    `Bulk removal:     ${bulkRemoval ? "Yes" : "No"}\n` +
    `Campaign:         ${title}\n` +
    `Discount:         ${discountLabel}\n` +
    `Valid from:       ${startsAt}\n` +
    `Valid until:      ${endsAt}\n` +
    `\n` +
    `THIS CODE\n` +
    `  Times used:     ${usageCountLabel}\n` +
    `  Impact:         ${thisCodeImpact}\n` +
    `\n` +
    `CAMPAIGN TOTAL\n` +
    `  Total uses:     ${totalUsageCount ?? "Unknown"}\n` +
    `  Total impact:   ${campaignImpact}\n` +
    `\n` +
    `CODE BREAKDOWN\n` +
    `  ${codesRoster}\n` +
    `\n` +
    `Removed at:       ${removedAt}`;

const safeSummary = summary
  .replace(/\\/g, "\\\\")   // escape backslashes first
  .replace(/"/g, '\\"')     // escape quotes
  .replace(/\n/g, "\\n")    // escape newlines
  .replace(/\r/g, "\\r");

  return {
    code:           removedCode,
    bulkRemoval,
    title,
    discountLabel,
    startsAt,
    endsAt,
    usageCount:     usageCount ?? 0,
    usageCountLabel,
    thisCodeImpact,
    totalUsageCount: totalUsageCount ?? 0,
    campaignImpact,
    allCodes,
    codesRoster,
    removedAt,
    summary: safeSummary,
  };
}
Executar etapa de código no Shopify Flow com a consulta, os resultados e o gerador de relatórios em JavaScript
Executar etapa de código no Shopify Flow com a consulta, os resultados e o gerador de relatórios em JavaScript

Adicione a ação “Solicitação HTTP”. No campo “Variáveis” ou “Substituição do corpo (JSON)”, envie o resumo retornado pela etapa de código “Executar”:

css
{
  "body": {
    "text": "{{runCode.summary}}"
  }
}

Isso publica o resumo gerado no fluxo de trabalho do webhook do Slack usando a variável text.

Ação “Solicitação HTTP” no Shopify Flow, enviando o resumo do runCode no campo de texto
Ação de solicitação HTTP em Shopify Flow, enviando o resumo do runCode no campo de texto

Salve o fluxo de trabalho depois que todas as etapas estiverem configuradas.

Para testar, exclua um código de desconto da sua campanha de descontos e verifique se o canal do Slack recebe a mensagem de resumo.

Mensagem no Slack mostrando o resumo do código de desconto removido
Mensagem no Slack mostrando o resumo do código de desconto removido

O que o alerta do Slack inclui

  • O código de desconto removido
  • Seja uma remoção em grande volume
  • O título da campanha
  • O valor do desconto
  • Datas de início e término
  • Tempos utilizados para o código removido
  • Impacto estimado da remoção do código
  • Utilização e impacto em toda a campanha
  • Uma análise detalhada código por código, quando disponível
  • A data e hora em que a remoção foi processada

Solução de problemas

Volte para Aplicativos > Workflow Trigger Extensions e confirme se a opção “Conceder acesso a descontos” está ativada. Os gatilhos de desconto só aparecem depois que o acesso é concedido.

Verifique novamente a consulta avançada em “Editar consulta”. O ID deve estar formatado exatamente como mostrado:

bash
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"

Certifique-se de que o fluxo de trabalho do Slack seja iniciado por um webhook, que a URL do webhook seja a mesma utilizada pela sua solicitação HTTP e que o corpo da solicitação inclua o campo text.

Algumas remoções podem fazer parte de uma ação em massa ou podem não retornar detalhes completos de uso. Nesses casos, o resumo ainda enviará as melhores informações disponíveis e identificará claramente os valores ausentes.

Melhores práticas

  • Envie esses alertas para um canal específico de finanças ou operações, em vez de um canal geral de suporte.
  • Escolha um nome específico para o fluxo de trabalho, como “Código de desconto removido”, para que seja fácil identificá-lo no Shopify Flow e no Slack.
  • Teste primeiro com um código de desconto que não seja de produção para confirmar o formato da mensagem e o comportamento do webhook.