b3de9c4d22
Existing test fixtures (ClaimDrawer, ClaimDrawerHeader, Claims pages) construct partial ClaimDetail objects without the new slim lineReconciliation projection. Other SP7 fields follow the optional pattern (matchedLines?, serviceLinePayments?, claimLevelAdjustments?), so apply the same to lineReconciliation. Backend always emits it for matched claims; UI treats absent as "no per-line audit yet".
785 lines
21 KiB
TypeScript
785 lines
21 KiB
TypeScript
// ---------------------------------------------------------------------------
|
|
// UI-shaped types (used by the existing pages; backed by in-memory sample data
|
|
// when no API is configured). Keep these stable — the rest of the app reads
|
|
// from them.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export type ClaimStatus =
|
|
| "draft"
|
|
| "submitted"
|
|
| "accepted"
|
|
| "denied"
|
|
| "paid"
|
|
| "pending";
|
|
|
|
export type RemittanceStatus = "received" | "posted" | "reconciled";
|
|
|
|
export type ActivityKind =
|
|
| "claim_submitted"
|
|
| "claim_paid"
|
|
| "claim_denied"
|
|
| "claim_accepted"
|
|
| "remit_received"
|
|
| "provider_added"
|
|
// Emitted by `cyclone.store.record_manual_match` when an operator
|
|
// pairs a remit to a claim by hand. Surface as a neutral event on
|
|
// the Activity Log; do NOT treat it as a status change.
|
|
| "manual_match";
|
|
|
|
export interface Claim {
|
|
id: string;
|
|
patientName: string;
|
|
providerNpi: string;
|
|
payerName: string;
|
|
cptCode: string;
|
|
billedAmount: number;
|
|
receivedAmount: number;
|
|
status: ClaimStatus;
|
|
submissionDate: string;
|
|
denialReason?: string;
|
|
}
|
|
|
|
export interface Provider {
|
|
npi: string;
|
|
name: string;
|
|
taxId: string;
|
|
address: string;
|
|
city: string;
|
|
state: string;
|
|
zip: string;
|
|
phone: string;
|
|
claimCount: number;
|
|
outstandingAr: number;
|
|
}
|
|
|
|
export interface Remittance {
|
|
id: string;
|
|
claimId: string;
|
|
payerName: string;
|
|
paidAmount: number;
|
|
adjustmentAmount: number;
|
|
receivedDate: string;
|
|
checkNumber: string;
|
|
status: RemittanceStatus;
|
|
denialReason?: string | null;
|
|
validationWarnings?: string[];
|
|
/**
|
|
* Persisted CAS adjustment rows, labeled by the backend via the bundled
|
|
* CARC dictionary. Optional — the list endpoint omits it to keep the
|
|
* payload small; the detail endpoint (`/api/remittances/{id}`) populates it.
|
|
*/
|
|
adjustments?: CasAdjustment[];
|
|
/**
|
|
* SP7: per-line 835 SVC composites on this remittance. Ordered by
|
|
* ``lineNumber``. Each SLP carries the per-line CAS adjustments under
|
|
* ``serviceLinePayments[i].adjustments`` via the line-reconciliation
|
|
* endpoint, or via a follow-up CAS query in the remit drawer.
|
|
*/
|
|
serviceLinePayments?: ServiceLinePayment[];
|
|
/**
|
|
* SP7: CLP-level (claim-level) CAS bucket — adjustments that were
|
|
* not attached to any SVC composite. Powers the ClaimLevelAdjustments
|
|
* panel in the remit drawer.
|
|
*/
|
|
claimLevelAdjustments?: RemittanceClaimLevelAdjustment[];
|
|
}
|
|
|
|
/**
|
|
* One Claim Adjustment Segment (CAS) row, labeled.
|
|
* Source: backend `cyclone.parsers.cas_codes.reason_label(group, reason)`.
|
|
*/
|
|
export interface CasAdjustment {
|
|
group: string; // "CO", "PR", "OA", "PI", "CR"
|
|
reason: string; // "45", "1", etc.
|
|
label: string; // "Charge exceeds fee schedule"
|
|
amount: number;
|
|
quantity: number | null;
|
|
}
|
|
|
|
export interface Activity {
|
|
id: string;
|
|
kind: ActivityKind;
|
|
message: string;
|
|
timestamp: string;
|
|
npi?: string;
|
|
amount?: number;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Backend-aligned types (snake_case to match FastAPI JSON output 1:1).
|
|
// These mirror the Pydantic models in
|
|
// backend/src/cyclone/parsers/models.py (837P)
|
|
// backend/src/cyclone/parsers/models_835.py (835 ERA)
|
|
// Numeric fields are strings (Decimals serialized); dates are ISO strings.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// --- 837P ------------------------------------------------------------------
|
|
|
|
export interface Address {
|
|
line1: string;
|
|
line2?: string | null;
|
|
city: string;
|
|
state: string;
|
|
zip: string;
|
|
}
|
|
|
|
export interface BillingProvider {
|
|
name: string;
|
|
npi: string;
|
|
tax_id?: string | null;
|
|
address?: Address | null;
|
|
}
|
|
|
|
export interface Subscriber {
|
|
first_name: string;
|
|
last_name: string;
|
|
member_id: string;
|
|
dob?: string | null;
|
|
gender?: "M" | "F" | "U" | null;
|
|
address?: Address | null;
|
|
}
|
|
|
|
export interface Payer {
|
|
name: string;
|
|
id: string;
|
|
}
|
|
|
|
export interface ClaimHeader {
|
|
claim_id: string;
|
|
total_charge: string; // Decimal serialized
|
|
place_of_service?: string | null;
|
|
facility_code_qualifier?: string | null;
|
|
frequency_code?: string | null;
|
|
provider_signature?: string | null;
|
|
assignment?: string | null;
|
|
release_of_info?: string | null;
|
|
prior_auth?: string | null;
|
|
}
|
|
|
|
export interface Diagnosis {
|
|
code: string;
|
|
qualifier?: string | null;
|
|
}
|
|
|
|
export interface Procedure {
|
|
qualifier: string;
|
|
code: string;
|
|
modifiers: string[];
|
|
}
|
|
|
|
export interface ServiceLine {
|
|
line_number: number;
|
|
procedure: Procedure;
|
|
charge: string; // Decimal serialized
|
|
unit_type?: string | null;
|
|
units?: string | null; // Decimal serialized
|
|
place_of_service?: string | null;
|
|
service_date?: string | null;
|
|
provider_reference?: string | null;
|
|
}
|
|
|
|
export interface ValidationIssue {
|
|
rule: string;
|
|
severity: "error" | "warning";
|
|
message: string;
|
|
segment_index?: number | null;
|
|
}
|
|
|
|
export interface ValidationReport {
|
|
passed: boolean;
|
|
errors: ValidationIssue[];
|
|
warnings: ValidationIssue[];
|
|
}
|
|
|
|
export interface Envelope {
|
|
sender_id: string;
|
|
receiver_id: string;
|
|
control_number: string;
|
|
transaction_date: string; // ISO date
|
|
transaction_time?: string | null;
|
|
implementation_guide?: string | null;
|
|
}
|
|
|
|
export interface BatchSummary {
|
|
input_file: string;
|
|
control_number?: string | null;
|
|
transaction_date?: string | null;
|
|
total_claims: number;
|
|
passed: number;
|
|
failed: number;
|
|
failed_claim_ids: string[];
|
|
issues_by_rule: Record<string, number>;
|
|
output_dir?: string | null;
|
|
}
|
|
|
|
export interface ClaimOutput {
|
|
claim_id: string;
|
|
control_number: string;
|
|
transaction_date: string; // ISO date
|
|
billing_provider: BillingProvider;
|
|
subscriber: Subscriber;
|
|
payer: Payer;
|
|
claim: ClaimHeader;
|
|
diagnoses: Diagnosis[];
|
|
service_lines: ServiceLine[];
|
|
validation: ValidationReport;
|
|
raw_segments: string[][];
|
|
}
|
|
|
|
export interface ParseResult837 {
|
|
envelope: Envelope | null;
|
|
claims: ClaimOutput[];
|
|
summary: BatchSummary;
|
|
}
|
|
|
|
// --- 835 ERA ---------------------------------------------------------------
|
|
|
|
export interface FinancialInfo {
|
|
handling_code: string;
|
|
paid_amount: string; // Decimal serialized
|
|
credit_debit_flag: string;
|
|
payment_method?: string | null;
|
|
payer_tax_id?: string | null;
|
|
payment_date?: string | null; // ISO date
|
|
}
|
|
|
|
export interface ReassociationTrace {
|
|
trace_type_code: string;
|
|
trace_number: string;
|
|
originating_company_id: string;
|
|
payer_id?: string | null;
|
|
}
|
|
|
|
export interface Payer835 {
|
|
name: string;
|
|
id?: string | null;
|
|
address?: Address | null;
|
|
contact_url?: string | null;
|
|
}
|
|
|
|
export interface Payee835 {
|
|
name: string;
|
|
npi: string;
|
|
address?: Address | null;
|
|
}
|
|
|
|
export interface ClaimAdjustment {
|
|
group_code: string;
|
|
reason_code: string;
|
|
amount: string; // Decimal serialized
|
|
quantity?: string | null;
|
|
}
|
|
|
|
export interface ServicePayment {
|
|
line_number: number;
|
|
procedure_qualifier: string;
|
|
procedure_code: string;
|
|
modifiers: string[];
|
|
charge: string;
|
|
payment: string;
|
|
units?: string | null;
|
|
unit_type?: string | null;
|
|
service_date?: string | null;
|
|
adjustments: ClaimAdjustment[];
|
|
ref_benefit_plan?: string | null;
|
|
}
|
|
|
|
export interface ClaimPayment {
|
|
payer_claim_control_number: string;
|
|
status_code: string;
|
|
status_label?: string | null;
|
|
total_charge: string;
|
|
total_paid: string;
|
|
patient_responsibility?: string | null;
|
|
claim_filing_indicator?: string | null;
|
|
original_claim_id?: string | null;
|
|
facility_type?: string | null;
|
|
frequency_code?: string | null;
|
|
per_diem_covered_days?: string | null;
|
|
ref_benefit_plan?: string | null;
|
|
service_payments: ServicePayment[];
|
|
raw_segments: string[][];
|
|
}
|
|
|
|
export interface ParseResult835 {
|
|
envelope: Envelope;
|
|
financial_info: FinancialInfo;
|
|
trace: ReassociationTrace;
|
|
payer: Payer835;
|
|
payee: Payee835;
|
|
claims: ClaimPayment[];
|
|
summary: BatchSummary;
|
|
validation?: ValidationReport | null;
|
|
}
|
|
|
|
// --- NDJSON streaming ------------------------------------------------------
|
|
// The backend emits one JSON object per line during an NDJSON stream:
|
|
// { "type": "<event>", "data": <object> }
|
|
// See backend/src/cyclone/api.py:_ndjson_stream* for the source of truth.
|
|
|
|
export type NdjsonEventType =
|
|
| "envelope"
|
|
| "claim"
|
|
| "claim_payment"
|
|
| "financial_info"
|
|
| "trace"
|
|
| "payer"
|
|
| "payee"
|
|
| "summary";
|
|
|
|
export interface NdjsonEvent<T = unknown> {
|
|
type: NdjsonEventType;
|
|
data: T;
|
|
}
|
|
|
|
// --- Parsed-batch slice (used by the Upload page + store) ------------------
|
|
|
|
export type ParsedBatchKind = "837p" | "835";
|
|
|
|
export interface ParsedBatch {
|
|
id: string;
|
|
kind: ParsedBatchKind;
|
|
inputFilename: string;
|
|
parsedAt: string; // ISO timestamp
|
|
claimCount: number;
|
|
passed: number;
|
|
failed: number;
|
|
claimIds: string[];
|
|
summary: BatchSummary;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Reconciliation (7-state claim model + match audit trail)
|
|
// Mirrors cyclone.db.ClaimState (Python enum) 1:1. The reconciliation page
|
|
// uses these to drive the unmatched bucket and the manual-match UI.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export type ClaimState =
|
|
| "submitted"
|
|
| "received"
|
|
| "paid"
|
|
| "partial"
|
|
| "denied"
|
|
| "reconciled"
|
|
| "reversed";
|
|
|
|
export const CLAIM_STATES: ClaimState[] = [
|
|
"submitted",
|
|
"received",
|
|
"paid",
|
|
"partial",
|
|
"denied",
|
|
"reconciled",
|
|
"reversed",
|
|
];
|
|
|
|
export interface Match {
|
|
id: number;
|
|
claim_id: string;
|
|
remittance_id: string;
|
|
strategy: "auto" | "manual";
|
|
matched_at: string;
|
|
prior_claim_state?: ClaimState | null;
|
|
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;
|
|
patientName: string;
|
|
billedAmount: number;
|
|
providerNpi: 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;
|
|
payerName?: string;
|
|
status: string;
|
|
paidAmount: number;
|
|
adjustmentAmount: number;
|
|
batchId: string;
|
|
receivedDate?: string;
|
|
parsedAt?: string;
|
|
claimId?: string;
|
|
denialReason?: string | null;
|
|
validationWarnings?: string[];
|
|
isReversal?: boolean;
|
|
totalCharge?: number;
|
|
serviceDate?: string | null;
|
|
}
|
|
|
|
export interface UnmatchedResponse {
|
|
claims: UnmatchedClaim[];
|
|
remittances: UnmatchedRemittance[];
|
|
}
|
|
|
|
export interface MatchResponse {
|
|
claim: UnmatchedClaim;
|
|
match: { id: number; strategy: "auto" | "manual" };
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// 999 ACKs (SP3 P3 T16)
|
|
// Mirrors the `acks` table (cyclone.db.Ack) and the `/api/acks` response.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* One persisted 999 ACK row, camelCased for the UI. The backend
|
|
* (snake_case) is re-shaped in `src/hooks/useAcks.ts` via the
|
|
* `mapAck` helper, so this interface matches what the page actually
|
|
* consumes.
|
|
*/
|
|
export interface Ack {
|
|
id: number;
|
|
sourceBatchId: string;
|
|
acceptedCount: number;
|
|
rejectedCount: number;
|
|
receivedCount: number;
|
|
ackCode: "A" | "E" | "R" | "P";
|
|
parsedAt: string;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SP4 claim detail drawer types (Task 4).
|
|
// Mirrors the JSON shape of `GET /api/claims/{claim_id}` 1:1 — camelCase
|
|
// keys, numeric money fields (coerced from Decimal on the backend), ISO
|
|
// timestamps with a trailing `Z`. Distinct from the parser-aligned
|
|
// snake_case types above (e.g. ``BillingProvider``, ``ServiceLine``) which
|
|
// describe the EDI parse tree; these describe the UI-ready detail payload.
|
|
// The ``ClaimDetail*`` prefix keeps the two flavors side-by-side without
|
|
// a TypeScript duplicate-identifier collision.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface ClaimDetailDiagnosis {
|
|
code: string;
|
|
qualifier: string | null;
|
|
}
|
|
|
|
export interface ClaimDetailServiceLine {
|
|
lineNumber: number;
|
|
procedureQualifier: string;
|
|
procedureCode: string;
|
|
modifiers: string[];
|
|
charge: number;
|
|
units: number | null;
|
|
unitType: string | null;
|
|
serviceDate: string | null; // ISO date YYYY-MM-DD or null
|
|
}
|
|
|
|
/**
|
|
* The backend can return ``{}`` for a missing address (see
|
|
* ``store._address_to_ui``); callers that want a populated address must
|
|
* branch on ``Object.keys(addr).length === 0`` before reading fields.
|
|
*/
|
|
export interface ClaimDetailAddress {
|
|
line1: string;
|
|
line2: string | null;
|
|
city: string;
|
|
state: string;
|
|
zip: string;
|
|
}
|
|
|
|
export interface ClaimDetailBillingProvider {
|
|
name: string;
|
|
npi: string;
|
|
taxId: string;
|
|
address: ClaimDetailAddress | Record<string, never>;
|
|
}
|
|
|
|
export interface ClaimDetailSubscriber {
|
|
firstName: string;
|
|
lastName: string;
|
|
memberId: string;
|
|
dob: string | null;
|
|
gender: string | null;
|
|
}
|
|
|
|
export interface ClaimDetailPayer {
|
|
name: string;
|
|
id: string;
|
|
}
|
|
|
|
export interface ClaimDetailParties {
|
|
billingProvider: ClaimDetailBillingProvider;
|
|
subscriber: ClaimDetailSubscriber;
|
|
payer: ClaimDetailPayer;
|
|
}
|
|
|
|
export interface ClaimDetailValidationIssue {
|
|
rule: string;
|
|
severity: "error" | "warning";
|
|
message: string;
|
|
}
|
|
|
|
export interface ClaimDetailValidation {
|
|
passed: boolean;
|
|
errors: ClaimDetailValidationIssue[];
|
|
warnings: ClaimDetailValidationIssue[];
|
|
}
|
|
|
|
export interface ClaimDetailMatchedRemittance {
|
|
id: string;
|
|
totalPaid: number;
|
|
/** Mirrors the same `"received" | "reconciled"` mapping as the list endpoint. */
|
|
status: string;
|
|
receivedAt: string; // ISO Z
|
|
/**
|
|
* SP7: per-line counts for the badge. Optional for backward
|
|
* compatibility — older claim-detail responses (pre-SP7) won't have
|
|
* these fields. The card omits the badge when undefined.
|
|
*/
|
|
matchedLines?: number;
|
|
totalLines?: number;
|
|
}
|
|
|
|
export interface ClaimDetailStateHistoryEvent {
|
|
kind: string;
|
|
ts: string; // ISO Z (most-recent-first, capped at 50 by the backend)
|
|
batchId: string | null;
|
|
remittanceId: string | null;
|
|
}
|
|
|
|
/**
|
|
* One claim with the full drawer context: header, state, parties,
|
|
* validation, service lines, diagnoses, raw segments, recent
|
|
* ``stateHistory`` (most-recent-first, capped at 50), and a populated
|
|
* ``matchedRemittance`` block when the claim has been paired with an
|
|
* ERA. Mirrors ``CycloneStore.get_claim_detail`` (backend/src/cyclone/store.py)
|
|
* and the ``GET /api/claims/{claim_id}`` endpoint contract.
|
|
*/
|
|
export interface ClaimDetail {
|
|
id: string;
|
|
batchId: string;
|
|
state: string;
|
|
stateLabel: string;
|
|
billedAmount: number;
|
|
patientName: string;
|
|
providerNpi: string;
|
|
providerName: string;
|
|
payerName: string;
|
|
payerId: string;
|
|
submissionDate: string; // ISO Z
|
|
serviceDateFrom: string | null;
|
|
serviceDateTo: string | null;
|
|
parsedAt: string; // ISO Z
|
|
diagnoses: ClaimDetailDiagnosis[];
|
|
serviceLines: ClaimDetailServiceLine[];
|
|
parties: ClaimDetailParties;
|
|
validation: ClaimDetailValidation;
|
|
rawSegments: string[][];
|
|
matchedRemittance: ClaimDetailMatchedRemittance | null;
|
|
stateHistory: ClaimDetailStateHistoryEvent[];
|
|
/**
|
|
* SP7: per-line reconciliation slim projection. Parallel to
|
|
* ``serviceLines`` and indexed by ``lineNumber``. Populated by the
|
|
* claim-detail endpoint so the ServiceLinesTable can render Paid +
|
|
* Adjustments columns without a second fetch. ``paid`` /
|
|
* ``adjustmentsSum`` are null when the line has no matched 835 SVC
|
|
* composite.
|
|
*/
|
|
lineReconciliation?: ClaimDetailLineReconciliation[];
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Side-by-side batch diff (SP3 P4 / T18)
|
|
// Mirrors `GET /api/batch-diff?a=<batch_id>&b=<batch_id>` (see
|
|
// `backend/src/cyclone/batch_diff.py` and `backend/src/cyclone/api.py`).
|
|
// The contract is deliberately small: no raw segments, no service-line
|
|
// details — just the summary fields the operator needs to spot the
|
|
// deltas between two parsed files at a glance.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export type BatchKind = "837p" | "835";
|
|
|
|
export interface BatchDiffSideMeta {
|
|
id: string;
|
|
kind: BatchKind;
|
|
parsedAt: string; // ISO Z
|
|
inputFilename: string;
|
|
claimCount: number;
|
|
}
|
|
|
|
/**
|
|
* One claim (or remittance) row projected for the diff view. Carries
|
|
* just enough context to render side-by-side without the EDI parse
|
|
* tree. ``status`` carries the validation-derived label for 837P
|
|
* (``submitted`` / ``pending`` / ``draft`` / ``denied``) and the CLP02
|
|
* code/label for 835.
|
|
*/
|
|
export interface BatchClaimDiffSummary {
|
|
claim_id: string;
|
|
patient_name: string;
|
|
total_charge: number;
|
|
service_date: string | null;
|
|
status: string;
|
|
cpt_codes: string[];
|
|
}
|
|
|
|
/**
|
|
* One changed field between the two sides of a claim. ``field``
|
|
* identifies which column changed (``status`` / ``total_charge`` /
|
|
* ``service_date`` / ``cpt_codes``); ``a`` and ``b`` are the values
|
|
* from each side, rendered verbatim.
|
|
*/
|
|
export interface BatchDiffFieldDiff {
|
|
field: "status" | "total_charge" | "service_date" | "cpt_codes";
|
|
a: string | number | string[] | null;
|
|
b: string | number | string[] | null;
|
|
}
|
|
|
|
export interface BatchDiffChangedRow {
|
|
a: BatchClaimDiffSummary;
|
|
b: BatchClaimDiffSummary;
|
|
diff: BatchDiffFieldDiff[];
|
|
}
|
|
|
|
export interface BatchDiffSummary {
|
|
addedCount: number;
|
|
removedCount: number;
|
|
changedCount: number;
|
|
unchangedCount: number;
|
|
}
|
|
|
|
/**
|
|
* Full response from `GET /api/batch-diff`. The three bucket arrays
|
|
* (``added`` / ``removed`` / ``changed``) are always present (never
|
|
* absent) so the UI can index unconditionally; ``summary`` is
|
|
* precomputed by the backend so the four count cards don't have to
|
|
* derive them on the client.
|
|
*/
|
|
export interface BatchDiff {
|
|
a: BatchDiffSideMeta;
|
|
b: BatchDiffSideMeta;
|
|
added: BatchClaimDiffSummary[];
|
|
removed: BatchClaimDiffSummary[];
|
|
changed: BatchDiffChangedRow[];
|
|
summary: BatchDiffSummary;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SP7 — Per-Service-Line Adjustment Audit types.
|
|
// See docs/superpowers/specs/2026-06-20-cyclone-line-reconciliation-design.md
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/** One 835 SVC composite (Loop 2110) projected to wire shape. */
|
|
export interface ServiceLinePayment {
|
|
id: number;
|
|
lineNumber: number;
|
|
procedureQualifier: string;
|
|
procedureCode: string;
|
|
modifiers: string[];
|
|
charge: string;
|
|
payment: string;
|
|
units: string | null;
|
|
unitType: string | null;
|
|
serviceDate: string | null;
|
|
}
|
|
|
|
/** Status of one line on either side of a reconciliation. */
|
|
export type LineReconciliationStatus =
|
|
| "matched"
|
|
| "unmatched_835_only"
|
|
| "unmatched_837_only"
|
|
| "superseded";
|
|
|
|
/** Slim per-line projection embedded in `GET /api/claims/{id}`. */
|
|
export interface ClaimDetailLineReconciliation {
|
|
lineNumber: number;
|
|
status: LineReconciliationStatus;
|
|
paid: string | null;
|
|
adjustmentsSum: string | null;
|
|
}
|
|
|
|
/** Summary block at the top of the line-reconciliation response. */
|
|
export interface LineReconciliationSummary {
|
|
billedTotal: string;
|
|
paidTotal: string;
|
|
adjustmentTotal: string;
|
|
matchedLines: number;
|
|
totalLines: number;
|
|
}
|
|
|
|
/** One line in the line-reconciliation response. */
|
|
export interface LineReconciliationRow {
|
|
claimServiceLine: {
|
|
lineNumber: number;
|
|
procedureQualifier: string;
|
|
procedureCode: string;
|
|
modifiers: string[];
|
|
charge: string;
|
|
units: string | null;
|
|
unitType: string | null;
|
|
serviceDate: string | null;
|
|
} | null;
|
|
serviceLinePayment: ServiceLinePayment | null;
|
|
status: LineReconciliationStatus;
|
|
adjustments: Array<{
|
|
groupCode: string;
|
|
reasonCode: string;
|
|
amount: string;
|
|
}>;
|
|
}
|
|
|
|
/** Top-level shape of `GET /api/claims/{id}/line-reconciliation`. */
|
|
export interface LineReconciliationResponse {
|
|
claimId: string;
|
|
summary: LineReconciliationSummary;
|
|
lines: LineReconciliationRow[];
|
|
}
|
|
|
|
/** One CLP-level (claim-level) CAS adjustment on a remittance. */
|
|
export interface RemittanceClaimLevelAdjustment {
|
|
id: number;
|
|
groupCode: string;
|
|
reasonCode: string;
|
|
amount: string;
|
|
quantity: string | null;
|
|
}
|
|
|
|
/** Counts embedded in inbox-lane rows for the `MatchedRemitCard` badge. */
|
|
export interface MatchedRemittanceLineCounts {
|
|
matchedLines: number;
|
|
totalLines: number;
|
|
}
|
|
|
|
/** Inbox-lane claim row carrying the matched-remittance block. */
|
|
export interface InboxClaimRow {
|
|
id: string;
|
|
kind: "claim" | "remit";
|
|
patientControlNumber: string;
|
|
chargeAmount: number | null;
|
|
payerId: string | null;
|
|
providerNpi: string | null;
|
|
state: string;
|
|
rejectionReason: string | null;
|
|
rejectedAt: string | null;
|
|
serviceDateFrom: string | null;
|
|
score: number | null;
|
|
scoreTier: string | null;
|
|
scoreBreakdown: {
|
|
patient: number;
|
|
date: number;
|
|
amount: number;
|
|
provider: number;
|
|
} | null;
|
|
matchedRemittance: {
|
|
id: string;
|
|
matchedLines: number;
|
|
totalLines: number;
|
|
} | null;
|
|
}
|