test_pl_plan_contract_gap.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from sqlalchemy.dialects import mysql
  2. from app.schemas.pl.plan import PlanDeliveryRead, PlanLoadRead
  3. from app.services.pl_internal_customer import INTERNAL_CUSTOMER_NAMES
  4. from app.services.pl_plan_contract_gap import (
  5. compute_contract_gap_sides,
  6. compute_plan_gap_sides_from_stops,
  7. plan_has_contract_gap_exists,
  8. stop_contract_gap,
  9. )
  10. INTERNAL = next(iter(INTERNAL_CUSTOMER_NAMES))
  11. def test_both_external_no_contracts_gaps_both():
  12. sides = compute_contract_gap_sides(
  13. supplier_name="外部供方A",
  14. customer_name="外部需方B",
  15. supplier_contract_count=0,
  16. demander_contract_count=0,
  17. )
  18. assert sides == ["supplier", "demander"]
  19. def test_internal_supplier_external_demander_missing_only_demander():
  20. sides = compute_contract_gap_sides(
  21. supplier_name=INTERNAL,
  22. customer_name="外部需方B",
  23. supplier_contract_count=0,
  24. demander_contract_count=0,
  25. )
  26. assert sides == ["demander"]
  27. def test_both_internal_no_gap():
  28. sides = compute_contract_gap_sides(
  29. supplier_name=INTERNAL,
  30. customer_name=INTERNAL,
  31. supplier_contract_count=0,
  32. demander_contract_count=0,
  33. )
  34. assert sides == []
  35. def test_external_with_contracts_no_gap():
  36. sides = compute_contract_gap_sides(
  37. supplier_name="外部供方A",
  38. customer_name="外部需方B",
  39. supplier_contract_count=1,
  40. demander_contract_count=2,
  41. )
  42. assert sides == []
  43. def test_empty_names_treated_as_non_internal_gap_both():
  44. sides = compute_contract_gap_sides(
  45. supplier_name=None,
  46. customer_name="",
  47. supplier_contract_count=0,
  48. demander_contract_count=0,
  49. )
  50. assert sides == ["supplier", "demander"]
  51. def test_stop_contract_gap_internal_exempt():
  52. assert stop_contract_gap(INTERNAL, 0) is False
  53. assert stop_contract_gap("外部客户", 0) is True
  54. assert stop_contract_gap("外部客户", 1) is False
  55. def test_compute_plan_gap_sides_from_stops_multi_delivery():
  56. load = PlanLoadRead(
  57. id="load1",
  58. planId="p1",
  59. tenantNo="t1",
  60. customerName=INTERNAL,
  61. products=[],
  62. contracts=[],
  63. createTime="2026-08-27T00:00:00",
  64. updateTime="2026-08-27T00:00:00",
  65. )
  66. delivery_ok = PlanDeliveryRead(
  67. id="d1",
  68. planId="p1",
  69. tenantNo="t1",
  70. seq=1,
  71. customerName="外部客户A",
  72. products=[],
  73. contracts=[{"contractId": "c1", "contractNo": "HT001"}],
  74. createTime="2026-08-27T00:00:00",
  75. updateTime="2026-08-27T00:00:00",
  76. )
  77. delivery_gap = PlanDeliveryRead(
  78. id="d2",
  79. planId="p1",
  80. tenantNo="t1",
  81. seq=2,
  82. customerName="外部客户B",
  83. products=[],
  84. contracts=[],
  85. createTime="2026-08-27T00:00:00",
  86. updateTime="2026-08-27T00:00:00",
  87. )
  88. sides = compute_plan_gap_sides_from_stops(load, [delivery_ok, delivery_gap])
  89. assert sides == ["demander"]
  90. def test_compute_plan_gap_sides_from_stops_internal_load_no_gap():
  91. load = PlanLoadRead(
  92. id="load1",
  93. planId="p1",
  94. tenantNo="t1",
  95. customerName=INTERNAL,
  96. products=[],
  97. contracts=[],
  98. createTime="2026-08-27T00:00:00",
  99. updateTime="2026-08-27T00:00:00",
  100. )
  101. delivery = PlanDeliveryRead(
  102. id="d1",
  103. planId="p1",
  104. tenantNo="t1",
  105. seq=1,
  106. customerName=INTERNAL,
  107. products=[],
  108. contracts=[],
  109. createTime="2026-08-27T00:00:00",
  110. updateTime="2026-08-27T00:00:00",
  111. )
  112. assert compute_plan_gap_sides_from_stops(load, [delivery]) == []
  113. def _compile(clause) -> str:
  114. return str(
  115. clause.compile(dialect=mysql.dialect(), compile_kwargs={"literal_binds": True})
  116. ).lower()
  117. def test_plan_has_contract_gap_exists_mentions_contract_and_internal_names():
  118. clause = plan_has_contract_gap_exists("shanxia2.0")
  119. sql = _compile(clause)
  120. assert "pl_plan_contract" in sql
  121. assert "pl_plan_load" in sql
  122. assert "pl_plan_delivery" in sql