Avvisi relativi alla rimozione dei codici sconto

Quando utilizzare questo flusso di lavoro

Utilizza questo flusso di lavoro quando viene rimosso un codice sconto e hai bisogno di una registrazione immediata degli elementi interessati. Ti aiuta a registrare il codice rimosso, il numero di utilizzi, i dettagli della campagna e un riepilogo che puoi inviare al reparto finanziario o operativo su Slack.

Ciò risulta particolarmente utile in caso di divulgazione accidentale dei codici degli influencer, di diffusione non pianificata di coupon o in qualsiasi situazione in cui sia necessario redigere un rapporto documentato sull'impatto dopo la rimozione di un codice.

Cosa realizzerai

  • Un flusso di lavoro di Slack che riceve una variabile text da un webhook e pubblica lo stesso testo in un canale di Slack.
  • Un flusso di lavoro Shopify Flow attivato dall'evento "Codice sconto rimosso".
  • Un passo dati "Ottieni sconto" che recupera lo sconto utilizzando l'ID proveniente dal trigger.
  • Un passo "Esegui codice" che genera un report di rimozione.
  • Un passaggio "Richiesta HTTP" che invia il report a Slack.

Prima di iniziare

  • Assicurati che l'app sia installata e visibile nella sezione di amministrazione di Shopify, alla voce "Apps" > "Workflow Trigger Extensions".
  • Assicurati di poter accedere a Shopify Flow.
  • Crea o seleziona un canale Slack in cui devono apparire gli avvisi.
  • Crea un flusso di lavoro su Slack che si avvii tramite un webhook e accetti un campo text.

Guida video

Puoi anche guardare il video completo sull'implementazione.

Per prima cosa, crea il flusso di lavoro su Slack

In Slack, crea un flusso di lavoro con il trigger “Inizia con un webhook”. Aggiungi una variabile di testo denominata text, quindi aggiungi il passaggio “Messaggio” che invia un messaggio al canale scelto utilizzando proprio quella variabile text.

Flusso di lavoro su Slack che parte da un webhook e invia la variabile di testo a un canale di Slack
Flusso di lavoro su Slack che parte da un webhook e invia la variabile di testo a un canale di Slack

Concedere l'accesso a prezzo scontato in Workflow Trigger Extensions

Prima che il trigger compaia in Shopify Flow, abilita l’accesso agli sconti nell’app.

Nella dashboard di Shopify, vai su App > Workflow Trigger Extensions.

Nella Dashboard, cerca la lista di controllo per la configurazione.

Attiva l'opzione "Concedi accesso agli sconti". In questo modo vengono abilitati i trigger relativi agli sconti, quali "Sconto creato", "Sconto aggiornato", "Sconto eliminato", "Codice sconto aggiunto", "Codice sconto rimosso" e "Sconto scaduto".

Workflow Trigger Extensions dashboard che mostra che l'accesso con sconto Grant è abilitato
Workflow Trigger Extensions dashboard che mostra che l'accesso con sconto Grant è abilitato

Costruisci l’Shopify Flow

Apri Shopify Flow e crea un nuovo flusso di lavoro.

Cerca i trigger relativi agli sconti e seleziona “Codice sconto rimosso” da “Workflow Trigger Extensions”.

Shopify Flow Selettore di trigger con codice sconto: "Rimosso" selezionato
Shopify Flow Selettore di trigger con codice sconto: "Rimosso" selezionato

Aggiungi l'azione Shopify "Ottieni i dati sugli sconti".

In "Seleziona una query per filtrare i dati", scegli "Avanzate". In "Modifica query", utilizza l'ID dello sconto presente nel trigger e rimuovi il prefisso GID Shopify:

bash
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Ottieni i dati relativi agli sconti utilizzando una query avanzata con l'ID dello sconto già elaborato
Ottieni i dati relativi agli sconti utilizzando una query avanzata con l'ID sconto pulito

Aggiungi un passaggio "Esegui codice" dopo "Ottieni dati sullo sconto".

Utilizza la seguente query GraphQL nei campi di selezione dei passaggi precedenti:

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
            }
          }
        }
      }
    }
  }
}

Definisci le uscite in questo modo:

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!
}

Quindi incolla questo codice nel campo "Scrivi codice":

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,
  };
}
Esegui una fase di codice in Shopify Flow con la query, i risultati e il generatore di report JavaScript
Esegui una fase di codice in Shopify Flow con la query, i risultati e il generatore di report JavaScript

Aggiungi l'azione "Richiesta HTTP". Nel campo "Variabili" o "Sostituzione corpo (JSON)", invia il riepilogo restituito dal passo "Esegui codice":

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

Questo invia il riepilogo generato al flusso di lavoro del webhook di Slack utilizzando la variabile text.

Azione "Richiesta HTTP" in Shopify Flow che invia il riepilogo del runCode nel campo di testo
Azione "Richiesta HTTP" in Shopify Flow che invia il riepilogo del runCode nel campo di testo

Salva il flusso di lavoro una volta completati tutti i passaggi.

Per effettuare un test, elimina un codice sconto dalla tua campagna di sconti e verifica che il canale Slack riceva il messaggio di riepilogo.

Messaggio su Slack che mostra il riepilogo del codice sconto rimosso
Messaggio su Slack che mostra il riepilogo del codice sconto rimosso

Cosa comprende l'avviso su Slack

  • Il codice sconto rimosso
  • Che si trattasse di uno sgombero di grandi quantità
  • Il titolo della campagna
  • Il valore dello sconto
  • Date di inizio e di fine
  • Tempi impiegati per il codice rimosso
  • Impatto stimato della rimozione del codice
  • Utilizzo e impatto a livello di campagna
  • Una ripartizione per codice, ove disponibile
  • La data e l'ora in cui è stata elaborata la rimozione

Risoluzione dei problemi

Torna su App > Workflow Trigger Extensions e verifica che l'opzione "Concedi accesso agli sconti" sia abilitata. I trigger relativi agli sconti compaiono solo dopo che è stato concesso l'accesso.

Controlla attentamente la query avanzata nella sezione “Modifica query”. L’ID deve essere formattato esattamente come mostrato:

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

Assicurati che il flusso di lavoro di Slack abbia inizio con un webhook, che l'URL del webhook sia quello utilizzato dalla tua richiesta HTTP e che il corpo della richiesta includa il campo text.

Alcune rimozioni potrebbero rientrare in un'azione collettiva oppure potrebbero non fornire dettagli completi sull'utilizzo. In tali casi, il riepilogo fornirà comunque le migliori informazioni disponibili e indicherà chiaramente i valori mancanti.

Migliori pratiche

  • Invia questi avvisi a un canale dedicato alla finanza o alle operazioni, anziché a un canale di assistenza generale.
  • Assegna al flusso di lavoro un nome specifico, ad esempio “Codice sconto rimosso”, in modo che sia facile da identificare su Shopify Flow e su Slack.
  • Effettua prima un test con un codice sconto non destinato alla produzione per verificare il formato del messaggio e il funzionamento del webhook.