feat(sp9): multi-payer, multi-NPI, SFTP stub for dzinesco/TOC
- providers table seeded with 3 NPIs (Montrose, Delta, Salida) - payers + payer_configs (per-tx config) join table - clearhouse singleton (dzinesco identity, SFTP block, filename block) - config/payers.yaml loader with Pydantic schema validation - cyclone/edi/filenames.py: HCPF X12 File Naming Standards helpers - cyclone/clearhouse/sftp.py: stub that copies to ./var/sftp/staging/... - cyclone/secrets.py: macOS Keychain wrapper via keyring - 11 new validation rules R200-R210 (CO MAP + HCPF naming) - 6 new API endpoints (/api/clearhouse/*, /api/config/*, /api/admin/reload-config) - migration 0007 - 72 new tests (646 total passing, was 574) See spec: docs/superpowers/specs/2026-06-20-cyclone-multi-payer-npi-sftp-design.md
This commit is contained in:
@@ -15,6 +15,102 @@ Financing (HCPF) requires.
|
||||
These appear in the `NM1*PR` (payer) and `NM1*40` (receiver) segments of
|
||||
the 837P file.
|
||||
|
||||
## dzinesco's TPID (clearinghouse identity)
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Clearinghouse name | `dzinesco` |
|
||||
| dzinesco TPID | `11525703` |
|
||||
| Submitter name (`NM1*41`) | `Dzinesco` |
|
||||
| Submitter contact | Tyler Martinez <tyler@dzinesco.com> |
|
||||
| SFTP host | `mft.gainwelltechnologies.com` |
|
||||
| SFTP username | `colorado-fts\coxix_prod_11525703` |
|
||||
| SFTP outbound dir | `/CO XIX/PROD/coxix_prod_11525703/FromHPE` |
|
||||
| SFTP inbound dir | `/CO XIX/PROD/coxix_prod_11525703/ToHPE` |
|
||||
|
||||
## dzinesco's 3 billing-provider NPIs
|
||||
|
||||
All 3 NPIs are registered to the same Montrose corporate office. They
|
||||
share tax ID `721587149` and taxonomy `251E00000X` (Home Health).
|
||||
|
||||
| NPI | Label | Legal name | Address |
|
||||
|---|---|---|---|
|
||||
| `1881068062` | Montrose | TOC, Inc. | 1100 East Main St, Suite A, Montrose, CO 814014063 |
|
||||
| `1851446637` | Delta | TOC, Inc. | 1100 East Main St, Suite A, Montrose, CO 814014063 |
|
||||
| `1467507269` | Salida | TOC, Inc. | 1100 East Main St, Suite A, Montrose, CO 814014063 |
|
||||
|
||||
Production data (June 2026) confirms all 3 NPIs submit through the same
|
||||
Montrose address block. See SP9 spec
|
||||
`docs/superpowers/specs/2026-06-20-cyclone-multi-payer-npi-sftp-design.md`.
|
||||
|
||||
## SFTP submission to Gainwell
|
||||
|
||||
dzinesco submits 837P files to Gainwell's MFT (Managed File Transfer)
|
||||
at `mft.gainwelltechnologies.com`. The full SFTP path layout is
|
||||
specified by the user (2026-06-20):
|
||||
|
||||
- **Outbound** (we send): `/CO XIX/PROD/coxix_prod_11525703/FromHPE`
|
||||
- **Inbound** (HPE/Gainwell sends to us): `/CO XIX/PROD/coxix_prod_11525703/ToHPE`
|
||||
|
||||
### File naming
|
||||
|
||||
Per the HCPF X12 File Naming Standards Quick Guide
|
||||
(<https://hcpf.colorado.gov/tp-x12-filenaming>):
|
||||
|
||||
- **Outbound** (we send): `TPID-TransactionType-yyyymmddhhmmssSSS-1of1.X12`
|
||||
- Example: `11525703-837P-20260620132243505-1of1.x12`
|
||||
- 17-digit millisecond precision, Mountain Time (NOT UTC)
|
||||
- "1of1" is the only accepted sequence value
|
||||
- **Inbound** (HPE sends): `TP<TPID>-<OrigTx>_M<Tracking>-<ts>-1of1_<FileType>.x12`
|
||||
- Example: `TP11525703-837P_M019048402-20260520231513488-1of1_999.x12`
|
||||
- `FileType` is one of: `999`, `TA1`, `270`, `271`, `276`, `277`, `277CA`, `278`, `820`, `834`, `835`, `ENCR`
|
||||
- 277CA is distinguished by `ST*277CA` content (filename uses `277`)
|
||||
|
||||
### SP9 stub vs SP13 wire-up
|
||||
|
||||
The SP9 SFTP client is a **stub** that writes generated 837 files to
|
||||
`./var/sftp/staging/{outbound_path}/{filename}` instead of opening a
|
||||
real SFTP connection. The structural interface matches the future
|
||||
`paramiko`-backed implementation, so SP13 is a one-file swap.
|
||||
|
||||
`clearhouse.sftp_block.stub` is `true` by default. Set to `false` (and
|
||||
create the Keychain entry, see below) to enable real SFTP.
|
||||
|
||||
### Keychain setup (one-time, by operator)
|
||||
|
||||
```sh
|
||||
security add-generic-password -s cyclone -a sftp.gainwell.password -w '<password>'
|
||||
security find-generic-password -s cyclone -a sftp.gainwell.password -w
|
||||
```
|
||||
|
||||
The `cyclone/secrets.py` module fetches the secret by name. When the
|
||||
entry is missing or `keyring` is not installed, the SFTP stub falls
|
||||
back to `<stub-secret>` so the local flow still works.
|
||||
|
||||
### Verification
|
||||
|
||||
```sh
|
||||
# List providers (3 NPIs)
|
||||
curl http://localhost:8000/api/config/providers
|
||||
|
||||
# List payers (1 = CO_TXIX)
|
||||
curl http://localhost:8000/api/config/payers
|
||||
|
||||
# List CO_TXIX configs
|
||||
curl http://localhost:8000/api/config/payers/CO_TXIX/configs
|
||||
|
||||
# Clearhouse identity
|
||||
curl http://localhost:8000/api/clearhouse
|
||||
|
||||
# Submit 2 claims to the SFTP stub
|
||||
curl -X POST http://localhost:8000/api/clearhouse/submit \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"claim_ids": ["CLM-1", "CLM-2"], "payer_id": "CO_TXIX"}'
|
||||
|
||||
# Files appear at ./var/sftp/staging/CO XIX/PROD/coxix_prod_11525703/FromHPE/
|
||||
ls -la "./var/sftp/staging/CO XIX/PROD/coxix_prod_11525703/FromHPE/"
|
||||
```
|
||||
|
||||
## Payer IDs
|
||||
|
||||
### 837P (claims)
|
||||
|
||||
Reference in New Issue
Block a user