mcpField
S
shoplazza-orders

shoplazza-orders

github.com/shoplazzaOther1750 installsUpdated 1w ago
Repository

About shoplazza-orders

shoplazza-orders is a Shoplazza CLI skill for handling orders and related records, including fulfillment, refunds, and payment activity. It maps common requests to commands and emphasizes confirmation and dry runs for sensitive writes.

Key features

  1. 01Search and count orders
  2. 02Ship orders and update tracking
  3. 03Refund or update orders
  4. 04Handle fulfillment and refund records
  5. 05Manage risks and payment transactions
  6. 06Safety checks for sensitive writes

Use cases

  1. 01Finding orders by customer or status
  2. 02Shipping an order with tracking details
  3. 03Preparing and confirming a refund
  4. 04Updating order tracking information

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/shoplazza/shoplazza-cli --skill shoplazza-orders

After installing, type/shoplazza-ordersin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
fulfillments.md
orders-create.md
post-sales.md
refunds.md
risks.md
shipping-schemas.md
tracking-carriers.md
transactions.md

Details

From the project README

shoplazza CLI — orders module

CRITICAL — before anything else, use Read on ../shoplazza-common/SKILL.md. It owns every cross-cutting mechanic: the three access tiers, the output envelope (.data), --dry-run, --jq (incl. "don't pass -r"), --fields, schema, api rest, auth / profiles, and the safety protocol. This file covers only the orders domain and never repeats them.

Overview

The orders module manages the order lifecycle (search, count, get, create, update, cancel, pay, delete) and its sub-resources: fulfillments (shipping records), refunds, fraud risks, payment transactions, after-sales (post-sales) records, shipping zones/rates, and tracking carriers. All three access tiers apply (tier-selection rule is in shoplazza-common — prefer +shortcut).

Shortcuts exist for +search / +count / +ship / +refund / +update-tracking only — every other operation (get, cancel, create, pay, and all sub-resources) is a spec leaf. Orders is a large domain: this file is the router plus the high-frequency operations; per-sub-resource depth lives in references/.

Command map

Intent → command, highest-fit tier first. The authoritative flags/params live in shoplazza orders <cmd> --help and shoplazza schema orders.<cmd>, not this table.

User intentCommand
Search / filter ordersorders +search [--email <addr>] [--keyword <no/name/email>] [--status …] [--financial-status …] [--fulfillment-status …] [--customer-id <id>] [--since <t>] [--until <t>]
Count ordersorders +count — same filters as +search, minus --page-limit
Ship an order (发货)orders +ship --order-id <id> --tracking <no> [--company <name>] [--company-code <code>] [--line-items id:qty,…] [--notify]
Refund a buyer (退款; money → --dry-run first)orders +refund --order-id <id> --amount <n> [--note <txt>] [--return-items] [--payment-line-id <id>]
Fix / update tracking infoorders +update-tracking --order-id <id> --fulfillment-id <id> --tracking <no> [--company <name>] [--tracking-url <url>] [--notify]
Get one order by internal IDorders get --params '{"order_id":"<id>"}'
Get order by order NUMBER (#…)orders get-by-number --params '{"number":"<number>"}'
List with filters +search lacks (multi-status arrays, ids, skus, tags, fuzzy search…)orders list --params '{…}' (see schema orders.list)
Create an order on a customer's behalf (手工建单 / 代客下单)orders create --data '{"order":{…}}' — heavy nested body → references/orders-create.md
Update order note / tags / shipping addressorders update --params '{"order_id":"<id>"}' --data '{"order":{…}}'
Cancel an order (destructive → --dry-run first)orders cancel --params '{"order_id":"<id>"}' [--data '{"reason":"…"}']
Mark an order paidorders pay --params '{"order_id":"<id>"}' --data '{"payment_line":{"payment_channel":"<channel>","payment_method":"<method>","transaction_no":"<txn>"}}' — empty body = bogus TEST payment; real channel/method/txn go in payment_line, custom display name in gateway (schema orders.pay)
Delete an order (destructive → --dry-run first)orders delete --params '{"order_id":"<id>"}'
Fulfillment records CRUD / cancel / completeorders fulfillments … → references/fulfillments.md
Refund records (one order / store-wide / finish)orders refunds … → references/refunds.md
Fraud risk records (标记高风险)orders risks … → references/risks.md
Payment transactions on an order (支付流水)orders transactions list --params '{"order_id":"<id>"}' → references/transactions.md
After-sales records (售后)orders post-sales … → references/post-sales.md
Shipping zones / rates / available lines (运费区域)orders shipping-schemas … → references/shipping-schemas.md
Which carrier is this tracking number? (承运商识别)orders tracking-carriers detect --params '{"tracking_number":"<no>"}' → references/tracking-carriers.md

Acting on a request

"发货 / 退款 / 取消订单 / ship / refund / cancel" is an action, not a question:

  1. Match intent to a shortcut via the trigger table below (sub-resource leaves are in references/).
  2. Check required fields (each shortcut's no-default flags). Missing or ambiguous → ask with AskUserQuestion, never fabricate — especially --amount (money) and --tracking (a real-world tracking number you cannot invent). Bundle missing fields into ONE question batch.
  3. Never ask about a flag that has a CLI default or is omit-to-disable. Let the default win.
  4. All required present → execute, with safety per shoplazza-common:
    • +refund moves money — ALWAYS --dry-run first, restate in plain language (which order, how much, note, inventory returned or not), wait for the user's go-ahead, then run for real.
    • Destructive leaves (orders cancel / orders delete / fulfillments cancel / risks delete / post-sales delete / shipping-schemas delete-zone) — --dry-run first + restate, wait for the user's go-ahead, then run.
    • orders pay writes a payment record — same treatment as +refund: --dry-run first, restate (which order, channel, transaction no), wait for the user's go-ahead. Never send it with an empty body — no body silently records a bogus TEST payment. payment_line's payment_channel / payment_method / transaction_no are free strings, not enums — fill them from the user's wording (e.g. "走的 PayPal" → "payment_channel":"paypal","payment_method":"paypal"), transaction_no verbatim; do not block asking which enum value to use.
    • +ship / +update-tracking / +search / +count are safe to run directly once required values are confirmed.
Trigger phrase → shortcut
User saysShortcutHow to extract values
查订单 / 找订单 / 今天有没有新订单 / search or list orders+searcha known email → --email; a partial name / order-no fragment / anything else → --keyword; "今天/最近 N 天" → --since only (leave --until open); status words → the enum table below
还没发货的订单 / unshipped orders+search --fulfillment-status waiting未发货 = waiting — there is no unfulfilled value
某客户 / 某邮箱的订单 / orders from customer X+searchcustomer id → --customer-id; a full email address → --email (exact match, the precise path); never stuff an id or an address into --keyword when a dedicated flag exists
有多少订单 / 订单总数 / how many orders+count"总共" = no filters, do not ask for a time range; count from .data.count
发货 / 标记发货 / ship order X+shiptracking no → --tracking verbatim; carrier name → --company; "通知买家" → --notify; whole order = omit --line-items
部分发货 / ship only some items+ship --line-items id:qty,…per-line quantities as line-id:qty pairs
退款 / 给买家退 X 元 / refund the buyer+refundamount → --amount verbatim; stated reason → --note; "库存退回去/restock" → --return-items
改运单号 / 运单号填错了 / fix the tracking number+update-trackingneeds all three: --order-id, --fulfillment-id, --tracking
订单号 #… 的详情 / look up order by numberget-by-number (leaf)strip the leading # → --params '{"number":"…"}'; internal IDs go to get instead
手工建单 / 代客下单 / create an order for a customercreate (leaf)heavy nested body under order → references/orders-create.md; resolve variant_id via products +search; never fabricate buyer identity, address, or price
取消订单 / cancel order Xcancel (leaf)id → --params; a stated reason → --data '{"reason":"…"}' (optional); not fulfillments cancel
取消发货记录 / cancel a fulfillmentfulfillments cancel (leaf)both order_id and fulfillment_id in --params; not orders cancel
标记高风险 / 像欺诈单 / flag as fraudrisks create (leaf)高/中/低 → level high/medium/low; stated reason → details array → references/risks.md
订单支付流水 / payment transactionstransactions list (leaf)order id → --params; this is buyer payments, not billing
运单号 X 是哪家承运商 / which carriertracking-carriers detect (leaf)--params '{"tracking_number":"…"}' — don't list + match by hand
设置运费区域 / 邮费 / shipping zones & ratesshipping-schemas leaves→ references/shipping-schemas.md

If multiple rows match, ask which one. Don't guess.

Required-vs-ask matrix

Only no-default flags are askable.

ShortcutMust ASK if user did not specifyInfer if possibleDefault silently
+refund--amount (money — never fabricate; you may offer to look up the order total via orders get for a full refund, but still confirm the number); --order-id if absent--note from the stated reason; --return-items from 库存退回/restock wording--payment-line-id (only needed when the order has multiple payment lines — the CLI errors with candidates; pick or ask then)
+ship--tracking (never invent a tracking number); --order-id if absent--company from a named carrier (keep the user's naming); --notify from 通知买家 wording--line-items (omit = all fulfillable items), --company-code
+update-trackingwhichever of --order-id / --fulfillment-id / --tracking is missing--company, --tracking-url only if the user gave them--notify (set only on explicit re-notify wording)
+search / +count(nothing — all filters optional; never ask)filters from wording via the enum table--page-limit; time bounds only from the user's own time words
cancel (leaf)order id if absentreason body only if the user stated onereason (optional — omit if not given)
create (leaf)any missing required buyer/address sub-field (last_name, email, country_code, province_code, city, address, zip) and the line item(s) — never fabricate identity, address, or price; ask or look up variant_id via products +searchcurrency_code from the store (shop info get --jq '.data.currency'); a neutral shipping_name label ("Standard Shipping"); an omitted catalog price (the variant prices it)notify flags, tags, note, discount_application, payment_line (record payment via orders pay)
Never-ask list

Flags with a CLI default or omit-to-disable — they never appear in a question: --notify (omit unless the user asks to notify) · --line-items (default: all fulfillable) · --company / --company-code (optional carrier info) · --payment-line-id (only after a multi-payment-line error) · --note (only if a reason was given) · --return-items (explicit wording only) · --tracking-url · --page-limit · --since / --until (only from the user's own time words — never invent a time range).

Decision examples
User saysVerdict
"订单 111222 退 15.50 给买家,备注 wrong size,库存退回"REFUND — +refund --order-id 111222 --amount 15.50 --note "wrong size" --return-items; --dry-run first, restate, wait for go-ahead, then run
"给订单 333444 退个款"ASK — the amount (money; never invent). Do NOT ask which order — it's in the utterance. May offer a full-refund lookup, still confirm
"订单 555 可以发货了,运单号 YT123,中通,通知买家"SHIP — +ship --order-id 555 --tracking YT123 --company 中通 --notify; safe to run directly
"把订单 666 标记发货"ASK — the tracking number (required, never fabricate); carrier is optional, offer alongside but don't block on it
"找最近 7 天还没发货的订单"SEARCH — +search --fulfillment-status waiting --since <today-7d>; no --until
"取消订单 777,原因是买家申请"CANCEL — orders cancel --params '{"order_id":"777"}' --data '{"reason":"买家申请"}'; --dry-run first + restate
"订单 888 像欺诈单,标成高风险"RISK — orders risks create --params '{"order_id":"888"}' --data '{"risk":{"level":"high","details":["…"]}}'; restate before writing
"手工帮客户下个单:1 件 variant V123,单价 29.9,寄给 John Doe ([email protected]),美国加州洛杉矶 123 Main St 90012"CREATE — build the nested order body (line_items variant_id+quantity+price, full shipping_address incl. province_code, shipping_line, tax_total, currency_code), restate + --dry-run first → references/orders-create.md
"帮客户下个单" (no items / buyer given)ASK — which variant(s) & quantity, and the buyer's shipping details (name, email, address); never fabricate them. shipping_price/tax_total are money — use stated amounts, or "0.00" only when the user implies no charge and restate that

Status enums (memorize these three)

From schema orders.list — used by +search / +count / list:

FieldValues
--status (order)opened (pending payment) · placed (in progress) · finished · cancelled
--financial-statuswaiting · paying · authorized · partially_paid · paid · cancelled · failed · refunding · refund_failed · refunded · partially_refunded
--fulfillment-statusinitialled · waiting (未发货 / waiting to ship) · partially_shipped · shipped · partially_finished · finished · cancelled · returning · partially_returned · returned

unfulfilled / fulfilled are NOT valid values — "还没发货" maps to waiting. Each shortcut flag takes ONE value; to filter on several at once use the list leaf, whose status / financial_status / fulfillment_status params are JSON arrays. Time window — which field. +search --since/--until bound the placed time (placed_at_min/placed_at_max), ISO date or unix ts — that is the sales clock and the right default. To filter on a different moment, drop to the list leaf, which exposes one _min/_max pair per time field; pick it from the user's verb:

User's wordsParam
下单 / 支付 / 成交 / 售出 / 卖 / 卖了多少 / 销量 / 销售额 / placed / paid / soldplaced_at_min / placed_at_max
创建 / 新增 / createdcreated_at_min / created_at_max
更新 / 修改 / 最后交互 / updated / last changedupdated_at_min / updated_at_max
完成 / 订单完成 / finishedfinished_at_min / finished_at_max
发货完成 / 履约完成 / fulfilledfulfilled_at_min / fulfilled_at_max

created_at ≠ placed_at (easy to get wrong). A Shoplazza order row is created the moment a buyer enters checkout — before payment — so created_at counts abandoned / unpaid carts too. placed_at is when the order was actually placed (paid). For anything measuring real sales (销量 / 卖了多少 / 成交量 / 销售额 / how much sold), filter on placed_at_*, never created_at_*, or you fold abandoned carts into the number. Use created_at_* only when the user literally asks how many orders were created / 新增. With no time verb at all: if a financial_status or fulfillment_status filter is present the intent is sales → placed_at_*; otherwise created_at_*.

Restate the resolved window. When you turn a relative phrase (最近 7 天 / 这个月) into --since / --until, tell the user the concrete window you used (e.g. 2026-09-10 to 2026-09-17) — a wrong boundary or timezone then shows up instead of silently skewing the count.

Searching orders precisely

orders list exposes three ways to match on the same field. Pick the narrowest one that expresses the request — shoplazza-common's precision ladder, in this domain's terms:

TierParamsUse when
Exact-match arrayscustomer_emails, shipping_emails, shipping_phones, order_tags, skus, spus, product_ids, browser_ips, idsYou have the whole value. +search --email is the shortcut for customer_emails.
Keywordkeyword (+ optional keyword_scope_fields to narrow which fields it searches)A fragment, or the user did not say which field it is. +search --keyword maps here.
Fuzzy triofuzzy_fields + fuzzy_keywords + fuzzy_relationPrefix/fragment matching on specific named fields, or several fields AND/OR-ed together. Leaf only.

keyword_scope_fields and fuzzy_fields share one vocabulary — the field-name list in schema orders.list --view request under fuzzy_fields (name, number, id, shipping_email, tracking_number, discount_code, …). Read it there rather than guessing.

Boundaries

Reads like orders, actually belongs elsewhere (and lookalikes this domain owns):

Sounds likeActually belongs toCommand
退款 / 给顾客退钱 / refund a buyerHERE (not discounts — 折扣/优惠码 price the cart; not billing — app charges)orders +refund
订单支付流水 / buyer payment transactionsHEREorders transactions list
应用收费流水 / app-charge transactions billed to the merchantshoplazza-billingbilling transactions
快递承运商查询 / 运单号识别 / tracking carrier lookupHEREorders tracking-carriers {detect,list}
注册实时运费报价承运商 / real-time rate quote carriersshoplazza-shopshop carrier-services
运费区域 / 邮费方案 / shipping zones & ratesHEREorders shipping-schemas …
按邮箱查某客户的订单 / a customer's ordersHERE (+search --email <addr> or --customer-id)resolving the id via customers +search first is fine — the final query is an orders query
客户资料本身 / the customer recordshoplazza-customerscustomers +search / customers get
库存 / 补货 / product stockshoplazza-productsproducts +stock / products inventory
退款时库存退回 / restock on refundHEREorders +refund --return-items

Permissions · Scope

Authorization is by domain (the unit of --domain), not per command. Authorization flow is in shoplazza-common → Authentication.

OperationNeedsGrant
read (get / get-by-number / list / +search / +count / sub-resource reads)orders read scopeauth login --domain orders
write (+ship / +refund / +update-tracking / create / update / cancel / pay / delete / sub-resource writes)orders write scopeauth login --domain orders

Look up exact scope literals with shoplazza auth scopes; --domain orders expands into them.

Gotchas

Domain-specific pitfalls only (generic ones — .data prefix, --jq without -r — are in shoplazza-common).

SymptomCauseFix
Filtered on unfulfilled / fulfilledNot in the enum未发货 = waiting; see the enum table above
orders get finds nothing for a #… numberget takes the internal order_id; order numbers are a different keyget-by-number --params '{"number":"…"}' (strip the #)
+refund errors "order has N payment_lines"Multi-payment-line order needs an explicit choiceRe-run with --payment-line-id from the listed candidates
+refund / +ship dry-run prints TWO requestsThese shortcuts GET the order first (resolve payment lines / fulfillable items), then POSTExpected. The dry-run POST body omits looked-up data (e.g. refund_line_items, empty payment_line_id) — the live run fills them in
Cancelled the order when only a shipment should die (or vice versa)取消订单 ≠ 取消发货记录Order → orders cancel; fulfillment → orders fulfillments cancel (both path ids)
Hand-built refunds create body for a simple refundThe leaf needs the full body incl. refund_paymentsPrefer +refund; leaf only for split/itemized refunds → references/refunds.md
Store-wide refunds list for one order's recordsTwo different endpointsOne order → refunds list-by-order --params '{"order_id":"…"}'
--status with a comma list on +searchShortcut flags are single-valuedMulti-status → orders list --params '{"status":["opened","placed"]}'
A search "for one buyer" returns the whole storeThe filter was dropped, or the page just looks smallCross-check with orders +count filtered vs unfiltered before answering — see shoplazza-common → "Reading a filtered list"
keyword_scope_fields=["email"] or ["order_no"] returns 0 hitsThose are the schema description's example strings, not the accepted vocabularyUse the fuzzy_fields field names (shipping_email, number, name, …) — see "Searching orders precisely"
unknown flag: --fieldsNo orders command has --fieldsProject with --jq
orders create rejected for missing fieldsWhole body nests under an order wrapper; line_items[].quantity, shipping_address (last_name, email, country_code, province, province_code, city, address, zip), shipping_line (shipping_name, shipping_price), tax_total, currency_code are ALL requiredBuild the full nested body → references/orders-create.md (verified against schema orders.create --view request)
orders create order fails despite country/province setcountry_code / province_code (ISO: US, CA) are the required keys — the display-name country / province are optionalSend both codes; see references/orders-create.md
Copied the orders pay payment_line object into orders createIn orders create the schema types payment_line as a string (registry flattening), unlike orders pay where it is an objectOmit payment_line on create; record payment afterward with orders pay
orders pay with no body "succeeded" unexpectedlyEmpty body = bogus test paymentPass payment_line (payment_channel, payment_method, transaction_no) for a real channel, or gateway for a custom method
Schema summaries say "shopping zone"Registry typo — they mean shipping zoneIgnore; commands are shipping-schemas {create,update,delete}-zone

Recipes

# 1. Orders placed in the last 7 days that are not yet shipped
orders +search --fulfillment-status waiting --since <today-7d, e.g. 2026-07-16>

# 2. Paid orders for one customer
orders +search --customer-id 100200 --financial-status paid

# 3. All orders from a buyer email — exact, complete, and checked against the store total
orders +search --email [email protected] --page-limit 250
orders +count --email [email protected] --jq '.data.count'   # must be < the unfiltered count
orders +count --jq '.data.count'

# 4. Total order count, no filters
orders +count --jq '.data.count'

# 5. Order detail by order number
orders get-by-number --params '{"number":"2026071500123"}' --jq '.data.order'

# 6. Ship the whole order and notify the buyer
orders +ship --order-id 4300123 --tracking SF0011223344 --company "顺丰" --notify

# 7. Fix a mistyped tracking number (no re-notify)
orders +update-tracking --order-id 991100 --fulfillment-id 77001 --tracking YT5544332211

# 8. Partial refund + return inventory — dry-run, restate, wait for go-ahead, then run
orders +refund --order-id 887799 --amount 19.90 --note "wrong size" --return-items --dry-run
orders +refund --order-id 887799 --amount 19.90 --note "wrong size" --return-items

# 9. Cancel an order with a reason — dry-run first
orders cancel --params '{"order_id":"660011"}' --data '{"reason":"买家重复下单"}' --dry-run
orders cancel --params '{"order_id":"660011"}' --data '{"reason":"买家重复下单"}'

# 10. Flag an order as high fraud risk with a reason
orders risks create --params '{"order_id":"445500"}' \
  --data '{"risk":{"level":"high","details":["收货地址与 IP 所在国家不一致"]}}'

# 11. Which carrier owns this tracking number?
orders tracking-carriers detect --params '{"tracking_number":"9400111899223344556677"}'

# 12. Payment transactions on an order
orders transactions list --params '{"order_id":"778899"}'

# 13. One order's refund records
orders refunds list-by-order --params '{"order_id":"220033"}' --jq '.data.records'

References

  • references/orders-create.md — manual/draft order creation: full nested body (required vs optional), required-vs-ask, minimal + fuller examples
  • references/fulfillments.md — fulfillment records: leaf CRUD, cancel/complete, body shapes
  • references/refunds.md — refund record body (split/itemized refunds), store-wide vs per-order lists, finish for custom-channel refunds
  • references/risks.md — fraud risk records: level enum, details, CRUD
  • references/transactions.md — buyer payment transactions, status enum
  • references/post-sales.md — after-sales records: list filters, delete
  • references/shipping-schemas.md — general schema, zones, available shipping lines (GB special case)
  • references/tracking-carriers.md — carrier detect / list
  • Per-command flags: shoplazza orders <cmd> --help
  • Spec-leaf params / body / response: shoplazza schema orders.<cmd> (nested: schema orders.fulfillments.create)
  • Cross-cutting mechanics (auth / tiers / output envelope / --dry-run / --jq / safety): ../shoplazza-common/SKILL.md
  • Shortcut source of truth: shortcuts/orders/*.go

Comments

Markdown supported