Files
shanxia2.0/backend/app/crud/qc_task.py
T
2026-05-17 23:08:38 +08:00

267 lines
8.1 KiB
Python

"""质检任务 CRUD"""
from __future__ import annotations
from datetime import datetime
from decimal import Decimal
from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.crud.collection_protocol import urls_to_attachment_list
from app.models.models import BizQcTask, BizQcWorkOrder
def _dec(v: Any) -> Optional[float]:
if v is None:
return None
return float(v)
def _fmt_dt(t: Optional[datetime]) -> str:
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
def _gen_task_no(db: Session, work_order: BizQcWorkOrder, seq: int) -> str:
return f"{work_order.work_order_no}-{seq:02d}"
def _task_to_dict(t: BizQcTask, work_order_no: str = "") -> Dict[str, Any]:
return {
"id": t.id,
"workOrderId": t.work_order_id,
"workOrderNo": work_order_no,
"taskNo": t.task_no,
"taskType": t.task_type,
"sourceLineId": t.source_line_id,
"itemCode": t.item_code,
"itemName": t.item_name,
"companyId": t.company_id or "",
"companyName": t.company_name or "",
"feeAmount": _dec(t.fee_amount),
"taskStatus": t.task_status,
"thirdPartyAttachments": t.third_party_attachments or "",
"completedTime": _fmt_dt(t.completed_time),
"completedBy": t.completed_by or "",
"remark": t.remark or "",
"createTime": _fmt_dt(t.create_time),
"updateTime": _fmt_dt(t.update_time),
}
def create_task_for_line(
db: Session,
*,
work_order: BizQcWorkOrder,
task_type: str,
source_line_id: str,
item_code: str,
item_name: str,
tenant_no: str,
user_id: Optional[str] = None,
create_dept_id: str = "",
seq: int = 1,
company_id: Optional[str] = None,
company_name: Optional[str] = None,
fee_amount: Optional[Decimal] = None,
) -> BizQcTask:
obj = BizQcTask(
id=generate_uuid(),
work_order_id=work_order.id,
task_no=_gen_task_no(db, work_order, seq),
task_type=task_type,
source_line_id=source_line_id,
item_code=item_code,
item_name=item_name,
company_id=company_id,
company_name=company_name,
fee_amount=fee_amount,
task_status="dzx",
tenant_no=tenant_no,
order_num=seq,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(obj)
db.flush()
return obj
def list_tasks(
db: Session,
*,
page: int = 1,
page_size: int = 10,
keyword: Optional[str] = None,
task_type: Optional[str] = None,
task_status: Optional[str] = None,
work_order_id: Optional[str] = None,
tenant_no: Optional[str] = None,
) -> Tuple[List[Dict[str, Any]], int]:
def _filtered():
q0 = (
db.query(BizQcTask, BizQcWorkOrder.work_order_no)
.join(
BizQcWorkOrder,
and_(
BizQcWorkOrder.id == BizQcTask.work_order_id,
BizQcWorkOrder.del_flag == 0,
),
)
.filter(BizQcTask.del_flag == 0)
)
if tenant_no:
q0 = q0.filter(BizQcTask.tenant_no == tenant_no)
if work_order_id:
q0 = q0.filter(BizQcTask.work_order_id == work_order_id)
kw = (keyword or "").strip()
if kw:
like = f"%{kw}%"
q0 = q0.filter(
or_(
BizQcTask.task_no.like(like),
BizQcTask.item_name.like(like),
BizQcWorkOrder.work_order_no.like(like),
)
)
tt = (task_type or "").strip()
if tt:
q0 = q0.filter(BizQcTask.task_type == tt)
st = (task_status or "").strip()
if st:
q0 = q0.filter(BizQcTask.task_status == st)
return q0
total = _filtered().order_by(None).with_entities(func.count(BizQcTask.id)).scalar() or 0
page = max(1, page)
page_size = min(max(1, page_size), 100)
rows = (
_filtered()
.order_by(
BizQcTask.create_time.desc(),
BizQcWorkOrder.work_order_no.desc(),
BizQcTask.task_no.asc(),
)
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
return [_task_to_dict(t, wno or "") for t, wno in rows], int(total)
def list_tasks_by_work_order(db: Session, work_order_id: str, tenant_no: str) -> List[Dict[str, Any]]:
rows = (
db.query(BizQcTask, BizQcWorkOrder.work_order_no)
.join(BizQcWorkOrder, BizQcWorkOrder.id == BizQcTask.work_order_id)
.filter(
BizQcTask.work_order_id == work_order_id,
BizQcTask.tenant_no == tenant_no,
BizQcTask.del_flag == 0,
)
.order_by(BizQcTask.order_num.asc())
.all()
)
return [_task_to_dict(t, wno or "") for t, wno in rows]
def get_task(
db: Session, row_id: str, tenant_no: Optional[str] = None
) -> Optional[BizQcTask]:
q = db.query(BizQcTask).filter(BizQcTask.id == row_id, BizQcTask.del_flag == 0)
if tenant_no:
q = q.filter(BizQcTask.tenant_no == tenant_no)
return q.first()
def get_task_detail(db: Session, row_id: str, tenant_no: str) -> Dict[str, Any]:
row = (
db.query(BizQcTask, BizQcWorkOrder)
.join(BizQcWorkOrder, BizQcWorkOrder.id == BizQcTask.work_order_id)
.filter(BizQcTask.id == row_id, BizQcTask.tenant_no == tenant_no, BizQcTask.del_flag == 0)
.first()
)
if not row:
raise ValueError("任务不存在")
t, wo = row
out = _task_to_dict(t, wo.work_order_no or "")
out["protocolNo"] = wo.protocol_no or ""
out["sampleCode"] = wo.sample_code or ""
out["attachmentFiles"] = urls_to_attachment_list(t.third_party_attachments, db, tenant_no)
return out
def start_task(db: Session, row_id: str, *, tenant_no: str, user_id: Optional[str]) -> BizQcTask:
t = get_task(db, row_id, tenant_no=tenant_no)
if not t:
raise ValueError("任务不存在")
if t.task_type != "sysz":
raise ValueError("仅实验室自检任务可开始")
if t.task_status != "dzx":
raise ValueError("当前状态不可开始")
t.task_status = "jxz"
t.update_by = user_id
t.update_time = datetime.now()
db.add(t)
db.commit()
db.refresh(t)
return t
def complete_task(db: Session, row_id: str, *, tenant_no: str, user_id: Optional[str]) -> BizQcTask:
t = get_task(db, row_id, tenant_no=tenant_no)
if not t:
raise ValueError("任务不存在")
if t.task_type == "sysz":
if t.task_status not in ("dzx", "jxz"):
raise ValueError("当前状态不可完成")
elif t.task_type == "dsfjc":
if not (t.third_party_attachments or "").strip():
raise ValueError("请先上传第三方检测材料")
if t.task_status == "ywc":
raise ValueError("任务已完成")
else:
raise ValueError("任务类型无效")
t.task_status = "ywc"
t.completed_time = datetime.now()
t.completed_by = user_id
t.update_by = user_id
t.update_time = datetime.now()
db.add(t)
db.commit()
db.refresh(t)
from app.crud import qc_work_order as wo_svc
wo_svc.try_complete_work_order(db, t.work_order_id, tenant_no)
return t
def update_task_attachments(
db: Session,
row_id: str,
*,
attachments: str,
tenant_no: str,
user_id: Optional[str],
) -> BizQcTask:
t = get_task(db, row_id, tenant_no=tenant_no)
if not t:
raise ValueError("任务不存在")
if t.task_type != "dsfjc":
raise ValueError("仅第三方检测任务可上传材料")
if t.task_status == "ywc":
raise ValueError("任务已完成,不可修改附件")
t.third_party_attachments = (attachments or "").strip() or None
if t.task_status == "dzx" and t.third_party_attachments:
t.task_status = "jxz"
t.update_by = user_id
t.update_time = datetime.now()
db.add(t)
db.commit()
db.refresh(t)
return t