feat: Track 打通已完成/已入库/已出库状态闭环与外部联动
- 完工转交入库同步 status=COMPLETED;MOM 入库/出库回调同步 status - 新增 mom-outbound webhook(发货出库标记已出库),lookup 返回 material_id - VALID_OVERALL_STATUS 新增已出库;update_overall_status 同步 status 字段 - WIP 矩阵区分已入库/待仓库收货;虚拟节点正确处理已出库/转入在库人
This commit is contained in:
@ -160,12 +160,27 @@ async def get_dashboard_stats(
|
||||
)
|
||||
from app.models.notification import Notification
|
||||
from app.models.message import ProductMessage
|
||||
|
||||
# ── 产品(实时快照,不过滤) ──
|
||||
# 状态口径(用户确认):废弃 Product.status 恒值判断,
|
||||
# COMPLETED=待仓库收货,ARCHIVED=已入库('在库' 旧命名等价)。
|
||||
# 产品流转卡片第三段"已入库"= 全部完结(待收货 + 已实收 + 旧在库),保证三段和 = 总数。
|
||||
p_total = await db.scalar(select(func.count(Product.id)))
|
||||
p_pending = await db.scalar(select(func.count(Product.id)).where(Product.status == "pending"))
|
||||
p_progress = await db.scalar(select(func.count(Product.id)).where(Product.status == "in_progress"))
|
||||
p_done = await db.scalar(select(func.count(Product.id)).where(Product.status == "completed"))
|
||||
|
||||
finished_cond = Product.overall_status.in_(["待仓库收货", "已入库", "在库"])
|
||||
p_done = await db.scalar(select(func.count(Product.id)).where(finished_cond))
|
||||
|
||||
# 在制 WIP = 未完结 且 存在活跃任务(PENDING/WIP) 的产品数
|
||||
not_finished = or_(Product.overall_status.is_(None), ~finished_cond)
|
||||
has_active_task = select(Task.id).where(
|
||||
Task.product_id == Product.id,
|
||||
Task.status.in_([TASK_STATUS_PENDING, TASK_STATUS_WIP]),
|
||||
).exists()
|
||||
p_progress = await db.scalar(
|
||||
select(func.count(Product.id)).where(not_finished, has_active_task)
|
||||
)
|
||||
|
||||
# 待流转 = 总数 - 在制 - 完结(三段互斥,保证进度条总和=总数)
|
||||
p_pending = max((p_total or 0) - (p_progress or 0) - (p_done or 0), 0)
|
||||
|
||||
# ── 任务实时快照(PENDING/WIP/返工 — 永远不过滤) ──
|
||||
t_pending = await db.scalar(select(func.count(Task.id)).where(Task.status == TASK_STATUS_PENDING))
|
||||
@ -639,6 +654,8 @@ async def get_wip_matrix(
|
||||
Task.assignee_id,
|
||||
Task.created_at,
|
||||
Product.current_location_id,
|
||||
Product.overall_status,
|
||||
Product.status,
|
||||
)
|
||||
.join(Task, Task.product_id == Product.id)
|
||||
.where(
|
||||
@ -654,7 +671,7 @@ async def get_wip_matrix(
|
||||
# 每台设备 → (spec, 当前工序/负责人, 当前负责人ID)
|
||||
device_cur: dict[str, tuple] = {}
|
||||
seen: set[str] = set()
|
||||
for pid, spec, task_name, assignee, created, loc in rows:
|
||||
for pid, spec, task_name, assignee, created, loc, overall_status, product_status in rows:
|
||||
if pid in seen:
|
||||
continue
|
||||
seen.add(pid)
|
||||
@ -668,10 +685,15 @@ async def get_wip_matrix(
|
||||
continue
|
||||
|
||||
if dimension == "task_name":
|
||||
# 🔧 在库按设备实际位置判断:virtual_warehouse → 在库(生产完成)
|
||||
# 🔧 在仓库的设备按"已完成/已入库"区分:
|
||||
# 已入库 = MOM 已扫码实收 (overall_status=='已入库'/'在库' 或 status=='ARCHIVED')
|
||||
# 待仓库收货 = 完工已转交仓库、MOM 尚未扫码实收
|
||||
# 否则按最新主任务工序名(活跃/完成态都归该工序)
|
||||
if loc == "virtual_warehouse":
|
||||
key = "在库"
|
||||
if overall_status in ("已入库", "在库") or str(product_status).upper() == "ARCHIVED":
|
||||
key = "已入库"
|
||||
else:
|
||||
key = "待仓库收货"
|
||||
else:
|
||||
key = task_name or "—"
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user