material_stock_log.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """市场物料库存变动记录 CRUD"""
  2. from __future__ import annotations
  3. from datetime import datetime
  4. from typing import Any, Dict, List, Optional, Tuple
  5. from sqlalchemy import func, or_
  6. from sqlalchemy.orm import Session
  7. from app.models.material import BizMaterialStockLog
  8. from app.models.models import SysUser
  9. def _user_nick_name_map(db: Session, user_ids: List[str]) -> Dict[str, str]:
  10. ids = list({x for x in user_ids if x})
  11. if not ids:
  12. return {}
  13. rows = db.query(SysUser.id, SysUser.nick_name).filter(SysUser.id.in_(ids)).all()
  14. return {u.id: (u.nick_name or "").strip() for u in rows}
  15. def _dec(v: Any) -> float:
  16. if v is None:
  17. return 0.0
  18. return float(v)
  19. def _fmt_dt(t: Optional[datetime]) -> str:
  20. return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
  21. def _row_to_dict(r: BizMaterialStockLog, *, create_by_name: str = "") -> Dict[str, Any]:
  22. create_by = r.create_by or ""
  23. return {
  24. "id": r.id,
  25. "materialId": r.material_id,
  26. "materialCode": r.material_code or "",
  27. "materialName": r.material_name or "",
  28. "changeType": r.change_type,
  29. "changeQty": _dec(r.change_qty),
  30. "stockBefore": _dec(r.stock_before),
  31. "stockAfter": _dec(r.stock_after),
  32. "receiver": r.receiver or "",
  33. "purpose": r.purpose or "",
  34. "remark": r.remark or "",
  35. "createBy": create_by,
  36. "createByName": create_by_name or create_by,
  37. "createTime": _fmt_dt(r.create_time),
  38. "updateTime": _fmt_dt(r.update_time),
  39. }
  40. def list_stock_logs(
  41. db: Session,
  42. tenant_no: str,
  43. *,
  44. page: int = 1,
  45. page_size: int = 10,
  46. material_id: Optional[str] = None,
  47. change_type: Optional[str] = None,
  48. start_time: Optional[str] = None,
  49. end_time: Optional[str] = None,
  50. keyword: Optional[str] = None,
  51. user_info=None,
  52. ) -> Tuple[List[Dict[str, Any]], int]:
  53. def _filtered():
  54. q0 = db.query(BizMaterialStockLog).filter(
  55. BizMaterialStockLog.tenant_no == tenant_no,
  56. BizMaterialStockLog.del_flag == 0,
  57. )
  58. if material_id:
  59. q0 = q0.filter(BizMaterialStockLog.material_id == material_id)
  60. if change_type:
  61. q0 = q0.filter(BizMaterialStockLog.change_type == change_type)
  62. if start_time:
  63. q0 = q0.filter(BizMaterialStockLog.create_time >= start_time)
  64. if end_time:
  65. q0 = q0.filter(BizMaterialStockLog.create_time <= end_time + " 23:59:59")
  66. kw = (keyword or "").strip()
  67. if kw:
  68. like = f"%{kw}%"
  69. q0 = q0.filter(
  70. or_(
  71. BizMaterialStockLog.material_code.ilike(like),
  72. BizMaterialStockLog.material_name.ilike(like),
  73. )
  74. )
  75. if user_info:
  76. from app.core.data_scope import apply_data_scope
  77. q0 = apply_data_scope(q0, BizMaterialStockLog, user_info, db, tenant_no)
  78. return q0
  79. total = _filtered().order_by(None).with_entities(func.count(BizMaterialStockLog.id)).scalar() or 0
  80. page = max(1, page)
  81. page_size = min(max(1, page_size), 100)
  82. rows = (
  83. _filtered()
  84. .order_by(BizMaterialStockLog.create_time.desc())
  85. .offset((page - 1) * page_size)
  86. .limit(page_size)
  87. .all()
  88. )
  89. name_map = _user_nick_name_map(db, [x.create_by for x in rows if x.create_by])
  90. return [
  91. _row_to_dict(x, create_by_name=name_map.get(x.create_by or "", ""))
  92. for x in rows
  93. ], int(total)