feat(crud): add production work order CRUD operations
This commit is contained in:
1 parent
026b040db5
commit
9d9f43579d
1 file changed
+266
@@ -0,0 +1,266 @@
|
||||
"""入库生产工单 CRUD"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from sqlalchemy import func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.utils import generate_uuid
|
||||
from app.models.models import (
|
||||
BizCollectionProtocol,
|
||||
BizProductionWorkOrder,
|
||||
BizProtocolSample,
|
||||
BizSampleReception,
|
||||
)
|
||||
from app.models.research_donation import BizResearchDonation, BizResearchDonationSample
|
||||
from app.schemas.production_work_order import ProductionWorkOrderComplete, ProductionWorkOrderListQuery
|
||||
|
||||
_WORK_ORDER_STATUS_LABELS = {
|
||||
"dpz": "待配置",
|
||||
"ypz": "已配置",
|
||||
"jxz": "执行中",
|
||||
"ywc": "已完成",
|
||||
"yzf": "已作废",
|
||||
}
|
||||
_RECEPTION_SOURCE_LABELS = {
|
||||
"cell_storage": "细胞存储",
|
||||
"research_donation": "科研捐赠",
|
||||
}
|
||||
|
||||
|
||||
def _fmt_dt(t: Optional[datetime]) -> str:
|
||||
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
|
||||
|
||||
|
||||
def _generate_work_order_no(db: Session, tenant_no: str) -> str:
|
||||
today_str = datetime.now().strftime("%Y%m%d")
|
||||
prefix = f"SC{today_str}"
|
||||
last = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.work_order_no.like(f"{prefix}%"),
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.order_by(BizProductionWorkOrder.work_order_no.desc())
|
||||
.first()
|
||||
)
|
||||
seq = 1
|
||||
if last:
|
||||
seq = int(last.work_order_no[-4:]) + 1
|
||||
return f"{prefix}{seq:04d}"
|
||||
|
||||
|
||||
def _wo_to_dict(wo: BizProductionWorkOrder) -> Dict[str, Any]:
|
||||
return {
|
||||
"id": wo.id,
|
||||
"workOrderNo": wo.work_order_no,
|
||||
"receptionId": wo.reception_id,
|
||||
"protocolSampleId": wo.protocol_sample_id,
|
||||
"collectionProtocolId": wo.collection_protocol_id,
|
||||
"protocolNo": wo.protocol_no or "",
|
||||
"sampleCode": wo.sample_code or "",
|
||||
"receptionSource": getattr(wo, "reception_source", "cell_storage") or "cell_storage",
|
||||
"receptionSourceLabel": _RECEPTION_SOURCE_LABELS.get(
|
||||
getattr(wo, "reception_source", "cell_storage") or "cell_storage",
|
||||
getattr(wo, "reception_source", "cell_storage") or "cell_storage",
|
||||
),
|
||||
"workOrderStatus": wo.work_order_status,
|
||||
"workOrderStatusLabel": _WORK_ORDER_STATUS_LABELS.get(wo.work_order_status, wo.work_order_status),
|
||||
"remark": wo.remark or "",
|
||||
"createTime": _fmt_dt(wo.create_time),
|
||||
"updateTime": _fmt_dt(wo.update_time),
|
||||
}
|
||||
|
||||
|
||||
def create_production_work_order_from_reception(
|
||||
db: Session,
|
||||
reception: BizSampleReception,
|
||||
tenant_no: str,
|
||||
user_id: Optional[str] = None,
|
||||
create_dept_id: str = "",
|
||||
) -> Optional[BizProductionWorkOrder]:
|
||||
"""接收结论为 js 时创建待配置入库生产工单(flush,不 commit)。"""
|
||||
if (reception.accept_conclusion or "").strip() != "js":
|
||||
return None
|
||||
exists = (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.reception_id == reception.id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if exists:
|
||||
return exists
|
||||
|
||||
source = getattr(reception, "reception_source", "cell_storage") or "cell_storage"
|
||||
|
||||
if source == "research_donation":
|
||||
protocol_no = ""
|
||||
d = (
|
||||
db.query(BizResearchDonation)
|
||||
.filter(
|
||||
BizResearchDonation.id == (reception.research_donation_id or ""),
|
||||
BizResearchDonation.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if d:
|
||||
protocol_no = d.donation_no or ""
|
||||
sample_code = ""
|
||||
ds = (
|
||||
db.query(BizResearchDonationSample)
|
||||
.filter(
|
||||
BizResearchDonationSample.id == (reception.donation_sample_id or ""),
|
||||
BizResearchDonationSample.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if ds:
|
||||
sample_code = ds.sample_code or ""
|
||||
wo = BizProductionWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_generate_work_order_no(db, tenant_no),
|
||||
reception_id=reception.id,
|
||||
protocol_sample_id=reception.donation_sample_id or "",
|
||||
collection_protocol_id=reception.research_donation_id or "",
|
||||
protocol_no=protocol_no or None,
|
||||
sample_code=sample_code or None,
|
||||
reception_source="research_donation",
|
||||
work_order_status="dpz",
|
||||
tenant_no=tenant_no,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
else:
|
||||
protocol_no = ""
|
||||
p = (
|
||||
db.query(BizCollectionProtocol)
|
||||
.filter(
|
||||
BizCollectionProtocol.id == reception.collection_protocol_id,
|
||||
BizCollectionProtocol.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if p:
|
||||
protocol_no = p.protocol_no or ""
|
||||
sample_code = ""
|
||||
s = (
|
||||
db.query(BizProtocolSample)
|
||||
.filter(
|
||||
BizProtocolSample.id == reception.protocol_sample_id,
|
||||
BizProtocolSample.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if s:
|
||||
sample_code = s.sample_code or ""
|
||||
wo = BizProductionWorkOrder(
|
||||
id=generate_uuid(),
|
||||
work_order_no=_generate_work_order_no(db, tenant_no),
|
||||
reception_id=reception.id,
|
||||
protocol_sample_id=reception.protocol_sample_id,
|
||||
collection_protocol_id=reception.collection_protocol_id,
|
||||
protocol_no=protocol_no or None,
|
||||
sample_code=sample_code or None,
|
||||
reception_source="cell_storage",
|
||||
work_order_status="dpz",
|
||||
tenant_no=tenant_no,
|
||||
create_by=user_id,
|
||||
create_dept_id=create_dept_id or "",
|
||||
update_by=user_id,
|
||||
create_time=datetime.now(),
|
||||
update_time=datetime.now(),
|
||||
del_flag=0,
|
||||
)
|
||||
db.add(wo)
|
||||
db.flush()
|
||||
return wo
|
||||
|
||||
|
||||
def list_production_work_orders(
|
||||
db: Session,
|
||||
*,
|
||||
tenant_no: str,
|
||||
query: Optional[ProductionWorkOrderListQuery] = None,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
) -> Dict[str, Any]:
|
||||
def _filtered():
|
||||
q0 = db.query(BizProductionWorkOrder).filter(BizProductionWorkOrder.del_flag == 0)
|
||||
q0 = q0.filter(BizProductionWorkOrder.tenant_no == tenant_no)
|
||||
if not query:
|
||||
return q0
|
||||
if query.work_order_no and query.work_order_no.strip():
|
||||
like = f"%{query.work_order_no.strip()}%"
|
||||
q0 = q0.filter(BizProductionWorkOrder.work_order_no.like(like))
|
||||
if query.work_order_status and query.work_order_status.strip():
|
||||
q0 = q0.filter(BizProductionWorkOrder.work_order_status == query.work_order_status.strip())
|
||||
if query.protocol_no and query.protocol_no.strip():
|
||||
like = f"%{query.protocol_no.strip()}%"
|
||||
q0 = q0.filter(BizProductionWorkOrder.protocol_no.like(like))
|
||||
if query.sample_code and query.sample_code.strip():
|
||||
like = f"%{query.sample_code.strip()}%"
|
||||
q0 = q0.filter(BizProductionWorkOrder.sample_code.like(like))
|
||||
return q0
|
||||
|
||||
effective_page = query.page if query and query.page else page
|
||||
effective_size = query.page_size if query and query.page_size else page_size
|
||||
|
||||
total = _filtered().order_by(None).with_entities(func.count(BizProductionWorkOrder.id)).scalar() or 0
|
||||
effective_page = max(1, effective_page)
|
||||
effective_size = min(max(1, effective_size), 100)
|
||||
rows = (
|
||||
_filtered()
|
||||
.order_by(BizProductionWorkOrder.create_time.desc())
|
||||
.offset((effective_page - 1) * effective_size)
|
||||
.limit(effective_size)
|
||||
.all()
|
||||
)
|
||||
items = [_wo_to_dict(x) for x in rows]
|
||||
return {"items": items, "total": int(total)}
|
||||
|
||||
|
||||
def get_production_work_order(
|
||||
db: Session, row_id: str, tenant_no: str
|
||||
) -> Optional[BizProductionWorkOrder]:
|
||||
return (
|
||||
db.query(BizProductionWorkOrder)
|
||||
.filter(
|
||||
BizProductionWorkOrder.id == row_id,
|
||||
BizProductionWorkOrder.tenant_no == tenant_no,
|
||||
BizProductionWorkOrder.del_flag == 0,
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
|
||||
def complete_production_work_order(
|
||||
db: Session,
|
||||
row_id: str,
|
||||
tenant_no: str,
|
||||
user_id: str,
|
||||
data: Optional[ProductionWorkOrderComplete] = None,
|
||||
) -> BizProductionWorkOrder:
|
||||
wo = get_production_work_order(db, row_id, tenant_no)
|
||||
if not wo:
|
||||
raise ValueError("工单不存在")
|
||||
if wo.work_order_status == "ywc":
|
||||
raise ValueError("工单已完成")
|
||||
wo.work_order_status = "ywc"
|
||||
wo.update_by = user_id
|
||||
wo.update_time = datetime.now()
|
||||
if data and data.remark is not None:
|
||||
wo.remark = data.remark
|
||||
db.add(wo)
|
||||
db.commit()
|
||||
db.refresh(wo)
|
||||
return wo
|
||||
Reference in new issue
Block a user