sample_payment_progress.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. """样本缴费方案进度汇总(列表「按样本」维度)"""
  2. from __future__ import annotations
  3. from decimal import Decimal
  4. from typing import Any, Dict, Iterable, List, Mapping
  5. def _dec(v: Any) -> Decimal:
  6. if v is None or v == "":
  7. return Decimal("0")
  8. return Decimal(str(v))
  9. def _status(row: Mapping[str, Any], *keys: str) -> str:
  10. for k in keys:
  11. if k in row and row[k] is not None:
  12. return str(row[k]).strip()
  13. return ""
  14. def compute_sample_payment_progress(
  15. *,
  16. schedules: Iterable[Mapping[str, Any]],
  17. transfers: Iterable[Mapping[str, Any]],
  18. ) -> Dict[str, Any]:
  19. """
  20. progressStatus 优先级:yjq > bfyj > dfj(不含付款确认中)
  21. 已缴仅计 pay_status=yjf;有效期排除 schedule_status=void
  22. canConfirm:无 jfqrz,且存在有效未清期
  23. """
  24. sch_list: List[Mapping[str, Any]] = list(schedules or [])
  25. tr_list: List[Mapping[str, Any]] = list(transfers or [])
  26. active = [
  27. s
  28. for s in sch_list
  29. if _status(s, "scheduleStatus", "schedule_status") != "void"
  30. ]
  31. active_schedule_count = len(active)
  32. cleared_schedule_count = sum(
  33. 1
  34. for s in active
  35. if _status(s, "scheduleStatus", "schedule_status") == "cleared"
  36. )
  37. paid = sum(
  38. (
  39. _dec(t.get("transferAmount", t.get("transfer_amount")))
  40. for t in tr_list
  41. if _status(t, "payStatus", "pay_status") == "yjf"
  42. ),
  43. Decimal("0"),
  44. )
  45. due_total = sum((_dec(s.get("dueAmount", s.get("due_amount"))) for s in active), Decimal("0"))
  46. due_remain = due_total - paid
  47. if due_remain < 0:
  48. due_remain = Decimal("0")
  49. has_jfqrz = any(_status(t, "payStatus", "pay_status") == "jfqrz" for t in tr_list)
  50. if active_schedule_count > 0 and cleared_schedule_count == active_schedule_count:
  51. progress = "yjq"
  52. elif paid > 0:
  53. progress = "bfyj"
  54. else:
  55. progress = "dfj"
  56. can_confirm = (not has_jfqrz) and any(
  57. _status(s, "scheduleStatus", "schedule_status") != "cleared" for s in active
  58. )
  59. return {
  60. "progressStatus": progress,
  61. "paidAmount": paid,
  62. "dueRemainAmount": due_remain,
  63. "clearedScheduleCount": cleared_schedule_count,
  64. "activeScheduleCount": active_schedule_count,
  65. "canConfirm": can_confirm,
  66. }