Files
shanxia2.0/backend/tests/test_pl_contract_qty_arrange_check.py
T
zlwuandCursor 3011cb9dae feat(pl): hard-block over-limit contract qty on arrange and remind after success
Validate arranged+this plan qty against fixed contract product quantities on
transport arrange; return post-success remaining/framework cumulative reminders.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 16:47:21 +08:00

124 lines
3.2 KiB
Python

"""安排运输时合同数量硬拦 / 提醒纯函数单测。"""
from app.services.pl_contract_plan_qty import (
contract_product_has_fixed_qty,
effective_arranged_total,
evaluate_product_qty_for_arrange,
)
def test_effective_arranged_total_subtracts_old():
assert effective_arranged_total(arranged_total=100, old_plan_qty=30, new_plan_qty=40) == 110.0
def test_effective_arranged_total_rounds():
assert effective_arranged_total(arranged_total=10.1234, old_plan_qty=1.1, new_plan_qty=2.2) == 11.223
def test_framework_customer_demand_not_fixed():
assert (
contract_product_has_fixed_qty(
contract_type="framework_sale",
quantity=0,
quantity_mode="customer_demand",
)
is False
)
def test_framework_fixed_mode_with_qty_is_fixed():
assert (
contract_product_has_fixed_qty(
contract_type="framework_purchase",
quantity=50,
quantity_mode="fixed",
)
is True
)
def test_sale_positive_qty_is_fixed():
assert (
contract_product_has_fixed_qty(
contract_type="sale",
quantity=100,
quantity_mode="fixed",
)
is True
)
def test_zero_or_empty_qty_not_fixed():
assert contract_product_has_fixed_qty(contract_type="sale", quantity=0, quantity_mode="fixed") is False
assert contract_product_has_fixed_qty(contract_type="sale", quantity=None, quantity_mode="fixed") is False
def test_evaluate_skip_when_no_new_qty():
assert (
evaluate_product_qty_for_arrange(
has_fixed_qty=True,
contract_qty=100,
arranged_total=80,
old_plan_qty=0,
new_plan_qty=0,
)
is None
)
def test_evaluate_overflow_violation():
r = evaluate_product_qty_for_arrange(
has_fixed_qty=True,
contract_qty=100,
arranged_total=80,
old_plan_qty=0,
new_plan_qty=30,
)
assert r is not None
assert r["kind"] == "violation"
assert r["overflowQty"] == 10.0
assert r["effectiveTotal"] == 110.0
assert r["arrangedTotalQty"] == 110.0
def test_evaluate_remaining_reminder():
r = evaluate_product_qty_for_arrange(
has_fixed_qty=True,
contract_qty=200,
arranged_total=150,
old_plan_qty=0,
new_plan_qty=40,
)
assert r is not None
assert r["kind"] == "remaining"
assert r["remainingQty"] == 10.0
assert r["arrangedTotalQty"] == 190.0
def test_evaluate_rearrange_deducts_old():
# arranged 已含旧 30;改为 40 → effective 110
r = evaluate_product_qty_for_arrange(
has_fixed_qty=True,
contract_qty=100,
arranged_total=100,
old_plan_qty=30,
new_plan_qty=40,
)
assert r is not None
assert r["kind"] == "violation"
assert r["overflowQty"] == 10.0
def test_evaluate_framework_cumulative():
r = evaluate_product_qty_for_arrange(
has_fixed_qty=False,
contract_qty=None,
arranged_total=126.5,
old_plan_qty=0,
new_plan_qty=28,
)
assert r is not None
assert r["kind"] == "framework_cumulative"
assert r["arrangedTotalQty"] == 154.5
assert r["thisPlanQty"] == 28.0