PayrollManagementSystem/backend/tests/unit/test_secondary_allocation_schema.py
liuwenxin 680661a80b feat(allocation): 二次分配方案录入/替换/终态门槛(分摊计算待澄清另批)
- SecondaryAllocationIn/Out:比例走金额红线口径(str 入参、两位小数、
  超 100 拒绝不静默舍入);参与人 schema 层去重(uk 前置友好提示)
- create/update 同事务写入(replace_allocations,先删后 flush 再插——
  uk 表防御写法);create 放编号重试循环内,rollback 后方案随业务重来
- 人员在职复用 ensure_active(label=分摊参与),personnel_name 冗余固化;
  FK RESTRICT:被方案引用人员禁删,方案回显不静默失联
- 合计不强制 100%(需求原文):详情 allocation_hint 只展示合计/余额,
  余额归属待澄清 #2 不落库
- 单测 13 例(比例边界/去重)+ 集成 9 例(回显/替换清空/离职 400/
  终态禁改/RESTRICT 保护)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-15 18:31:27 +08:00

112 lines
3.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""二次分配方案入参校验(schema 层,秒级)。
守的是:比例红线(字符串入参、两位小数、超限拒绝不静默舍入)与
参与人去重——uk(business_id, personnel_id) 的友好前置校验。
明细行同批创建的正常路径由集成测试覆盖,这里集中打边界。
"""
import pytest
from pydantic import ValidationError
from app.schemas.business import SecondaryAllocationIn
def _make(personnel_id: int = 1, ratio: str = "50.00") -> dict:
return {"personnel_id": personnel_id, "ratio": ratio}
class TestRatioBoundary:
"""比例边界:0 / 满额 / 超限 / 精度 / 非数字。"""
@pytest.mark.parametrize(
("ratio", "ok"),
[
("0", False), # 必须大于 0
("0.01", True),
("33.33", True),
("100", True),
("100.00", True),
("100.01", False), # 超上限
("-5", False), # 负数
("33.333", False), # 三位小数:拒绝不静默舍入
("abc", False), # 非数字
("", False), # 空串
],
)
def test_比例边界(self, ratio: str, *, ok: bool) -> None:
if ok:
assert SecondaryAllocationIn(**_make(ratio=ratio)).ratio == ratio
else:
with pytest.raises(ValidationError):
SecondaryAllocationIn(**_make(ratio=ratio))
def test_人员id必须为正整数(self) -> None:
with pytest.raises(ValidationError):
SecondaryAllocationIn(**_make(personnel_id=0))
with pytest.raises(ValidationError):
SecondaryAllocationIn(**_make(personnel_id=-1))
class TestDuplicate:
"""参与人去重(Create/Update 两个入参模型同款校验)。"""
def test_创建入参_重复参与人被拒(self) -> None:
from app.schemas.business import BusinessCreateIn
payload = {
"customer_id": 1,
"items": [
{
"product_name": "t_产品",
"product_category": "municipal_water",
"quantity": "1.00",
"sale_price": "10.00",
}
],
"secondary_allocations": [
_make(personnel_id=5, ratio="30.00"),
_make(personnel_id=5, ratio="20.00"),
],
}
with pytest.raises(ValidationError, match="重复"):
BusinessCreateIn(**payload)
def test_编辑入参_重复参与人被拒(self) -> None:
from app.schemas.business import BusinessUpdateIn
payload = {
"customer_id": 1,
"items": [
{
"product_name": "t_产品",
"product_category": "municipal_water",
"quantity": "1.00",
"sale_price": "10.00",
}
],
"secondary_allocations": [_make(personnel_id=5), _make(personnel_id=5)],
}
with pytest.raises(ValidationError, match="重复"):
BusinessUpdateIn(**payload)
def test_不同参与人合法(self) -> None:
from app.schemas.business import BusinessCreateIn
payload = {
"customer_id": 1,
"items": [
{
"product_name": "t_产品",
"product_category": "municipal_water",
"quantity": "1.00",
"sale_price": "10.00",
}
],
"secondary_allocations": [
_make(personnel_id=5, ratio="30.00"),
_make(personnel_id=6, ratio="20.00"),
],
}
model = BusinessCreateIn(**payload)
assert len(model.secondary_allocations) == 2