112 lines
3.2 KiB
Python
112 lines
3.2 KiB
Python
"""接口 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
|
||
|
||
_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, 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
|
||
)
|
||
"""
|
||
|
||
_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
|