From f4a545f379e98fb9898b13036efbcefd82deb1b9 Mon Sep 17 00:00:00 2001 From: Tyler Date: Sat, 20 Jun 2026 16:59:22 -0600 Subject: [PATCH] fix(frontend): UnmatchedClaim/UnmatchedRemittance types match store.to_ui_claim_from_orm wire shape The Reconciliation page crashed with 'c.chargeAmount.toFixed is undefined' because the TS types declared fields the backend never emitted (chargeAmount vs billedAmount, patientControlNumber vs patientName, statusCode vs status, totalPaid vs paidAmount). - UnmatchedClaim: chargeAmount -> billedAmount, patientControlNumber -> patientName, payerId/serviceDate now optional (backend omits them) - UnmatchedRemittance: statusCode -> status, totalPaid -> paidAmount, totalCharge/serviceDate/isReversal now optional - Reconciliation page + test fixtures updated to use the wire shape - Tests: 124/124 pass --- src/pages/Reconciliation.test.tsx | 15 ++++++------- src/pages/Reconciliation.tsx | 6 +++--- src/types/index.ts | 35 +++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/pages/Reconciliation.test.tsx b/src/pages/Reconciliation.test.tsx index 73bbba1..39b88e4 100644 --- a/src/pages/Reconciliation.test.tsx +++ b/src/pages/Reconciliation.test.tsx @@ -95,10 +95,10 @@ describe("ReconciliationPage", () => { claims: [ { id: "CLM-1", - patientControlNumber: "PCN-A", - serviceDate: "2026-06-01", - chargeAmount: 100, + patientName: "Patient A", + billedAmount: 100, providerNpi: "1234567890", + serviceDate: "2026-06-01", payerId: "P1", state: "submitted", }, @@ -107,12 +107,13 @@ describe("ReconciliationPage", () => { { id: "CLP-1:b1", payerClaimControlNumber: "PCN-A", - statusCode: "1", - totalCharge: 100, - totalPaid: 100, + status: "received", + paidAmount: 100, adjustmentAmount: 0, - serviceDate: "2026-06-01", + receivedDate: "2026-06-01", isReversal: false, + totalCharge: 100, + serviceDate: "2026-06-01", batchId: "b1", }, ], diff --git a/src/pages/Reconciliation.tsx b/src/pages/Reconciliation.tsx index d57ebd1..c909a3c 100644 --- a/src/pages/Reconciliation.tsx +++ b/src/pages/Reconciliation.tsx @@ -163,10 +163,10 @@ export function ReconciliationPage() { >
{c.id}
- {c.patientControlNumber} + {c.patientName}
- {c.serviceDate ?? "—"} · ${c.chargeAmount.toFixed(2)} · NPI{" "} + {c.serviceDate ?? "—"} · ${c.billedAmount.toFixed(2)} · NPI{" "} {c.providerNpi ?? "—"}
@@ -205,7 +205,7 @@ export function ReconciliationPage() { ) : null}
- Status {r.statusCode} · ${r.totalPaid.toFixed(2)} paid · $ + Status {r.status} · ${r.paidAmount.toFixed(2)} paid · $ {r.adjustmentAmount.toFixed(2)} adj
diff --git a/src/types/index.ts b/src/types/index.ts index b0a45f0..78b7a23 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -366,26 +366,43 @@ export interface Match { is_reversal: boolean; } +// Mirrors `cyclone.store.to_ui_claim_from_orm` (backend/src/cyclone/store.py). +// Fields the backend does not currently emit are optional so the type +// matches the actual wire shape (was previously assumed but never true). export interface UnmatchedClaim { id: string; - patientControlNumber: string; - serviceDate: string | null; - chargeAmount: number; + patientName: string; + billedAmount: number; providerNpi: string | null; - payerId: string | null; + payerName?: string; + payerId?: string | null; + serviceDate?: string | null; + cptCode?: string; + submissionDate?: string; state: ClaimState; } +// Mirrors `cyclone.store.list_unmatched` (backend/src/cyclone/store.py) for +// the remittances payload. `status` is the 3-state remittance lifecycle +// ("received" | "posted" | "reconciled"); the previous `statusCode` field +// was a confusion with the 835 claim-status code and never existed on the +// wire. Fields the backend omits are optional. export interface UnmatchedRemittance { id: string; payerClaimControlNumber: string; - statusCode: string; - totalCharge: number; - totalPaid: number; + payerName?: string; + status: string; + paidAmount: number; adjustmentAmount: number; - serviceDate: string | null; - isReversal: boolean; batchId: string; + receivedDate?: string; + parsedAt?: string; + claimId?: string; + denialReason?: string | null; + validationWarnings?: string[]; + isReversal?: boolean; + totalCharge?: number; + serviceDate?: string | null; } export interface UnmatchedResponse {