fix(acks): accept IK5 from Gainwell, trust set-level codes over bogus AK9, surface TA1 in UI
Two related fixes land together because the UI was reporting
"1 accepted 1 rejected" for every 999 even though every inbound file
Gainwell ships has IK5=A.
1. Gainwell's MFT uses IK5 where the X12 005010X231A1 spec calls
for AK5 (the per-set accept/reject segment). The parser only
recognized AK5, so set_responses[0].set_accept_reject.code
defaulted to 'R' and the count summary showed all rejections.
_consume_ak2 now accepts either AK5 or IK5; the orchestrator's
segment-skip set picks up IK5 too. A new fixture
(minimal_999_ik5_gainwell.txt) is a verbatim copy of one of the
files in the FromHPE inbound staging dir.
2. _ack_count_summary (api + scheduler) now trusts the per-set
IK5 codes over the functional-group AK9. Gainwell's AK9 is
internally inconsistent — the per-claim IK5=A but the AK9
reports accepted=1, rejected=1, received=1 (sum exceeds
received). Trusting the per-set codes restores the right
answer: accepted=1, rejected=0, code='A'.
3. The Acks page now has a TA1 envelope register alongside the
999 register. TA1s are the lower-level sibling of the 999
(one row per inbound ISA/IEA). The backend surface (parser,
store, API at /api/ta1-acks) was already in place; this
adds the UI: Ta1Ack type, listTa1Acks API method, useTa1Acks
hook, and a Ta1AcksSection card with KPIs + table.
After reprocessing 1056 cached 999s through the new code: every row
shows code='A' with accepted=1, rejected=0 — matches the Gainwell
portal's per-claim accepted state. The user's earlier observation
("the claims look to be accepted in the portal") was correct: the
underlying claim state was always fine, only the displayed count was
wrong.
- backend/src/cyclone/parsers/parse_999.py | 21 ++-
- backend/src/cyclone/api.py | 11 +-
- backend/src/cyclone/scheduler.py | 13 +-
- backend/tests/test_parse_999.py | 32 ++++
- backend/tests/fixtures/minimal_999_ik5_gainwell.txt
- src/types/index.ts | 32 ++++
- src/lib/api.ts | 62 +++++-
- src/hooks/useTa1Acks.ts | 26 +++ (new)
- src/pages/Acks.tsx | 209 +++++++++++++++++++-
This commit is contained in:
@@ -539,6 +539,38 @@ export interface Ack {
|
||||
patientControlNumber?: string | null;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TA1 (Interchange Acknowledgment) — mirrors the `ta1_acks` table
|
||||
// and the `/api/ta1-acks` response. A TA1 is the lowest-level X12
|
||||
// envelope ack: one per inbound ISA/IEA interchange, separate from
|
||||
// the per-batch 999. Colorado Medicaid currently doesn't ship TA1s
|
||||
// in the FromHPE path (the inbound MFT only carries 999s) but
|
||||
// Gainwell has shipped them historically, so the UI shows them
|
||||
// whenever one is on file.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* One persisted TA1 ACK row, camelCased for the UI. Re-shaped in
|
||||
* `src/lib/api.ts` (`mapTa1Ack`) from the snake_case backend payload.
|
||||
*
|
||||
* ``ackCode`` is the interchange ack code: ``A`` = accepted,
|
||||
* ``E`` = accepted with envelope errors, ``R`` = rejected.
|
||||
* ``noteCode`` is an optional 3-digit X12 note code (e.g. ``000`` = no
|
||||
* error, ``001`` = unsupported interchange version, etc.).
|
||||
*/
|
||||
export interface Ta1Ack {
|
||||
id: number;
|
||||
controlNumber: string;
|
||||
ackCode: "A" | "E" | "R";
|
||||
noteCode: string | null;
|
||||
interchangeDate: string | null;
|
||||
interchangeTime: string | null;
|
||||
senderId: string | null;
|
||||
receiverId: string | null;
|
||||
sourceBatchId: string;
|
||||
parsedAt: string | null;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SP4 claim detail drawer types (Task 4).
|
||||
// Mirrors the JSON shape of `GET /api/claims/{claim_id}` 1:1 — camelCase
|
||||
|
||||
Reference in New Issue
Block a user