用途
该技能遍历最近已批准或已关闭的退货单,对每个已实际收到并检验的 returnLineItem 执行重新入库。它使用 inventoryAdjustQuantities 调整退货目的地地点的可用数量,调整原因为 restock,并通过 referenceDocumentUri 关联到对应退货记录。适用于仓库处理在独立系统中完成、与 Shopify 不同步的情况,或人工入库被延迟后需要一次干净的补齐运行。
前置条件
- 已认证的 Shopify CLI 会话:
shopify store auth --store <domain> --scopes read_returns,write_inventory,read_locations - API 权限范围:read_returns、read_inventory、write_inventory
参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| store | string | 是 | — | 店铺域名(例如 mystore.myshopify.com) |
| format | string | 否 | human | 输出格式:human 或 json |
| dry_run | bool | 否 | true | 仅预览入库计划,不执行库存变更 |
| days_back | integer | 否 | 14 | 近期已完成退货的回溯窗口 |
| return_status | string | 否 | CLOSED | 仅处理该状态的退货:CLOSED、OPEN 或 ANY |
| location_id | string | 否 | — | 若设置,仅处理库存目的地匹配该地点 GID 的退货 |
| restock_only_return_reasons | array | 否 | — | 若设置(例如 ["UNWANTED", "SIZE_TOO_SMALL"]),仅入库这些原因的退货;默认排除 DEFECTIVE |
| skip_defective | bool | 否 | true | 排除 returnLineItem.returnReason 为 DEFECTIVE 的商品 |
安全提示
第 2 步会执行 inventoryAdjustQuantities 变更,立即向目的地地点的可用数量增加单位。对损坏或不可销售的库存重新入库会虚增可用库存并导致超卖。默认 dry_run: true,请先审阅预览 CSV,确认每个退货行项目确实可销售后再提交。默认 skip_defective: true 会排除 DEFECTIVE 退货。每次入库都会在 Shopify 库存活动日志中留下一条原因为 restock 的永久记录。
工作流程
-
returns 查询:输入查询
status:<return_status> updated_at:>='<NOW - days_back days>'(仅当 return_status:ANY 时使用 updated_at 条件),first: 250,选取 id、name、status、closedAt、order、returnLineItems(quantity、returnReason、fulfillmentLineItem 中的 variant 与 inventoryItem)、reverseFulfillmentOrders 及分页游标。预期输出:退货单及其行项目、退货原因、库存项目 ID 和目的地地点。 -
构建入库计划:对每个尚未入库、退货原因被参数允许且 inventoryItem.tracked: true 的 returnLineItem,按 (inventoryItemId, locationId) 分组并汇总数量增量。跳过变体缺失、tracked: false 或退货无目的地地点的项目。
-
inventoryAdjustQuantities 变更:输入 reason: "restock"、name: "available"、referenceDocumentUri: "shopify://returns/<return_id>"、changes 数组含 inventoryItemId、locationId、delta。预期输出:inventoryAdjustmentGroup.changes 含每项的 quantityAfterChange,以及 userErrors。
GraphQL 操作
# returns:query — validated against api_version 2025-01
query ReturnsForRestock($query: String!, $after: String) {
returns(first: 250, after: $after, query: $query) {
edges {
node {
id
name
status
closedAt
order { id name }
returnLineItems(first: 50) {
edges {
node {
id
quantity
returnReason
returnReasonNote
fulfillmentLineItem {
lineItem {
id
title
variant {
id
sku
inventoryItem { id tracked }
}
}
}
}
}
}
reverseFulfillmentOrders(first: 5) {
edges {
node {
id
reverseDeliveries(first: 5) { edges { node { id } } }
}
}
}
}
}
pageInfo { hasNextPage endCursor }
}
}
# inventoryAdjustQuantities:mutation — validated against api_version 2025-01
mutation RestockOnReturn($input: InventoryAdjustQuantitiesInput!) {
inventoryAdjustQuantities(input: $input) {
inventoryAdjustmentGroup {
id
reason
referenceDocumentUri
changes {
name
delta
quantityAfterChange
item { id sku }
location { id name }
}
}
userErrors { field message }
}
}
会话跟踪
Claude 必须在每个阶段输出以下内容,这是强制要求。
开始时输出:
╔══════════════════════════════════════════════╗
║ SKILL: Restock on Return ║
║ 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 默认):
══════════════════════════════════════════════
RESTOCK ON RETURN
Returns scanned: <n>
Line items eligible: <n>
Skipped (defective): <n>
Skipped (untracked): <n>
Units restocked: <n> (or "skipped — dry_run")
Adjustment groups: <n>
Errors: <n>
Output: restock_on_return_<date>.csv
══════════════════════════════════════════════
format: json 时输出:
{
"skill": "restock-on-return",
"store": "<domain>",
"started_at": "<ISO8601>",
"completed_at": "<ISO8601>",
"dry_run": true,
"outcome": {
"returns_scanned": 0,
"line_items_eligible": 0,
"skipped_defective": 0,
"skipped_untracked": 0,
"units_restocked": 0,
"adjustment_groups": 0,
"errors": 0,
"output_file": "restock_on_return_<date>.csv"
}
}
输出格式
CSV 文件 restock_on_return_<YYYY-MM-DD>.csv,列包括:return_id、return_name、order_name、sku、product_title、quantity_restocked、return_reason、location_name、quantity_after、inventory_item_id、status。
错误处理
| 错误 | 原因 | 恢复方式 |
|---|---|---|
| THROTTLED | 超出 API 速率限制 | 等待 2 秒,最多重试 3 次 |
| inventoryItem.tracked: false | 变体未启用跟踪 | 记录并跳过;需手动启用 |
| inventoryAdjustQuantities 返回 userErrors | 地点或项目无效 | 核对 GID 是否匹配退货目的地 |
| 退货无目的地地点 | 尚未确认逆向配送 | 跳过该退货;确认配送后重跑 |
| 变体已删除 | 销售后产品被移除 | 跳过该行项目;记录待审 |
最佳实践
- 始终先以 dry_run: true 运行并审计预览 CSV——对损坏单位入库会虚增库存并导致下游超卖。
- 常规操作保持 skip_defective: true。仅在明确检查缺陷单位并确认可翻新后设为 false。
- 使用 restock_only_return_reasons: ["UNWANTED", "SIZE_TOO_SMALL", "SIZE_TOO_LARGE", "STYLE", "COLOR"] 聚焦于几乎总能产生可再销售库存的原因。
- 按仓库运行时设置 location_id,将运行限制在单一站点的逆向物流流程内。
- 将运行后输出与 multi-location-inventory-audit 交叉核对,确认入库 SKU 对账无误。
- 对于尚未进行实物检验的活跃退货,推迟到 status: CLOSED(默认)再入库——切勿仅凭客户声明对 OPEN 退货入库。