| name | fbo-status |
| description | Ozon FBO 发货台账查询 (ledger/). 当用户说"看发货台账"、"FBO 全局状态"、"历史发了多少"、"总览 shipped/skipped"、"最近几天发货情况"、"哪个 SKU 发多少件"、"ledger 看一下"时触发。汇总所有 `shipment_ledger_*.json` + `pending_summary.json`, 展示 shipped 总览 (按日期/集群/SKU) + pending 清单. |
FBO 发货台账全局状态
综合读 ledger/shipment_ledger_*.json (每次 run 一份), 按日期/集群/SKU 聚合展示 shipped 和 skipped, 补 pending 总数.
触发场景
- "看一下 FBO 总体发货状态"
- "过去一周发了多少件"
- "所有 SKU 目前 shipped/pending 数"
- "哪个集群发得最多"
- "看看 ledger"
- "有没有新的 skipped"
路径
- 台账目录:
/Users/mac/Documents/ozns/丝绸生活/海外仓发货表/2026-04-23海外仓发货/ledger/
- 文件:
shipment_ledger_<YYYYMMDD_HHMMSS>.json, pending_summary.json
查看工具
没有独立 CLI, 用 bash + python 一段脚本即可. 标准用法:
1. 所有 run 的发货总览 (最常用)
cd /Users/mac/Documents/ozns/丝绸生活/海外仓发货表/2026-04-23海外仓发货
python3 <<'EOF'
import json, glob
from collections import defaultdict
files = sorted(glob.glob("ledger/shipment_ledger_*.json"))
print(f"=== {len(files)} runs in ledger/ ===\n")
total_ship = total_skip = 0
by_cluster_ship = defaultdict(int); by_cluster_skip = defaultdict(int)
by_sku_ship = defaultdict(int); by_sku_skip = defaultdict(int)
for f in files:
d = json.load(open(f))
run_at = d.get("run_at","")
ship_n = sum(sum(it.get("quantity",0) for it in s.get("items",[])) for s in d.get("shipped",[]))
skip_n = sum(s.get("quantity",0) for s in d.get("skipped",[]))
orders = len(d.get("shipped",[]))
print(f"{run_at[:19]:20} orders={orders:3} shipped={ship_n:6}件 skipped={skip_n:6}件 ({f.split('/')[-1]})")
total_ship += ship_n; total_skip += skip_n
for s in d.get("shipped",[]):
for it in s.get("items",[]):
for c in (s.get("cluster_names") or [s.get("cluster")]):
if c: by_cluster_ship[c] += it.get("quantity",0)
by_sku_ship[it.get("offer_id","")] += it.get("quantity",0)
for s in d.get("skipped",[]):
by_cluster_skip[s.get("cluster","")] += s.get("quantity",0)
by_sku_skip[s.get("offer_id","")] += s.get("quantity",0)
print(f"\n=== 汇总: shipped={total_ship} 件, skipped={total_skip} 件 (含重复, 看 pending 去重) ===")
print("\n按集群 shipped:")
for c,n in sorted(by_cluster_ship.items(), key=lambda x:-x[1]):
print(f" {c:40} {n:6} 件 (skipped={by_cluster_skip.get(c,0)})")
print("\n按 SKU shipped:")
for k,n in sorted(by_sku_ship.items(), key=lambda x:-x[1]):
print(f" {k:40} {n:6} 件 (skipped={by_sku_skip.get(k,0)})")
EOF
2. 看最新 run 的明细
python3 <<'EOF'
import json, glob
f = sorted(glob.glob("ledger/shipment_ledger_*.json"))[-1]
d = json.load(open(f))
print(f"=== {f.split('/')[-1]} ===")
print(f"run_at: {d.get('run_at')} account: {d.get('account')}")
print(f"shipped: {len(d.get('shipped',[]))} orders")
for s in d.get("shipped",[]):
cl = s.get("cluster_names") or [s.get("cluster")]
print(f" order={s.get('order_id')} supply={s.get('supply_id')} cluster={cl} mode={s.get('mode')}")
for it in s.get("items",[]):
print(f" {it.get('offer_id'):30} ×{it.get('quantity'):5} boxes={it.get('boxes')}")
print(f"\nskipped: {len(d.get('skipped',[]))} 条")
for s in d.get("skipped",[]):
print(f" {s.get('cluster'):25} {s.get('offer_id'):30} ×{s.get('quantity'):5} {s.get('reason_code','')}")
EOF
3. 看 pending 当前总数 (跨 run 去重后)
python3 list_pending.py
python3 list_pending.py --by-cluster
python3 list_pending.py --by-sku
python3 list_pending.py --by-reason
(list_pending.py 内部自动消解 — 后续 run 发成功的会从 pending 里移除)
4. 查某个 order_id 的历史记录
python3 <<'EOF'
import json, glob, sys
ORDER = 100532100
for f in sorted(glob.glob("ledger/shipment_ledger_*.json")):
d = json.load(open(f))
for s in d.get("shipped",[]):
if s.get("order_id") == ORDER:
print(f"--- {f.split('/')[-1]} / run_at={d.get('run_at')} ---")
print(json.dumps(s, ensure_ascii=False, indent=2))
EOF
5. 哪些 SKU 在哪个集群发最多
python3 <<'EOF'
import json, glob
from collections import defaultdict
grid = defaultdict(lambda: defaultdict(int))
for f in glob.glob("ledger/shipment_ledger_*.json"):
d = json.load(open(f))
for s in d.get("shipped",[]):
cl = s.get("cluster_names") or [s.get("cluster")]
for it in s.get("items",[]):
for c in cl:
if c: grid[it.get("offer_id","")][c] += it.get("quantity",0)
for sku, by in grid.items():
print(f"\n[{sku}]")
for c,n in sorted(by.items(), key=lambda x:-x[1]):
print(f" {c:40} {n:6} 件")
EOF
字段速查 (shipped 条)
{
"order_id": 100532100,
"mode": "CROSSDOCK" | "MULTI_CLUSTER",
"supply_id": 2000050076860,
"cluster_kws": ["Новосибирск"],
"cluster_names": ["Новосибирск"],
"macrolocal_cluster_ids": ["4067"],
"drop_off": {"id": 22190776129000, "name": "МО_ЩЕРБИНКА_ХАБ"},
"storage_warehouse": {"id": 18044341087000, "name": "НОВОСИБИРСК_РФЦ_НОВЫЙ"},
"timeslot":
......
字段速查 (skipped 条)
{
"cluster": "Новосибирск",
"cluster_kw": "Новосибирск",
"macrolocal_cluster_id": "4067",
"offer_id": "Q_MeiGongDao-HeiSe-Free",
"sku": 3214793665,
"barcode": "...",
"quantity": 1800,
"reason": "...",
"reason_code": "MATRIX_DROPPED_FROM_SUPPLY" | "NO_AVAILABLE_WAREHOUSE" | "DRAFT_OR_SUPPLY_FAILED",
"related_order_id": 100532100,
"related_supply_id": 2000050076860,
"timestamp": "..."
}
常见问题
Q1: 总 shipped 件数 vs Ozon 后台数对不上
ledger 是"本机发起的 run"维度. Ozon 后台还含:
- 手工在 UI 建的 supply
- 旧脚本 demo.py / writeShiploaction.py 发的 (没台账)
- 被取消的 (ledger 有 shipped 但 UI 可能 cancelled 了)
去 Ozon seller.ozon.ru 「供货单」里按 date 筛选再对.
Q2: pending_summary.json 和 list_pending.py 输出不一致
pending_summary.json 是 create_fbo_plan.py 写的快照, list_pending.py 是动态重算. 以后者为准 (能反映最新 run 的自动消解).
Q3: 想删某个 ledger 文件
可以直接 rm ledger/shipment_ledger_xxx.json, 不会影响已发的 Ozon 单. pending 会重新去重计算 (相应的 skipped 记录会被去掉).
Q4: 备份
整个 ledger/ 目录用 tar 压一下备份即可, 纯 JSON 文本无副作用. 恢复用 tar -xf 回来, list_pending.py 自动读.
build_shipment_overview.py — 计划 vs 已发对照表 (2026-04-25 起首选)
聚合 4181 plans (cap_total) + Ozon /supply-order/list+get+bundle (active) 出 Excel, 直观看每集群每 SKU 计划/已发/差额.
python3 build_shipment_overview.py --exclude-before 2026-04-23T00:00:00Z
输出列: 集群 | offer_id | 计划件数 | 已发件数 | 差额 | 状态 | 关联 supply_id
新加状态 (2026-04-25, per-SKU 算法配合):
改派抵扣已完成 — 本 cluster cap > active 但全 SKU 总 active ≥ cap_total (远东 600 → Москва 抵扣)
无计划-意外发货 (改派目标) — 本 cluster planned=0 但 active>0 (Москва 接了远东改派)
缺 X 件 — 还没发齐
已发齐 — cluster 单独够数
跟 list_pending 共用 per-SKU 算法 (cap_total / active_total); supply-order/list 必传 sort_by:1 (reference_shipment_overview_script.md).
同步本 skill 的 .py 文件
bash /Users/mac/.claude/skills/sync_fbo_scripts.sh
相关 skill
/fbo-retry — pending 清单 + 重试
/fbo-plan — 新一轮发货 run
- memory
reference_shipment_ledger.md — ledger schema + pending 去重规则完整说明
- memory
reference_shipment_overview_script.md — build_shipment_overview.py 详解