Files
shanxia2.0/backend/app/crud/consumable.py
T
2026-05-19 12:03:08 +08:00

188 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""耗材 CRUD(biz_consumable)"""
from __future__ import annotations
import math
from datetime import datetime
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.models.models import BizConsumable
def _row_to_dict(c: BizConsumable) -> Dict[str, Any]:
return {
"id": c.id,
"consumableCode": c.consumable_code,
"consumableName": c.consumable_name,
"specModel": c.spec_model or "",
"standardUsage": c.standard_usage or "",
"unit": c.unit or "",
"description": c.description or "",
"tenantNo": c.tenant_no,
"orderNum": c.order_num if c.order_num is not None else 0,
"remark": c.remark or "",
"createTime": c.create_time.strftime("%Y-%m-%d %H:%M:%S") if c.create_time else "",
"updateTime": c.update_time.strftime("%Y-%m-%d %H:%M:%S") if c.update_time else "",
}
def list_consumables(
db: Session,
*,
page: int = 1,
page_size: int = 10,
keyword: Optional[str] = None,
tenant_no: Optional[str] = None,
) -> Tuple[List[Dict[str, Any]], int]:
def _filtered():
q0 = db.query(BizConsumable).filter(BizConsumable.del_flag == 0)
if tenant_no:
q0 = q0.filter(BizConsumable.tenant_no == tenant_no)
kw = (keyword or "").strip()
if kw:
like = f"%{kw}%"
q0 = q0.filter(
or_(
BizConsumable.consumable_code.like(like),
BizConsumable.consumable_name.like(like),
)
)
return q0
total = _filtered().order_by(None).with_entities(func.count(BizConsumable.id)).scalar() or 0
page = max(1, page)
page_size = min(max(1, page_size), 100)
rows = (
_filtered()
.order_by(BizConsumable.create_time.desc())
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
return [_row_to_dict(x) for x in rows], int(total)
def get_consumable(db: Session, consumable_id: str) -> Optional[BizConsumable]:
return (
db.query(BizConsumable)
.filter(and_(BizConsumable.id == consumable_id, BizConsumable.del_flag == 0))
.first()
)
def consumable_code_exists(db: Session, code: str, tenant_no: str, exclude_id: Optional[str] = None) -> bool:
q = db.query(BizConsumable).filter(
and_(BizConsumable.consumable_code == code.strip(), BizConsumable.tenant_no == tenant_no, BizConsumable.del_flag == 0)
)
if exclude_id:
q = q.filter(BizConsumable.id != exclude_id)
return q.first() is not None
def create_consumable(
db: Session,
*,
consumable_code: str,
consumable_name: str,
spec_model: Optional[str] = None,
standard_usage: Optional[str] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
tenant_no: str = "zkxw",
order_num: Optional[int] = None,
remark: Optional[str] = None,
user_id: Optional[str] = None,
) -> BizConsumable:
cc = (consumable_code or "").strip()
if not cc:
raise ValueError("耗材编码不能为空")
if consumable_code_exists(db, cc, tenant_no):
raise ValueError("耗材编码已存在")
obj = BizConsumable(
id=generate_uuid(),
consumable_code=cc,
consumable_name=(consumable_name or "").strip() or cc,
spec_model=(spec_model or "").strip() or None,
standard_usage=(standard_usage or "").strip() or None,
unit=(unit or "").strip() or None,
description=(description or "").strip() or None,
tenant_no=tenant_no,
order_num=order_num if order_num is not None else 0,
remark=(remark or "").strip() or None,
create_by=user_id,
create_dept_id="",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def update_consumable(
db: Session,
consumable_id: str,
*,
consumable_code: Optional[str] = None,
consumable_name: Optional[str] = None,
spec_model: Optional[str] = None,
standard_usage: Optional[str] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
order_num: Optional[int] = None,
remark: Optional[str] = None,
user_id: Optional[str] = None,
) -> BizConsumable:
obj = get_consumable(db, consumable_id)
if not obj:
raise ValueError("耗材不存在")
if consumable_code is not None:
new_code = consumable_code.strip()
if not new_code:
raise ValueError("耗材编码不能为空")
if new_code != obj.consumable_code and consumable_code_exists(db, new_code, obj.tenant_no, exclude_id=consumable_id):
raise ValueError("耗材编码已存在")
obj.consumable_code = new_code
if consumable_name is not None:
obj.consumable_name = (consumable_name or "").strip() or obj.consumable_name
if spec_model is not None:
obj.spec_model = (spec_model or "").strip() or None
if standard_usage is not None:
obj.standard_usage = (standard_usage or "").strip() or None
if unit is not None:
obj.unit = (unit or "").strip() or None
if description is not None:
obj.description = (description or "").strip() or None
if order_num is not None:
obj.order_num = order_num
if remark is not None:
obj.remark = (remark or "").strip() or None
obj.update_by = user_id
obj.update_time = datetime.now()
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def soft_delete_consumable(db: Session, consumable_id: str) -> None:
obj = get_consumable(db, consumable_id)
if not obj:
raise ValueError("耗材不存在")
obj.del_flag = 1
obj.update_time = datetime.now()
db.add(obj)
db.commit()
def total_pages(total: int, page_size: int) -> int:
if total <= 0:
return 0
return int(math.ceil(total / float(page_size)))