Files
bj_power/demo_seed.py
T

538 lines
26 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""演示数据落库脚本(北京电力 WMS + MES)
用途:为交付甲方的《系统页面截图说明书》准备成体系的业务数据。
数据真实落库,可长期保留。脚本可重复执行(幂等:已存在则跳过)。
用法:
python demo_seed.py # 全部执行
python demo_seed.py inspect # 只探测库存/基线,不写库
"""
import json
import sys
import time
import urllib.request
import urllib.error
sys.stdout.reconfigure(encoding="utf-8")
WMS = "http://127.0.0.1:8890"
MES = "http://127.0.0.1:8888"
XAPI = "Hardman_2026"
OK, FAIL, SKIP = [], [], []
def req(base, method, path, body=None, token=None, xapi=None, timeout=20):
url = base + path
data = None
headers = {"Content-Type": "application/json"}
if token:
headers["Authorization"] = "Bearer " + token
if xapi:
headers["X-API-TOKEN"] = xapi
if body is not None:
data = json.dumps(body, ensure_ascii=False).encode("utf-8")
r = urllib.request.Request(url, data=data, headers=headers, method=method)
try:
with urllib.request.urlopen(r, timeout=timeout) as resp:
return resp.status, resp.read().decode("utf-8", "replace")
except urllib.error.HTTPError as e:
return e.code, e.read().decode("utf-8", "replace")
except Exception as e:
return 0, str(e)
def j(txt):
try:
return json.loads(txt)
except Exception:
return {"_raw": txt}
def d_of(txt):
d = j(txt)
return d.get("data") if isinstance(d, dict) else None
def step(label, st, txt, ok_cond=None, note=""):
body = j(txt)
ok = body.get("code") == 0 if isinstance(body, dict) else False
if ok_cond is not None:
ok = ok_cond
tag = "OK " if ok else "FAIL"
msg = body.get("message", "") if isinstance(body, dict) else txt[:120]
print(" [%s] %-38s %s %s" % (tag, label, msg, note))
(OK if ok else FAIL).append(label)
return body
def skip(label, why):
print(" [SKIP] %-38s %s" % (label, why))
SKIP.append(label)
# ============================== 登录 ==============================
def login_wms():
st, txt = req(WMS, "POST", "/api/auth/login", {"username": "admin", "password": "123456"})
return (d_of(txt) or {}).get("token", "")
def login_mes():
st, txt = req(MES, "POST", "/api/v1/login", {"username": "admin", "password": "123456"})
return (d_of(txt) or {}).get("accessToken", "")
def today(offset=0):
return time.strftime("%Y-%m-%d", time.localtime(time.time() + offset * 86400))
# ============================== 探测 ==============================
def fetch_details(wms_tok, manage_mode=0, page_size=200):
"""库存明细(原始行,含 batch_no / sn_code)——出库必须用它,聚合接口不返批次/SN"""
url = "/api/stock/details?page=1&pageSize=%d" % page_size
if manage_mode:
url += "&manageMode=%d" % manage_mode
st, txt = req(WMS, "GET", url, token=wms_tok)
d = d_of(txt) or {}
return d.get("list", [])
def inspect(wms_tok, mes_tok):
print("\n===== 库存探测(明细)=====")
rows = fetch_details(wms_tok)
print(" 库存明细行数=%d" % len(rows))
if rows:
print(" 样例字段:%s" % sorted(rows[0].keys()))
for r in rows[:12]:
print(" %s mode=%s qty=%s zone=%s batch=%s sn=%s qual=%s" % (
r.get("materialCode"), r.get("manageMode"), r.get("quantity"),
r.get("zoneCode"), r.get("batchNo"), r.get("snCode"), r.get("qualityStatus")))
print("\n===== MES 基线 =====")
st, txt = req(MES, "GET", "/api/v1/product-types", token=mes_tok)
print(" 产品类型:", json.dumps(d_of(txt), ensure_ascii=False)[:200])
st, txt = req(MES, "GET", "/api/v1/stations", token=mes_tok)
sts = d_of(txt) or []
print(" 工位:%s" % [(s.get("stationNo"), s.get("name"), s.get("flowId")) for s in sts][:12])
# ============================== MES 造数 ==============================
def mes_seed(mes_tok, wms_tok):
print("\n===== MES 演示数据 =====")
st, txt = req(MES, "GET", "/api/v1/product-types", token=mes_tok)
ptypes = d_of(txt) or []
ptype = ptypes[0]
ptype_id = ptype["id"]
prod_code = ptype.get("code")
prod_name = ptype.get("name")
print(" 产品类型 id=%s code=%s name=%s" % (ptype_id, prod_code, prod_name))
# ---- BOM(用 WMS 真实物料)----
# 说明:前三项库内有现货(可走通备料出库全链路),第四项为长周期采购件
bom_items = [
{"materialCode": "ST-A100", "materialName": "标准结构件A100", "spec": "A100", "unit": "件", "manageMode": "1", "unitQty": 2, "lossRate": 5},
{"materialCode": "GJ-GANGGUAN-002", "materialName": "无缝钢管114x8", "spec": "114x8", "unit": "米", "manageMode": "1", "unitQty": 4, "lossRate": 3},
{"materialCode": "PR-S100", "materialName": "精密传感器S100", "spec": "S100", "unit": "个", "manageMode": "2", "unitQty": 1, "lossRate": 0},
{"materialCode": "JM-ZHOUCHENG-6020", "materialName": "精密轴承6020", "spec": "6020", "unit": "个", "manageMode": "2", "unitQty": 2, "lossRate": 0},
]
step("BOM 保存(4 项物料)", *req(MES, "PUT", "/api/v1/bom", {"productCode": prod_code, "items": bom_items}, token=mes_tok))
# ---- 第二个产品类型(仅 1 项物料,用于演示台账"领料完结"状态)----
prod2_code = "PROD-20260904-002"
st, txt = req(MES, "GET", "/api/v1/product-types", token=mes_tok)
hit = [p for p in (d_of(txt) or []) if p.get("code") == prod2_code]
if hit:
ptype2_id = hit[0]["id"]
print(" [SKIP] 产品类型2 已存在 id=%s" % ptype2_id)
else:
st, txt = req(MES, "POST", "/api/v1/product-types",
{"code": prod2_code, "name": "接驳体总成", "category": "总成类",
"remark": "单物料演示产品", "isActive": True}, token=mes_tok)
b = j(txt)
print(" [%s] 创建产品类型2 %s" % ("OK " if b.get("code") == 0 else "FAIL", b.get("message", "")))
# 创建接口不返回 id,需回查
st, txt = req(MES, "GET", "/api/v1/product-types", token=mes_tok)
hit = [p for p in (d_of(txt) or []) if p.get("code") == prod2_code]
ptype2_id = hit[0]["id"] if hit else None
if ptype2_id:
step("BOM2 保存(单物料 PR-S100", *req(MES, "PUT", "/api/v1/bom", {
"productCode": prod2_code,
"items": [{"materialCode": "PR-S100", "materialName": "精密传感器S100", "spec": "S100",
"unit": "个", "manageMode": "2", "unitQty": 1, "lossRate": 0}]}, token=mes_tok))
# ---- 工单:覆盖各状态 ----
tag = time.strftime("%m%d")
orders = {}
def create_wo(no, qty, status_flow, p_id=None, p_code=None, p_name=None):
body = {"workOrderNo": no, "productTypeId": p_id or ptype_id, "productCode": p_code or prod_code,
"productName": p_name or prod_name, "quantity": qty, "status": "CREATED", "processSeq": ""}
st, txt = req(MES, "POST", "/api/v1/work-orders", body, token=mes_tok)
b = j(txt)
if b.get("code") != 0 and "已存在" not in b.get("message", ""):
step("工单创建 %s" % no, st, txt)
return None
st, txt = req(MES, "GET", "/api/v1/work-orders?orderNo=" + no, token=mes_tok)
rows = d_of(txt) or []
if not rows:
step("工单创建 %s" % no, st, txt)
return None
wo = rows[0]
print(" [OK ] 工单 %-30s id=%s qty=%s" % (no, wo.get("id"), qty))
OK.append("工单 " + no)
for s, reason in status_flow:
st2, txt2 = req(MES, "POST", "/api/v1/work-orders/status",
{"id": wo["id"], "status": s, "reason": reason}, token=mes_tok)
b2 = j(txt2)
if b2.get("code") == 0:
print(" -> %s" % s)
else:
print(" -> %s 失败: %s" % (s, b2.get("message")))
orders[no] = wo
return wo
# WO-01 执行中(主力演示)
create_wo("WO-2026%s-01" % tag, 30, [("RELEASED", ""), ("IN_PROGRESS", "按计划投产")])
# WO-02 已发布
create_wo("WO-2026%s-02" % tag, 20, [("RELEASED", "")])
# WO-03 暂停
create_wo("WO-2026%s-03" % tag, 15, [("RELEASED", ""), ("IN_PROGRESS", ""), ("PAUSED", "待料:轴承未到货")])
# WO-04 已完工
create_wo("WO-2026%s-04" % tag, 10, [("RELEASED", ""), ("IN_PROGRESS", ""), ("DONE", "按计划完工")])
# WO-05 草稿
create_wo("WO-2026%s-05" % tag, 25, [])
# WO-06 单物料小工单(用于演示台账"领料完结")
if ptype2_id:
create_wo("WO-2026%s-06" % tag, 2, [("RELEASED", ""), ("IN_PROGRESS", "小批量试产")],
p_id=ptype2_id, p_code=prod2_code, p_name="接驳体总成")
# ---- 日排产 ----
print(" --- 日排产 ---")
plans = [
("WO-2026%s-01" % tag, today(-1), 10),
("WO-2026%s-01" % tag, today(0), 12),
("WO-2026%s-01" % tag, today(1), 8),
("WO-2026%s-02" % tag, today(0), 10),
("WO-2026%s-02" % tag, today(2), 10),
("WO-2026%s-05" % tag, today(3), 15),
]
if ptype2_id:
plans.append(("WO-2026%s-06" % tag, today(4), 2))
for no, d, qty in plans:
st, txt = req(MES, "POST", "/api/v1/daily-plans",
{"orderNo": no, "planDate": d, "planQty": qty, "status": ""}, token=mes_tok)
b = j(txt)
okk = b.get("code") == 0 or "已存在" in b.get("message", "")
print(" [%s] 排产 %s %s qty=%s %s" % ("OK " if okk else "FAIL", no, d, qty, b.get("message", "")))
(OK if okk else FAIL).append("排产 %s %s" % (no, d))
# ---- 备料单(按日生成,幂等:已有该日记录则跳过)----
print(" --- 备料单生成 ---")
st, txt = req(MES, "GET", "/api/v1/material-requests", token=mes_tok)
exist_dates = {m.get("planDate") for m in (d_of(txt) or []) if m.get("planDate")}
for d in [today(-1), today(0), today(1)] + ([today(4)] if ptype2_id else []):
if d in exist_dates:
skip("备料单 %s" % d, "该日已生成过")
continue
st, txt = req(MES, "POST", "/api/v1/material-requests/generate", {"planDate": d}, token=mes_tok)
b = j(txt)
cnt = (b.get("data") or {}).get("count")
print(" [%s] 生成 %s 备料单 %s%s" % ("OK " if b.get("code") == 0 else "FAIL", d, cnt, b.get("message", "")))
(OK if b.get("code") == 0 else FAIL).append("备料单 %s" % d)
# ---- 工件:进线 / 工序报工 / 拧紧 / 完工 ----
print(" --- 工件与工序 ---")
main_no = "WO-2026%s-01" % tag
sns = ["SN2026%s-0001" % tag, "SN2026%s-0002" % tag, "SN2026%s-0003" % tag,
"SN2026%s-0004" % tag, "SN2026%s-0005" % tag]
for i, sn in enumerate(sns):
st, txt = req(MES, "POST", "/api/v1/workpiece/online", {"sn": sn, "orderNo": main_no}, token=mes_tok)
b = j(txt)
print(" [%s] 进线 %s %s" % ("OK " if b.get("code") == 0 else "FAIL", sn, b.get("message", "")))
# 前 3 件走完工序 1~6,后 2 件只到工序 2(在制)
upto = 6 if i < 3 else 2
for p in range(1, upto + 1):
req(MES, "POST", "/api/v1/workpiece/process/report",
{"sn": sn, "processCode": p, "stationNo": p, "steps": []}, token=mes_tok)
print(" 工序 1~%d 已报工" % upto)
# 拧紧数据
for i, sn in enumerate(sns[:3]):
st, txt = req(MES, "POST", "/api/v1/torque/report",
{"sn": sn, "workOrder": main_no, "stationNo": "7", "screwNo": "S-%03d" % (i + 1),
"torque": 48.5 + i, "angle": 88.0 + i * 2, "result": "OK"}, token=mes_tok)
b = j(txt)
print(" [%s] 拧紧 %s torque=%.1f" % ("OK " if b.get("code") == 0 else "FAIL", sn, 48.5 + i))
# 完工 3 件
for sn in sns[:3]:
st, txt = req(MES, "POST", "/api/v1/workpiece/done",
{"sn": sn, "batchItems": [], "serialItems": []}, token=mes_tok)
b = j(txt)
print(" [%s] 完工 %s %s" % ("OK " if b.get("code") == 0 else "FAIL", sn, b.get("message", "")))
# ---- 扫码报工 ----
print(" --- 扫码报工 ---")
for i, sn in enumerate(sns[3:]):
st, txt = req(MES, "POST", "/api/v1/scan/report",
{"station": "装配工位%d" % (i + 3), "sn": sn, "orderNo": main_no,
"type": "PROCESS", "processCode": i + 1, "operator": "张装配"}, token=mes_tok)
b = j(txt)
print(" [%s] 报工 %s %s" % ("OK " if b.get("code") == 0 else "FAIL", sn, b.get("message", "")))
# ---- PLC 下发(握手:每次间隔 7s)----
print(" --- PLC 工位组合下发 ---")
for sn in sns[3:5]:
st, txt = req(MES, "POST", "/api/v1/plc/send-process",
{"orderNo": main_no, "sn": sn, "stationNo": 3, "processCombination": "1"}, token=mes_tok)
b = j(txt)
print(" [%s] 下发 %s %s" % ("OK " if b.get("code") == 0 else "FAIL", sn, b.get("message", "")))
time.sleep(7)
# ---- 巡检记录 ----
print(" --- 巡检终端 ---")
insp = [
{"category": "CHECKIN", "stationNo": "1", "shift": "早", "orderNo": main_no, "sn": "",
"result": "OK", "items": ["劳保穿戴齐全", "设备点检完成"], "photo": "", "remark": "到岗签到", "operator": "李巡检"},
{"category": "POINT", "stationNo": "7", "shift": "早", "orderNo": main_no, "sn": "",
"result": "OK", "items": ["扭矩枪校准", "气压正常"], "photo": "", "remark": "班前点检", "operator": "李巡检"},
{"category": "PROCESS", "stationNo": "3", "shift": "中", "orderNo": main_no, "sn": sns[3],
"result": "OK", "items": ["装配到位", "标识清晰"], "photo": "", "remark": "过程巡检", "operator": "王质检"},
{"category": "DONE", "stationNo": "1", "shift": "晚", "orderNo": main_no, "sn": "",
"result": "OK", "items": ["现场清理", "设备断电"], "photo": "", "remark": "收工巡检", "operator": "李巡检"},
]
for it in insp:
st, txt = req(MES, "POST", "/api/v1/inspections", it, token=mes_tok)
b = j(txt)
print(" [%s] 巡检 %s/%s %s" % ("OK " if b.get("code") == 0 else "FAIL", it["category"], it["stationNo"], b.get("message", "")))
return {"ptype_id": ptype_id, "prod_code": prod_code, "main_no": main_no, "sns": sns, "tag": tag}
# ============================== WMS 造数 ==============================
def wms_seed(wms_tok, mes_info):
print("\n===== WMS 演示数据 =====")
tag = mes_info["tag"]
main_no = mes_info["main_no"]
# ---- 库存探测:取可用批次/SN(明细接口,聚合行无批次/SN)----
allrows = fetch_details(wms_tok)
batches = [r for r in allrows if r.get("manageMode") == 1 and (r.get("quantity") or 0) > 0]
snrows = [r for r in allrows if r.get("manageMode") == 2 and (r.get("quantity") or 0) > 0]
print(" 可用批次行=%d SN行=%d" % (len(batches), len(snrows)))
for r in batches[:6]:
print(" 批次 %s %s qty=%s zone=%s" % (r.get("materialCode"), r.get("batchNo"), r.get("quantity"), r.get("zoneCode")))
for r in snrows[:6]:
print(" SN %s %s zone=%s" % (r.get("materialCode"), r.get("snCode"), r.get("zoneCode")))
# ---- 补充入库:精密件 SN(演示出库会持续消耗,先保证后续链路有货)----
print(" --- 补充入库 ---")
for code, want in [("PR-S100", 12), ("ST-A100", 2)]:
have = sum(1 for r in allrows if r.get("materialCode") == code and (r.get("quantity") or 0) > 0)
if have >= want:
skip("补入库 %s" % code, "现有 %d 已充足" % have)
continue
need = want - have
if code == "PR-S100":
body = {"inboundType": "purchase", "materialCode": code,
"snList": ["PR-S100-DEMO%03d" % i for i in range(have, have + need)],
"zoneCode": "Z02", "operator": "孙采购"}
else:
body = {"inboundType": "purchase", "materialCode": code,
"batchNo": "B-DEMO-%s" % time.strftime("%H%M%S"), "quantity": 30 * need,
"zoneCode": "Z01", "operator": "孙采购"}
st, txt = req(WMS, "POST", "/api/inbound/create", body, token=wms_tok)
step("补入库 %s x%d" % (code, need), st, txt)
allrows = fetch_details(wms_tok)
# ---- 台账同步(MES 工单 → WMS 工单备料台账)----
print(" --- 工单备料台账同步 ---")
st, txt = req(MES, "GET", "/api/v1/material-requests", token=mes_info["mes_tok"])
mrs = d_of(txt) or []
by_order = {}
for m in mrs:
by_order.setdefault(m.get("orderNo"), []).append(m)
# 幂等:已同步过的工单不再同步(sync 会把 status 重置为"进行中",会抹掉"领料完结"
st, txt = req(WMS, "GET", "/api/ledger/query?page=1&pageSize=200", token=wms_tok)
synced = {x.get("orderNo") for x in ((d_of(txt) or {}).get("list") or [])}
for no, items in by_order.items():
if no in synced:
skip("台账同步 %s" % no, "已同步过")
continue
payload = {
"orderNo": no,
"productCode": mes_info["prod_code"],
"operator": "系统同步",
"items": [{"materialCode": i.get("materialCode"), "materialName": i.get("materialName"),
"totalQty": int(i.get("reqQty") or 0)} for i in items],
}
st, txt = req(WMS, "POST", "/api/internal/ledger/sync", payload, xapi=XAPI)
b = j(txt)
print(" [%s] 台账同步 %s (%d 项) %s" % ("OK " if b.get("code") == 0 else "FAIL", no, len(items), b.get("message", "")))
(OK if b.get("code") == 0 else FAIL).append("台账同步 " + no)
# ---- 备料出库(受台账约束:累计出库 ≤ BOM 需求)----
print(" --- 备料出库(按台账)---")
st, txt = req(WMS, "GET", "/api/ledger/query?page=1&pageSize=200", token=wms_tok)
lg = (d_of(txt) or {}).get("list") or []
print(" 台账共 %d 项" % len(lg))
for item in lg:
code, total = item.get("materialCode"), item.get("totalQty") or 0
out = item.get("outQty") or 0
need = total - out
if need <= 0:
skip("备料出库 %s/%s" % (item.get("orderNo"), code), "已领料完结")
continue
cand = [r for r in allrows if r.get("materialCode") == code and (r.get("quantity") or 0) > 0]
if not cand:
skip("备料出库 %s/%s" % (item.get("orderNo"), code), "库内无可用库存")
continue
r0 = cand[0]
# 小单(需求≤6)一次领足 → 演示"领料完结";大单只领一部分 → 演示"部分领料"
want = need if need <= 6 else min(need, 3)
if r0.get("manageMode") == 2:
take = cand[:min(want, len(cand))]
body = {"orderNo": item.get("orderNo"), "materialCode": code,
"snList": [x.get("snCode") for x in take], "qty": len(take),
"operator": "刘库管", "targetDock": "DOCK03",
"zoneCode": r0.get("zoneCode"), "remark": "工单备料"}
else:
qty = min(want, r0.get("quantity") or 1)
body = {"orderNo": item.get("orderNo"), "materialCode": code, "batchNo": r0.get("batchNo"),
"qty": qty, "operator": "刘库管", "targetDock": "DOCK03",
"zoneCode": r0.get("zoneCode"), "remark": "工单备料"}
st, txt = req(WMS, "POST", "/api/outbound/create", body, token=wms_tok)
step("备料出库 %s/%s x%s" % (item.get("orderNo"), code, body["qty"]), st, txt)
# 出库后刷新库存视图,避免同一行被重复分配
allrows = fetch_details(wms_tok)
# ---- 通用出库(含装箱/合同号;用最新库存,避免与备料出库抢同一行)----
print(" --- 通用出库 ---")
allrows = fetch_details(wms_tok)
fresh_batch = [r for r in allrows if r.get("manageMode") == 1 and (r.get("quantity") or 0) > 0]
fresh_sn = [r for r in allrows if r.get("manageMode") == 2 and (r.get("quantity") or 0) > 0]
for i, (r, box, contract) in enumerate([(fresh_batch[0], "BOX-2026-001", "HT2026-0117"),
(fresh_batch[1] if len(fresh_batch) > 1 else None, "BOX-2026-002", "HT2026-0118")]):
if not r:
continue
st, txt = req(WMS, "POST", "/api/outbound/general", {
"materialCode": r.get("materialCode"), "batchNo": r.get("batchNo"),
"qty": min(3, r.get("quantity") or 1), "operator": "刘库管",
"zoneCode": r.get("zoneCode"), "boxNo": box, "contractNo": contract,
"remark": "销售发货",
}, token=wms_tok)
step("通用出库 %s/%s" % (r.get("materialCode"), box), st, txt)
# SN 出库(挑库内仍可用的 SN
s0 = next((r for r in fresh_sn if r.get("materialCode") == "PR-S100"), fresh_sn[0] if fresh_sn else None)
if s0:
st, txt = req(WMS, "POST", "/api/outbound/general", {
"materialCode": s0.get("materialCode"), "snList": [s0.get("snCode")],
"operator": "刘库管", "zoneCode": s0.get("zoneCode"),
"boxNo": "BOX-2026-003", "contractNo": "HT2026-0119", "remark": "精密件领用",
}, token=wms_tok)
step("通用出库 SN %s" % s0.get("snCode"), st, txt)
# ---- 半成品入库 ----
print(" --- 半成品管理 ---")
semi_plan = [
("BP-2026%s-001" % tag, "BCP-JIEKOUTI", [1, 2, 3], "装配三", "Z02", main_no),
("BP-2026%s-002" % tag, "BCP-JIEKOUTI", [1, 2], "装配二", "Z02", main_no),
("BP-2026%s-003" % tag, "BCP-JIEKOUTI", [1, 2, 3, 4, 5, 6], "装配六", "Z02", main_no),
("BP-2026%s-004" % tag, "BCP-JIEKOUTI", [1], "装配一", "Z02", main_no),
]
for sn, mat, done, comp, zone, order in semi_plan:
st, txt = req(WMS, "POST", "/api/semi/inbound", {
"sn": sn, "materialCode": mat, "doneProcessCodes": done,
"completedProcess": comp, "zoneCode": zone, "orderNo": order, "operator": "陈产线",
}, token=wms_tok)
step("半成品入库 %s" % sn, st, txt)
# ---- 盘点 ----
print(" --- 库存盘点 ---")
st, txt = req(WMS, "GET", "/api/stocktake/query", token=wms_tok)
existing = (d_of(txt) or {}).get("list") or []
if existing:
skip("发起盘点", "已存在 %d 张盘点单" % len(existing))
else:
zone_pick = []
for r in allrows[:60]:
z = r.get("zoneCode")
if z and z not in zone_pick:
zone_pick.append(z)
if len(zone_pick) >= 2:
break
st, txt = req(WMS, "POST", "/api/stocktake/start", {"operator": "赵盘点", "zones": zone_pick}, token=wms_tok)
b = j(txt)
st_no = (b.get("data") or {}).get("stocktakeNo") if b.get("code") == 0 else None
print(" [%s] 发起盘点 zones=%s no=%s %s" % ("OK " if st_no else "FAIL", zone_pick, st_no, b.get("message", "")))
if st_no:
OK.append("发起盘点")
st, txt = req(WMS, "GET", "/api/stocktake/query?stocktakeNo=" + st_no + "&pageSize=200", token=wms_tok)
bb = j(txt)
items = (bb.get("data") or {}).get("list") or []
print(" 盘点项 %d 条" % len(items))
# 录入前 8 条实盘:前 6 条账实相符,后 2 条制造差异
for i, it in enumerate(items[:8]):
tid = it.get("target_id")
if not tid:
continue
sysq = it.get("book_qty") or 1
scan = sysq if i < 6 else max(0, sysq - 1)
req(WMS, "POST", "/api/stocktake/record", {
"stocktakeNo": st_no, "targetType": it.get("target_type") or "",
"targetId": tid, "scanQty": scan}, token=wms_tok)
print(" 已录入 8 条实盘(含 2 条差异)")
st, txt = req(WMS, "POST", "/api/stocktake/finish", {"stocktakeNo": st_no, "adjust": True}, token=wms_tok)
step("完成盘点 %s" % st_no, st, txt)
# ---- AGV 配送 ----
print(" --- AGV 配送 ---")
rows_payload = []
for i, m in enumerate((d_of(req(MES, "GET", "/api/v1/material-requests", token=mes_info["mes_tok"])[1]) or [])[:4]):
rows_payload.append({
"requestNo": m.get("requestNo"), "materialCode": m.get("materialCode"),
"materialName": m.get("materialName"), "unit": m.get("unit") or "件",
"qty": float(m.get("reqQty") or 1), "targetDock": "DOCK%02d" % (i + 1),
})
if rows_payload:
st, txt = req(WMS, "POST", "/api/agv/submit", {"rows": rows_payload, "sourceDock": "DOCK21"}, token=wms_tok)
step("AGV 下发 %d 行" % len(rows_payload), st, txt)
# ============================== main ==============================
def main():
mode = sys.argv[1] if len(sys.argv) > 1 else "all"
print("=" * 70)
print("演示数据落库 WMS=%s MES=%s" % (WMS, MES))
print("=" * 70)
wms_tok = login_wms()
mes_tok = login_mes()
if not wms_tok:
print("WMS 登录失败")
sys.exit(1)
if not mes_tok:
print("MES 登录失败")
sys.exit(1)
print("登录成功")
if mode == "inspect":
inspect(wms_tok, mes_tok)
return
mes_info = mes_seed(mes_tok, wms_tok)
mes_info["mes_tok"] = mes_tok
wms_seed(wms_tok, mes_info)
print("\n" + "=" * 70)
print("成功 %d / 失败 %d / 跳过 %d" % (len(OK), len(FAIL), len(SKIP)))
if FAIL:
print("失败项:")
for f in FAIL:
print(" - " + f)
print("=" * 70)
if __name__ == "__main__":
main()