consumable_pack.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. """耗材包 CRUD(biz_consumable_pack + biz_consumable_pack_item)"""
  2. from __future__ import annotations
  3. import math
  4. from datetime import datetime
  5. from typing import Any, Dict, List, Optional, Tuple
  6. from sqlalchemy import and_, func, or_
  7. from sqlalchemy.orm import Session
  8. from app.core.utils import generate_uuid
  9. from app.models.models import BizConsumablePack, BizConsumablePackItem
  10. def _item_row_to_dict(item: BizConsumablePackItem) -> Dict[str, Any]:
  11. return {
  12. "id": item.id,
  13. "packId": item.pack_id,
  14. "consumableCode": item.consumable_code,
  15. "consumableName": item.consumable_name,
  16. "specModel": item.spec_model or "",
  17. "standardUsage": item.standard_usage or "",
  18. "unit": item.unit or "",
  19. "remark": item.remark or "",
  20. }
  21. def _row_to_dict(p: BizConsumablePack) -> Dict[str, Any]:
  22. return {
  23. "id": p.id,
  24. "packCode": p.pack_code,
  25. "packName": p.pack_name,
  26. "usageScene": p.usage_scene or "",
  27. "packType": p.pack_type or "",
  28. "status": int(p.status) if p.status not in (None, "") else 0,
  29. "tenantNo": p.tenant_no,
  30. "orderNum": p.order_num if p.order_num is not None else 0,
  31. "remark": p.remark or "",
  32. "createTime": p.create_time.strftime("%Y-%m-%d %H:%M:%S") if p.create_time else "",
  33. "updateTime": p.update_time.strftime("%Y-%m-%d %H:%M:%S") if p.update_time else "",
  34. }
  35. def list_consumable_packs(
  36. db: Session,
  37. *,
  38. page: int = 1,
  39. page_size: int = 10,
  40. keyword: Optional[str] = None,
  41. tenant_no: Optional[str] = None,
  42. user_info=None,
  43. ) -> Tuple[List[Dict[str, Any]], int]:
  44. def _filtered():
  45. q0 = db.query(BizConsumablePack).filter(BizConsumablePack.del_flag == 0)
  46. if tenant_no:
  47. q0 = q0.filter(BizConsumablePack.tenant_no == tenant_no)
  48. kw = (keyword or "").strip()
  49. if kw:
  50. like = f"%{kw}%"
  51. q0 = q0.filter(
  52. or_(
  53. BizConsumablePack.pack_code.like(like),
  54. BizConsumablePack.pack_name.like(like),
  55. )
  56. )
  57. if user_info:
  58. from app.core.data_scope import apply_data_scope
  59. q0 = apply_data_scope(q0, BizConsumablePack, user_info, db, tenant_no)
  60. return q0
  61. total = _filtered().order_by(None).with_entities(func.count(BizConsumablePack.id)).scalar() or 0
  62. page = max(1, page)
  63. page_size = min(max(1, page_size), 100)
  64. rows = (
  65. _filtered()
  66. .order_by(BizConsumablePack.create_time.desc())
  67. .offset((page - 1) * page_size)
  68. .limit(page_size)
  69. .all()
  70. )
  71. return [_row_to_dict(x) for x in rows], int(total)
  72. def list_all_packs(db: Session, tenant_no: str, user_info=None) -> List[Dict[str, Any]]:
  73. q0 = db.query(BizConsumablePack).filter(and_(BizConsumablePack.tenant_no == tenant_no, BizConsumablePack.del_flag == 0))
  74. if user_info:
  75. from app.core.data_scope import apply_data_scope
  76. q0 = apply_data_scope(q0, BizConsumablePack, user_info, db, tenant_no)
  77. rows = q0.order_by(BizConsumablePack.create_time.desc()).all()
  78. return [_row_to_dict(x) for x in rows]
  79. def get_consumable_pack(db: Session, pack_id: str) -> Optional[BizConsumablePack]:
  80. return (
  81. db.query(BizConsumablePack)
  82. .filter(and_(BizConsumablePack.id == pack_id, BizConsumablePack.del_flag == 0))
  83. .first()
  84. )
  85. def get_pack_detail(db: Session, pack_id: str) -> Optional[Dict[str, Any]]:
  86. pack = get_consumable_pack(db, pack_id)
  87. if not pack:
  88. return None
  89. result = _row_to_dict(pack)
  90. items = (
  91. db.query(BizConsumablePackItem)
  92. .filter(and_(BizConsumablePackItem.pack_id == pack_id, BizConsumablePackItem.del_flag == 0))
  93. .order_by(BizConsumablePackItem.create_time.asc())
  94. .all()
  95. )
  96. result["items"] = [_item_row_to_dict(i) for i in items]
  97. return result
  98. def pack_code_exists(db: Session, code: str, tenant_no: str, exclude_id: Optional[str] = None) -> bool:
  99. q = db.query(BizConsumablePack).filter(
  100. and_(BizConsumablePack.pack_code == code.strip(), BizConsumablePack.tenant_no == tenant_no, BizConsumablePack.del_flag == 0)
  101. )
  102. if exclude_id:
  103. q = q.filter(BizConsumablePack.id != exclude_id)
  104. return q.first() is not None
  105. def create_consumable_pack(
  106. db: Session,
  107. *,
  108. pack_code: str,
  109. pack_name: str,
  110. usage_scene: Optional[str] = None,
  111. pack_type: Optional[str] = None,
  112. status: Optional[int] = None,
  113. items: Optional[List[Dict[str, Any]]] = None,
  114. tenant_no: str = "zkxw",
  115. order_num: Optional[int] = None,
  116. remark: Optional[str] = None,
  117. user_id: Optional[str] = None,
  118. ) -> BizConsumablePack:
  119. pc = (pack_code or "").strip()
  120. if not pc:
  121. raise ValueError("耗材包编码不能为空")
  122. if pack_code_exists(db, pc, tenant_no):
  123. raise ValueError("耗材包编码已存在")
  124. now = datetime.now()
  125. obj = BizConsumablePack(
  126. id=generate_uuid(),
  127. pack_code=pc,
  128. pack_name=(pack_name or "").strip() or pc,
  129. usage_scene=(usage_scene or "").strip() or None,
  130. pack_type=(pack_type or "").strip() or None,
  131. status=str(status) if status is not None else "1",
  132. tenant_no=tenant_no,
  133. order_num=order_num if order_num is not None else 0,
  134. remark=(remark or "").strip() or None,
  135. create_by=user_id,
  136. create_dept_id="",
  137. create_time=now,
  138. update_by=user_id,
  139. update_time=now,
  140. del_flag=0,
  141. )
  142. db.add(obj)
  143. db.flush()
  144. if items:
  145. for it in items:
  146. item_obj = BizConsumablePackItem(
  147. id=generate_uuid(),
  148. pack_id=obj.id,
  149. consumable_code=(it.get("consumable_code") or "").strip(),
  150. consumable_name=(it.get("consumable_name") or "").strip(),
  151. spec_model=(it.get("spec_model") or "").strip() or None,
  152. standard_usage=(it.get("standard_usage") or "").strip() or None,
  153. unit=(it.get("unit") or "").strip() or None,
  154. remark=(it.get("remark") or "").strip() or None,
  155. tenant_no=tenant_no,
  156. order_num=0,
  157. create_by=user_id,
  158. create_dept_id="",
  159. create_time=now,
  160. update_by=user_id,
  161. update_time=now,
  162. del_flag=0,
  163. )
  164. db.add(item_obj)
  165. db.commit()
  166. db.refresh(obj)
  167. return obj
  168. def update_consumable_pack(
  169. db: Session,
  170. pack_id: str,
  171. *,
  172. pack_code: Optional[str] = None,
  173. pack_name: Optional[str] = None,
  174. usage_scene: Optional[str] = None,
  175. pack_type: Optional[str] = None,
  176. status: Optional[int] = None,
  177. items: Optional[List[Dict[str, Any]]] = None,
  178. order_num: Optional[int] = None,
  179. remark: Optional[str] = None,
  180. user_id: Optional[str] = None,
  181. ) -> BizConsumablePack:
  182. obj = get_consumable_pack(db, pack_id)
  183. if not obj:
  184. raise ValueError("耗材包不存在")
  185. if pack_code is not None:
  186. new_code = pack_code.strip()
  187. if not new_code:
  188. raise ValueError("耗材包编码不能为空")
  189. if new_code != obj.pack_code and pack_code_exists(db, new_code, obj.tenant_no, exclude_id=pack_id):
  190. raise ValueError("耗材包编码已存在")
  191. obj.pack_code = new_code
  192. if pack_name is not None:
  193. obj.pack_name = (pack_name or "").strip() or obj.pack_name
  194. if usage_scene is not None:
  195. obj.usage_scene = (usage_scene or "").strip() or None
  196. if pack_type is not None:
  197. obj.pack_type = (pack_type or "").strip() or None
  198. if status is not None:
  199. obj.status = str(status)
  200. if order_num is not None:
  201. obj.order_num = order_num
  202. if remark is not None:
  203. obj.remark = (remark or "").strip() or None
  204. obj.update_by = user_id
  205. obj.update_time = datetime.now()
  206. db.add(obj)
  207. if items is not None:
  208. existing = (
  209. db.query(BizConsumablePackItem)
  210. .filter(and_(BizConsumablePackItem.pack_id == pack_id, BizConsumablePackItem.del_flag == 0))
  211. .all()
  212. )
  213. now = datetime.now()
  214. for ei in existing:
  215. ei.del_flag = 1
  216. ei.update_time = now
  217. db.add(ei)
  218. for it in items:
  219. item_obj = BizConsumablePackItem(
  220. id=generate_uuid(),
  221. pack_id=pack_id,
  222. consumable_code=(it.get("consumable_code") or "").strip(),
  223. consumable_name=(it.get("consumable_name") or "").strip(),
  224. spec_model=(it.get("spec_model") or "").strip() or None,
  225. standard_usage=(it.get("standard_usage") or "").strip() or None,
  226. unit=(it.get("unit") or "").strip() or None,
  227. remark=(it.get("remark") or "").strip() or None,
  228. tenant_no=obj.tenant_no,
  229. order_num=0,
  230. create_by=user_id,
  231. create_dept_id="",
  232. create_time=now,
  233. update_by=user_id,
  234. update_time=now,
  235. del_flag=0,
  236. )
  237. db.add(item_obj)
  238. db.commit()
  239. db.refresh(obj)
  240. return obj
  241. def soft_delete_consumable_pack(db: Session, pack_id: str) -> None:
  242. obj = get_consumable_pack(db, pack_id)
  243. if not obj:
  244. raise ValueError("耗材包不存在")
  245. now = datetime.now()
  246. obj.del_flag = 1
  247. obj.update_time = now
  248. db.add(obj)
  249. items = (
  250. db.query(BizConsumablePackItem)
  251. .filter(and_(BizConsumablePackItem.pack_id == pack_id, BizConsumablePackItem.del_flag == 0))
  252. .all()
  253. )
  254. for it in items:
  255. it.del_flag = 1
  256. it.update_time = now
  257. db.add(it)
  258. db.commit()
  259. def total_pages(total: int, page_size: int) -> int:
  260. if total <= 0:
  261. return 0
  262. return int(math.ceil(total / float(page_size)))