Files
bj_power/demo_seed.py
T
SunYF 92f0439d89 feat: 新增产线看板功能并优化多端系统体验
1. 新增SSE看板广播机制,业务操作后主动推送刷新事件
2. 新增产线工序横道图与工位状态展示面板
3. 移除dashboard无用的three.js依赖
4. 重构WMS客户端布局与WMS前端资源哈希
5. 新增工位终端时钟图标与大屏自适应布局
6. 新增系统截图脚本与说明书生成工具
7. 修复多处代码细节与空值处理逻辑
2026-09-04 17:31:18 +08:00

538 lines
26 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()