PayrollManagementSystem/backend/tests/integration/test_no_generator.py

83 lines
3.6 KiB
Python
Raw Normal View History

"""单据编号生成器的跨位宽正确性(no_generator)。
守:当日序号超过 4 位宽度(9999→10000)后,VARCHAR 字典序排序会失效
("-10000" < "-9999",'1'<'9')——MAX 检索若按纯字典序,seq 会恒重算出
同一号码,每笔建单都撞唯一键。修复口径:长度优先、同级按字典序
(同前缀下长度大即数值大;同长时字典序与数值序一致)。
"""
import pytest
from sqlalchemy import select
from app.core.constants import NO_PREFIX_BUSINESS
from app.core.db import get_session_factory
from app.models import Business, Customer
from app.services.no_generator import next_no, today_prefix
pytestmark = pytest.mark.integration
def _insert_business_nos(nos: list[str]) -> None:
"""直插同日前缀的业务编号行(仅编号用于 MAX 检索;其余列取默认/可空)。
直插绕过服务层(服务层走完整创建链太重),业务行为挂在 t_ 客户名下,
由 integration/conftest 兜底清理(YW% 单据 + t\\_% 客户)。
"""
factory = get_session_factory()
with factory() as session:
customer = Customer(
company_name="t_no_generator_client",
owner_name="t_no_generator_owner",
customer_type="enterprise",
)
session.add(customer)
session.flush()
session.add_all(Business(business_no=no, customer_id=customer.id) for no in nos)
session.commit()
class TestMaxCrossWidth:
"""MAX 检索在同日前缀下跨位宽取最大序号。"""
def test_序号破四位宽后仍按数值取最大(self) -> None:
"""4 位与 5 位并存:"-9999" 字典序大于 "-10000",纯字典序会取错。"""
prefix = today_prefix(NO_PREFIX_BUSINESS)
_insert_business_nos([f"{prefix}9999", f"{prefix}10000"])
factory = get_session_factory()
with factory() as session:
no = next_no(
session, model=Business, column_name="business_no", prefix=NO_PREFIX_BUSINESS
)
assert no == f"{prefix}10001"
def test_同位宽内字典序与数值序一致仍取最大(self) -> None:
"""同宽多行(修复的排序不破坏原行为):是长度优先而非只按长度取首行。"""
prefix = today_prefix(NO_PREFIX_BUSINESS)
_insert_business_nos([f"{prefix}0099", f"{prefix}8499", f"{prefix}8500"])
factory = get_session_factory()
with factory() as session:
no = next_no(
session, model=Business, column_name="business_no", prefix=NO_PREFIX_BUSINESS
)
assert no == f"{prefix}8501"
def test_无当日编号时从1起编(self) -> None:
"""当日无同前缀行(昨日编号不被 like 命中):从 0001 起,不受历史天数影响。
当日若已有其他用例留下的同前缀编号(用例间无隔离库),跳过——
空表场景由每次 `down -v` 重建后的首个用例覆盖。
"""
prefix = today_prefix(NO_PREFIX_BUSINESS)
factory = get_session_factory()
with factory() as session:
existing = session.execute(
select(Business.id).where(Business.business_no.like(f"{prefix}%")).limit(1)
).scalar()
if existing is not None:
pytest.skip(f"当日已有同前缀编号 {existing},空表场景跳过")
with factory() as session:
no = next_no(
session, model=Business, column_name="business_no", prefix=NO_PREFIX_BUSINESS
)
assert no == f"{prefix}0001"