用途
该技能用于在不打开 Shopify 管理界面的情况下处理订单退款,并可在退款后可选地创建替换用的草稿订单。退款与替换草稿订单可在同一工作流中完成。
前置条件
- 已认证的 Shopify CLI 会话:
shopify auth login --store <domain> - API 权限范围:
read_orders、write_orders
参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| store | string | 是 | — | 商店域名(例如 mystore.myshopify.com) |
| format | string | 否 | human | 输出格式:human 或 json |
| dry_run | bool | 否 | false | 预览操作而不执行变更 |
| order_id | string | 是 | — | 订单的 GID(例如 gid://shopify/Order/12345) |
| refund_line_items | array | 否 | 全部可退款 | 要退款的行项目数组 {line_item_id, quantity};省略则退款所有可退款数量 |
| reason | string | 否 | other | 退款原因:customer、fraud、inventory、declined、other |
| create_replacement | bool | 否 | false | 若为 true,退款后创建包含相同行项目的草稿订单 |
| notify_customer | bool | 否 | true | 向客户发送退款通知邮件 |
安全提示
步骤 2 和步骤 3 会执行不可逆的财务变更。refundCreate 无法撤销——退款一旦处理,款项无法重新捕获。draftOrderCreate 会创建新的草稿订单,需单独开具发票并支付。建议先以 dry_run: true 运行,确认退款行项目和金额后再提交。执行前请根据步骤 1 的输出核实每个行项目的 refundableQuantity。
工作流步骤
-
OPERATION: order — query
- 输入:
id: <order_id> - 预期输出:包含
displayFinancialStatus、lineItems(含refundableQuantity)、transactions、customer、shippingAddress的完整订单;继续前确认订单可退款。
- 输入:
-
OPERATION: refundCreate — mutation
- 输入:
input.orderId、input.refundLineItems(来自参数或全部可退款项)、input.notify、input.note: <reason> - 预期输出:
refund.id、refund.totalRefundedSet、userErrors
- 输入:
-
OPERATION: draftOrderCreate — mutation(仅当 create_replacement: true)
- 输入:
input.lineItems(来自原始订单行项目)、input.customerId、input.shippingAddress、input.note: "Replacement for order <name>" - 预期输出:
draftOrder.id、draftOrder.name、draftOrder.invoiceUrl、userErrors
- 输入:
GraphQL 操作
以下操作已针对 api_version 2025-01 验证。
order:query
query OrderForRefund($id: ID!) {
order(id: $id) {
id
name
displayFinancialStatus
displayFulfillmentStatus
totalPriceSet {
shopMoney { amount currencyCode }
}
lineItems(first: 50) {
edges {
node {
id
title
quantity
refundableQuantity
variant {
id
sku
price
}
}
}
}
transactions(first: 10) {
id
kind
status
amountSet {
shopMoney { amount currencyCode }
}
gateway
}
refunds {
id
createdAt
totalRefundedSet {
shopMoney { amount currencyCode }
}
}
customer {
id
defaultEmailAddress {
emailAddress
}
firstName
lastName
}
shippingAddress {
address1
city
province
country
zip
}
}
}
refundCreate:mutation
mutation RefundCreate($input: RefundInput!) {
refundCreate(input: $input) {
refund {
id
createdAt
totalRefundedSet {
shopMoney { amount currencyCode }
}
}
userErrors {
field
message
}
}
}
draftOrderCreate:mutation
mutation DraftOrderCreate($input: DraftOrderInput!) {
draftOrderCreate(input: $input) {
draftOrder {
id
name
invoiceUrl
}
userErrors {
field
message
}
}
}
会话跟踪
在每个阶段必须输出以下内容。
开始时输出:
╔══════════════════════════════════════════════╗
║ SKILL: refund-and-reorder ║
║ 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
Order: <name>
Refund ID: <id>
Amount refunded: <amount> <currency>
Replacement draft: <draft order name or "none">
Errors: 0
Output: none
══════════════════════════════════════════════
对于 format: json,输出:
{
"skill": "refund-and-reorder",
"store": "<domain>",
"started_at": "<ISO8601>",
"completed_at": "<ISO8601>",
"dry_run": false,
"steps": [
{ "step": 1, "operation": "OrderForRefund", "type": "query", "params_summary": "order <id>", "result_summary": "<status>", "skipped": false },
{ "step": 2, "operation": "RefundCreate", "type": "mutation", "params_summary": "<n> line items, reason: <reason>", "result_summary": "refund <id>", "skipped": false },
{ "step": 3, "operation": "DraftOrderCreate", "type": "mutation", "params_summary": "<n> line items, customer <id>", "result_summary": "draft <name>", "skipped": false }
],
"outcome": {
"order_name": "<name>",
"refund_id": "<id>",
"amount_refunded": "<amount>",
"currency": "<currency>",
"draft_order_name": "<name or null>",
"draft_order_invoice_url": "<url or null>",
"errors": 0,
"output_file": null
}
}
输出格式
无 CSV 输出。会话完成摘要报告退款 ID 和金额。若 create_replacement: true,输出中包含草稿订单名称和发票 URL。
错误处理
| 错误 | 原因 | 恢复方式 |
|---|---|---|
| refundableQuantity 为 0 | 行项目已全额退款 | 检查订单退款历史 |
| refundCreate 返回 userErrors | 退款金额无效或订单不可退款 | 检查 displayFinancialStatus——不能为 REFUNDED |
| draftOrderCreate 返回 userErrors | 行项目或客户无效 | 确认产品变体仍然存在 |
| 订单未找到 | 订单 GID 无效 | 使用 order-lookup-and-summary 技能查找正确的订单 ID |
最佳实践
- 始终先运行
dry_run: true——步骤 2 不可逆。提交前在步骤 1 输出中核实每个行项目的refundableQuantity。 - 对于部分退款,明确指定
refund_line_items——省略它会退款所有可退款项目,可能并非本意。 create_replacement草稿订单不会自动开具发票或履行——将invoiceUrl分享给客户以完成支付。- 对于不应通知客户的内部更正,使用
notify_customer: false。 - 检查步骤 1 的
displayFinancialStatus——若为 REFUNDED,则没有可退款内容。