feat: 合同班合单录入写表4

This commit is contained in:
Yuuuu 2026-10-05 22:59:06 +08:00
parent 71fc1c3b60
commit 58ef8f280e
2 changed files with 105 additions and 1 deletions

46
rpa_contract/job.py Normal file
View File

@ -0,0 +1,46 @@
"""合同班次:领取表 3 → 按供应商合单 → runner 录合同 → 写表 4。"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable
from contract_draft import ContractDraft
from group import draft_from_group, group_by_supplier, missing_mdm_reason
from persist import KIND_FAIL, KIND_OK, ContractOutcome, build_save
Runner = Callable[[ContractDraft], ContractOutcome]
@dataclass
class JobSummary:
claimed: int = 0
groups: int = 0
ok: int = 0
failed: int = 0
def run_batch(repo, *, runner: Runner, limit: int | None = None) -> JobSummary:
claimed = repo.claim_pending(limit=limit)
summary = JobSummary(claimed=len(claimed), groups=0)
for rows in group_by_supplier(claimed):
summary.groups += 1
outcome = _run_group(rows, runner)
repo.save_group(build_save(rows, outcome))
if outcome.kind == KIND_OK and (outcome.contract_no or "").strip():
summary.ok += 1
else:
summary.failed += 1
return summary
def _run_group(rows, runner: Runner) -> ContractOutcome:
reason = missing_mdm_reason(rows)
if reason:
return ContractOutcome(KIND_FAIL, None, reason)
try:
outcome = runner(draft_from_group(rows))
except Exception as exc:
return ContractOutcome(KIND_FAIL, None, str(exc))
if outcome.kind == KIND_OK and not (outcome.contract_no or "").strip():
return ContractOutcome(KIND_FAIL, None, "submit 模式未读取到真实合同编号")
return outcome

View File

@ -1,7 +1,8 @@
from datetime import date from datetime import date
from decimal import Decimal from decimal import Decimal
from persist import KIND_OK, ContractOutcome, build_save from job import run_batch
from persist import KIND_DILIGENCE, KIND_OK, ContractOutcome, build_save
from repo import MemoryContractRepo, PurchaseContractRow from repo import MemoryContractRepo, PurchaseContractRow
@ -70,3 +71,60 @@ def test_save_group_inserts_one_table4_row_per_oms_id():
assert {row["push_status"] for row in repo.table4} == {0} assert {row["push_status"] for row in repo.table4} == {0}
assert repo.table3[1].process_status == 1 assert repo.table3[1].process_status == 1
assert repo.table3[3].process_status == 1 assert repo.table3[3].process_status == 1
def test_job_merges_same_supplier_and_writes_table4():
repo = MemoryContractRepo(
[
_row(),
_row(fid=2, oms_id=2026100502, goods_id="G0002"),
_row(fid=3, oms_id=2026100503, contract_entry_status=0, contract_no="HT-OLD"),
]
)
calls: list = []
def runner(draft):
calls.append(draft)
return ContractOutcome(KIND_OK, "HT20261005001", None)
run_batch(repo, runner=runner)
assert len(calls) == 1
assert [line.goods_code for line in calls[0].goods_lines] == ["G0001", "G0002"]
assert calls[0].customer_code == "DW0100046361"
assert [row["oms_id"] for row in repo.table4] == [2026100501, 2026100502]
assert {row["contract_no"] for row in repo.table4} == {"HT20261005001"}
assert {row["action_code"] for row in repo.table4} == {1}
assert {row["contract_status"] for row in repo.table4} == {1}
assert {row["push_status"] for row in repo.table4} == {0}
assert repo.table3[1].process_status == 1
assert repo.table3[2].process_status == 1
assert repo.table3[3].process_status == 0
def test_job_marks_diligence_fail():
repo = MemoryContractRepo([_row()])
def runner(draft):
return ContractOutcome(KIND_DILIGENCE, None, "客户未尽调")
run_batch(repo, runner=runner)
assert repo.table3[1].process_status == 2
assert "客户未尽调" in repo.table3[1].process_result
assert repo.table4[0]["contract_status"] == 3
assert repo.table4[0]["contract_no"] is None
assert repo.table4[0]["contract_fail_reason"] == "客户未尽调"
def test_job_skips_runner_when_mdm_missing():
repo = MemoryContractRepo([_row(supplier_mdm_code="")])
called = {"n": 0}
def runner(draft):
called["n"] += 1
return ContractOutcome(KIND_OK, "HT-X", None)
run_batch(repo, runner=runner)
assert called["n"] == 0
assert repo.table3[1].process_status == 2
assert "缺少供应商MDM码" in repo.table3[1].process_result