"""接口 1 Oracle 落表。 11.2 只能 thick(Instant Client)。Windows 把 Instant Client 目录设到 RPA_ORACLE_CLIENT_LIB。fid 由序列触发器生成,INSERT 不绑这一列。 唯一约束冲突(ORA-00001)当成 oms_id 重复。 """ from __future__ import annotations import os from collections.abc import Callable from .repo import DuplicateOmsId, RepoUnavailable # 接口入站无登录用户:创建人/更新人固定 0 / 系统管理员,时间用库时钟。 _INSERT_SQL = """ INSERT INTO rpa_sales_goods_mapping_data ( oms_id, bar_code, order_date, sale_price, sale_qty, plan_purchase_qty, goods_id, goods_name, goods_spec, manufacturer, approval_no, unit, customer_id, customer_name, org_code, goods_mdm_code, customer_mdm_code, create_time, create_user_id, create_user_name, update_time, update_user_id, update_user_name, deal_flag ) VALUES ( :oms_id, :bar_code, :order_date, :sale_price, :sale_qty, :plan_purchase_qty, :goods_id, :goods_name, :goods_spec, :manufacturer, :approval_no, :unit, :customer_id, :customer_name, :org_code, :goods_mdm_code, :customer_mdm_code, SYSDATE, 0, '系统管理员', SYSDATE, 0, '系统管理员', 0 ) """ _BIND_KEYS = ( "oms_id", "bar_code", "order_date", "sale_price", "sale_qty", "plan_purchase_qty", "goods_id", "goods_name", "goods_spec", "manufacturer", "approval_no", "unit", "customer_id", "customer_name", "org_code", "goods_mdm_code", "customer_mdm_code", ) _client_ready = False class OracleSalesGoodsRepo: def __init__(self, connect: Callable): self._connect = connect @classmethod def from_env(cls) -> "OracleSalesGoodsRepo": user = os.getenv("RPA_ORACLE_USER", "") password = os.getenv("RPA_ORACLE_PASSWORD", "") host = os.getenv("RPA_ORACLE_HOST", "") if not user or not password or not host: raise RepoUnavailable("未配置 RPA_ORACLE_HOST / RPA_ORACLE_USER / RPA_ORACLE_PASSWORD") port = os.getenv("RPA_ORACLE_PORT", "1521") service = os.getenv("RPA_ORACLE_SERVICE", "rpa") dsn = f"{host}:{port}/{service}" def connect(): _ensure_client() import oracledb return oracledb.connect(user=user, password=password, dsn=dsn) return cls(connect=connect) def insert(self, record: dict) -> None: conn = self._connect() try: with conn.cursor() as cur: cur.execute(_INSERT_SQL, {key: record[key] for key in _BIND_KEYS}) conn.commit() except DuplicateOmsId: raise except Exception as exc: try: conn.rollback() except Exception: pass if _ora_code(exc) == 1: raise DuplicateOmsId(record["oms_id"]) from exc raise RepoUnavailable(str(exc)) from exc finally: conn.close() def _ora_code(exc: BaseException) -> int | None: if not exc.args: return None return getattr(exc.args[0], "code", None) def _ensure_client() -> None: # init_oracle_client 每个进程只能调一次。 global _client_ready if _client_ready: return import oracledb if os.getenv("RPA_ORACLE_THICK", "1") == "1": lib_dir = os.getenv("RPA_ORACLE_CLIENT_LIB", "") kwargs = {"lib_dir": lib_dir} if lib_dir else {} oracledb.init_oracle_client(**kwargs) _client_ready = True