"""合同班次:领取表 3 → 按供应商合单 → runner 录合同 → 写表 4。""" from __future__ import annotations from dataclasses import dataclass from typing import Callable from contract_draft import ContractDraft from errors import DiligenceError, NodeError from group import draft_from_group, group_by_supplier, missing_mdm_reason from persist import KIND_DILIGENCE, 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 def outcome_from_run(run: Callable[[], str]) -> ContractOutcome: try: number = (run() or "").strip() except DiligenceError: return ContractOutcome(KIND_DILIGENCE, None, "客户未尽调") except NodeError as exc: return ContractOutcome(KIND_FAIL, None, str(exc)) except Exception as exc: return ContractOutcome(KIND_FAIL, None, str(exc)) if not number: return ContractOutcome(KIND_FAIL, None, "submit 模式未读取到真实合同编号") return ContractOutcome(KIND_OK, number, None)