shopify-admin-discount-hygiene-cleanup
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePurpose
用途
Audits the discount catalog for expired codes, codes with zero redemptions, and duplicate code prefixes. Discount sprawl accumulates over months of campaigns and makes the admin difficult to navigate. Optionally deletes flagged codes. Replaces manual discount cleanup and builds on the skill with a write step.
discount-ab-analysis审计折扣目录,查找过期折扣码、零兑换记录的折扣码以及重复的码前缀。经过数月的营销活动后,折扣码会大量堆积,导致管理员难以管理。本工具可选择性删除标记的折扣码,替代手动折扣清理工作,在技能的基础上新增了写入步骤。
discount-ab-analysisPrerequisites
前提条件
- Authenticated Shopify CLI session:
shopify store auth --store <domain> --scopes read_discounts,write_discounts - API scopes: ,
read_discountswrite_discounts
- 已完成身份验证的Shopify CLI会话:
shopify store auth --store <domain> --scopes read_discounts,write_discounts - API权限:、
read_discountswrite_discounts
Parameters
参数
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| store | string | yes | — | Store domain (e.g., mystore.myshopify.com) |
| flag_expired | bool | no | true | Flag/delete discounts past their end date |
| flag_zero_usage | bool | no | true | Flag/delete discounts with 0 redemptions older than N days |
| zero_usage_min_age_days | integer | no | 30 | Age threshold for zero-usage flags |
| dry_run | bool | no | true | Preview without executing mutations |
| format | string | no | human | Output format: |
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| store | string | 是 | — | 店铺域名(例如:mystore.myshopify.com) |
| flag_expired | bool | 否 | true | 标记/删除已过截止日期的折扣 |
| flag_zero_usage | bool | 否 | true | 标记/删除超过N天未使用的零兑换折扣 |
| zero_usage_min_age_days | integer | 否 | 30 | 零使用折扣的时间阈值(天) |
| dry_run | bool | 否 | true | 预览模式,不执行变更操作 |
| format | string | 否 | human | 输出格式: |
Safety
安全提示
⚠️permanently removes discount codes. Deleted codes cannot be recovered. Customers who received a deleted code will find it invalid. Run withdiscountCodeDeleteto review the flagged list before committing. Always check that expired codes are not referenced in active email campaigns before deleting.dry_run: true
⚠️会永久移除折扣码,已删除的码无法恢复。收到已删除折扣码的顾客会发现该码无效。请先使用discountCodeDelete模式运行,确认标记的列表后再执行操作。删除前请务必检查过期折扣码未被活跃的邮件营销活动引用。dry_run: true
Workflow Steps
工作流步骤
-
OPERATION:— query Inputs:
discountNodes, selectfirst: 250, pagination cursor Expected output: All discount codes with usage and expiry data; paginate untildiscount { ... on DiscountCodeBasic { codes, usageLimit, asyncUsageCount, endsAt, status } }hasNextPage: false -
Flag discounts matching:(status = EXPIRED) and/or
flag_expired(asyncUsageCount == 0 AND created >flag_zero_usageago)zero_usage_min_age_days -
OPERATION:— mutation Inputs:
discountCodeDeleteExpected output:id: <discount_node_id>,deletedCodeDiscountIduserErrors
-
操作:— 查询 输入:
discountNodes,选择first: 250,分页游标 预期输出: 所有折扣码及其使用、过期数据;持续分页直到discount { ... on DiscountCodeBasic { codes, usageLimit, asyncUsageCount, endsAt, status } }hasNextPage: false -
标记符合以下条件的折扣:(状态 = EXPIRED)和/或
flag_expired(asyncUsageCount == 0 且创建时间早于flag_zero_usage天前)zero_usage_min_age_days -
操作:— 变更 输入:
discountCodeDelete预期输出:id: <discount_node_id>、deletedCodeDiscountIduserErrors
GraphQL Operations
GraphQL操作
graphql
undefinedgraphql
undefineddiscountNodes:query — validated against api_version 2025-01
discountNodes:query — validated against api_version 2025-01
query DiscountAudit($after: String) {
discountNodes(first: 250, after: $after) {
edges {
node {
id
discount {
... on DiscountCodeBasic {
title
status
createdAt
endsAt
asyncUsageCount
usageLimit
codes(first: 5) {
edges {
node {
id
code
}
}
}
}
... on DiscountCodeBxgy {
title
status
createdAt
endsAt
asyncUsageCount
usageLimit
}
... on DiscountCodeFreeShipping {
title
status
createdAt
endsAt
asyncUsageCount
usageLimit
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
```graphqlquery DiscountAudit($after: String) {
discountNodes(first: 250, after: $after) {
edges {
node {
id
discount {
... on DiscountCodeBasic {
title
status
createdAt
endsAt
asyncUsageCount
usageLimit
codes(first: 5) {
edges {
node {
id
code
}
}
}
}
... on DiscountCodeBxgy {
title
status
createdAt
endsAt
asyncUsageCount
usageLimit
}
... on DiscountCodeFreeShipping {
title
status
createdAt
endsAt
asyncUsageCount
usageLimit
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
```graphqldiscountCodeDelete:mutation — validated against api_version 2025-01
discountCodeDelete:mutation — validated against api_version 2025-01
mutation DiscountCodeDelete($id: ID!) {
discountCodeDelete(id: $id) {
deletedCodeDiscountId
userErrors {
field
message
}
}
}
undefinedmutation DiscountCodeDelete($id: ID!) {
discountCodeDelete(id: $id) {
deletedCodeDiscountId
userErrors {
field
message
}
}
}
undefinedSession Tracking
会话跟踪
Claude MUST emit the following output at each stage. This is mandatory.
On start, emit:
╔══════════════════════════════════════════════╗
║ SKILL: Discount Hygiene Cleanup ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝After each step, emit:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>If , prefix every mutation step with and do not execute it.
dry_run: true[DRY RUN]On completion, emit:
For (default):
format: human══════════════════════════════════════════════
OUTCOME SUMMARY
Discounts scanned: <n>
Expired: <n>
Zero usage (> <n> days): <n>
Total flagged: <n>
Deleted: <n>
Errors: <n>
Output: discount_cleanup_<date>.csv
══════════════════════════════════════════════For , emit:
format: jsonjson
{
"skill": "discount-hygiene-cleanup",
"store": "<domain>",
"started_at": "<ISO8601>",
"dry_run": true,
"outcome": {
"scanned": 0,
"flagged_expired": 0,
"flagged_zero_usage": 0,
"deleted": 0,
"errors": 0,
"output_file": "discount_cleanup_<date>.csv"
}
}Claude必须在每个阶段输出以下内容,这是强制要求。
启动时输出:
╔══════════════════════════════════════════════╗
║ SKILL: Discount Hygiene Cleanup ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝每步完成后输出:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>如果,请在每个变更步骤前添加前缀,且不执行该步骤。
dry_run: true[DRY RUN]完成时输出:
对于(默认):
format: human══════════════════════════════════════════════
OUTCOME SUMMARY
Discounts scanned: <n>
Expired: <n>
Zero usage (> <n> days): <n>
Total flagged: <n>
Deleted: <n>
Errors: <n>
Output: discount_cleanup_<date>.csv
══════════════════════════════════════════════对于,输出:
format: jsonjson
{
"skill": "discount-hygiene-cleanup",
"store": "<domain>",
"started_at": "<ISO8601>",
"dry_run": true,
"outcome": {
"scanned": 0,
"flagged_expired": 0,
"flagged_zero_usage": 0,
"deleted": 0,
"errors": 0,
"output_file": "discount_cleanup_<date>.csv"
}
}Output Format
输出格式
CSV file with columns:
, , , , , , , ,
discount_cleanup_<YYYY-MM-DD>.csvdiscount_idtitlestatuscreated_atends_atusage_countusage_limitflag_reasonactionCSV文件,包含以下列:
、、、、、、、、
discount_cleanup_<YYYY-MM-DD>.csvdiscount_idtitlestatuscreated_atends_atusage_countusage_limitflag_reasonactionError Handling
错误处理
| Error | Cause | Recovery |
|---|---|---|
| API rate limit exceeded | Wait 2 seconds, retry up to 3 times |
| Discount already deleted or active order using it | Log error, skip, continue |
| No discounts flagged | Clean discount catalog | Exit with ✅ no cleanup needed |
| 错误 | 原因 | 解决方法 |
|---|---|---|
| API速率限制超出 | 等待2秒,最多重试3次 |
删除时出现 | 折扣已被删除,或有活跃订单正在使用该折扣 | 记录错误,跳过该折扣,继续执行 |
| 无标记的折扣 | 折扣目录干净 | 退出并提示✅无需清理 |
Best Practices
最佳实践
- Run quarterly — discount code sprawl accumulates quickly with seasonal campaigns.
- Check with your email marketing team before deleting zero-usage codes — they may be in a scheduled campaign that hasn't launched yet.
- Keep age at 30+ days to avoid deleting codes from recently launched campaigns.
flag_zero_usage - Automatic/percentage discounts (not code-based) are not cleaned up by this skill — those are managed separately.
- 每季度运行一次——季节性营销活动会导致折扣码快速堆积。
- 删除零使用折扣码前请与邮件营销团队确认——这些码可能属于尚未启动的计划营销活动。
- 将的时间阈值设为30天以上,避免删除最近启动的营销活动的折扣码。
flag_zero_usage - 自动/百分比折扣(非基于码的折扣)不会被本技能清理——这些折扣需单独管理。