weighing_logic.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. """地磅单联动业务逻辑 — 迁移自 simple-dibang-xiaoshou weighing._process_weighing_business_logic。"""
  2. from __future__ import annotations
  3. from datetime import datetime
  4. from sqlalchemy import or_
  5. from sqlalchemy.orm import Session
  6. from app.models.db_models import DbInboundOutbound, DbPurchasePlan, DbWeighingSlip
  7. def _has_weight_time(value: datetime | str | None) -> bool:
  8. if value is None:
  9. return False
  10. if isinstance(value, datetime):
  11. return True
  12. return bool(str(value).strip())
  13. def process_weighing_business_logic(db: Session, weighing: DbWeighingSlip) -> None:
  14. """
  15. 处理地磅单的业务逻辑:
  16. 1. 更新计划单的已执行量(单位:kg)
  17. 2. 更新出入库单的状态
  18. 3. 重新计算地磅单的 executed_quantity(按创建时间顺序累计)
  19. """
  20. plan_ids_to_process: set[str] = set()
  21. inventory_ids_to_process: set[str] = set()
  22. if weighing.purchase_plan_id:
  23. plan_ids_to_process.add(weighing.purchase_plan_id)
  24. if weighing.inbound_outbound_id:
  25. inventory_ids_to_process.add(weighing.inbound_outbound_id)
  26. if weighing.plan_no:
  27. plans = (
  28. db.query(DbPurchasePlan)
  29. .filter(
  30. DbPurchasePlan.plan_no == weighing.plan_no,
  31. DbPurchasePlan.del_flag == 0,
  32. DbPurchasePlan.tenant_no == weighing.tenant_no,
  33. )
  34. .all()
  35. )
  36. for plan in plans:
  37. plan_ids_to_process.add(plan.id)
  38. for plan_id in plan_ids_to_process:
  39. plan = db.query(DbPurchasePlan).filter(DbPurchasePlan.id == plan_id).one_or_none()
  40. if not plan:
  41. continue
  42. plan_weighings = (
  43. db.query(DbWeighingSlip)
  44. .filter(
  45. DbWeighingSlip.is_voided == 0,
  46. DbWeighingSlip.del_flag == 0,
  47. DbWeighingSlip.tenant_no == plan.tenant_no,
  48. or_(
  49. DbWeighingSlip.plan_no == plan.plan_no,
  50. DbWeighingSlip.purchase_plan_id == plan.id,
  51. ),
  52. )
  53. .order_by(DbWeighingSlip.create_time.asc())
  54. .all()
  55. )
  56. total_executed = sum(w.net_weight for w in plan_weighings if w.net_weight)
  57. plan.executed_quantity = total_executed
  58. planned_quantity_kg = plan.planned_quantity * 1000
  59. if total_executed >= planned_quantity_kg:
  60. plan.execution_status = "已入库" if plan.business_type == "入库" else "已出库"
  61. elif total_executed > 0:
  62. plan.execution_status = "入库中" if plan.business_type == "入库" else "出库中"
  63. else:
  64. plan.execution_status = "待入库" if plan.business_type == "入库" else "待出库"
  65. db.commit()
  66. db.refresh(plan)
  67. cumulative_executed = 0.0
  68. for slip in plan_weighings:
  69. cumulative_executed += slip.net_weight if slip.net_weight else 0.0
  70. slip.executed_quantity = cumulative_executed
  71. db.commit()
  72. for inventory_id in inventory_ids_to_process:
  73. inventory = (
  74. db.query(DbInboundOutbound)
  75. .filter(DbInboundOutbound.id == inventory_id)
  76. .one_or_none()
  77. )
  78. if not inventory:
  79. continue
  80. related_weighings = (
  81. db.query(DbWeighingSlip)
  82. .filter(
  83. DbWeighingSlip.inbound_outbound_id == inventory_id,
  84. DbWeighingSlip.is_voided == 0,
  85. DbWeighingSlip.del_flag == 0,
  86. )
  87. .all()
  88. )
  89. all_complete = (
  90. len(related_weighings) > 0
  91. and all(
  92. _has_weight_time(w.gross_weight_time) and _has_weight_time(w.tare_weight_time)
  93. for w in related_weighings
  94. )
  95. )
  96. if all_complete:
  97. inventory.status = "已完成"
  98. else:
  99. inventory.status = (
  100. "待入库" if inventory.business_type == "入库" else "待出库"
  101. )
  102. db.commit()
  103. db.refresh(inventory)