AutoRpa/rpa_oms
Yuuuu 586db4be90 feat: 班次可重跑,避免对方单据重复
领取 UPDATE 按 500 个 fid 分段,同一事务,任一段失败整单回滚。选品一行一落并续租,系统故障改回待领。页面和商城调用期间归还连接。坏连接丢弃后再借一次,未提交语句只重试一次。

加购登录或查询失败放回待领。传入购物车读数且已够量则不再加车。合同按「我的合同」三态:没有则起草,唯一则复用合同号,多条保持处理中。返利送审前按合同号查已有总单,读到则补写不再新建;读号失败保持处理中。

同一次提交带上本分支尚未入库的 Oracle 连接层(rpa_oracle / rpa_browser)及各班次改接。
2026-10-24 02:41:13 +08:00
..
app feat: 班次可重跑,避免对方单据重复 2026-10-24 02:41:13 +08:00
examples feat: 接口4只读表4未推行 2026-10-05 22:42:22 +08:00
tests feat: 班次可重跑,避免对方单据重复 2026-10-24 02:41:13 +08:00
.env.example feat: 本机.env启动,入站与选品落表补审计字段 2026-10-02 22:46:22 +08:00
README.md feat: 班次可重跑,避免对方单据重复 2026-10-24 02:41:13 +08:00
pyproject.toml feat: 班次可重跑,避免对方单据重复 2026-10-24 02:41:13 +08:00
start.ps1 feat: 本机.env启动,入站与选品落表补审计字段 2026-10-02 22:46:22 +08:00
uv.lock feat: 接口1销售商品收件,按omsId幂等落表 2026-10-02 10:57:21 +08:00

README.md

rpa_oms

订单中心四个 HTTP 口,一个 FastAPI。HTTP 收件不同步跑作业。作业在 rpa_selection / rpa_cart / rpa_contract / rpa_rebate。

口径:docs/RPA订单中心接口开发口径_20260930.md。DDL:docs/ddl/rpa_oms_staging_tables.sql。

口 方向 底表 代码
1 订单中心 → 本方 rpa_sales_goods_mapping_data POST /api/oms/v1/sales-goods
2 本方 → 订单中心 rpa_cart_settlement_goods_data app/outbound/cart_settlement.py 取 push_status=0 组装报文。路径仍空,不发 HTTP
3 订单中心 → 本方 rpa_purchase_contract_data POST /api/oms/v1/purchase-contracts,按对方 fid 幂等
4 本方 → 订单中心 rpa_contract_agreement_result app/outbound/contract_agreement.py 取 push_status=0 组装报文。路径仍空,不发 HTTP

入站(1、3):

  • 鉴权:header X-Oms-Token,环境变量 OMS_INBOUND_TOKEN
  • 信封:{"data":[...]},一批最多 100 条
  • 接口 1 落表 deal_flag=0,请求里不跑选品
  • 接口 3 落表 process_status=0,请求里不录合同

接口 2 出站组装:load_cart_settlement_envelope(repo),同一 omsId 不拆批。上限默认 500,环境变量 OMS_OUTBOUND_BATCH_LIMIT 可改。SQL 侧按组截断。不改 push_status,不发 HTTP。连接从 rpa_oracle 池借。

from rpa_oracle.pool import create_pool
from app.outbound.cart_settlement import load_cart_settlement_envelope
from app.outbound.oracle_repo import OracleCartSettlementRepo

pool = create_pool(role="oms")
with pool.acquire() as conn:
    envelope = load_cart_settlement_envelope(OracleCartSettlementRepo(conn))

接口 4 出站组装:load_contract_agreement_envelope(repo),同一非空 contractNo 不拆批。上限同样默认 500。不改 push_status,不发 HTTP。

from rpa_oracle.pool import create_pool
from app.outbound.contract_agreement import load_contract_agreement_envelope
from app.outbound.oracle_repo import OracleContractAgreementRepo

pool = create_pool(role="oms")
with pool.acquire() as conn:
    envelope = load_contract_agreement_envelope(OracleContractAgreementRepo(conn))

运行时只落 / 读 Oracle。入站单测用假连接录 SQL,不连库。

真库

Oracle 11.2 需要 Instant Client(thick)。密码只放本机 rpa_oms/.env(已 gitignore),不要写进仓库、README、命令行历史。

cd rpa_oms
uv sync --python 3.12
export OMS_INBOUND_TOKEN=dev-oms-token
export RPA_ORACLE_HOST=192.168.12.244
export RPA_ORACLE_PORT=1521
export RPA_ORACLE_SERVICE=rpa
export RPA_ORACLE_USER=rpainit
export RPA_ORACLE_PASSWORD=...
export RPA_ORACLE_THICK=1
# 如需指定 Instant Client 目录:
# export RPA_ORACLE_CLIENT_LIB=/path/to/instantclient
uv run uvicorn app.main:app --reload --port 8001

缺 RPA_ORACLE_HOST / 用户 / 密码时,收件接口回 503。

Windows 真库

本机 Mac 打不到 192.168.12.244,连库测试在 Windows 上做。Python 3.12 + Instant Client(位数一致),密码不要写进仓库。

PowerShell:

cd rpa_oms
uv sync --python 3.12
Copy-Item -LiteralPath .env.example -Destination .env
# 只编辑本机 .env 的 RPA_ORACLE_PASSWORD,不要 git add .env
.\start.ps1

先 GET http://127.0.0.1:8001/health,再把 examples/sales_goods_batch.json POST 两次:

  1. 第一次:两条 ACCEPTED,表里各一行 deal_flag=0
  2. 第二次:两条 DUPLICATE,表行数不变
curl.exe -sS http://127.0.0.1:8001/api/oms/v1/sales-goods `
  -H "Content-Type: application/json" `
  -H "X-Oms-Token: dev-oms-token" `
  --data-binary "@examples/sales_goods_batch.json"

接口 3 同样 POST 两次 examples/purchase_contract_batch.json:第一次两条 ACCEPTED(process_status=0),第二次两条 DUPLICATE。

curl.exe -sS http://127.0.0.1:8001/api/oms/v1/purchase-contracts `
  -H "Content-Type: application/json" `
  -H "X-Oms-Token: dev-oms-token" `
  --data-binary "@examples/purchase_contract_batch.json"

运维

怎么跑

Windows 真库见上一节:本机 .env 配 OMS_INBOUND_TOKEN 和 RPA_ORACLE_*,.\start.ps1 起 8001。缺 HOST / 用户 / 密码时收件回 503。审计表 DDL 在 docs/ddl/rpa_oms_staging_tables.sql 末尾 rpa_oms_inbound_audit,真库要先建这张表。

看表 1/3 哪列

  • 接口 1:rpa_sales_goods_mapping_data。看 oms_id、deal_flag(0 待选品)、bar_code、goods_mdm_code。同一 oms_id 不应有第二行。
  • 接口 3:rpa_purchase_contract_data。看 fid、process_status(0 待合同班)、contract_entry_status、contract_no。按对方 fid 幂等。
  • 审计:rpa_oms_inbound_audit。看 api_no(1 或 3)、http_code、error_text、token_masked。
  • 接口 2:rpa_cart_settlement_goods_data。看 oms_id、push_status(0 未推,1 成功,2 失败,3 推送中)、push_result。
  • 接口 4:rpa_contract_agreement_result。看 contract_no、push_status、push_result。

出站批次和重推

  • 一批上限:环境变量 OMS_OUTBOUND_BATCH_LIMIT,默认 500。口 2 同一 omsId 不拆批;口 4 同一非空 contractNo 不拆批。
  • 未推:SELECT * FROM rpa_cart_settlement_goods_data WHERE push_status = 0(口 4 换表名)。
  • 已推成功:push_status = 1。
  • 失败重推:把 push_status 改回 0(例如 UPDATE ... SET push_status = 0 WHERE push_status = 2)。mark_pushed 已备,路径仍空,不要把未 POST 的行标成已推。
  • 缺 HOST / 用户 / 密码时 create_pool 抛「数据库不可用」,文案不含环境变量名。

崩溃与审计失败

入站请求里不跑选品、不录合同,没有班次那种「停在 3」的戳。库故障整包 503,一条业务行都不落。审计 INSERT 失败只记本机日志,不把已经 200 的收件打成 500。

503 对外 vs 审计原文

对外 msg 固定「数据库不可用」,HTTP body 不含 DSN、Instant Client 路径、ORA-、表名。ORA 原文在审计表 error_text。401 对外「身份认证失败」,token 只存 ***。

点名命令

cd rpa_oms
uv run pytest tests/test_sales_goods_receive.py -q
uv run pytest tests/test_oracle_repo.py -q
uv run pytest tests/test_purchase_contract_receive.py -q
uv run pytest tests/test_oracle_contract_repo.py -q
uv run pytest tests/test_cart_settlement_outbound.py::test_assembles_unpushed_rows_as_document_envelope -q
uv run pytest tests/test_oracle_cart_repo.py::test_list_unpushed_keeps_whole_oms_group_when_limit_is_3 -q
uv run pytest tests/test_contract_agreement_outbound.py::test_assembles_unpushed_rows_as_document_envelope -q

真库:同一 JSON POST 两次 → 先 ACCEPTED 后 DUPLICATE。再人为断库,接口回固定「数据库不可用」,审计表有原文。