From 60efc5d5d3fceec9ee6ab6494e66ad346d075bf3 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Tue, 13 Oct 2026 13:11:25 +0800 Subject: [PATCH] feat(backend): allocate research donation monthly verify numbers Co-authored-by: Cursor --- backend/app/crud/research_donation.py | 34 +++++++++++++++++++ ...est_research_donation_monthly_verify_no.py | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 backend/tests/test_research_donation_monthly_verify_no.py diff --git a/backend/app/crud/research_donation.py b/backend/app/crud/research_donation.py index 95d9ca3e..5e625751 100644 --- a/backend/app/crud/research_donation.py +++ b/backend/app/crud/research_donation.py @@ -144,6 +144,40 @@ def next_donation_sample_code( return f"{prefix}{str(max_seq + 1).zfill(_DONATION_SAMPLE_CODE_SEQ_LEN)}" + + +def allocate_monthly_verify_no( + db: Session, + *, + tenant_no: str, + create_time: datetime, +) -> str: + """按租户 + create_time 年月分配 YYYYMM###;含软删占用,不回收。""" + ym = create_time.strftime("%Y%m") + prefix_len = len(ym) + row = ( + db.query(BizResearchDonation.monthly_verify_no) + .filter( + BizResearchDonation.tenant_no == tenant_no, + BizResearchDonation.monthly_verify_no.isnot(None), + BizResearchDonation.monthly_verify_no.like(f"{ym}%"), + ) + .order_by(BizResearchDonation.monthly_verify_no.desc()) + .first() + ) + max_no = (row[0] if row else None) or "" + seq = 0 + if max_no.startswith(ym) and len(max_no) >= prefix_len + 3: + try: + seq = int(max_no[prefix_len : prefix_len + 3]) + except ValueError: + seq = 0 + nxt = seq + 1 + if nxt > 999: + raise ValueError(f"当月核量号已用尽({ym})") + return f"{ym}{nxt:03d}" + + def _fmt_dt(t: Optional[datetime]) -> str: return t.strftime("%Y-%m-%d %H:%M:%S") if t else "" diff --git a/backend/tests/test_research_donation_monthly_verify_no.py b/backend/tests/test_research_donation_monthly_verify_no.py new file mode 100644 index 00000000..790d0169 --- /dev/null +++ b/backend/tests/test_research_donation_monthly_verify_no.py @@ -0,0 +1,34 @@ +"""当月核量号:按租户+创建年月自增,含软删占用。""" +from datetime import datetime +from unittest.mock import MagicMock + +from app.crud import research_donation as crud + + +def test_allocate_monthly_verify_no_first_of_month(): + db = MagicMock() + db.query.return_value.filter.return_value.order_by.return_value.first.return_value = (None,) + no = crud.allocate_monthly_verify_no( + db, tenant_no="zkxw", create_time=datetime(2025, 8, 15, 10, 0, 0) + ) + assert no == "202508001" + + +def test_allocate_monthly_verify_no_increments(): + db = MagicMock() + db.query.return_value.filter.return_value.order_by.return_value.first.return_value = ( + "202508007", + ) + no = crud.allocate_monthly_verify_no( + db, tenant_no="zkxw", create_time=datetime(2025, 8, 20, 12, 0, 0) + ) + assert no == "202508008" + + +def test_allocate_monthly_verify_no_new_month_resets(): + db = MagicMock() + db.query.return_value.filter.return_value.order_by.return_value.first.return_value = (None,) + no = crud.allocate_monthly_verify_no( + db, tenant_no="zkxw", create_time=datetime(2025, 9, 1, 9, 0, 0) + ) + assert no == "202509001"