From a79e8a3e1251df853028f66c4316e54fe3192236 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Thu, 20 Aug 2026 11:54:10 +0800 Subject: [PATCH] feat(pl): add plan contract gap side computation helpers Co-authored-by: Cursor --- backend/app/services/pl_plan_contract_gap.py | 24 +++++++++++ backend/tests/test_pl_plan_contract_gap.py | 44 ++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 backend/app/services/pl_plan_contract_gap.py create mode 100644 backend/tests/test_pl_plan_contract_gap.py diff --git a/backend/app/services/pl_plan_contract_gap.py b/backend/app/services/pl_plan_contract_gap.py new file mode 100644 index 000000000..1869c4515 --- /dev/null +++ b/backend/app/services/pl_plan_contract_gap.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import List, Optional + +from app.services.pl_internal_customer import is_internal_customer_name + + +def compute_contract_gap_sides( + *, + supplier_name: Optional[str], + customer_name: Optional[str], + supplier_contract_count: int, + demander_contract_count: int, +) -> List[str]: + gaps: List[str] = [] + if not is_internal_customer_name(supplier_name) and supplier_contract_count <= 0: + gaps.append("supplier") + if not is_internal_customer_name(customer_name) and demander_contract_count <= 0: + gaps.append("demander") + return gaps + + +def side_is_exempt(name: Optional[str]) -> bool: + return is_internal_customer_name(name) diff --git a/backend/tests/test_pl_plan_contract_gap.py b/backend/tests/test_pl_plan_contract_gap.py new file mode 100644 index 000000000..46cfc56d7 --- /dev/null +++ b/backend/tests/test_pl_plan_contract_gap.py @@ -0,0 +1,44 @@ +from app.services.pl_internal_customer import INTERNAL_CUSTOMER_NAMES +from app.services.pl_plan_contract_gap import compute_contract_gap_sides + +INTERNAL = next(iter(INTERNAL_CUSTOMER_NAMES)) + + +def test_both_external_no_contracts_gaps_both(): + sides = compute_contract_gap_sides( + supplier_name="外部供方A", + customer_name="外部需方B", + supplier_contract_count=0, + demander_contract_count=0, + ) + assert sides == ["supplier", "demander"] + + +def test_internal_supplier_external_demander_missing_only_demander(): + sides = compute_contract_gap_sides( + supplier_name=INTERNAL, + customer_name="外部需方B", + supplier_contract_count=0, + demander_contract_count=0, + ) + assert sides == ["demander"] + + +def test_both_internal_no_gap(): + sides = compute_contract_gap_sides( + supplier_name=INTERNAL, + customer_name=INTERNAL, + supplier_contract_count=0, + demander_contract_count=0, + ) + assert sides == [] + + +def test_external_with_contracts_no_gap(): + sides = compute_contract_gap_sides( + supplier_name="外部供方A", + customer_name="外部需方B", + supplier_contract_count=1, + demander_contract_count=2, + ) + assert sides == []