| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- """配置试剂配方 BOM CRUD"""
- from __future__ import annotations
- from datetime import datetime
- from decimal import Decimal
- from typing import Any, Dict, List, Optional
- from sqlalchemy import and_
- from sqlalchemy.orm import Session
- from app.core.utils import generate_uuid
- from app.crud.production_material import _dec, _fmt_dt
- from app.models.production_material import BizProductionMaterial, BizProductionMaterialFormula
- COMPONENT_TYPES = ("reagent", "consumable")
- def _line_to_dict(r: BizProductionMaterialFormula) -> Dict[str, Any]:
- return {
- "id": r.id,
- "configuredMaterialId": r.configured_material_id,
- "componentMaterialId": r.component_material_id,
- "componentMaterialType": r.component_material_type or "",
- "componentMaterialCode": r.component_material_code or "",
- "componentMaterialName": r.component_material_name or "",
- "standardQty": _dec(r.standard_qty),
- "usageUnit": r.usage_unit or "",
- "orderNum": r.order_num if r.order_num is not None else 0,
- "remark": r.remark or "",
- }
- def _get_configured_material(
- db: Session, material_id: str, tenant_no: str
- ) -> BizProductionMaterial:
- row = (
- db.query(BizProductionMaterial)
- .filter(
- BizProductionMaterial.id == material_id,
- BizProductionMaterial.tenant_no == tenant_no,
- BizProductionMaterial.del_flag == 0,
- )
- .first()
- )
- if not row:
- raise ValueError("配置试剂不存在")
- if (row.material_type or "").strip() != "configured_reagent":
- raise ValueError("仅配置试剂目录可维护配方")
- return row
- def get_formula(
- db: Session, configured_material_id: str, tenant_no: str
- ) -> List[Dict[str, Any]]:
- _get_configured_material(db, configured_material_id, tenant_no)
- rows = (
- db.query(BizProductionMaterialFormula)
- .filter(
- BizProductionMaterialFormula.configured_material_id == configured_material_id,
- BizProductionMaterialFormula.tenant_no == tenant_no,
- BizProductionMaterialFormula.del_flag == 0,
- )
- .order_by(
- BizProductionMaterialFormula.order_num.asc(),
- BizProductionMaterialFormula.create_time.asc(),
- )
- .all()
- )
- return [_line_to_dict(r) for r in rows]
- def replace_formula(
- db: Session,
- configured_material_id: str,
- *,
- lines: List[Dict[str, Any]],
- tenant_no: str,
- user_id: Optional[str] = None,
- dept_id: str = "",
- ) -> List[Dict[str, Any]]:
- configured = _get_configured_material(db, configured_material_id, tenant_no)
- now = datetime.now()
- if not lines:
- raise ValueError("请至少添加一条配方明细")
- seen_components: set = set()
- new_rows: List[BizProductionMaterialFormula] = []
- for idx, it in enumerate(lines):
- comp_id = (
- it.get("componentMaterialId") or it.get("component_material_id") or ""
- ).strip()
- if not comp_id:
- raise ValueError("请选择子物料")
- if comp_id in seen_components:
- raise ValueError("配方中存在重复的子物料")
- seen_components.add(comp_id)
- comp_type = (
- it.get("componentMaterialType") or it.get("component_material_type") or ""
- ).strip().lower()
- if comp_type not in COMPONENT_TYPES:
- raise ValueError("子物料类型无效,应为试剂或耗材")
- comp = (
- db.query(BizProductionMaterial)
- .filter(
- BizProductionMaterial.id == comp_id,
- BizProductionMaterial.tenant_no == tenant_no,
- BizProductionMaterial.del_flag == 0,
- )
- .first()
- )
- if not comp:
- raise ValueError("子物料不存在")
- if (comp.material_type or "").strip() != comp_type:
- raise ValueError(f"子物料「{comp.material_name}」类型与所选不一致")
- qty_raw = it.get("standardQty") if it.get("standardQty") is not None else it.get("standard_qty")
- if qty_raw is None or Decimal(str(qty_raw)) <= 0:
- raise ValueError("标准用量必须大于0")
- standard_qty = Decimal(str(qty_raw))
- usage_unit = (
- it.get("usageUnit") or it.get("usage_unit") or comp.unit or ""
- ).strip()[:32]
- new_rows.append(
- BizProductionMaterialFormula(
- id=generate_uuid(),
- configured_material_id=configured_material_id,
- component_material_id=comp_id,
- component_material_type=comp_type,
- component_material_code=comp.material_code,
- component_material_name=comp.material_name,
- standard_qty=standard_qty,
- usage_unit=usage_unit or None,
- tenant_no=tenant_no,
- order_num=idx,
- remark=(it.get("remark") or "").strip()[:512] or None,
- create_by=user_id,
- create_dept_id=dept_id or configured.create_dept_id or "",
- create_time=now,
- update_by=user_id,
- update_time=now,
- del_flag=0,
- )
- )
- existing = (
- db.query(BizProductionMaterialFormula)
- .filter(
- BizProductionMaterialFormula.configured_material_id == configured_material_id,
- BizProductionMaterialFormula.tenant_no == tenant_no,
- BizProductionMaterialFormula.del_flag == 0,
- )
- .all()
- )
- for row in existing:
- row.del_flag = 1
- row.update_by = user_id
- row.update_time = now
- db.add(row)
- for row in new_rows:
- db.add(row)
- db.commit()
- return get_formula(db, configured_material_id, tenant_no)
|