feat(corporate-bank-account-payment-order): 基于原模板生成建行制单

这个提交包含在:
2026-08-03 01:18:10 +08:00
父节点 91564d6774
当前提交 23c3768c46
共修改 19 个文件,包含 713 行新增和 152 行删除
+35 -3
查看文件
@@ -36,6 +36,10 @@
APIs return only bank name and masked account.
- Payment-order API: `POST /api/payment-batches/:id/payment-order` with a reason;
success is an in-memory BIFF8 `.xls` download with `Cache-Control: no-store`.
- Runtime: Node passes validated row JSON through stdin to the fixed
`fill-payment-order-template.py`; the dedicated Python runtime returns BIFF8
bytes on stdout. `PAYMENT_ORDER_PYTHON_BIN` may select the fixed interpreter,
but requests cannot select the script or template path.
### 3. Contracts
@@ -62,6 +66,19 @@
supposed frozen account through a live-profile fallback.
- A payment-order file is an efficiency artifact. A bank receipt remains the
hard evidence required before registering bank payment complete.
- Generate bank files by filling the controlled, blank BIFF8 template asset.
Rebuilding a workbook with matching headers is forbidden when it loses the
bank template's column widths, row heights, fonts, fills, borders or
alignment. The asset contains headers and formatted blank rows only, and its
SHA-256 is verified before every fill.
- Node owns authorization, snapshot decryption, blockers, ordering, serials,
amounts, audit and export counters. Python only copies the fixed template and
fills the already validated 15-cell rows. Full accounts travel only on child
stdin; never place them in argv, environment variables, logs, stderr or a
temporary workbook file.
- CI and the production image install `xlrd`, `xlwt` and `xlutils` from the same
`--require-hashes` requirements. Do not fall back to a style-dropping
generator when Python, a dependency or the template is unavailable.
### 4. Validation & Error Matrix
@@ -76,6 +93,12 @@
- Reveal/export without a 2-500 character reason -> `400 VALID_001` and no full
account/file response.
- Successful export audit/update failure -> no download response.
- Template hash/structure mismatch -> `409 PAYMENT_ORDER_EXPORT_BLOCKED`, no
export increment and no file bytes; manual payment plus receipt remains
available.
- Python executable/dependency missing, timeout, oversized output, non-zero exit
or invalid OLE magic -> fixed safe generation error; never copy child stderr
into the API error or application log.
### 5. Good/Base/Bad Cases
@@ -85,6 +108,10 @@
payment and receipt, and clearly has no payment-order capability.
- Bad: export or manual-transfer reveal re-queries the employee profile after
review, silently uses a changed account, or returns raw snapshot JSON.
- Good: a fourth synthetic row copies the first template data-row style and
height while the amount cell changes only to numeric `0.00` formatting.
- Bad: create a fresh workbook from the 15 labels, or invoke Python with an
account in argv/env, even if the resulting values look correct in a parser.
### 6. Tests Required
@@ -94,9 +121,14 @@
accounts, `v1:` and raw snapshots.
- Batch creation tests for single legal entity, direct ciphertext copy,
CCB-only, decrypt failure and legacy behavior.
- BIFF8 generator tests plus independent `xlrd==2.0.2` readback for three sheets,
15 headers, seven string columns, leading-zero `01`, long accounts, Chinese,
amount formatting and deterministic row order.
- BIFF8 template-fill tests plus independent readback for three sheets, 15
headers, leading-zero `01`, long account text, Chinese, numeric `0.00`
amounts and deterministic row order. Compare visual signatures for column
widths, row heights, font/bold, fill, border, alignment and wrapped text;
include a row beyond the three preformatted template rows.
- Negative tests cover missing Python/dependencies, template hash drift, child
failure and a child that echoes the synthetic input to stderr; exposed errors
and logs must not contain the account or original row payload.
- Build one synthetic batch with at least two independent payer/payee blockers;
assert the DTO/error contains both safe blocker entries and emits no file,
export counter or success audit.