Powiadomienia o usunięciu kodu rabatowego
Skonfiguruj Shopify Flow, by po usunięciu kodu rabatowego wysyłać do Slacka raport z kodem, liczbą użyć i szczegółami kampanii przez webhook.
Kiedy należy stosować ten schemat postępowania
Proszę skorzystać z tego schematu działania, gdy kod rabatowy zostanie usunięty i konieczne jest natychmiastowe zarejestrowanie informacji o tym, na co miało to wpływ. Umożliwia on zarejestrowanie usuniętego kodu, liczby jego wykorzystań, szczegółów kampanii oraz podsumowania, które można przesłać do działu finansowego lub operacyjnego za pośrednictwem Slacka.
Jest to szczególnie przydatne w przypadku wycieku kodów influencerów, nieplanowanego ujawnienia kuponów lub w każdej sytuacji, w której po usunięciu kodu konieczne jest sporządzenie udokumentowanego raportu dotyczącego skutków.
Co Państwo stworzą
- Proces w serwisie Slack, który odbiera zmienną
textz webhooka i publikuje ten sam tekst w kanale Slacka. - Proces w Shopify Flow uruchomiony przez usunięcie kodu rabatowego.
- Etap przetwarzania danych Pobierz rabat, który wyszukuje rabat na podstawie identyfikatora z wyzwalacza.
- Krok Uruchom kod, który formatuje raport dotyczący usunięcia.
- Krok HTTP Request, który wysyła raport do serwisu Slack.
Zanim zaczną Państwo
- Proszę upewnić się, że aplikacja jest zainstalowana i widoczna w panelu administracyjnym Shopify w sekcji Aplikacje > Workflow Trigger Extensions.
- Proszę upewnić się, że mają Państwo dostęp do serwisu Shopify Flow.
- Proszę utworzyć lub wybrać kanał w serwisie Slack, na którym mają pojawiać się powiadomienia.
- Proszę utworzyć przepływ pracy w serwisie Slack, który uruchamia się na podstawie webhooka i obsługuje pole typu
text.
Przewodnik wideo
Można również obejrzeć film przedstawiający pełną realizację.
Najpierw proszę utworzyć przepływ pracy w Slacku
W serwisie Slack proszę utworzyć przepływ pracy z wyzwalaczem Rozpoczyna się od webhooka. Proszę dodać zmienną tekstową o nazwie text, a następnie dodać krok „Wiadomość”, który wysyła wiadomość do wybranego kanału, wykorzystując tę samą zmienną text.

Przyznanie dostępu z rabatem w rozszerzeniach wyzwalaczy przepływu pracy (Workflow Trigger Extensions)
Zanim wyzwalacz pojawi się w Shopify Flow, należy włączyć dostęp do rabatów w aplikacji.
W panelu administracyjnym Shopify przejdź do sekcji Aplikacje > Workflow Trigger Extensions.
Na pulpicie nawigacyjnym proszę odszukać listę kontrolną dotyczącą konfiguracji.
Włącz opcję Przyznaj dostęp do rabatów. Spowoduje to aktywację zdarzeń związanych z rabatami, takich jak: Utworzono rabat, Zaktualizowano rabat, Usunięto rabat, Dodano kod rabatowy, Usunięto kod rabatowy oraz Rabat wygasł.

Skonfiguruj usługę Shopify Flow
Proszę otworzyć aplikację Shopify Flow i utworzyć nowy przepływ pracy.
Proszę wyszukać wyzwalacze związane z rabatami i wybrać opcję Usunięcie kodu rabatowego z sekcji Workflow Trigger Extensions.

Proszę dodać akcję Pobierz dane dotyczące zniżek w Shopify.
W sekcji „Wybierz zapytanie, aby filtrować dane” proszę wybrać opcję Zaawansowane. W sekcji Edytuj zapytanie proszę użyć identyfikatora rabatu z wyzwalacza i usunąć prefiks GID serwisu Shopify:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Proszę dodać krok Uruchom kod po kroku Pobierz dane dotyczące zniżek.
W polach wyboru z poprzednich kroków proszę użyć następującego zapytania 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
}
}
}
}
}
}
}Proszę zdefiniować dane wyjściowe w następujący sposób:
"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!
}Następnie wklej ten kod w polu Wpisz kod:
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,
};
}
Proszę dodać akcję HTTP Request. W polu Zmienne** lub Zastąpienie treści (JSON)** proszę przesłać podsumowanie zwrócone przez krok Uruchom kod:
{
"body": {
"text": "{{runCode.summary}}"
}
}Spowoduje to wysłanie wygenerowanego podsumowania do przepływu pracy webhooka serwisu Slack przy użyciu zmiennej text.

Po skonfigurowaniu wszystkich kroków proszę zapisać przepływ pracy.
Aby to sprawdzić, proszę usunąć kod rabatowy z kampanii rabatowej i upewnić się, że kanał Slack otrzymał komunikat podsumowujący.

Co zawiera powiadomienie w serwisie Slack
- Usunięty kod rabatowy
- Niezależnie od tego, czy chodziło o wywóz dużych ilości odpadów
- Tytuł kampanii
- Wartość zniżki
- Daty rozpoczęcia i zakończenia
- Czasy zastosowane w usuniętym kodzie
- Szacowany wpływ usunięcia kodu
- Wykorzystanie i wpływ w ramach całej kampanii
- Podział według poszczególnych kodów, o ile są one dostępne
- Sygnatura czasowa momentu przetworzenia operacji usunięcia
Rozwiązywanie problemów
Proszę powrócić do sekcji Aplikacje > Workflow Trigger Extensions i upewnić się, że opcja Grant Discount Access jest włączona. Wyzwalacze rabatów pojawiają się dopiero po przyznaniu dostępu.
Proszę dokładnie sprawdzić zapytanie zaawansowane w sekcji Edytuj zapytanie. Identyfikator powinien być oczyszczony dokładnie tak, jak pokazano poniżej:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"Proszę upewnić się, że przepływ pracy w Slacku rozpoczyna się od webhooka, że adres URL webhooka jest zgodny z tym używanym w Państwa żądaniu HTTP oraz że treść żądania zawiera pole text.
Niektóre usunięcia mogą stanowić część operacji zbiorczej lub mogą nie zawierać pełnych danych dotyczących wykorzystania. W takich przypadkach w podsumowaniu nadal będą przekazywane najlepsze dostępne informacje, a brakujące wartości zostaną wyraźnie oznaczone.
Najlepsze praktyki
- Prosimy o przesyłanie tych powiadomień na dedykowany kanał ds. finansów lub operacji zamiast na ogólny kanał pomocy technicznej.
- Prosimy o nadanie przepływowi pracy konkretnej nazwy, np. Usunięto kod rabatowy, tak aby można go było łatwo zidentyfikować w aplikacjach Shopify Flow i Slack.
- Prosimy najpierw przeprowadzić test przy użyciu kodu rabatowego spoza środowiska produkcyjnego, aby sprawdzić format komunikatu oraz działanie webhooka.
