239 lines
7.4 KiB
Python
239 lines
7.4 KiB
Python
"""表 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()
|
|
|
|
|