AutoRpa/rpa_rebate/job.py

83 lines
2.2 KiB
Python

"""返利班次:领表 4 起草行 / 表 3 只录协议行 → 查号 → 录协议替身 → 写表 4。"""
from __future__ import annotations
from collections import OrderedDict
from dataclasses import dataclass
from typing import Callable
from persist import (
KIND_FAIL,
AgreementOutcome,
RebateGroup,
agreement_ok,
build_found,
build_not_found,
)
from repo import Claimed
Finder = Callable[[str], bool]
Recorder = Callable[[str], AgreementOutcome]
@dataclass
class JobSummary:
claimed: int = 0
groups: int = 0
ok: int = 0
not_found: int = 0
failed: int = 0
def run_batch(
repo,
*,
finder: Finder,
recorder: Recorder,
limit: int | None = None,
) -> JobSummary:
claimed = repo.claim_pending(limit=limit)
groups = group_claimed(claimed)
summary = JobSummary(
claimed=len(claimed.drafts) + len(claimed.protocols),
groups=len(groups),
)
for group in groups:
try:
found = bool(finder(group.contract_no))
except Exception:
repo.save_group(build_not_found(group))
summary.not_found += 1
continue
if not found:
repo.save_group(build_not_found(group))
summary.not_found += 1
continue
try:
outcome = recorder(group.contract_no)
except Exception as exc:
outcome = AgreementOutcome(KIND_FAIL, None, None, str(exc))
if outcome is None:
outcome = AgreementOutcome(KIND_FAIL, None, None, "协议录入失败")
repo.save_group(build_found(group, outcome))
if agreement_ok(outcome):
summary.ok += 1
else:
summary.failed += 1
return summary
def group_claimed(claimed: Claimed) -> list[RebateGroup]:
groups: OrderedDict[str, RebateGroup] = OrderedDict()
def bucket(contract_no: str) -> RebateGroup:
number = (contract_no or "").strip()
if number not in groups:
groups[number] = RebateGroup(contract_no=number)
return groups[number]
for row in claimed.drafts:
bucket(row["contract_no"]).drafts.append(row)
for row in claimed.protocols:
bucket(row["contract_no"]).protocols.append(row)
return list(groups.values())