fix: WIP矩阵口径重构-在制无条件计入,终结态按完工时间锚点(completed_at兜底created_at)过滤,多维终结归类(含扫码入库/出库节点),下钻同步
This commit is contained in:
@ -652,7 +652,9 @@ async def get_wip_matrix(
|
||||
- 其他已完成工序(如「测试」完成)按原工序显示,不强制归仓库态
|
||||
|
||||
这样一台设备在「上一步已完成 + 下一步待确认」时只算一次(待确认),不会重复计数。
|
||||
since/until 按设备最新主任务的创建时间过滤。
|
||||
since/until 时间过滤为“动静分离”:仅对 终结(收口/在库/出库) 设备过滤,锚点取
|
||||
最新主线任务的 completed_at(完工/变动时间,兜底 created_at,schema 无 updated_at);
|
||||
在制(未收口)设备无条件全量计入,保证与人员看板实时在制不脱节。
|
||||
|
||||
dimension:
|
||||
- assignee: 按当前任务负责人聚合(dimension_key 为中文姓名)
|
||||
@ -671,6 +673,7 @@ async def get_wip_matrix(
|
||||
Task.task_name,
|
||||
Task.assignee_id,
|
||||
Task.created_at,
|
||||
Task.completed_at,
|
||||
Product.current_location_id,
|
||||
Product.overall_status,
|
||||
Product.status,
|
||||
@ -679,7 +682,7 @@ async def get_wip_matrix(
|
||||
.where(
|
||||
or_(
|
||||
Task.parent_task_id.is_(None),
|
||||
Task.task_type.in_(["TRANSFER", "RECOVERY"]),
|
||||
Task.task_type.in_(["TRANSFER", "RECOVERY", "WAREHOUSE"]),
|
||||
)
|
||||
)
|
||||
.order_by(Product.id, Task.created_at.desc())
|
||||
@ -689,33 +692,43 @@ async def get_wip_matrix(
|
||||
# 每台设备 → (spec, 当前工序/负责人, 当前负责人ID)
|
||||
device_cur: dict[str, tuple] = {}
|
||||
seen: set[str] = set()
|
||||
for pid, spec, product_name, task_name, assignee, created, loc, overall_status, product_status in rows:
|
||||
for pid, spec, product_name, task_name, assignee, created, completed, loc, overall_status, product_status in rows:
|
||||
if pid in seen:
|
||||
continue
|
||||
seen.add(pid)
|
||||
|
||||
# 时间筛选:设备最新主任务的创建时间
|
||||
if created is not None and created.tzinfo is None:
|
||||
created = created.replace(tzinfo=dt_timezone.utc)
|
||||
if since and created is not None and created < since:
|
||||
continue
|
||||
if until and created is not None and created > until:
|
||||
continue
|
||||
# ── 真实产出时间锚点:完工/变动时间优先,创建时间仅兜底 ──
|
||||
# 说明:tasks 表无 updated_at 列(已核实 information_schema),故锚点取
|
||||
# completed_at or created_at;若后续新增 updated_at 可并入。
|
||||
anchor = completed or created
|
||||
|
||||
# ── 动静分离:仅终结(收口/在库/出库)设备按 since~until 过滤;在制设备无条件全量 ──
|
||||
is_terminal = (
|
||||
loc == "virtual_warehouse"
|
||||
or overall_status in ("待仓库收货", "已入库", "在库", "已出库")
|
||||
or str(product_status).upper() in ("ARCHIVED", "OUTBOUND")
|
||||
or task_name in ("扫码入库", "扫码出库")
|
||||
)
|
||||
if is_terminal:
|
||||
if anchor is not None and anchor.tzinfo is None:
|
||||
anchor = anchor.replace(tzinfo=dt_timezone.utc)
|
||||
if since and anchor is not None and anchor < since:
|
||||
continue
|
||||
if until and anchor is not None and anchor > until:
|
||||
continue
|
||||
# else: 在制设备无视时间参数,保证与人员看板“实时在制”总数一致
|
||||
|
||||
if dimension == "task_name":
|
||||
# 🔧 在仓库的设备按"已入库/已出库/待仓库收货"区分:
|
||||
# 已入库 = MOM 已扫码实收 (overall_status=='已入库'/'在库' 或 status=='ARCHIVED')
|
||||
# 已出库 = MOM 已发货出库 (overall_status=='已出库' 或 status=='OUTBOUND')
|
||||
# 待仓库收货 = 完工已转交仓库、MOM 尚未扫码实收
|
||||
# 否则按最新主任务工序名(活跃/完成态都归该工序)
|
||||
if loc == "virtual_warehouse":
|
||||
# 统一术语:待仓库收货(车间完工) → "已完成";扫码实收 → "已入库";已出库保持
|
||||
if overall_status in ("已入库", "在库") or str(product_status).upper() == "ARCHIVED":
|
||||
key = "已入库"
|
||||
elif overall_status == "已出库" or str(product_status).upper() == "OUTBOUND":
|
||||
key = "已出库"
|
||||
else:
|
||||
key = "已完成"
|
||||
# ── 终结三列判定(多维防御,不依赖单一 loc / overall)──
|
||||
# 已入库: 整体实收(已入库/在库) 或 status==ARCHIVED 或 收口节点「扫码入库」
|
||||
if overall_status in ("已入库", "在库") or str(product_status).upper() == "ARCHIVED" or task_name == "扫码入库":
|
||||
key = "已入库"
|
||||
# 已出库: 整体已出库 或 status==OUTBOUND 或 收口节点「扫码出库」
|
||||
elif overall_status == "已出库" or str(product_status).upper() == "OUTBOUND" or task_name == "扫码出库":
|
||||
key = "已出库"
|
||||
# 已完成: 车间完工待实收(待仓库收货) 或 处于仓库(未实收/未出库)
|
||||
elif overall_status == "待仓库收货" or loc == "virtual_warehouse":
|
||||
key = "已完成"
|
||||
else:
|
||||
key = task_name or "—"
|
||||
else:
|
||||
@ -796,13 +809,14 @@ async def get_wip_matrix_detail(
|
||||
Task.assignee_id,
|
||||
Task.status.label("task_status"),
|
||||
Task.created_at,
|
||||
Task.completed_at,
|
||||
Task.received_at,
|
||||
)
|
||||
.join(Task, Task.product_id == Product.id)
|
||||
.where(
|
||||
or_(
|
||||
Task.parent_task_id.is_(None),
|
||||
Task.task_type.in_(["TRANSFER", "RECOVERY"]),
|
||||
Task.task_type.in_(["TRANSFER", "RECOVERY", "WAREHOUSE"]),
|
||||
)
|
||||
)
|
||||
.order_by(Product.id, Task.created_at.desc())
|
||||
@ -814,7 +828,7 @@ async def get_wip_matrix_detail(
|
||||
matched: list[WipMatrixDetailRow] = []
|
||||
raw_names: set[str] = set()
|
||||
|
||||
for pid, serial, ext, mat_name, spec, loc, overall, pstatus, task_name, assignee, tstatus, created, received in rows:
|
||||
for pid, serial, ext, mat_name, spec, loc, overall, pstatus, task_name, assignee, tstatus, created, completed, received in rows:
|
||||
if pid in seen:
|
||||
continue
|
||||
seen.add(pid)
|
||||
@ -822,22 +836,32 @@ async def get_wip_matrix_detail(
|
||||
if spec_model and (spec or "") != spec_model:
|
||||
continue
|
||||
|
||||
# 时间筛选(设备最新主任务创建时间)
|
||||
if created is not None and created.tzinfo is None:
|
||||
created = created.replace(tzinfo=dt_timezone.utc)
|
||||
if since and created is not None and created < since:
|
||||
continue
|
||||
if until and created is not None and created > until:
|
||||
continue
|
||||
# ── 真实产出时间锚点:完工/变动时间优先,创建时间仅兜底(schema 无 updated_at)──
|
||||
anchor = completed or created
|
||||
|
||||
# 当前工序归类(与 get_wip_matrix 一致)
|
||||
if loc == "virtual_warehouse":
|
||||
if overall in ("已入库", "在库") or str(pstatus).upper() == "ARCHIVED":
|
||||
key = "已入库"
|
||||
elif overall == "已出库" or str(pstatus).upper() == "OUTBOUND":
|
||||
key = "已出库"
|
||||
else:
|
||||
key = "已完成"
|
||||
# ── 动静分离:仅终结(收口/在库/出库)设备按 since~until 过滤;在制设备无条件全量 ──
|
||||
is_terminal = (
|
||||
loc == "virtual_warehouse"
|
||||
or overall in ("待仓库收货", "已入库", "在库", "已出库")
|
||||
or str(pstatus).upper() in ("ARCHIVED", "OUTBOUND")
|
||||
or task_name in ("扫码入库", "扫码出库")
|
||||
)
|
||||
if is_terminal:
|
||||
if anchor is not None and anchor.tzinfo is None:
|
||||
anchor = anchor.replace(tzinfo=dt_timezone.utc)
|
||||
if since and anchor is not None and anchor < since:
|
||||
continue
|
||||
if until and anchor is not None and anchor > until:
|
||||
continue
|
||||
# else: 在制设备无视时间参数,保证与人员看板“实时在制”总数一致
|
||||
|
||||
# ── 终结三列判定(与 get_wip_matrix 一字不差同步,多维防御)──
|
||||
if overall in ("已入库", "在库") or str(pstatus).upper() == "ARCHIVED" or task_name == "扫码入库":
|
||||
key = "已入库"
|
||||
elif overall == "已出库" or str(pstatus).upper() == "OUTBOUND" or task_name == "扫码出库":
|
||||
key = "已出库"
|
||||
elif overall == "待仓库收货" or loc == "virtual_warehouse":
|
||||
key = "已完成"
|
||||
else:
|
||||
key = task_name or "—"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user