147 lines
6.8 KiB
Markdown
147 lines
6.8 KiB
Markdown
# 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` 池借。
|
||
|
||
```python
|
||
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。
|
||
|
||
```python
|
||
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、命令行历史。
|
||
|
||
```bash
|
||
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:
|
||
|
||
```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`,表行数不变
|
||
|
||
```powershell
|
||
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`。
|
||
|
||
```powershell
|
||
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 只存 `***`。
|
||
|
||
### 点名命令
|
||
|
||
```bash
|
||
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。再人为断库,接口回固定「数据库不可用」,审计表有原文。
|