Varsler om fjernede rabattkoder

Varsler om fjernede rabattkoder

Kopier side

Sett opp en Shopify Flow-arbeidsflyt som sender en rapport til Slack når en rabattkode fjernes, med bruksantall og kampanjedetaljer.

Når skal denne arbeidsflyten brukes?

Bruk denne arbeidsflyten når en rabattkode fjernes og du trenger en umiddelbar oversikt over hva som ble berørt. Den hjelper deg med å registrere den fjernede koden, antall ganger den har blitt brukt, kampanjedetaljene og en oppsummering som du kan sende til økonomiavdelingen eller driftsavdelingen i Slack.

Dette er spesielt nyttig ved lekkede influencer-koder, utilsiktet offentliggjøring av kuponger eller i alle tilfeller der du trenger en dokumentert konsekvensrapport etter at en kode er fjernet.

Hva du skal bygge

  • En Slack-arbeidsflyt som mottar en text-variabel fra en webhook og legger ut den samme teksten i en Slack-kanal.
  • En Shopify Flow-arbeidsflyt utløst av Rabattkode fjernet.
  • Et Hent rabatt-datatrinn som slår opp rabatten ved hjelp av ID-en fra utløseren.
  • Et Kjør kode-trinn som formaterer en fjerningsrapport.
  • Et HTTP Request-trinn som sender rapporten til Slack.

Før du begynner

  • Sørg for at appen er installert og synlig i Shopify-administrasjonspanelet under Apps > Workflow Trigger Extensions.
  • Sørg for at du har tilgang til Shopify Flow.
  • Opprett eller velg en Slack-kanal der varslene skal vises.
  • Opprett en Slack-arbeidsflyt som starter med en webhook og godtar et text-felt.

Videoveiledning

Du kan også se hele implementeringsvideoen.

Opprett først Slack-arbeidsflyten

I Slack oppretter du en arbeidsflyt med utløseren Starter med en webhook. Legg til en tekstvariabel med navnet text, og legg deretter til et meldingstrinn som sender en melding til den valgte kanalen ved hjelp av den samme text-variabelen.

En Slack-arbeidsflyt som starter med en webhook og sender tekstvariabelen til en Slack-kanal
En Slack-arbeidsflyt som starter med en webhook og sender tekstvariabelen til en Slack-kanal

Gi tilgang med rabatt i Workflow Trigger Extensions

Før utløseren vises i Shopify Flow, må du aktivere tilgang til rabatter i appen.

I Shopify-administrasjonspanelet går du til Apper > Workflow Trigger Extensions.

Se etter sjekklisten for oppsett på dashbordet.

Slå på Gi tilgang til rabatter. Dette aktiverer utløsere knyttet til rabatter, for eksempel Rabatt opprettet, Rabatt oppdatert, Rabatt slettet, Rabattkode lagt til, Rabattkode fjernet og Rabatt utløpt.

Dashbordet for Workflow Trigger Extensions, som viser at «Grant Discount Access» er aktivert
Dashbordet for Workflow Trigger Extensions, som viser at «Grant Discount Access» er aktivert

Opprett en Shopify Flow

Åpne Shopify Flow og opprett en ny arbeidsflyt.

Søk etter utløsere knyttet til rabatter, og velg Rabattkode fjernet fra Workflow Trigger Extensions.

Shopify Flow-utløservalger med «Rabattkode fjernet» valgt
Shopify Flow-utløservalger med «Rabattkode fjernet» valgt

Legg til Shopify-handlingen Hent rabattdata.

I Velg et søk for å filtrere data velger du Avansert. I Rediger søk bruker du rabatt-ID-en fra utløseren og fjerner Shopify-GID-prefikset:

bash
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Få frem rabattdata ved hjelp av et avansert søk med den rensede rabatt-ID-en
Få frem rabattdata ved hjelp av et avansert søk med den rensede rabatt-ID-en

Legg til et Kjør kode-trinn etter Hent rabattdata.

Bruk følgende GraphQL-spørring i Velg inndata fra de foregående trinnene:

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

Definer utgangene slik:

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

Lim deretter inn denne koden i feltet Skriv kode:

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,
  };
}
Kjør et kodetrinn i Shopify Flow med spørringen, utdataene og JavaScript-rapportgeneratoren
Kjør et kodetrinn i Shopify Flow med spørringen, utdataene og JavaScript-rapportgeneratoren

Legg til handlingen HTTP Request. I feltet Variabler** eller Body Override (JSON)** sender du sammendraget som returneres av kodetrinnet Kjør:

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

Dette sender det genererte sammendraget til Slack-webhook-arbeidsflyten ved hjelp av variabelen text.

HTTP Request-handlingen i Shopify Flow sender runCode-sammendraget i tekstfeltet
HTTP Request-handlingen i Shopify Flow sender runCode-sammendraget i tekstfeltet

Lagre arbeidsflyten når alle trinnene er på plass.

For å teste dette, slett en rabattkode fra rabattkampanjen din og sjekk at Slack-kanalen mottar oppsummeringsmeldingen.

Slack-melding som viser at rabattkoden er fjernet - sammendrag
Slack-melding som viser at rabattkoden er fjernet - sammendrag

Hva Slack-varselet inneholder

  • Den fjernede rabattkoden
  • Uansett om det dreide seg om en storstilt fjerning
  • Kampanjetittelen
  • Rabattbeløpet
  • Start- og sluttdatoer
  • Tider brukt på den fjernede koden
  • Anslått innvirkning av den fjernede koden
  • Bruk og virkning på tvers av kampanjene
  • En oversikt kode for kode, der dette er tilgjengelig
  • Tidspunktet da slettingen ble gjennomført

Feilsøking

Gå tilbake til Apps > Workflow Trigger Extensions og sjekk at Grant Discount Access er aktivert. Rabattutløserne vises først etter at tilgang er gitt.

Kontroller den avanserte søkeformelen nøye under Rediger søkeformel. ID-en skal renses nøyaktig slik det er vist:

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

Sørg for at Slack-arbeidsflyten starter med en webhook, at webhook-URL-en er den samme som brukes i HTTP-forespørselen din, og at forespørselens innhold inneholder feltet text.

Noen slettinger kan være en del av en samlet handling, eller det kan hende at de ikke gir fullstendige bruksopplysninger. I slike tilfeller vil oversikten likevel inneholde den beste tilgjengelige informasjonen, og manglende verdier vil bli tydelig merket.

Gode praksiseksempler

  • Send disse varslene til en egen kanal for økonomi eller drift i stedet for til en generell supportkanal.
  • Gi arbeidsflyten et konkret navn, for eksempel Rabattkode fjernet, slik at den er lett å gjenkjenne i Shopify Flow og Slack.
  • Test først med en rabattkode som ikke er ment for produksjonsbruk for å bekrefte meldingsformatet og hvordan webhooken fungerer.