Przeglądaj źródła

feat(backend): allocate research donation monthly verify numbers

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 2 tygodni temu
rodzic
commit
60efc5d5d3

+ 34 - 0
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 ""
 

+ 34 - 0
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"