PayrollManagementSystem/backend/app/services/tplus/progress.py

68 lines
3.3 KiB
Python
Raw Normal View History

"""批次读取进度元数据;只暴露类别和数量,不携带业务原始载荷。"""
import copy
from datetime import datetime
from app.services.tplus.mapping import DETAIL_MAPPINGS, TPLUS_MAPPINGS
ENTITIES = frozenset(mapping.entity_type for mapping in (*TPLUS_MAPPINGS, *DETAIL_MAPPINGS))
def write(batch, *, phase=None, totals=None, active=None, read=None, done=None, failed=None):
report = copy.deepcopy(batch.audit_result_json or {})
value = report.setdefault("progress", {"phase": "COUNTING", "entities": {}})
if phase:
value["phase"] = phase
if totals is not None:
value["total_records"] = sum(totals.values())
for entity, count in totals.items():
value["entities"][entity] = {"total": count, "processed": 0, "status": "WAITING"}
if active is not None:
value["active_entity"] = active
value["entities"].setdefault(active, {"total": None, "processed": 0})["status"] = "READING"
if read is not None and value.get("active_entity"):
value["entities"][value["active_entity"]]["processed"] = read
if done:
value["entities"][done]["status"] = "COMPLETED"
if failed:
value["entities"].setdefault(failed, {"total": None, "processed": 0})["status"] = "FAILED"
value["updated_at"] = datetime.now().isoformat()
batch.audit_result_json = report
def public(batch, report=None):
"""旧任务总量未知时不给百分比;成功必须以批次终态为准。"""
report = report or batch.__dict__.get("audit_result_json") or {}
value = report.get("progress") or {}
if not isinstance(value, dict):
value = {}
total = value.get("total_records")
total = total if isinstance(total, int) and not isinstance(total, bool) and total >= 0 else None
processed = batch.source_record_count
status = batch.status
percentage = None
if status == "SUCCEEDED":
total, percentage = processed, 100.0
elif total and processed >= 0:
percentage = min(99.9, round(processed * 100 / total, 1))
entities = []
observed = report.get("observed_entities", [])
for entity in batch.entity_types_json or []:
if not isinstance(entity, str) or entity not in ENTITIES:
continue
details = value.get("entities", {}).get(entity, {})
count = details.get("total")
entities.append({"entity_type": entity, "total_records": count,
"processed_records": details.get("processed"),
"status": details.get("status", "COMPLETED" if entity in observed else "WAITING")})
updated = value.get("updated_at")
try:
updated = datetime.fromisoformat(updated) if updated else None
except (ValueError, TypeError):
updated = None
elapsed = max(0, int(((batch.finished_at or datetime.now()) - batch.started_at).total_seconds())) if batch.started_at else 0
phase = "COMPLETED" if status == "SUCCEEDED" else "FAILED" if status in ("FAILED", "PARTIAL") else value.get("phase", status)
return {"phase": phase, "total_records": total, "processed_records": processed,
"percentage": percentage, "active_entity": value.get("active_entity")
if value.get("active_entity") in ENTITIES else None,
"updated_at": updated, "elapsed_seconds": elapsed, "entities": entities}