diff --git a/backend/app/services/pl_plan_stop_service.py b/backend/app/services/pl_plan_stop_service.py index b5c17cee2..e2c9f4aae 100644 --- a/backend/app/services/pl_plan_stop_service.py +++ b/backend/app/services/pl_plan_stop_service.py @@ -467,6 +467,18 @@ def _normalize_contract_links(links: Optional[list[PlanContractLink]]) -> list[P return out +def assert_at_most_one_contract( + links: list[PlanContractLink], + side_label: str, +) -> list[PlanContractLink]: + if len(links) > 1: + raise HTTPException( + status_code=422, + detail=f"{side_label}只能选择 1 份", + ) + return links + + def _resolve_stop_contracts( db: Session, tenant_no: str, @@ -478,6 +490,7 @@ def _resolve_stop_contracts( if is_internal_customer_name(customer_name): return [] links = _normalize_contract_links(contracts) + links = assert_at_most_one_contract(links, side_label) if not links: return [] resolved: list[PlanContractLink] = [] diff --git a/backend/tests/test_pl_plan_single_contract_rules.py b/backend/tests/test_pl_plan_single_contract_rules.py new file mode 100644 index 000000000..b9d6aa6bf --- /dev/null +++ b/backend/tests/test_pl_plan_single_contract_rules.py @@ -0,0 +1,22 @@ +import pytest +from fastapi import HTTPException + +from app.schemas.pl.plan import PlanContractLink +from app.services.pl_plan_stop_service import assert_at_most_one_contract + + +def test_assert_at_most_one_contract_allows_zero_or_one(): + assert assert_at_most_one_contract([], "装货合同") == [] + one = [PlanContractLink(contractId="c1", contractNo="N1")] + assert assert_at_most_one_contract(one, "装货合同") == one + + +def test_assert_at_most_one_contract_rejects_two(): + links = [ + PlanContractLink(contractId="c1", contractNo="N1"), + PlanContractLink(contractId="c2", contractNo="N2"), + ] + with pytest.raises(HTTPException) as exc: + assert_at_most_one_contract(links, "装货合同") + assert exc.value.status_code == 422 + assert "只能选择 1 份" in str(exc.value.detail)