dd7da18279
The dzinesco SP9 seed had `paths.inbound` and `paths.outbound` mapped to
the wrong Gainwell MFT directories:
- paths.outbound was FromHPE/ (HPE sends files FROM here TO us — inbound)
- paths.inbound was ToHPE/ (we send files TO here — outbound)
So `/api/clearhouse/submit` was writing 837P claims to FromHPE (where
HPE puts acks/835s) and the SP16 scheduler was polling ToHPE (where our
claims go). 999 / TA1 / 835 files in the real FromHPE inbox were
unreachable.
Semantics per operator (2026-06-24):
- FromHPE = HPE/Gainwell → us = 999, TA1, 835 (inbound)
- ToHPE = us → HPE/Gainwell = 837P claims (outbound)
**Runtime code (the actual fix):**
- backend/src/cyclone/store.py — SP9 seed paths flipped
- backend/src/cyclone/edi/filenames.py — docstring corrected
**Test fixtures + assertions (would otherwise fail on the new seed):**
- backend/tests/test_clearhouse_api.py
- backend/tests/test_providers_seed.py
- backend/tests/test_sftp_stub.py — incl. inbound dir paths
- backend/tests/test_sftp_paramiko.py
- backend/tests/test_store_update_clearhouse.py
- backend/tests/test_api_clearhouse_patch.py
- backend/tests/test_scheduler.py
- backend/tests/test_api_scheduler.py
**Docs (text-only — keeps the codebase self-consistent):**
- README.md
- docs/reference/co-medicaid.md
- docs/superpowers/specs/2026-06-20-cyclone-multi-payer-npi-sftp-design.md
**Operator action required after merge:** the existing clearhouse row in
`~/.local/share/cyclone/cyclone.db` was seeded with the old wrong
paths. Easiest recovery:
1. `rm ~/.local/share/cyclone/cyclone.db` and let `ensure_clearhouse_seeded` re-run on next boot, OR
2. PATCH /api/clearhouse with the new `paths` block (the SP25
reconfigure hook picks it up live, including by the running scheduler).
**Verification:**
- 82 tests in the affected files pass (test_clearhouse_api, test_providers_seed,
test_sftp_stub, test_sftp_paramiko, test_store_update_clearhouse,
test_api_clearhouse_patch, test_scheduler, test_api_scheduler, test_filenames).
- Full backend suite: 1029 pass + 36 pre-existing order-dependent flakes
unrelated to this change (verified by running the same tests in isolation).
90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
"""SP25 — store.update_clearhouse() round-trip test.
|
|
|
|
The PATCH /api/clearhouse endpoint needs a way to replace the singleton
|
|
clearhouse row inside one session. This test exercises the method
|
|
directly against a fresh in-memory DB.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from cyclone import db
|
|
from cyclone.providers import Clearhouse, SftpBlock
|
|
from cyclone.store import store as cycl_store
|
|
|
|
|
|
def _seed_clearhouse():
|
|
"""Insert the default clearhouse row used by SP9's lifespan seed."""
|
|
cycl_store.ensure_clearhouse_seeded()
|
|
|
|
|
|
def test_update_clearhouse_round_trip():
|
|
"""Replace all fields on the singleton row; GET returns the new values."""
|
|
_seed_clearhouse()
|
|
|
|
new_block = SftpBlock(
|
|
host="mft.gainwelltechnologies.com",
|
|
port=22,
|
|
username="colorado-fts\\coxix_prod_11525703",
|
|
paths={
|
|
"outbound": "/CO XIX/PROD/coxix_prod_11525703/ToHPE",
|
|
"inbound": "/CO XIX/PROD/coxix_prod_11525703/FromHPE",
|
|
},
|
|
stub=False,
|
|
staging_dir="./var/sftp/staging",
|
|
auth={"password_keychain_account": "sftp.gainwell.password"},
|
|
)
|
|
|
|
new_clearhouse = Clearhouse.model_validate({
|
|
"id": 1,
|
|
"name": "dzinesco",
|
|
"tpid": "11525703",
|
|
"submitter_name": "Dzinesco",
|
|
"submitter_id_qual": "46",
|
|
"submitter_contact_name": "Tyler Martinez",
|
|
"submitter_contact_email": "tyler@dzinesco.com",
|
|
"filename_block": {
|
|
"tz": "America/Denver",
|
|
"outbound_template": "{tpid}-{tx}-{ts_mt}-1of1.{ext}",
|
|
"inbound_template": "TP{tpid}-{orig_tx}_M{tracking}-{ts}-1of1_{file_type}.x12",
|
|
},
|
|
"sftp_block": new_block.model_dump(),
|
|
"updated_at": "2026-06-24T00:00:00+00:00",
|
|
})
|
|
|
|
cycl_store.update_clearhouse(new_clearhouse)
|
|
|
|
fetched = cycl_store.get_clearhouse()
|
|
assert fetched is not None
|
|
assert fetched.sftp_block.stub is False
|
|
assert fetched.sftp_block.host == "mft.gainwelltechnologies.com"
|
|
assert fetched.sftp_block.auth == {"password_keychain_account": "sftp.gainwell.password"}
|
|
|
|
|
|
def test_update_clearhouse_missing_row_raises():
|
|
"""If the singleton row was never seeded, update raises LookupError."""
|
|
# Wipe the DB.
|
|
db._reset_for_tests()
|
|
db.init_db()
|
|
|
|
new_block = SftpBlock(
|
|
host="mft.example.com", port=22, username="u",
|
|
paths={"outbound": "/o", "inbound": "/i"},
|
|
stub=True, staging_dir="/tmp", auth={},
|
|
)
|
|
new_clearhouse = Clearhouse.model_validate({
|
|
"id": 1, "name": "x", "tpid": "1",
|
|
"submitter_name": "X", "submitter_id_qual": "46",
|
|
"submitter_contact_name": "X", "submitter_contact_email": "x@x",
|
|
"filename_block": {
|
|
"tz": "America/Denver",
|
|
"outbound_template": "{tpid}-{tx}-{ts}-1of1.{ext}",
|
|
"inbound_template": "TP{tpid}-{tx}_{ts}.x12",
|
|
},
|
|
"sftp_block": new_block.model_dump(),
|
|
"updated_at": "2026-06-24T00:00:00+00:00",
|
|
})
|
|
|
|
with pytest.raises(LookupError):
|
|
cycl_store.update_clearhouse(new_clearhouse)
|