101 lines
3.1 KiB
Python
101 lines
3.1 KiB
Python
from datetime import date
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from app.crud.crm.contract import (
|
|
align_contract_no_to_sign_date,
|
|
generate_contract_no,
|
|
replace_contract_no_date,
|
|
)
|
|
|
|
|
|
def test_replace_keeps_seq_and_swaps_date():
|
|
assert (
|
|
replace_contract_no_date("SX/X-JT20250803001", date(2025, 8, 10))
|
|
== "SX/X-JT20250810001"
|
|
)
|
|
|
|
|
|
def test_replace_noop_when_same_date():
|
|
assert replace_contract_no_date("SX/X-JT20250803001", date(2025, 8, 3)) == "SX/X-JT20250803001"
|
|
|
|
|
|
def test_replace_returns_none_for_nonstandard():
|
|
assert replace_contract_no_date("CUSTOM-001", date(2025, 8, 10)) is None
|
|
assert replace_contract_no_date("", date(2025, 8, 10)) is None
|
|
assert replace_contract_no_date(None, date(2025, 8, 10)) is None
|
|
|
|
|
|
def test_align_returns_original_when_nonstandard():
|
|
db = MagicMock()
|
|
assert (
|
|
align_contract_no_to_sign_date(
|
|
db, "t1", "CUSTOM-001", date(2025, 8, 10)
|
|
)
|
|
== "CUSTOM-001"
|
|
)
|
|
|
|
|
|
def test_align_bumps_seq_when_occupied():
|
|
db = MagicMock()
|
|
|
|
def _exists(db_, tenant, no, exclude_id=None):
|
|
return no == "SX/X-JT20250810001"
|
|
|
|
with patch("app.crud.crm.contract.contract_no_exists", side_effect=_exists):
|
|
out = align_contract_no_to_sign_date(
|
|
db, "t1", "SX/X-JT20250803001", date(2025, 8, 10)
|
|
)
|
|
assert out == "SX/X-JT20250810002"
|
|
|
|
|
|
def test_align_exclude_id_skips_self():
|
|
db = MagicMock()
|
|
|
|
def _exists(db_, tenant, no, exclude_id=None):
|
|
if exclude_id == "self-id":
|
|
return False
|
|
return no == "SX/X-JT20250810001"
|
|
|
|
with patch("app.crud.crm.contract.contract_no_exists", side_effect=_exists):
|
|
out = align_contract_no_to_sign_date(
|
|
db,
|
|
"t1",
|
|
"SX/X-JT20250803001",
|
|
date(2025, 8, 10),
|
|
exclude_id="self-id",
|
|
)
|
|
assert out == "SX/X-JT20250810001"
|
|
|
|
|
|
def _mock_last_contract(contract_no: str):
|
|
db = MagicMock()
|
|
last = MagicMock()
|
|
last.contract_no = contract_no
|
|
q = MagicMock()
|
|
q.filter.return_value = q
|
|
q.order_by.return_value = q
|
|
q.first.return_value = last
|
|
db.query.return_value = q
|
|
return db
|
|
|
|
|
|
def test_generate_bumps_past_soft_deleted_occupied_no():
|
|
"""软删占用的编号仍占唯一索引,生成时须跳过(对齐 uk_contract_tenant_no)。"""
|
|
db = _mock_last_contract("SX/X-JT20260804005")
|
|
|
|
def _exists(db_, tenant, no, exclude_id=None):
|
|
return no == "SX/X-JT20260804006"
|
|
|
|
with patch("app.crud.crm.contract.contract_no_exists", side_effect=_exists):
|
|
out = generate_contract_no(db, "shanxia2.0", sign_date=date(2026, 8, 4))
|
|
assert out == "SX/X-JT20260804007"
|
|
|
|
|
|
def test_generate_starts_after_soft_deleted_max():
|
|
"""取最大流水号须含软删,避免复用已软删的最大编号。"""
|
|
db = _mock_last_contract("SX/X-JT20260804006")
|
|
|
|
with patch("app.crud.crm.contract.contract_no_exists", return_value=False):
|
|
out = generate_contract_no(db, "shanxia2.0", sign_date=date(2026, 8, 4))
|
|
assert out == "SX/X-JT20260804007"
|