172 lines
5.5 KiB
Python
172 lines
5.5 KiB
Python
# 接口 2 / 4:读 push_status=0,按组在 SQL 侧截断。
|
||
#
|
||
# 连接由调用方从 rpa_oracle 池借入,仓库不 connect、不 close。
|
||
# 不向订单中心发 HTTP。mark_pushed 备好回写,本段不接推送。
|
||
|
||
from __future__ import annotations
|
||
|
||
from rpa_oracle.errors import RepoUnavailable
|
||
|
||
from ..inbound.oracle_repo import in_binds
|
||
|
||
_LIST_UNPUSHED_SQL = """
|
||
WITH src AS (
|
||
SELECT
|
||
fid, operate_type, oms_id, platform_type, supplier_name, bar_code,
|
||
purchase_price, purchase_qty, purchase_total, status, fail_reason,
|
||
pay_order_no, pay_order_dtl_id, org_code, push_status
|
||
FROM rpa_cart_settlement_goods_data
|
||
WHERE push_status = 0
|
||
),
|
||
ranked AS (
|
||
SELECT
|
||
src.*,
|
||
COUNT(*) OVER (PARTITION BY oms_id) AS grp_size
|
||
FROM src
|
||
),
|
||
grp AS (
|
||
SELECT oms_id, MIN(grp_size) AS grp_size
|
||
FROM ranked
|
||
GROUP BY oms_id
|
||
),
|
||
run AS (
|
||
SELECT
|
||
oms_id,
|
||
grp_size,
|
||
SUM(grp_size) OVER (ORDER BY oms_id) AS running_end,
|
||
SUM(grp_size) OVER (ORDER BY oms_id) - grp_size AS running_start
|
||
FROM grp
|
||
)
|
||
SELECT
|
||
r.fid, r.operate_type, r.oms_id, r.platform_type, r.supplier_name, r.bar_code,
|
||
r.purchase_price, r.purchase_qty, r.purchase_total, r.status, r.fail_reason,
|
||
r.pay_order_no, r.pay_order_dtl_id, r.org_code, r.push_status
|
||
FROM ranked r
|
||
JOIN run ON run.oms_id = r.oms_id
|
||
WHERE run.running_start = 0 OR run.running_end <= :limit
|
||
ORDER BY r.oms_id, r.fid
|
||
"""
|
||
|
||
_LIST_AGREEMENT_SQL = """
|
||
WITH src AS (
|
||
SELECT
|
||
fid, oms_id, action_code, contract_status, contract_fail_reason,
|
||
contract_no, agreement_status, agreement_fail_reason,
|
||
agreement_id, agreement_dtl_id, org_code, push_status,
|
||
CASE
|
||
WHEN TRIM(contract_no) IS NULL THEN 'F:' || TO_CHAR(fid)
|
||
ELSE 'N:' || TRIM(contract_no)
|
||
END AS grp_key
|
||
FROM rpa_contract_agreement_result
|
||
WHERE push_status = 0
|
||
),
|
||
ranked AS (
|
||
SELECT
|
||
src.*,
|
||
COUNT(*) OVER (PARTITION BY grp_key) AS grp_size
|
||
FROM src
|
||
),
|
||
grp AS (
|
||
SELECT grp_key, MIN(grp_size) AS grp_size, MIN(fid) AS grp_first_fid
|
||
FROM ranked
|
||
GROUP BY grp_key
|
||
),
|
||
run AS (
|
||
SELECT
|
||
grp_key,
|
||
grp_size,
|
||
SUM(grp_size) OVER (ORDER BY grp_first_fid, grp_key) AS running_end,
|
||
SUM(grp_size) OVER (ORDER BY grp_first_fid, grp_key) - grp_size AS running_start
|
||
FROM grp
|
||
)
|
||
SELECT
|
||
r.fid, r.oms_id, r.action_code, r.contract_status, r.contract_fail_reason,
|
||
r.contract_no, r.agreement_status, r.agreement_fail_reason,
|
||
r.agreement_id, r.agreement_dtl_id, r.org_code, r.push_status
|
||
FROM ranked r
|
||
JOIN run ON run.grp_key = r.grp_key
|
||
WHERE run.running_start = 0 OR run.running_end <= :limit
|
||
ORDER BY r.fid
|
||
"""
|
||
|
||
_CART_TABLE = "rpa_cart_settlement_goods_data"
|
||
_AGREEMENT_TABLE = "rpa_contract_agreement_result"
|
||
|
||
|
||
# 接口 2 连 Oracle 的仓库,管表 2 未推取数和回写。
|
||
class OracleCartSettlementRepo:
|
||
# 挂上调用方借来的连接。不要在仓库里再 connect 或 close。
|
||
def __init__(self, conn):
|
||
self._conn = conn
|
||
|
||
# 捞 push_status=0,同一 oms_id 不拆组,在 SQL 侧按 limit 截断。
|
||
def list_unpushed(self, limit: int = 500) -> list[dict]:
|
||
return _fetch(self._conn, _LIST_UNPUSHED_SQL, {"limit": limit})
|
||
|
||
# 一次 UPDATE 回写表 2 的 push_status。空列表不访问库。
|
||
def mark_pushed(self, fids: list[int], status: int, reason: str | None) -> None:
|
||
_mark(self._conn, _CART_TABLE, fids, status, reason, "SYSDATE")
|
||
|
||
|
||
# 接口 4 连 Oracle 的仓库,管表 4 未推取数和回写。
|
||
class OracleContractAgreementRepo:
|
||
# 挂上调用方借来的连接。不要在仓库里再 connect 或 close。
|
||
def __init__(self, conn):
|
||
self._conn = conn
|
||
|
||
# 捞 push_status=0,同一非空 contract_no 不拆组,在 SQL 侧按 limit 截断。
|
||
def list_unpushed(self, limit: int = 500) -> list[dict]:
|
||
return _fetch(self._conn, _LIST_AGREEMENT_SQL, {"limit": limit})
|
||
|
||
# 一次 UPDATE 回写表 4 的 push_status。空列表不访问库。
|
||
def mark_pushed(self, fids: list[int], status: int, reason: str | None) -> None:
|
||
_mark(self._conn, _AGREEMENT_TABLE, fids, status, reason, "SYSTIMESTAMP")
|
||
|
||
|
||
# 执行查询并把列名转小写。失败抛「数据库不可用」,不含 ORA。
|
||
def _fetch(conn, sql: str, binds: dict) -> list[dict]:
|
||
try:
|
||
with conn.cursor() as cur:
|
||
cur.execute(sql, binds)
|
||
cols = [item[0].lower() for item in cur.description]
|
||
return [dict(zip(cols, row)) for row in cur.fetchall()]
|
||
except Exception as exc:
|
||
raise RepoUnavailable("数据库不可用") from exc
|
||
|
||
|
||
# 一次 UPDATE ... WHERE fid IN (...)。失败回滚并抛「数据库不可用」。
|
||
def _mark(
|
||
conn,
|
||
table: str,
|
||
fids: list[int],
|
||
status: int,
|
||
reason: str | None,
|
||
time_expr: str,
|
||
) -> None:
|
||
if not fids:
|
||
return
|
||
placeholders, binds = in_binds(fids)
|
||
binds["status"] = status
|
||
binds["reason"] = reason
|
||
sql = (
|
||
f"UPDATE {table} "
|
||
f"SET push_status = :status, push_result = :reason, "
|
||
f"push_time = {time_expr}, update_time = {time_expr} "
|
||
f"WHERE fid IN ({placeholders})"
|
||
)
|
||
try:
|
||
with conn.cursor() as cur:
|
||
cur.execute(sql, binds)
|
||
conn.commit()
|
||
except Exception as exc:
|
||
_rollback(conn)
|
||
raise RepoUnavailable("数据库不可用") from exc
|
||
|
||
|
||
# 回滚本连接已写入的行;回滚失败忽略。
|
||
def _rollback(conn) -> None:
|
||
try:
|
||
conn.rollback()
|
||
except Exception:
|
||
pass
|