shopify-admin-discount-hygiene-cleanup

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Purpose

用途

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
discount-ab-analysis
skill with a write step.
审计折扣目录,查找过期折扣码、零兑换记录的折扣码以及重复的码前缀。经过数月的营销活动后,折扣码会大量堆积,导致管理员难以管理。本工具可选择性删除标记的折扣码,替代手动折扣清理工作,在
discount-ab-analysis
技能的基础上新增了写入步骤。

Prerequisites

前提条件

  • Authenticated Shopify CLI session:
    shopify store auth --store <domain> --scopes read_discounts,write_discounts
  • API scopes:
    read_discounts
    ,
    write_discounts
  • 已完成身份验证的Shopify CLI会话:
    shopify store auth --store <domain> --scopes read_discounts,write_discounts
  • API权限:
    read_discounts
    write_discounts

Parameters

参数

ParameterTypeRequiredDefaultDescription
storestringyesStore domain (e.g., mystore.myshopify.com)
flag_expiredboolnotrueFlag/delete discounts past their end date
flag_zero_usageboolnotrueFlag/delete discounts with 0 redemptions older than N days
zero_usage_min_age_daysintegerno30Age threshold for zero-usage flags
dry_runboolnotruePreview without executing mutations
formatstringnohumanOutput format:
human
or
json
参数类型必填默认值说明
storestring店铺域名(例如:mystore.myshopify.com)
flag_expiredbooltrue标记/删除已过截止日期的折扣
flag_zero_usagebooltrue标记/删除超过N天未使用的零兑换折扣
zero_usage_min_age_daysinteger30零使用折扣的时间阈值(天)
dry_runbooltrue预览模式,不执行变更操作
formatstringhuman输出格式:
human
json

Safety

安全提示

⚠️
discountCodeDelete
permanently removes discount codes. Deleted codes cannot be recovered. Customers who received a deleted code will find it invalid. Run with
dry_run: true
to review the flagged list before committing. Always check that expired codes are not referenced in active email campaigns before deleting.
⚠️
discountCodeDelete
会永久移除折扣码,已删除的码无法恢复。收到已删除折扣码的顾客会发现该码无效。请先使用
dry_run: true
模式运行,确认标记的列表后再执行操作。删除前请务必检查过期折扣码未被活跃的邮件营销活动引用。

Workflow Steps

工作流步骤

  1. OPERATION:
    discountNodes
    — query Inputs:
    first: 250
    , select
    discount { ... on DiscountCodeBasic { codes, usageLimit, asyncUsageCount, endsAt, status } }
    , pagination cursor Expected output: All discount codes with usage and expiry data; paginate until
    hasNextPage: false
  2. Flag discounts matching:
    flag_expired
    (status = EXPIRED) and/or
    flag_zero_usage
    (asyncUsageCount == 0 AND created >
    zero_usage_min_age_days
    ago)
  3. OPERATION:
    discountCodeDelete
    — mutation Inputs:
    id: <discount_node_id>
    Expected output:
    deletedCodeDiscountId
    ,
    userErrors
  1. 操作:
    discountNodes
    — 查询 输入:
    first: 250
    ,选择
    discount { ... on DiscountCodeBasic { codes, usageLimit, asyncUsageCount, endsAt, status } }
    ,分页游标 预期输出: 所有折扣码及其使用、过期数据;持续分页直到
    hasNextPage: false
  2. 标记符合以下条件的折扣:
    flag_expired
    (状态 = EXPIRED)和/或
    flag_zero_usage
    (asyncUsageCount == 0 且创建时间早于
    zero_usage_min_age_days
    天前)
  3. 操作:
    discountCodeDelete
    — 变更 输入:
    id: <discount_node_id>
    预期输出:
    deletedCodeDiscountId
    userErrors

GraphQL Operations

GraphQL操作

graphql
undefined
graphql
undefined

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

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

```graphql

discountCodeDelete: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 } } }
undefined
mutation DiscountCodeDelete($id: ID!) { discountCodeDelete(id: $id) { deletedCodeDiscountId userErrors { field message } } }
undefined

Session 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
dry_run: true
, prefix every mutation step with
[DRY RUN]
and do not execute it.
On completion, emit:
For
format: human
(default):
══════════════════════════════════════════════
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
format: json
, emit:
json
{
  "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: json
,输出:
json
{
  "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
discount_cleanup_<YYYY-MM-DD>.csv
with columns:
discount_id
,
title
,
status
,
created_at
,
ends_at
,
usage_count
,
usage_limit
,
flag_reason
,
action
CSV文件
discount_cleanup_<YYYY-MM-DD>.csv
,包含以下列:
discount_id
title
status
created_at
ends_at
usage_count
usage_limit
flag_reason
action

Error Handling

错误处理

ErrorCauseRecovery
THROTTLED
API rate limit exceededWait 2 seconds, retry up to 3 times
userErrors
on delete
Discount already deleted or active order using itLog error, skip, continue
No discounts flaggedClean discount catalogExit with ✅ no cleanup needed
错误原因解决方法
THROTTLED
API速率限制超出等待2秒,最多重试3次
删除时出现
userErrors
折扣已被删除,或有活跃订单正在使用该折扣记录错误,跳过该折扣,继续执行
无标记的折扣折扣目录干净退出并提示✅无需清理

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
    flag_zero_usage
    age at 30+ days to avoid deleting codes from recently launched campaigns.
  • Automatic/percentage discounts (not code-based) are not cleaned up by this skill — those are managed separately.
  • 每季度运行一次——季节性营销活动会导致折扣码快速堆积。
  • 删除零使用折扣码前请与邮件营销团队确认——这些码可能属于尚未启动的计划营销活动。
  • flag_zero_usage
    的时间阈值设为30天以上,避免删除最近启动的营销活动的折扣码。
  • 自动/百分比折扣(非基于码的折扣)不会被本技能清理——这些折扣需单独管理。