"""表 3 领取、表 4 写入。""" from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass from datetime import date from decimal import Decimal from typing import Any from db import RepoUnavailable, connect_from_env, oracle_dsn @dataclass class PurchaseContractRow: fid: int oms_id: int supplier_id: str supplier_name: str contract_sign_date: date | None contract_start_date: date | None contract_end_date: date | None payment_term: int goods_id: str goods_name: str reg_no: str spec: str unit: str qty: Decimal | float | int unit_price: Decimal | float | int purchaser_id: str purchaser_name: str planner_id: str planner_name: str contract_entry_status: int | None contract_no: str | None process_status: int org_code: str | None goods_mdm_code: str | None supplier_mdm_code: str | None process_result: str = "" class MemoryContractRepo: def __init__(self, rows: list[PurchaseContractRow]): self.table3 = {row.fid: row for row in rows} self.table4: list[dict] = [] self._next_fid = 1 def claim_pending(self, limit: int | None = None) -> list[PurchaseContractRow]: from group import is_claimable pending = sorted( (row for row in self.table3.values() if is_claimable(row)), key=lambda row: row.fid, ) if limit is not None: pending = pending[:limit] for row in pending: row.process_status = 3 return pending def save_group(self, payload: Any) -> None: for row in payload.table4_rows: item = dict(row) item["fid"] = self._next_fid self._next_fid += 1 self.table4.append(item) for fid in payload.fids: target = self.table3[fid] target.process_status = payload.process_status target.process_result = payload.process_result _SELECT_PENDING = """ SELECT fid, oms_id, supplier_id, supplier_name, contract_sign_date, contract_start_date, contract_end_date, payment_term, goods_id, goods_name, reg_no, spec, unit, qty, unit_price, purchaser_id, purchaser_name, planner_id, planner_name, contract_entry_status, contract_no, process_status, org_code, goods_mdm_code, supplier_mdm_code, NVL(process_result, '') AS process_result FROM rpa_purchase_contract_data WHERE process_status = 0 AND NOT (NVL(contract_entry_status, -1) = 0 AND contract_no IS NOT NULL AND LENGTH(TRIM(contract_no)) > 0) ORDER BY fid """ _SELECT_PENDING_LIMIT = f""" SELECT * FROM ( {_SELECT_PENDING} ) WHERE ROWNUM <= :limit """ _CLAIM_SQL = """ UPDATE rpa_purchase_contract_data SET process_status = 3, process_time = SYSTIMESTAMP, update_time = SYSTIMESTAMP WHERE fid = :fid AND process_status = 0 """ _INSERT_TABLE4_SQL = """ INSERT INTO rpa_contract_agreement_result ( oms_id, action_code, contract_status, contract_fail_reason, contract_no, agreement_status, agreement_fail_reason, agreement_id, agreement_dtl_id, push_status, create_time, update_time, create_user_id, create_user_name, update_user_id, update_user_name, org_code ) VALUES ( :oms_id, :action_code, :contract_status, :contract_fail_reason, :contract_no, :agreement_status, :agreement_fail_reason, :agreement_id, :agreement_dtl_id, 0, SYSTIMESTAMP, SYSTIMESTAMP, 0, '合同班', 0, '合同班', :org_code ) """ _COMPLETE_SQL = """ UPDATE rpa_purchase_contract_data SET process_status = :process_status, process_result = :process_result, process_time = SYSTIMESTAMP, update_time = SYSTIMESTAMP WHERE fid = :fid AND process_status = 3 """ _TABLE4_BIND_KEYS = ( "oms_id", "action_code", "contract_status", "contract_fail_reason", "contract_no", "agreement_status", "agreement_fail_reason", "agreement_id", "agreement_dtl_id", "org_code", ) def _row_from_record(cols: list[str], rec) -> PurchaseContractRow: data = dict(zip(cols, rec)) return PurchaseContractRow( fid=int(data["fid"]), oms_id=int(data["oms_id"]), supplier_id=data["supplier_id"], supplier_name=data["supplier_name"], contract_sign_date=data["contract_sign_date"], contract_start_date=data["contract_start_date"], contract_end_date=data["contract_end_date"], payment_term=int(data["payment_term"]), goods_id=data["goods_id"], goods_name=data["goods_name"], reg_no=data["reg_no"], spec=data["spec"], unit=data["unit"], qty=data["qty"], unit_price=data["unit_price"], purchaser_id=data["purchaser_id"], purchaser_name=data["purchaser_name"], planner_id=data["planner_id"], planner_name=data["planner_name"], contract_entry_status=data["contract_entry_status"], contract_no=data["contract_no"], process_status=int(data["process_status"]), org_code=data["org_code"], goods_mdm_code=data["goods_mdm_code"], supplier_mdm_code=data["supplier_mdm_code"], process_result=data.get("process_result") or "", ) class OracleContractRepo: def __init__(self, connect: Callable): self._connect = connect @classmethod def from_env(cls) -> "OracleContractRepo": oracle_dsn() return cls(connect=connect_from_env) def claim_pending(self, limit: int | None = None) -> list[PurchaseContractRow]: conn = self._connect() try: with conn.cursor() as cur: if limit is None: cur.execute(_SELECT_PENDING) else: cur.execute(_SELECT_PENDING_LIMIT, {"limit": int(limit)}) cols = [item[0].lower() for item in cur.description] fetched = [_row_from_record(cols, rec) for rec in cur.fetchall()] claimed: list[PurchaseContractRow] = [] for row in fetched: cur.execute(_CLAIM_SQL, {"fid": row.fid}) if cur.rowcount == 1: row.process_status = 3 claimed.append(row) conn.commit() return claimed except Exception as exc: try: conn.rollback() except Exception: pass raise RepoUnavailable(str(exc)) from exc finally: conn.close() def save_group(self, payload: Any) -> None: conn = self._connect() try: with conn.cursor() as cur: for row in payload.table4_rows: cur.execute( _INSERT_TABLE4_SQL, {key: row.get(key) for key in _TABLE4_BIND_KEYS}, ) for fid in payload.fids: cur.execute( _COMPLETE_SQL, { "process_status": payload.process_status, "process_result": payload.process_result, "fid": fid, }, ) conn.commit() except Exception as exc: try: conn.rollback() except Exception: pass raise RepoUnavailable(str(exc)) from exc finally: conn.close()