test_pl_contract_qty_arrange_check.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. """安排运输时合同数量硬拦 / 提醒纯函数单测。"""
  2. from app.services.pl_contract_plan_qty import (
  3. contract_product_has_fixed_qty,
  4. effective_arranged_total,
  5. evaluate_product_qty_for_arrange,
  6. )
  7. def test_effective_arranged_total_subtracts_old():
  8. assert effective_arranged_total(arranged_total=100, old_plan_qty=30, new_plan_qty=40) == 110.0
  9. def test_effective_arranged_total_rounds():
  10. assert effective_arranged_total(arranged_total=10.1234, old_plan_qty=1.1, new_plan_qty=2.2) == 11.223
  11. def test_framework_customer_demand_not_fixed():
  12. assert (
  13. contract_product_has_fixed_qty(
  14. contract_type="framework_sale",
  15. quantity=0,
  16. quantity_mode="customer_demand",
  17. )
  18. is False
  19. )
  20. def test_framework_fixed_mode_with_qty_is_fixed():
  21. assert (
  22. contract_product_has_fixed_qty(
  23. contract_type="framework_purchase",
  24. quantity=50,
  25. quantity_mode="fixed",
  26. )
  27. is True
  28. )
  29. def test_sale_positive_qty_is_fixed():
  30. assert (
  31. contract_product_has_fixed_qty(
  32. contract_type="sale",
  33. quantity=100,
  34. quantity_mode="fixed",
  35. )
  36. is True
  37. )
  38. def test_zero_or_empty_qty_not_fixed():
  39. assert contract_product_has_fixed_qty(contract_type="sale", quantity=0, quantity_mode="fixed") is False
  40. assert contract_product_has_fixed_qty(contract_type="sale", quantity=None, quantity_mode="fixed") is False
  41. def test_evaluate_skip_when_no_new_qty():
  42. assert (
  43. evaluate_product_qty_for_arrange(
  44. has_fixed_qty=True,
  45. contract_qty=100,
  46. arranged_total=80,
  47. old_plan_qty=0,
  48. new_plan_qty=0,
  49. )
  50. is None
  51. )
  52. def test_evaluate_overflow_violation():
  53. r = evaluate_product_qty_for_arrange(
  54. has_fixed_qty=True,
  55. contract_qty=100,
  56. arranged_total=80,
  57. old_plan_qty=0,
  58. new_plan_qty=30,
  59. )
  60. assert r is not None
  61. assert r["kind"] == "violation"
  62. assert r["overflowQty"] == 10.0
  63. assert r["effectiveTotal"] == 110.0
  64. assert r["arrangedTotalQty"] == 110.0
  65. def test_evaluate_remaining_reminder():
  66. r = evaluate_product_qty_for_arrange(
  67. has_fixed_qty=True,
  68. contract_qty=200,
  69. arranged_total=150,
  70. old_plan_qty=0,
  71. new_plan_qty=40,
  72. )
  73. assert r is not None
  74. assert r["kind"] == "remaining"
  75. assert r["remainingQty"] == 10.0
  76. assert r["arrangedTotalQty"] == 190.0
  77. def test_evaluate_rearrange_deducts_old():
  78. # arranged 已含旧 30;改为 40 → effective 110
  79. r = evaluate_product_qty_for_arrange(
  80. has_fixed_qty=True,
  81. contract_qty=100,
  82. arranged_total=100,
  83. old_plan_qty=30,
  84. new_plan_qty=40,
  85. )
  86. assert r is not None
  87. assert r["kind"] == "violation"
  88. assert r["overflowQty"] == 10.0
  89. def test_evaluate_framework_cumulative():
  90. r = evaluate_product_qty_for_arrange(
  91. has_fixed_qty=False,
  92. contract_qty=None,
  93. arranged_total=126.5,
  94. old_plan_qty=0,
  95. new_plan_qty=28,
  96. )
  97. assert r is not None
  98. assert r["kind"] == "framework_cumulative"
  99. assert r["arrangedTotalQty"] == 154.5
  100. assert r["thisPlanQty"] == 28.0