@cosyte/x12 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +756 -17
- package/KNOWN-LIMITATIONS.md +804 -0
- package/README.md +7 -5
- package/dist/index.cjs +440 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +331 -16
- package/dist/index.d.ts +331 -16
- package/dist/index.mjs +435 -175
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -140,7 +140,12 @@ var WARNING_CODES = {
|
|
|
140
140
|
X12_837_UNKNOWN_VARIANT: "X12_837_UNKNOWN_VARIANT",
|
|
141
141
|
X12_UNKNOWN_CLAIM_STATUS_CATEGORY: "X12_UNKNOWN_CLAIM_STATUS_CATEGORY",
|
|
142
142
|
X12_UNKNOWN_CLAIM_STATUS: "X12_UNKNOWN_CLAIM_STATUS",
|
|
143
|
-
X12_834_UNKNOWN_MAINTENANCE_TYPE: "X12_834_UNKNOWN_MAINTENANCE_TYPE"
|
|
143
|
+
X12_834_UNKNOWN_MAINTENANCE_TYPE: "X12_834_UNKNOWN_MAINTENANCE_TYPE",
|
|
144
|
+
X12_UNPARSEABLE_DECIMAL: "X12_UNPARSEABLE_DECIMAL",
|
|
145
|
+
X12_837_SERVICE_LINE_NOT_DECODED: "X12_837_SERVICE_LINE_NOT_DECODED",
|
|
146
|
+
X12_837_SERVICE_LINE_DROPPED: "X12_837_SERVICE_LINE_DROPPED",
|
|
147
|
+
X12_837_SERVICE_SEGMENT_WITHOUT_LX: "X12_837_SERVICE_SEGMENT_WITHOUT_LX",
|
|
148
|
+
X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX: "X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX"
|
|
144
149
|
};
|
|
145
150
|
var CONTROL_NUMBER_PAIRS = {
|
|
146
151
|
/** ISA-13 against IEA-02. */
|
|
@@ -213,7 +218,12 @@ var WARNING_MESSAGES = {
|
|
|
213
218
|
X12_837_UNKNOWN_VARIANT: `837 variant could not be resolved: ST-03's implementation convention reference is not one of "005010X222A2" / "005010X223A3" / "005010X224A2", and no SVx service-line segment was present to fall back on. The verbatim reference is preserved on the model.`,
|
|
214
219
|
X12_UNKNOWN_CLAIM_STATUS_CATEGORY: "Unknown claim status category (CSCC): the STC composite's first component is outside the bundled snapshot. The verbatim code is preserved on the status; only its description is unavailable.",
|
|
215
220
|
X12_UNKNOWN_CLAIM_STATUS: "Unknown claim status code (CSC): the STC composite's second component is outside the bundled snapshot. The verbatim code is preserved on the status; only its description is unavailable.",
|
|
216
|
-
X12_834_UNKNOWN_MAINTENANCE_TYPE: "Unknown 834 maintenance type: the INS-03/HD-01 code is outside the bundled snapshot. The verbatim code is preserved on the enrollment and the action is NEVER inferred."
|
|
221
|
+
X12_834_UNKNOWN_MAINTENANCE_TYPE: "Unknown 834 maintenance type: the INS-03/HD-01 code is outside the bundled snapshot. The verbatim code is preserved on the enrollment and the action is NEVER inferred.",
|
|
222
|
+
X12_UNPARSEABLE_DECIMAL: "Unparseable decimal: the element at `position.elementIndex` held bytes this library could not decode as a decimal, so NO value was decoded from it. Whatever occupies that slot on the model, including 0 and undefined, is a stand-in and is NOT a value the sender supplied. The verbatim bytes are preserved on the segment; read them there before acting on the amount, quantity or percent.",
|
|
223
|
+
X12_837_SERVICE_LINE_NOT_DECODED: "837 service line with no decoded service segment: the Loop 2400 line opened at `position.segmentIndex` is followed by no SV1 / SV2 / SV3 matching the variant this submission resolved to, so NOTHING carried by the service segment was read. The line's `charge` and `units` hold 0 as a stand-in and are NOT values the sender supplied; its procedure code, modifiers, unit of measure and place of service are equally undecoded. Two common causes: the line carries no SVx at all, or it carries one for a different 837 variant than ST-03 (or the caller's `type` option) named. Which side is wrong is NOT decided here, because a caller-supplied `type` can disagree with a perfectly conformant document. The verbatim segments are preserved on the transaction set; read them there before acting on the charge or the quantity.",
|
|
224
|
+
X12_837_SERVICE_LINE_DROPPED: "837 service line dropped from the typed model: the LX at `position.segmentIndex` opened no Loop 2400, so no line appears on any claim's `serviceLines` for it and the SV1 / SV2 / SV3 that followed - its charge, units, procedure code and modifiers - was read into nothing. Compare `X12_837_SERVICE_LINE_NOT_DECODED`, where the line IS on the model and only its service segment went unread. Two causes: no Loop 2300 (CLM) is open at this LX, so there is no claim to attach a line to; or the submission's variant is not one of P / I / D, so no variant-specific line shape could be built. Read `submission.variant` and `submission.claims` to tell them apart; do NOT expect `X12_837_UNKNOWN_VARIANT` alongside this code, because a caller-supplied `type` outside P / I / D reaches the second cause without it. Nothing is fabricated to stand in for the missing line and no claim is synthesized. What becomes of a DTP / AMT / NTE / REF that follows the dropped LX depends on the route and this message does not say; see KNOWN-LIMITATIONS.md. The verbatim segments are preserved on the transaction set; read them there before concluding the claim had no service lines.",
|
|
225
|
+
X12_837_SERVICE_SEGMENT_WITHOUT_LX: "837 service segment with no Loop 2400 to read it into: no service line was open at the SV1 / SV2 / SV3 at `position.segmentIndex`, so NOTHING it carries - its charge, units, procedure code, modifiers, unit of measure and place of service - was read. Read that literally: an LX may well appear earlier in the transaction, and what this reports is that none of them had opened a Loop 2400 still current at this segment. No line appears on any claim's `serviceLines` for it and nothing is fabricated to stand in. Compare the two codes anchored at an LX: `X12_837_SERVICE_LINE_DROPPED`, where an LX IS present and opened no line, and `X12_837_SERVICE_LINE_NOT_DECODED`, where the line is on the model and only its service segment went unread. Neither of those can report the SAME service segment as this code, because both are raised at an LX and this one only where no Loop 2400 is open; a document with several claims can still carry all three. This says NOTHING about how the submission's variant resolved: absent a caller-supplied `type` option, and where ST-03 names no known implementation convention, the reader falls back to the first SV1 / SV2 / SV3 in the transaction, and a segment reported here is eligible for that fallback like any other, so a stray one can decide the variant every line is read against. Read `submission.variant`. The verbatim segments are preserved on the transaction set; read them there before concluding the claim had no service lines.",
|
|
226
|
+
X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX: "837 entity segment read into nothing after a dropped LX: the N3 / N4 / PER / REF at `position.segmentIndex` arrived while no entity loop was open, because an earlier LX in this transaction opened no Loop 2400 (no CLM was open at it) and closed the entity loop that was current there. NOTHING this segment carries reached the model: no party's `address`, `contacts` or `references` was written from it, and no party, claim or line was synthesized to hold it. This is the code that names THAT loss; `X12_837_SERVICE_LINE_DROPPED` is raised at the LX itself and names the SERVICE LINE's loss, never an entity segment, so the two report different things about the same stretch of the document. Read the bound literally, because this code does NOT report every unattached entity segment: it reports one discarded after such an LX and only while nothing since has opened a new loop, so an N3 / N4 / PER / REF that reaches no party by any other route is still silent, and one arriving after a later NM1 is outside this code's scope, whether or not this reader surfaces that segment kind on that party. It reports that the segment reached NO party; it does not claim it would have reached one had the LX been absent, because this reader does not surface every one of these segment kinds on every party (a PER on a patient or a pay-to address, for one). Which party a segment following a stray LX belongs to is not derivable from the TR3s in either direction, so it is discarded rather than attributed: see KNOWN-LIMITATIONS.md. The verbatim segments are preserved on the transaction set; read them there before concluding a party had no address, no secondary identifier or no contact."
|
|
217
227
|
};
|
|
218
228
|
var ALL_WARNING_MESSAGES = new Set(
|
|
219
229
|
Object.values(WARNING_MESSAGES)
|
|
@@ -374,6 +384,34 @@ function unknown837Variant(position) {
|
|
|
374
384
|
position
|
|
375
385
|
};
|
|
376
386
|
}
|
|
387
|
+
function serviceLineNotDecoded(position) {
|
|
388
|
+
return {
|
|
389
|
+
code: WARNING_CODES.X12_837_SERVICE_LINE_NOT_DECODED,
|
|
390
|
+
message: WARNING_MESSAGES.X12_837_SERVICE_LINE_NOT_DECODED,
|
|
391
|
+
position
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function serviceLineDropped(position) {
|
|
395
|
+
return {
|
|
396
|
+
code: WARNING_CODES.X12_837_SERVICE_LINE_DROPPED,
|
|
397
|
+
message: WARNING_MESSAGES.X12_837_SERVICE_LINE_DROPPED,
|
|
398
|
+
position
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function serviceSegmentWithoutLx(position) {
|
|
402
|
+
return {
|
|
403
|
+
code: WARNING_CODES.X12_837_SERVICE_SEGMENT_WITHOUT_LX,
|
|
404
|
+
message: WARNING_MESSAGES.X12_837_SERVICE_SEGMENT_WITHOUT_LX,
|
|
405
|
+
position
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function entitySegmentDiscardedAfterLx(position) {
|
|
409
|
+
return {
|
|
410
|
+
code: WARNING_CODES.X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX,
|
|
411
|
+
message: WARNING_MESSAGES.X12_837_ENTITY_SEGMENT_DISCARDED_AFTER_LX,
|
|
412
|
+
position
|
|
413
|
+
};
|
|
414
|
+
}
|
|
377
415
|
function unknownClaimStatusCategory(position) {
|
|
378
416
|
return {
|
|
379
417
|
code: WARNING_CODES.X12_UNKNOWN_CLAIM_STATUS_CATEGORY,
|
|
@@ -395,6 +433,13 @@ function unknownMaintenanceType(position) {
|
|
|
395
433
|
position
|
|
396
434
|
};
|
|
397
435
|
}
|
|
436
|
+
function unparseableDecimal(position) {
|
|
437
|
+
return {
|
|
438
|
+
code: WARNING_CODES.X12_UNPARSEABLE_DECIMAL,
|
|
439
|
+
message: WARNING_MESSAGES.X12_UNPARSEABLE_DECIMAL,
|
|
440
|
+
position
|
|
441
|
+
};
|
|
442
|
+
}
|
|
398
443
|
|
|
399
444
|
// src/parser/release.ts
|
|
400
445
|
var RELEASE_CHAR = "?";
|
|
@@ -908,13 +953,26 @@ function componentOptional(seg, n, p, delimiters) {
|
|
|
908
953
|
const v = getSegmentValue(seg, `${String(n).padStart(2, "0")}-${String(p)}`, delimiters);
|
|
909
954
|
return v === void 0 || v === "" ? void 0 : v;
|
|
910
955
|
}
|
|
911
|
-
function
|
|
956
|
+
function readElementDecimal(seg, n, delimiters) {
|
|
912
957
|
const raw = elementOptional(seg, n, delimiters);
|
|
913
|
-
if (raw === void 0) return void 0;
|
|
914
|
-
|
|
958
|
+
if (raw === void 0) return { value: void 0, status: "absent" };
|
|
959
|
+
const value = X12Decimal.fromString(raw);
|
|
960
|
+
if (value === void 0) return { value: void 0, status: "unparseable" };
|
|
961
|
+
return { value, status: "decoded" };
|
|
915
962
|
}
|
|
916
|
-
function
|
|
917
|
-
|
|
963
|
+
function elementDecimal(seg, n, delimiters, sink) {
|
|
964
|
+
const read = readElementDecimal(seg, n, delimiters);
|
|
965
|
+
if (read.status === "unparseable" && sink !== void 0) {
|
|
966
|
+
sink.warnings.push(unparseableDecimal({ ...sink.position, elementIndex: n }));
|
|
967
|
+
}
|
|
968
|
+
return read.value;
|
|
969
|
+
}
|
|
970
|
+
function elementDecimalOrZero(seg, n, delimiters, sink) {
|
|
971
|
+
const read = readElementDecimal(seg, n, delimiters);
|
|
972
|
+
if (read.status === "unparseable" && sink !== void 0) {
|
|
973
|
+
sink.warnings.push(unparseableDecimal({ ...sink.position, elementIndex: n }));
|
|
974
|
+
}
|
|
975
|
+
return read.value ?? X12Decimal.ZERO;
|
|
918
976
|
}
|
|
919
977
|
function collectElementValues(seg, start, end, delimiters) {
|
|
920
978
|
const out = [];
|
|
@@ -1420,6 +1478,7 @@ function defineLoopSpec(input) {
|
|
|
1420
1478
|
// src/code-lists/meta.ts
|
|
1421
1479
|
function makeLookup(snapshot) {
|
|
1422
1480
|
return (code) => {
|
|
1481
|
+
if (!Object.hasOwn(snapshot.codes, code)) return void 0;
|
|
1423
1482
|
const description = snapshot.codes[code];
|
|
1424
1483
|
if (description === void 0) return void 0;
|
|
1425
1484
|
return Object.freeze({ code, description });
|
|
@@ -1668,7 +1727,7 @@ var CLAIM_ADJUSTMENT_GROUP_CODES = {
|
|
|
1668
1727
|
PI: "PI"
|
|
1669
1728
|
};
|
|
1670
1729
|
function isClaimAdjustmentGroupCode(value) {
|
|
1671
|
-
return value
|
|
1730
|
+
return Object.hasOwn(CLAIM_ADJUSTMENT_GROUP_CODES, value);
|
|
1672
1731
|
}
|
|
1673
1732
|
|
|
1674
1733
|
// src/code-lists/rarc.ts
|
|
@@ -1808,6 +1867,7 @@ var HI_QUALIFIERS = {
|
|
|
1808
1867
|
}
|
|
1809
1868
|
};
|
|
1810
1869
|
function resolveHiQualifier(qualifier) {
|
|
1870
|
+
if (!Object.hasOwn(HI_QUALIFIERS, qualifier)) return void 0;
|
|
1811
1871
|
return HI_QUALIFIERS[qualifier];
|
|
1812
1872
|
}
|
|
1813
1873
|
function isDiagnosisQualifier(qualifier) {
|
|
@@ -1917,9 +1977,10 @@ function get835(delimiters, tx) {
|
|
|
1917
1977
|
const seg = body[i];
|
|
1918
1978
|
if (seg === void 0) continue;
|
|
1919
1979
|
const position = { segmentIndex: i + 1, transactionIndex: 0 };
|
|
1980
|
+
const sink = { warnings, position };
|
|
1920
1981
|
switch (seg.id) {
|
|
1921
1982
|
case "BPR": {
|
|
1922
|
-
payment = decodeBpr(seg, delimiters);
|
|
1983
|
+
payment = decodeBpr(seg, delimiters, sink);
|
|
1923
1984
|
bprSegmentIndex = position.segmentIndex;
|
|
1924
1985
|
break;
|
|
1925
1986
|
}
|
|
@@ -1994,7 +2055,7 @@ function get835(delimiters, tx) {
|
|
|
1994
2055
|
case "CLP": {
|
|
1995
2056
|
flushClaim();
|
|
1996
2057
|
lastParty = void 0;
|
|
1997
|
-
currentClaim = openClaim(seg, delimiters, position.segmentIndex);
|
|
2058
|
+
currentClaim = openClaim(seg, delimiters, position.segmentIndex, sink);
|
|
1998
2059
|
break;
|
|
1999
2060
|
}
|
|
2000
2061
|
case "CAS": {
|
|
@@ -2046,7 +2107,7 @@ function get835(delimiters, tx) {
|
|
|
2046
2107
|
break;
|
|
2047
2108
|
}
|
|
2048
2109
|
case "AMT": {
|
|
2049
|
-
const amount = decodeAmt(seg, delimiters);
|
|
2110
|
+
const amount = decodeAmt(seg, delimiters, sink);
|
|
2050
2111
|
if (amount === void 0) break;
|
|
2051
2112
|
if (currentServiceLine !== void 0) currentServiceLine.amounts.push(amount);
|
|
2052
2113
|
else if (currentClaim !== void 0) currentClaim.amounts.push(amount);
|
|
@@ -2065,12 +2126,12 @@ function get835(delimiters, tx) {
|
|
|
2065
2126
|
}
|
|
2066
2127
|
case "SVC": {
|
|
2067
2128
|
flushServiceLine();
|
|
2068
|
-
currentServiceLine = openServiceLine(seg, delimiters);
|
|
2129
|
+
currentServiceLine = openServiceLine(seg, delimiters, sink);
|
|
2069
2130
|
break;
|
|
2070
2131
|
}
|
|
2071
2132
|
case "PLB": {
|
|
2072
2133
|
flushClaim();
|
|
2073
|
-
for (const p of decodePlb(seg, delimiters)) providerAdjustments.push(p);
|
|
2134
|
+
for (const p of decodePlb(seg, delimiters, sink)) providerAdjustments.push(p);
|
|
2074
2135
|
break;
|
|
2075
2136
|
}
|
|
2076
2137
|
}
|
|
@@ -2101,10 +2162,10 @@ function get835(delimiters, tx) {
|
|
|
2101
2162
|
warnings: Object.freeze(warnings.slice())
|
|
2102
2163
|
});
|
|
2103
2164
|
}
|
|
2104
|
-
function decodeBpr(seg, delimiters) {
|
|
2165
|
+
function decodeBpr(seg, delimiters, sink) {
|
|
2105
2166
|
return Object.freeze({
|
|
2106
2167
|
transactionHandlingCode: elementValue(seg, 1, delimiters),
|
|
2107
|
-
totalActualPayment: elementDecimalOrZero(seg, 2, delimiters),
|
|
2168
|
+
totalActualPayment: elementDecimalOrZero(seg, 2, delimiters, sink),
|
|
2108
2169
|
creditDebitFlag: elementValue(seg, 3, delimiters),
|
|
2109
2170
|
method: elementValue(seg, 4, delimiters),
|
|
2110
2171
|
paymentFormatCode: elementOptional(seg, 5, delimiters),
|
|
@@ -2163,8 +2224,8 @@ function decodePer(seg, delimiters) {
|
|
|
2163
2224
|
communications: Object.freeze(comms)
|
|
2164
2225
|
});
|
|
2165
2226
|
}
|
|
2166
|
-
function decodeAmt(seg, delimiters) {
|
|
2167
|
-
const amount = elementDecimal(seg, 2, delimiters);
|
|
2227
|
+
function decodeAmt(seg, delimiters, sink) {
|
|
2228
|
+
const amount = elementDecimal(seg, 2, delimiters, sink);
|
|
2168
2229
|
if (amount === void 0) return void 0;
|
|
2169
2230
|
return Object.freeze({
|
|
2170
2231
|
qualifier: elementValue(seg, 1, delimiters),
|
|
@@ -2200,13 +2261,14 @@ function collectMoaRemarks(seg, delimiters) {
|
|
|
2200
2261
|
return out;
|
|
2201
2262
|
}
|
|
2202
2263
|
function decodeCasAdjustments(seg, delimiters, warnings, position) {
|
|
2264
|
+
const sink = { warnings, position };
|
|
2203
2265
|
const groupCode = elementValue(seg, 1, delimiters);
|
|
2204
2266
|
const out = [];
|
|
2205
2267
|
for (let triple = 0; triple < 6; triple += 1) {
|
|
2206
2268
|
const base = 2 + triple * 3;
|
|
2207
2269
|
const reasonCode = elementOptional(seg, base, delimiters);
|
|
2208
|
-
const amount = elementDecimal(seg, base + 1, delimiters);
|
|
2209
|
-
const quantity = elementDecimal(seg, base + 2, delimiters);
|
|
2270
|
+
const amount = elementDecimal(seg, base + 1, delimiters, sink);
|
|
2271
|
+
const quantity = elementDecimal(seg, base + 2, delimiters, sink);
|
|
2210
2272
|
if (reasonCode === void 0 && amount === void 0) continue;
|
|
2211
2273
|
const code = reasonCode ?? "";
|
|
2212
2274
|
const entry = code === "" ? void 0 : lookupCarc(code);
|
|
@@ -2250,7 +2312,7 @@ function decodeNm1(seg, delimiters) {
|
|
|
2250
2312
|
})
|
|
2251
2313
|
};
|
|
2252
2314
|
}
|
|
2253
|
-
function openClaim(seg, delimiters, clpSegmentIndex) {
|
|
2315
|
+
function openClaim(seg, delimiters, clpSegmentIndex, sink) {
|
|
2254
2316
|
const claimStatusCode = elementValue(seg, 2, delimiters);
|
|
2255
2317
|
const claimStatusDescription = lookupClpStatus(claimStatusCode)?.description;
|
|
2256
2318
|
const facilityTypeCode = componentOptional(seg, 8, 1, delimiters) ?? elementOptional(seg, 8, delimiters);
|
|
@@ -2260,9 +2322,9 @@ function openClaim(seg, delimiters, clpSegmentIndex) {
|
|
|
2260
2322
|
patientControlNumber: elementValue(seg, 1, delimiters),
|
|
2261
2323
|
claimStatusCode,
|
|
2262
2324
|
claimStatusDescription,
|
|
2263
|
-
totalChargeAmount: elementDecimalOrZero(seg, 3, delimiters),
|
|
2264
|
-
totalPaymentAmount: elementDecimalOrZero(seg, 4, delimiters),
|
|
2265
|
-
patientResponsibilityAmount: elementDecimalOrZero(seg, 5, delimiters),
|
|
2325
|
+
totalChargeAmount: elementDecimalOrZero(seg, 3, delimiters, sink),
|
|
2326
|
+
totalPaymentAmount: elementDecimalOrZero(seg, 4, delimiters, sink),
|
|
2327
|
+
patientResponsibilityAmount: elementDecimalOrZero(seg, 5, delimiters, sink),
|
|
2266
2328
|
claimFilingIndicatorCode: elementOptional(seg, 6, delimiters),
|
|
2267
2329
|
payerClaimControlNumber: elementOptional(seg, 7, delimiters),
|
|
2268
2330
|
facilityTypeCode,
|
|
@@ -2281,7 +2343,7 @@ function openClaim(seg, delimiters, clpSegmentIndex) {
|
|
|
2281
2343
|
serviceLines: []
|
|
2282
2344
|
};
|
|
2283
2345
|
}
|
|
2284
|
-
function openServiceLine(seg, delimiters) {
|
|
2346
|
+
function openServiceLine(seg, delimiters, sink) {
|
|
2285
2347
|
const productServiceIdQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
|
|
2286
2348
|
const productServiceId = componentOptional(seg, 1, 2, delimiters) ?? "";
|
|
2287
2349
|
const modifiers = [];
|
|
@@ -2289,18 +2351,20 @@ function openServiceLine(seg, delimiters) {
|
|
|
2289
2351
|
const m = componentOptional(seg, 1, comp, delimiters);
|
|
2290
2352
|
if (m !== void 0) modifiers.push(m);
|
|
2291
2353
|
}
|
|
2292
|
-
const revenueCode = elementOptional(seg,
|
|
2293
|
-
const paidUnitsOfService = elementDecimal(seg,
|
|
2354
|
+
const revenueCode = elementOptional(seg, 4, delimiters);
|
|
2355
|
+
const paidUnitsOfService = elementDecimal(seg, 5, delimiters, sink);
|
|
2356
|
+
const originalUnitsOfService = elementDecimal(seg, 7, delimiters, sink);
|
|
2294
2357
|
const originalServiceIdQualifier = componentOptional(seg, 6, 1, delimiters);
|
|
2295
2358
|
const originalServiceId = componentOptional(seg, 6, 2, delimiters);
|
|
2296
2359
|
return {
|
|
2297
2360
|
productServiceIdQualifier,
|
|
2298
2361
|
productServiceId,
|
|
2299
2362
|
modifiers,
|
|
2300
|
-
chargeAmount: elementDecimalOrZero(seg, 2, delimiters),
|
|
2301
|
-
paymentAmount: elementDecimalOrZero(seg, 3, delimiters),
|
|
2363
|
+
chargeAmount: elementDecimalOrZero(seg, 2, delimiters, sink),
|
|
2364
|
+
paymentAmount: elementDecimalOrZero(seg, 3, delimiters, sink),
|
|
2302
2365
|
revenueCode,
|
|
2303
2366
|
paidUnitsOfService,
|
|
2367
|
+
originalUnitsOfService,
|
|
2304
2368
|
originalServiceId,
|
|
2305
2369
|
originalServiceIdQualifier,
|
|
2306
2370
|
serviceDateStart: void 0,
|
|
@@ -2326,13 +2390,13 @@ function attachServiceLineDtm(line, seg, delimiters) {
|
|
|
2326
2390
|
if (qualifier === "472" || qualifier === "150") line.serviceDateStart = date;
|
|
2327
2391
|
if (qualifier === "472" || qualifier === "151") line.serviceDateEnd = date;
|
|
2328
2392
|
}
|
|
2329
|
-
function decodePlb(seg, delimiters) {
|
|
2393
|
+
function decodePlb(seg, delimiters, sink) {
|
|
2330
2394
|
const providerId = elementValue(seg, 1, delimiters);
|
|
2331
2395
|
const fiscalPeriodDate = elementValue(seg, 2, delimiters);
|
|
2332
2396
|
const out = [];
|
|
2333
2397
|
for (let pair = 0; pair < 6; pair += 1) {
|
|
2334
2398
|
const composite = 3 + pair * 2;
|
|
2335
|
-
const amount = elementDecimal(seg, composite + 1, delimiters);
|
|
2399
|
+
const amount = elementDecimal(seg, composite + 1, delimiters, sink);
|
|
2336
2400
|
const reasonCode = componentOptional(seg, composite, 1, delimiters);
|
|
2337
2401
|
const subCode = componentOptional(seg, composite, 2, delimiters);
|
|
2338
2402
|
if (amount === void 0 && reasonCode === void 0) continue;
|
|
@@ -2396,6 +2460,7 @@ function freezeServiceLine(acc) {
|
|
|
2396
2460
|
paymentAmount: acc.paymentAmount,
|
|
2397
2461
|
revenueCode: acc.revenueCode,
|
|
2398
2462
|
paidUnitsOfService: acc.paidUnitsOfService,
|
|
2463
|
+
originalUnitsOfService: acc.originalUnitsOfService,
|
|
2399
2464
|
originalServiceId: acc.originalServiceId,
|
|
2400
2465
|
originalServiceIdQualifier: acc.originalServiceIdQualifier,
|
|
2401
2466
|
serviceDateStart: acc.serviceDateStart,
|
|
@@ -2481,7 +2546,7 @@ function renderCallerJson(value) {
|
|
|
2481
2546
|
var NONE = Object.freeze([]);
|
|
2482
2547
|
function describeShape(value) {
|
|
2483
2548
|
if (typeof value !== "object") {
|
|
2484
|
-
return `a ${typeof value}
|
|
2549
|
+
return `a ${typeof value}`;
|
|
2485
2550
|
}
|
|
2486
2551
|
let length;
|
|
2487
2552
|
try {
|
|
@@ -2511,6 +2576,50 @@ function isRealArray(value) {
|
|
|
2511
2576
|
return Array.isArray(value);
|
|
2512
2577
|
}
|
|
2513
2578
|
|
|
2579
|
+
// src/builder/caller-decimal.ts
|
|
2580
|
+
function describeCallerDecimal(value) {
|
|
2581
|
+
if (value === null) return "null";
|
|
2582
|
+
if (value === void 0) return "undefined";
|
|
2583
|
+
const type = typeof value;
|
|
2584
|
+
if (type === "object") return Array.isArray(value) ? "an array" : "an object";
|
|
2585
|
+
if (type === "function") return "a function";
|
|
2586
|
+
return `a ${type}`;
|
|
2587
|
+
}
|
|
2588
|
+
function requireCallerDecimal(value, at, refuse) {
|
|
2589
|
+
if (value instanceof X12Decimal) return value;
|
|
2590
|
+
refuse(
|
|
2591
|
+
`${at}: every numeric element value must be an X12Decimal, but received ${describeCallerDecimal(value)}. Values are never coerced - a JavaScript number has no X12 lexical form (0.1 + 0.2 renders as "0.30000000000000004", 1e21 as "1e+21", NaN as "NaN"), and rounding one here would guess a scale the caller never stated. Build it with X12Decimal.fromString() at the call site.`
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
// src/builder/caller-segment.ts
|
|
2596
|
+
var SEGMENT_ID_RE2 = /^[A-Z][A-Z0-9]{1,2}$/u;
|
|
2597
|
+
function describeSegmentValue(value) {
|
|
2598
|
+
if (value === null) return "null";
|
|
2599
|
+
if (value === void 0) return "undefined";
|
|
2600
|
+
const type = typeof value;
|
|
2601
|
+
if (type === "object") return Array.isArray(value) ? "an array" : "an object";
|
|
2602
|
+
if (type === "function") return "a function";
|
|
2603
|
+
return `a ${type}`;
|
|
2604
|
+
}
|
|
2605
|
+
function locateSlot(parts, index) {
|
|
2606
|
+
const id = parts[0];
|
|
2607
|
+
const position = String(index).padStart(2, "0");
|
|
2608
|
+
if (typeof id !== "string" || !SEGMENT_ID_RE2.test(id)) return `element ${String(index)}`;
|
|
2609
|
+
return `"${id}"-${position}`;
|
|
2610
|
+
}
|
|
2611
|
+
function requireCallerSegment(parts, at, refuse) {
|
|
2612
|
+
let index = 0;
|
|
2613
|
+
for (const part of parts) {
|
|
2614
|
+
if (typeof part !== "string") {
|
|
2615
|
+
refuse(
|
|
2616
|
+
`${at}: ${locateSlot(parts, index)} must be a string, but received ${describeSegmentValue(part)}. Values are never coerced - a JavaScript number cannot carry a leading-zero identifier, so converting here could emit a different value than the caller sent. Convert at the call site.`
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
index += 1;
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2514
2623
|
// src/builder/caller-string.ts
|
|
2515
2624
|
function describeCallerValue(value) {
|
|
2516
2625
|
if (value === null) return "null";
|
|
@@ -2518,7 +2627,7 @@ function describeCallerValue(value) {
|
|
|
2518
2627
|
const type = typeof value;
|
|
2519
2628
|
if (type === "object") return Array.isArray(value) ? "an array" : "an object";
|
|
2520
2629
|
if (type === "function") return "a function";
|
|
2521
|
-
return `a ${type}
|
|
2630
|
+
return `a ${type}`;
|
|
2522
2631
|
}
|
|
2523
2632
|
function requireCallerString(value, at, refuse) {
|
|
2524
2633
|
if (typeof value === "string") return value;
|
|
@@ -2534,6 +2643,9 @@ function makeCallerEscaper(delimiters, at, refuse) {
|
|
|
2534
2643
|
function refuseSpec(message) {
|
|
2535
2644
|
throw new Remit835BuildError(REMIT_835_BUILD_ERROR_CODES.X12_835_BUILD_INVALID_SPEC, message);
|
|
2536
2645
|
}
|
|
2646
|
+
function escDec(value, esc) {
|
|
2647
|
+
return esc(requireCallerDecimal(value, "build835", refuseSpec).toString());
|
|
2648
|
+
}
|
|
2537
2649
|
var X221A1_VERSION_RELEASE = "005010X221A1";
|
|
2538
2650
|
var X12_835_FUNCTIONAL_ID = "HP";
|
|
2539
2651
|
var X12_AGENCY_CODE = "X";
|
|
@@ -2557,6 +2669,7 @@ function build835(spec) {
|
|
|
2557
2669
|
};
|
|
2558
2670
|
const esc = makeCallerEscaper(delimiters, "build835", refuseSpec);
|
|
2559
2671
|
const seg = (parts) => {
|
|
2672
|
+
requireCallerSegment(parts, "build835", refuseSpec);
|
|
2560
2673
|
let end = parts.length;
|
|
2561
2674
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
2562
2675
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -2618,9 +2731,9 @@ function build835(spec) {
|
|
|
2618
2731
|
// GS-02
|
|
2619
2732
|
esc(applicationReceiverCode),
|
|
2620
2733
|
// GS-03
|
|
2621
|
-
groupDate,
|
|
2734
|
+
esc(groupDate),
|
|
2622
2735
|
// GS-04 - CCYYMMDD
|
|
2623
|
-
groupTime,
|
|
2736
|
+
esc(groupTime),
|
|
2624
2737
|
// GS-05 - HHMM
|
|
2625
2738
|
esc(envelope.groupControlNumber),
|
|
2626
2739
|
// GS-06
|
|
@@ -2636,7 +2749,7 @@ function build835(spec) {
|
|
|
2636
2749
|
seg([
|
|
2637
2750
|
"BPR",
|
|
2638
2751
|
esc(spec.payment.transactionHandlingCode),
|
|
2639
|
-
|
|
2752
|
+
escDec(spec.payment.totalActualPayment, esc),
|
|
2640
2753
|
esc(spec.payment.creditDebitFlag),
|
|
2641
2754
|
esc(spec.payment.method),
|
|
2642
2755
|
esc(spec.payment.paymentFormatCode ?? ""),
|
|
@@ -2771,6 +2884,7 @@ function materializeServiceLine(spec) {
|
|
|
2771
2884
|
paymentAmount: spec.paymentAmount,
|
|
2772
2885
|
revenueCode: spec.revenueCode,
|
|
2773
2886
|
paidUnitsOfService: spec.paidUnitsOfService,
|
|
2887
|
+
originalUnitsOfService: spec.originalUnitsOfService,
|
|
2774
2888
|
originalServiceId: spec.originalServiceId,
|
|
2775
2889
|
originalServiceIdQualifier: spec.originalServiceIdQualifier,
|
|
2776
2890
|
serviceDateStart: spec.serviceDateStart,
|
|
@@ -2866,9 +2980,9 @@ function emitClaim(claim, body, seg, esc, comp) {
|
|
|
2866
2980
|
"CLP",
|
|
2867
2981
|
esc(claim.patientControlNumber),
|
|
2868
2982
|
esc(claim.claimStatusCode),
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2983
|
+
escDec(claim.totalChargeAmount, esc),
|
|
2984
|
+
escDec(claim.totalPaymentAmount, esc),
|
|
2985
|
+
escDec(claim.patientResponsibilityAmount, esc),
|
|
2872
2986
|
esc(claim.claimFilingIndicatorCode ?? ""),
|
|
2873
2987
|
esc(claim.payerClaimControlNumber ?? ""),
|
|
2874
2988
|
comp([claim.facilityTypeCode ?? "", "", claim.claimFrequencyCode ?? ""])
|
|
@@ -2890,7 +3004,7 @@ function emitClaim(claim, body, seg, esc, comp) {
|
|
|
2890
3004
|
}
|
|
2891
3005
|
for (const ref of claim.references ?? []) body.push(emitRef(ref, seg, esc));
|
|
2892
3006
|
for (const amt of claim.amounts ?? []) {
|
|
2893
|
-
body.push(seg(["AMT", esc(amt.qualifier),
|
|
3007
|
+
body.push(seg(["AMT", esc(amt.qualifier), escDec(amt.amount, esc)]));
|
|
2894
3008
|
}
|
|
2895
3009
|
for (const remark of claim.remarks ?? []) {
|
|
2896
3010
|
body.push(seg(["LQ", esc(remark.system), esc(remark.code)]));
|
|
@@ -2910,20 +3024,24 @@ function emitServiceLine(line, body, seg, esc, comp) {
|
|
|
2910
3024
|
seg([
|
|
2911
3025
|
"SVC",
|
|
2912
3026
|
svc01,
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
// SVC-
|
|
3027
|
+
escDec(line.chargeAmount, esc),
|
|
3028
|
+
escDec(line.paymentAmount, esc),
|
|
3029
|
+
// SVC-04 is the NUBC revenue code (element 234, Product/Service ID) and
|
|
3030
|
+
// SVC-05 is the Units of Service PAID Count (element 380, Quantity).
|
|
3031
|
+
// SVC-07 is the ORIGINAL (submitted) units, a different quantity from
|
|
3032
|
+
// SVC-05 - so the two never share a field. See the SVC note in
|
|
3033
|
+
// KNOWN-LIMITATIONS.md for the sources.
|
|
2917
3034
|
esc(line.revenueCode ?? ""),
|
|
3035
|
+
line.paidUnitsOfService === void 0 ? "" : escDec(line.paidUnitsOfService, esc),
|
|
2918
3036
|
svc06,
|
|
2919
|
-
line.
|
|
3037
|
+
line.originalUnitsOfService === void 0 ? "" : escDec(line.originalUnitsOfService, esc)
|
|
2920
3038
|
])
|
|
2921
3039
|
);
|
|
2922
3040
|
emitServiceLineDtm(line, body, seg, esc);
|
|
2923
3041
|
emitCasGroup(line.adjustments, "build835: serviceLine.adjustments", body, seg, esc);
|
|
2924
3042
|
for (const ref of line.references ?? []) body.push(emitRef(ref, seg, esc));
|
|
2925
3043
|
for (const amt of line.amounts ?? []) {
|
|
2926
|
-
body.push(seg(["AMT", esc(amt.qualifier),
|
|
3044
|
+
body.push(seg(["AMT", esc(amt.qualifier), escDec(amt.amount, esc)]));
|
|
2927
3045
|
}
|
|
2928
3046
|
for (const remark of line.remarks ?? []) {
|
|
2929
3047
|
body.push(seg(["LQ", esc(remark.system), esc(remark.code)]));
|
|
@@ -2955,8 +3073,8 @@ function emitCasGroup(raw, at, body, seg, esc) {
|
|
|
2955
3073
|
if (adj === void 0 || adj.groupCode !== groupCode) break;
|
|
2956
3074
|
parts.push(
|
|
2957
3075
|
esc(adj.reasonCode),
|
|
2958
|
-
|
|
2959
|
-
adj.quantity === void 0 ? "" :
|
|
3076
|
+
escDec(adj.amount, esc),
|
|
3077
|
+
adj.quantity === void 0 ? "" : escDec(adj.quantity, esc)
|
|
2960
3078
|
);
|
|
2961
3079
|
triples += 1;
|
|
2962
3080
|
i += 1;
|
|
@@ -3014,7 +3132,7 @@ function emitProviderAdjustments(raw, at, body, seg, esc, comp) {
|
|
|
3014
3132
|
if (adj === void 0 || adj.providerId !== providerId || adj.fiscalPeriodDate !== fiscalPeriodDate) {
|
|
3015
3133
|
break;
|
|
3016
3134
|
}
|
|
3017
|
-
parts.push(comp([adj.reasonCode, adj.subCode ?? ""]),
|
|
3135
|
+
parts.push(comp([adj.reasonCode, adj.subCode ?? ""]), escDec(adj.amount, esc));
|
|
3018
3136
|
pairs += 1;
|
|
3019
3137
|
i += 1;
|
|
3020
3138
|
}
|
|
@@ -3112,13 +3230,22 @@ var REMIT_835_LOOP_1000B = defineLoopSpec({
|
|
|
3112
3230
|
]
|
|
3113
3231
|
});
|
|
3114
3232
|
|
|
3233
|
+
// src/parser/lookup.ts
|
|
3234
|
+
function wireLookup(entries) {
|
|
3235
|
+
const table = /* @__PURE__ */ Object.create(null);
|
|
3236
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
3237
|
+
table[key] = value;
|
|
3238
|
+
}
|
|
3239
|
+
return Object.freeze(table);
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3115
3242
|
// src/transactions/claim/get-837.ts
|
|
3116
|
-
var VARIANT_BY_ICR =
|
|
3243
|
+
var VARIANT_BY_ICR = wireLookup({
|
|
3117
3244
|
"005010X222A2": "P",
|
|
3118
3245
|
"005010X223A3": "I",
|
|
3119
3246
|
"005010X224A2": "D"
|
|
3120
3247
|
});
|
|
3121
|
-
var VARIANT_BY_SV_SEGMENT =
|
|
3248
|
+
var VARIANT_BY_SV_SEGMENT = wireLookup({
|
|
3122
3249
|
SV1: "P",
|
|
3123
3250
|
SV2: "I",
|
|
3124
3251
|
SV3: "D"
|
|
@@ -3139,7 +3266,7 @@ var NM1_QUALIFIERS = Object.freeze({
|
|
|
3139
3266
|
PAYER: "PR",
|
|
3140
3267
|
PATIENT: "QC"
|
|
3141
3268
|
});
|
|
3142
|
-
var EXPECTED_PARENT_LEVEL =
|
|
3269
|
+
var EXPECTED_PARENT_LEVEL = wireLookup({
|
|
3143
3270
|
[HL_LEVEL_CODES.INFORMATION_SOURCE]: void 0,
|
|
3144
3271
|
[HL_LEVEL_CODES.SUBSCRIBER]: HL_LEVEL_CODES.INFORMATION_SOURCE,
|
|
3145
3272
|
[HL_LEVEL_CODES.DEPENDENT]: HL_LEVEL_CODES.SUBSCRIBER
|
|
@@ -3161,7 +3288,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3161
3288
|
}
|
|
3162
3289
|
const variant = explicitType ?? variantFromIcr ?? variantFromSegment ?? "unknown";
|
|
3163
3290
|
if (variant === "unknown") {
|
|
3164
|
-
warnings.push(unknown837Variant({ segmentIndex:
|
|
3291
|
+
warnings.push(unknown837Variant({ segmentIndex: 0, transactionIndex: 0 }));
|
|
3165
3292
|
}
|
|
3166
3293
|
const hierarchies = [];
|
|
3167
3294
|
const hlIndex = /* @__PURE__ */ new Map();
|
|
@@ -3184,7 +3311,9 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3184
3311
|
let currentOtherSubscriber;
|
|
3185
3312
|
let currentAdjudication;
|
|
3186
3313
|
let context = { kind: "header" };
|
|
3314
|
+
let droppedLineReported = false;
|
|
3187
3315
|
let activeEntity;
|
|
3316
|
+
let entityLoopClosedByStrayLx = false;
|
|
3188
3317
|
const flushAdjudication = () => {
|
|
3189
3318
|
if (currentAdjudication !== void 0 && currentServiceLine !== void 0) {
|
|
3190
3319
|
currentServiceLine.adjudications.push(freezeAdjudication(currentAdjudication));
|
|
@@ -3194,9 +3323,21 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3194
3323
|
const flushServiceLine = () => {
|
|
3195
3324
|
flushAdjudication();
|
|
3196
3325
|
if (currentServiceLine !== void 0 && currentClaim !== void 0) {
|
|
3326
|
+
if (!currentServiceLine.serviceSegmentDecoded) {
|
|
3327
|
+
warnings.push(serviceLineNotDecoded(currentServiceLine.position));
|
|
3328
|
+
}
|
|
3197
3329
|
currentClaim.serviceLines.push(freezeServiceLine2(currentServiceLine));
|
|
3198
3330
|
}
|
|
3199
3331
|
currentServiceLine = void 0;
|
|
3332
|
+
droppedLineReported = false;
|
|
3333
|
+
};
|
|
3334
|
+
const reportOrphanServiceSegment = (position) => {
|
|
3335
|
+
if (droppedLineReported) return;
|
|
3336
|
+
warnings.push(serviceSegmentWithoutLx(position));
|
|
3337
|
+
};
|
|
3338
|
+
const reportDiscardedEntitySegment = (position) => {
|
|
3339
|
+
if (!entityLoopClosedByStrayLx) return;
|
|
3340
|
+
warnings.push(entitySegmentDiscardedAfterLx(position));
|
|
3200
3341
|
};
|
|
3201
3342
|
const flushOtherSubscriber = () => {
|
|
3202
3343
|
if (currentOtherSubscriber !== void 0 && currentClaim !== void 0) {
|
|
@@ -3267,6 +3408,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3267
3408
|
const seg = body[i];
|
|
3268
3409
|
if (seg === void 0) continue;
|
|
3269
3410
|
const position = { segmentIndex: i + 1, transactionIndex: 0 };
|
|
3411
|
+
const sink = { warnings, position };
|
|
3270
3412
|
switch (seg.id) {
|
|
3271
3413
|
case "HL": {
|
|
3272
3414
|
flushClaim();
|
|
@@ -3299,6 +3441,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3299
3441
|
context = { kind: "header" };
|
|
3300
3442
|
}
|
|
3301
3443
|
activeEntity = void 0;
|
|
3444
|
+
entityLoopClosedByStrayLx = false;
|
|
3302
3445
|
break;
|
|
3303
3446
|
}
|
|
3304
3447
|
case "SBR": {
|
|
@@ -3315,6 +3458,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3315
3458
|
otherPayer: void 0
|
|
3316
3459
|
};
|
|
3317
3460
|
activeEntity = { kind: "otherSubscriber" };
|
|
3461
|
+
entityLoopClosedByStrayLx = false;
|
|
3318
3462
|
}
|
|
3319
3463
|
break;
|
|
3320
3464
|
}
|
|
@@ -3330,6 +3474,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3330
3474
|
case "NM1": {
|
|
3331
3475
|
const qualifier = elementValue(seg, 1, delimiters);
|
|
3332
3476
|
const entity = decodeNm12(seg, delimiters);
|
|
3477
|
+
entityLoopClosedByStrayLx = false;
|
|
3333
3478
|
if (qualifier === NM1_QUALIFIERS.SUBMITTER) {
|
|
3334
3479
|
submitter = entity;
|
|
3335
3480
|
activeEntity = { kind: "submitter" };
|
|
@@ -3374,16 +3519,19 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3374
3519
|
case "N3": {
|
|
3375
3520
|
const lines = collectElementValues(seg, 1, 2, delimiters);
|
|
3376
3521
|
attachAddressLines(lines, activeEntity, entityMutators);
|
|
3522
|
+
reportDiscardedEntitySegment(position);
|
|
3377
3523
|
break;
|
|
3378
3524
|
}
|
|
3379
3525
|
case "N4": {
|
|
3380
3526
|
const partial = decodeN42(seg, delimiters);
|
|
3381
3527
|
attachAddressFields(partial, activeEntity, entityMutators);
|
|
3528
|
+
reportDiscardedEntitySegment(position);
|
|
3382
3529
|
break;
|
|
3383
3530
|
}
|
|
3384
3531
|
case "PER": {
|
|
3385
3532
|
const contact = decodePer2(seg, delimiters);
|
|
3386
3533
|
attachContact(contact, activeEntity, entityMutators);
|
|
3534
|
+
reportDiscardedEntitySegment(position);
|
|
3387
3535
|
break;
|
|
3388
3536
|
}
|
|
3389
3537
|
case "REF": {
|
|
@@ -3395,6 +3543,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3395
3543
|
currentClaim.references.push(ref);
|
|
3396
3544
|
} else {
|
|
3397
3545
|
attachReference(ref, activeEntity, entityMutators);
|
|
3546
|
+
reportDiscardedEntitySegment(position);
|
|
3398
3547
|
}
|
|
3399
3548
|
break;
|
|
3400
3549
|
}
|
|
@@ -3414,17 +3563,23 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3414
3563
|
warnings.push(missingRequiredLoop(position, REQUIRED_LOOPS.PAYER_NAME_2010BB));
|
|
3415
3564
|
}
|
|
3416
3565
|
}
|
|
3417
|
-
currentClaim = openClaim2(
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3566
|
+
currentClaim = openClaim2(
|
|
3567
|
+
seg,
|
|
3568
|
+
delimiters,
|
|
3569
|
+
{
|
|
3570
|
+
variant,
|
|
3571
|
+
hierarchy: currentPatientHl ?? currentSubscriberHl,
|
|
3572
|
+
billingProvider,
|
|
3573
|
+
payToAddress,
|
|
3574
|
+
payToPlan,
|
|
3575
|
+
subscriber: currentSubscriberMember,
|
|
3576
|
+
payer: currentPayer,
|
|
3577
|
+
patient: currentPatientMember
|
|
3578
|
+
},
|
|
3579
|
+
sink
|
|
3580
|
+
);
|
|
3427
3581
|
activeEntity = void 0;
|
|
3582
|
+
entityLoopClosedByStrayLx = false;
|
|
3428
3583
|
context = { kind: "loop2300" };
|
|
3429
3584
|
break;
|
|
3430
3585
|
}
|
|
@@ -3462,7 +3617,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3462
3617
|
break;
|
|
3463
3618
|
}
|
|
3464
3619
|
case "AMT": {
|
|
3465
|
-
const amount = decodeAmt2(seg, delimiters);
|
|
3620
|
+
const amount = decodeAmt2(seg, delimiters, sink);
|
|
3466
3621
|
if (amount === void 0) break;
|
|
3467
3622
|
if (currentAdjudication !== void 0) break;
|
|
3468
3623
|
if (currentServiceLine !== void 0) currentServiceLine.amounts.push(amount);
|
|
@@ -3471,22 +3626,55 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3471
3626
|
}
|
|
3472
3627
|
case "LX": {
|
|
3473
3628
|
flushServiceLine();
|
|
3474
|
-
if (currentClaim === void 0)
|
|
3475
|
-
|
|
3629
|
+
if (currentClaim === void 0) {
|
|
3630
|
+
warnings.push(serviceLineDropped(position));
|
|
3631
|
+
droppedLineReported = true;
|
|
3632
|
+
entityLoopClosedByStrayLx ||= activeEntity !== void 0;
|
|
3633
|
+
activeEntity = void 0;
|
|
3634
|
+
break;
|
|
3635
|
+
}
|
|
3636
|
+
currentServiceLine = openServiceLine2(seg, delimiters, currentClaim.variant, position);
|
|
3637
|
+
if (currentServiceLine === void 0) {
|
|
3638
|
+
warnings.push(serviceLineDropped(position));
|
|
3639
|
+
droppedLineReported = true;
|
|
3640
|
+
}
|
|
3476
3641
|
activeEntity = void 0;
|
|
3642
|
+
entityLoopClosedByStrayLx = false;
|
|
3477
3643
|
context = { kind: "loop2400" };
|
|
3478
3644
|
break;
|
|
3479
3645
|
}
|
|
3646
|
+
// A service segment with no line open to decode into is a loss the
|
|
3647
|
+
// walker used to take in silence. Two ways to reach it, and only one
|
|
3648
|
+
// was ever reported: an LX that opened nothing already warned at the
|
|
3649
|
+
// LX (`droppedLineReported`), while a segment with no Loop 2400 open
|
|
3650
|
+
// at all had no anchor to warn at and so reported on no channel - a
|
|
3651
|
+
// charge, a quantity, a procedure code and its modifiers off the wire
|
|
3652
|
+
// and onto nothing. `reportOrphanServiceSegment` closes only the
|
|
3653
|
+
// second: it anchors at the service segment itself, because that is
|
|
3654
|
+
// the only segment the case has. Note the condition is "no line open",
|
|
3655
|
+
// NOT "no LX in the file": an LX in an earlier claim is still an LX.
|
|
3656
|
+
//
|
|
3657
|
+
// It does NOT decode the segment. The charge is SV1-02 / SV2-03 and
|
|
3658
|
+
// the units SV1-04 / SV2-05 / SV3-06, so reading a service segment
|
|
3659
|
+
// into a line the walker never opened is how a mis-read charge gets
|
|
3660
|
+
// minted. Refusing to read is the safe half; doing it silently was the
|
|
3661
|
+
// defect. This says nothing about VARIANT resolution, which happens
|
|
3662
|
+
// before the walk and scans every SVx in the body: an orphan segment
|
|
3663
|
+
// is eligible for that fallback like any other, which is pre-existing
|
|
3664
|
+
// and disclosed in KNOWN-LIMITATIONS.md rather than changed here.
|
|
3480
3665
|
case "SV1": {
|
|
3481
|
-
if (currentServiceLine !== void 0) decodeSv1(currentServiceLine, seg, delimiters);
|
|
3666
|
+
if (currentServiceLine !== void 0) decodeSv1(currentServiceLine, seg, delimiters, sink);
|
|
3667
|
+
else reportOrphanServiceSegment(position);
|
|
3482
3668
|
break;
|
|
3483
3669
|
}
|
|
3484
3670
|
case "SV2": {
|
|
3485
|
-
if (currentServiceLine !== void 0) decodeSv2(currentServiceLine, seg, delimiters);
|
|
3671
|
+
if (currentServiceLine !== void 0) decodeSv2(currentServiceLine, seg, delimiters, sink);
|
|
3672
|
+
else reportOrphanServiceSegment(position);
|
|
3486
3673
|
break;
|
|
3487
3674
|
}
|
|
3488
3675
|
case "SV3": {
|
|
3489
|
-
if (currentServiceLine !== void 0) decodeSv3(currentServiceLine, seg, delimiters);
|
|
3676
|
+
if (currentServiceLine !== void 0) decodeSv3(currentServiceLine, seg, delimiters, sink);
|
|
3677
|
+
else reportOrphanServiceSegment(position);
|
|
3490
3678
|
break;
|
|
3491
3679
|
}
|
|
3492
3680
|
case "TOO": {
|
|
@@ -3512,7 +3700,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3512
3700
|
}
|
|
3513
3701
|
currentServiceLine.drug = {
|
|
3514
3702
|
...currentServiceLine.drug,
|
|
3515
|
-
quantity: elementDecimal(seg, 4, delimiters),
|
|
3703
|
+
quantity: elementDecimal(seg, 4, delimiters, sink),
|
|
3516
3704
|
unitOfMeasure: componentOptional(seg, 5, 1, delimiters)
|
|
3517
3705
|
};
|
|
3518
3706
|
break;
|
|
@@ -3520,7 +3708,7 @@ function get837Claims(delimiters, tx, opts) {
|
|
|
3520
3708
|
case "SVD": {
|
|
3521
3709
|
flushAdjudication();
|
|
3522
3710
|
if (currentServiceLine === void 0) break;
|
|
3523
|
-
currentAdjudication = openAdjudication(seg, delimiters);
|
|
3711
|
+
currentAdjudication = openAdjudication(seg, delimiters, sink);
|
|
3524
3712
|
break;
|
|
3525
3713
|
}
|
|
3526
3714
|
case "CAS": {
|
|
@@ -3698,19 +3886,20 @@ function decodeNte(seg, delimiters) {
|
|
|
3698
3886
|
description: note
|
|
3699
3887
|
});
|
|
3700
3888
|
}
|
|
3701
|
-
function decodeAmt2(seg, delimiters) {
|
|
3702
|
-
const amount = elementDecimal(seg, 2, delimiters);
|
|
3889
|
+
function decodeAmt2(seg, delimiters, sink) {
|
|
3890
|
+
const amount = elementDecimal(seg, 2, delimiters, sink);
|
|
3703
3891
|
if (amount === void 0) return void 0;
|
|
3704
3892
|
return Object.freeze({ qualifier: elementValue(seg, 1, delimiters), amount });
|
|
3705
3893
|
}
|
|
3706
3894
|
function decodeCas(seg, delimiters, warnings, position) {
|
|
3895
|
+
const sink = { warnings, position };
|
|
3707
3896
|
const groupCode = elementValue(seg, 1, delimiters);
|
|
3708
3897
|
const out = [];
|
|
3709
3898
|
for (let triple = 0; triple < 6; triple += 1) {
|
|
3710
3899
|
const base = 2 + triple * 3;
|
|
3711
3900
|
const reasonCode = elementOptional(seg, base, delimiters);
|
|
3712
|
-
const amount = elementDecimal(seg, base + 1, delimiters);
|
|
3713
|
-
const quantity = elementDecimal(seg, base + 2, delimiters);
|
|
3901
|
+
const amount = elementDecimal(seg, base + 1, delimiters, sink);
|
|
3902
|
+
const quantity = elementDecimal(seg, base + 2, delimiters, sink);
|
|
3714
3903
|
if (reasonCode === void 0 && amount === void 0) continue;
|
|
3715
3904
|
const code = reasonCode ?? "";
|
|
3716
3905
|
const entry = code === "" ? void 0 : lookupCarc(code);
|
|
@@ -3745,7 +3934,7 @@ var EMPTY_SUBSCRIBER_INFO = Object.freeze({
|
|
|
3745
3934
|
groupName: void 0,
|
|
3746
3935
|
claimFilingIndicator: void 0
|
|
3747
3936
|
});
|
|
3748
|
-
function openClaim2(seg, delimiters, ctx) {
|
|
3937
|
+
function openClaim2(seg, delimiters, ctx, sink) {
|
|
3749
3938
|
const {
|
|
3750
3939
|
variant,
|
|
3751
3940
|
hierarchy,
|
|
@@ -3766,7 +3955,7 @@ function openClaim2(seg, delimiters, ctx) {
|
|
|
3766
3955
|
payer,
|
|
3767
3956
|
patient,
|
|
3768
3957
|
claimId: elementValue(seg, 1, delimiters),
|
|
3769
|
-
totalCharge: elementDecimalOrZero(seg, 2, delimiters),
|
|
3958
|
+
totalCharge: elementDecimalOrZero(seg, 2, delimiters, sink),
|
|
3770
3959
|
placeOfServiceCode: componentOptional(seg, 5, 1, delimiters),
|
|
3771
3960
|
facilityCodeQualifier: componentOptional(seg, 5, 2, delimiters),
|
|
3772
3961
|
claimFrequencyCode: componentOptional(seg, 5, 3, delimiters),
|
|
@@ -3786,10 +3975,12 @@ function openClaim2(seg, delimiters, ctx) {
|
|
|
3786
3975
|
serviceLines: []
|
|
3787
3976
|
};
|
|
3788
3977
|
}
|
|
3789
|
-
function openServiceLine2(seg, delimiters, variant) {
|
|
3978
|
+
function openServiceLine2(seg, delimiters, variant, position) {
|
|
3790
3979
|
const lineNumber = elementValue(seg, 1, delimiters);
|
|
3791
3980
|
const base = {
|
|
3792
3981
|
lineNumber,
|
|
3982
|
+
position,
|
|
3983
|
+
serviceSegmentDecoded: false,
|
|
3793
3984
|
charge: X12Decimal.ZERO,
|
|
3794
3985
|
units: X12Decimal.ZERO,
|
|
3795
3986
|
unitOfMeasure: void 0,
|
|
@@ -3841,8 +4032,9 @@ function openServiceLine2(seg, delimiters, variant) {
|
|
|
3841
4032
|
}
|
|
3842
4033
|
return void 0;
|
|
3843
4034
|
}
|
|
3844
|
-
function decodeSv1(acc, seg, delimiters) {
|
|
4035
|
+
function decodeSv1(acc, seg, delimiters, sink) {
|
|
3845
4036
|
if (acc.variant !== "P") return;
|
|
4037
|
+
acc.serviceSegmentDecoded = true;
|
|
3846
4038
|
acc.procedureQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
|
|
3847
4039
|
acc.procedureCode = componentOptional(seg, 1, 2, delimiters) ?? "";
|
|
3848
4040
|
const mods = [];
|
|
@@ -3851,9 +4043,9 @@ function decodeSv1(acc, seg, delimiters) {
|
|
|
3851
4043
|
if (m !== void 0) mods.push(m);
|
|
3852
4044
|
}
|
|
3853
4045
|
acc.modifiers = mods;
|
|
3854
|
-
acc.charge = elementDecimalOrZero(seg, 2, delimiters);
|
|
4046
|
+
acc.charge = elementDecimalOrZero(seg, 2, delimiters, sink);
|
|
3855
4047
|
acc.unitOfMeasure = elementOptional(seg, 3, delimiters);
|
|
3856
|
-
acc.units = elementDecimalOrZero(seg, 4, delimiters);
|
|
4048
|
+
acc.units = elementDecimalOrZero(seg, 4, delimiters, sink);
|
|
3857
4049
|
acc.placeOfServiceCode = elementOptional(seg, 5, delimiters);
|
|
3858
4050
|
const pointers = [];
|
|
3859
4051
|
for (let p = 1; p <= 4; p += 1) {
|
|
@@ -3865,8 +4057,9 @@ function decodeSv1(acc, seg, delimiters) {
|
|
|
3865
4057
|
acc.epsdtIndicator = elementOptional(seg, 11, delimiters);
|
|
3866
4058
|
acc.familyPlanningIndicator = elementOptional(seg, 12, delimiters);
|
|
3867
4059
|
}
|
|
3868
|
-
function decodeSv2(acc, seg, delimiters) {
|
|
4060
|
+
function decodeSv2(acc, seg, delimiters, sink) {
|
|
3869
4061
|
if (acc.variant !== "I") return;
|
|
4062
|
+
acc.serviceSegmentDecoded = true;
|
|
3870
4063
|
acc.revenueCode = elementValue(seg, 1, delimiters);
|
|
3871
4064
|
acc.procedureQualifier = componentOptional(seg, 2, 1, delimiters);
|
|
3872
4065
|
acc.procedureCode = componentOptional(seg, 2, 2, delimiters);
|
|
@@ -3876,14 +4069,15 @@ function decodeSv2(acc, seg, delimiters) {
|
|
|
3876
4069
|
if (m !== void 0) mods.push(m);
|
|
3877
4070
|
}
|
|
3878
4071
|
acc.modifiers = mods;
|
|
3879
|
-
acc.charge = elementDecimalOrZero(seg, 3, delimiters);
|
|
4072
|
+
acc.charge = elementDecimalOrZero(seg, 3, delimiters, sink);
|
|
3880
4073
|
acc.unitOfMeasure = elementOptional(seg, 4, delimiters);
|
|
3881
|
-
acc.units = elementDecimalOrZero(seg, 5, delimiters);
|
|
3882
|
-
acc.serviceLineRate = elementDecimal(seg, 6, delimiters);
|
|
3883
|
-
acc.nonCoveredCharge = elementDecimal(seg, 7, delimiters);
|
|
4074
|
+
acc.units = elementDecimalOrZero(seg, 5, delimiters, sink);
|
|
4075
|
+
acc.serviceLineRate = elementDecimal(seg, 6, delimiters, sink);
|
|
4076
|
+
acc.nonCoveredCharge = elementDecimal(seg, 7, delimiters, sink);
|
|
3884
4077
|
}
|
|
3885
|
-
function decodeSv3(acc, seg, delimiters) {
|
|
4078
|
+
function decodeSv3(acc, seg, delimiters, sink) {
|
|
3886
4079
|
if (acc.variant !== "D") return;
|
|
4080
|
+
acc.serviceSegmentDecoded = true;
|
|
3887
4081
|
acc.procedureQualifier = componentOptional(seg, 1, 1, delimiters) ?? "";
|
|
3888
4082
|
acc.procedureCode = componentOptional(seg, 1, 2, delimiters) ?? "";
|
|
3889
4083
|
const mods = [];
|
|
@@ -3892,7 +4086,7 @@ function decodeSv3(acc, seg, delimiters) {
|
|
|
3892
4086
|
if (m !== void 0) mods.push(m);
|
|
3893
4087
|
}
|
|
3894
4088
|
acc.modifiers = mods;
|
|
3895
|
-
acc.charge = elementDecimalOrZero(seg, 2, delimiters);
|
|
4089
|
+
acc.charge = elementDecimalOrZero(seg, 2, delimiters, sink);
|
|
3896
4090
|
acc.placeOfServiceCode = elementOptional(seg, 3, delimiters);
|
|
3897
4091
|
const cavities = [];
|
|
3898
4092
|
for (let p = 1; p <= 5; p += 1) {
|
|
@@ -3901,15 +4095,15 @@ function decodeSv3(acc, seg, delimiters) {
|
|
|
3901
4095
|
}
|
|
3902
4096
|
acc.oralCavityArea = cavities;
|
|
3903
4097
|
acc.prosthesisCrownInlayCode = elementOptional(seg, 5, delimiters);
|
|
3904
|
-
acc.units = elementDecimalOrZero(seg, 6, delimiters);
|
|
4098
|
+
acc.units = elementDecimalOrZero(seg, 6, delimiters, sink);
|
|
3905
4099
|
}
|
|
3906
|
-
function openAdjudication(seg, delimiters) {
|
|
4100
|
+
function openAdjudication(seg, delimiters, sink) {
|
|
3907
4101
|
return {
|
|
3908
4102
|
otherPayerId: elementValue(seg, 1, delimiters),
|
|
3909
|
-
amountPaid: elementDecimalOrZero(seg, 2, delimiters),
|
|
4103
|
+
amountPaid: elementDecimalOrZero(seg, 2, delimiters, sink),
|
|
3910
4104
|
procedureQualifier: componentOptional(seg, 3, 1, delimiters),
|
|
3911
4105
|
procedureCode: componentOptional(seg, 3, 2, delimiters),
|
|
3912
|
-
paidUnits: elementDecimal(seg, 5, delimiters),
|
|
4106
|
+
paidUnits: elementDecimal(seg, 5, delimiters, sink),
|
|
3913
4107
|
adjustments: [],
|
|
3914
4108
|
dateAdjudicated: void 0
|
|
3915
4109
|
};
|
|
@@ -4201,6 +4395,12 @@ function refuseHierarchy(message) {
|
|
|
4201
4395
|
function refuseSpec2(message) {
|
|
4202
4396
|
throw new Claim837BuildError(CLAIM_837_BUILD_ERROR_CODES.X12_837_BUILD_INVALID_SPEC, message);
|
|
4203
4397
|
}
|
|
4398
|
+
function decStr(value) {
|
|
4399
|
+
return requireCallerDecimal(value, "build837", refuseSpec2).toString();
|
|
4400
|
+
}
|
|
4401
|
+
function escDec2(value, esc) {
|
|
4402
|
+
return esc(decStr(value));
|
|
4403
|
+
}
|
|
4204
4404
|
var VERSION_BY_VARIANT = {
|
|
4205
4405
|
P: "005010X222A2",
|
|
4206
4406
|
I: "005010X223A3",
|
|
@@ -4234,6 +4434,7 @@ function buildClaim837(variant, spec) {
|
|
|
4234
4434
|
};
|
|
4235
4435
|
const esc = makeCallerEscaper(delimiters, "build837", refuseSpec2);
|
|
4236
4436
|
const seg = (parts) => {
|
|
4437
|
+
requireCallerSegment(parts, "build837", refuseSpec2);
|
|
4237
4438
|
let end = parts.length;
|
|
4238
4439
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
4239
4440
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -4277,8 +4478,8 @@ function buildClaim837(variant, spec) {
|
|
|
4277
4478
|
X12_837_FUNCTIONAL_ID,
|
|
4278
4479
|
esc(applicationSenderCode),
|
|
4279
4480
|
esc(applicationReceiverCode),
|
|
4280
|
-
groupDate,
|
|
4281
|
-
groupTime,
|
|
4481
|
+
esc(groupDate),
|
|
4482
|
+
esc(groupTime),
|
|
4282
4483
|
esc(envelope.groupControlNumber),
|
|
4283
4484
|
X12_AGENCY_CODE2,
|
|
4284
4485
|
versionRelease
|
|
@@ -4493,7 +4694,7 @@ function emitClaim2(variant, claim, body, ctx) {
|
|
|
4493
4694
|
ctx.seg([
|
|
4494
4695
|
"CLM",
|
|
4495
4696
|
ctx.esc(claim.claimId),
|
|
4496
|
-
|
|
4697
|
+
escDec2(claim.totalCharge, ctx.esc),
|
|
4497
4698
|
"",
|
|
4498
4699
|
"",
|
|
4499
4700
|
ctx.comp([
|
|
@@ -4541,8 +4742,8 @@ function emitOtherSubscriber(other, body, ctx) {
|
|
|
4541
4742
|
if (other.otherPayer !== void 0) emitEntity(other.otherPayer, body, ctx);
|
|
4542
4743
|
}
|
|
4543
4744
|
function emitServiceLine2(variant, line, lineNumber, body, ctx) {
|
|
4544
|
-
body.push(ctx.seg(["LX", line.lineNumber ?? String(lineNumber)]));
|
|
4545
|
-
const units = line.units === void 0 ? "0" : line.units
|
|
4745
|
+
body.push(ctx.seg(["LX", ctx.esc(line.lineNumber ?? String(lineNumber))]));
|
|
4746
|
+
const units = line.units === void 0 ? "0" : decStr(line.units);
|
|
4546
4747
|
if (line.variant === "P") {
|
|
4547
4748
|
const proc = ctx.comp([line.procedureQualifier, line.procedureCode, ...line.modifiers ?? []]);
|
|
4548
4749
|
const pointers = ctx.comp(line.diagnosisPointers ?? []);
|
|
@@ -4550,7 +4751,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
|
|
|
4550
4751
|
ctx.seg([
|
|
4551
4752
|
"SV1",
|
|
4552
4753
|
proc,
|
|
4553
|
-
|
|
4754
|
+
escDec2(line.charge, ctx.esc),
|
|
4554
4755
|
ctx.esc(line.unitOfMeasure ?? ""),
|
|
4555
4756
|
ctx.esc(units),
|
|
4556
4757
|
ctx.esc(line.placeOfServiceCode ?? ""),
|
|
@@ -4574,11 +4775,11 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
|
|
|
4574
4775
|
"SV2",
|
|
4575
4776
|
ctx.esc(line.revenueCode),
|
|
4576
4777
|
proc,
|
|
4577
|
-
|
|
4778
|
+
escDec2(line.charge, ctx.esc),
|
|
4578
4779
|
ctx.esc(line.unitOfMeasure ?? ""),
|
|
4579
4780
|
ctx.esc(units),
|
|
4580
|
-
line.serviceLineRate === void 0 ? "" :
|
|
4581
|
-
line.nonCoveredCharge === void 0 ? "" :
|
|
4781
|
+
line.serviceLineRate === void 0 ? "" : escDec2(line.serviceLineRate, ctx.esc),
|
|
4782
|
+
line.nonCoveredCharge === void 0 ? "" : escDec2(line.nonCoveredCharge, ctx.esc)
|
|
4582
4783
|
])
|
|
4583
4784
|
);
|
|
4584
4785
|
} else {
|
|
@@ -4588,7 +4789,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
|
|
|
4588
4789
|
ctx.seg([
|
|
4589
4790
|
"SV3",
|
|
4590
4791
|
proc,
|
|
4591
|
-
|
|
4792
|
+
escDec2(line.charge, ctx.esc),
|
|
4592
4793
|
ctx.esc(line.placeOfServiceCode ?? ""),
|
|
4593
4794
|
cavity,
|
|
4594
4795
|
ctx.esc(line.prosthesisCrownInlayCode ?? ""),
|
|
@@ -4607,7 +4808,7 @@ function emitServiceLine2(variant, line, lineNumber, body, ctx) {
|
|
|
4607
4808
|
"",
|
|
4608
4809
|
"",
|
|
4609
4810
|
"",
|
|
4610
|
-
drug.quantity === void 0 ? "" :
|
|
4811
|
+
drug.quantity === void 0 ? "" : escDec2(drug.quantity, ctx.esc),
|
|
4611
4812
|
ctx.esc(drug.unitOfMeasure ?? "")
|
|
4612
4813
|
])
|
|
4613
4814
|
);
|
|
@@ -4637,10 +4838,10 @@ function emitAdjudication(adj, body, ctx) {
|
|
|
4637
4838
|
ctx.seg([
|
|
4638
4839
|
"SVD",
|
|
4639
4840
|
ctx.esc(adj.otherPayerId),
|
|
4640
|
-
|
|
4841
|
+
escDec2(adj.amountPaid, ctx.esc),
|
|
4641
4842
|
proc,
|
|
4642
4843
|
"",
|
|
4643
|
-
adj.paidUnits === void 0 ? "" :
|
|
4844
|
+
adj.paidUnits === void 0 ? "" : escDec2(adj.paidUnits, ctx.esc)
|
|
4644
4845
|
])
|
|
4645
4846
|
);
|
|
4646
4847
|
emitCasGroup2(adj.adjustments, "build837: adjudication.adjustments", body, ctx);
|
|
@@ -4665,8 +4866,8 @@ function emitCasGroup2(raw, at, body, ctx) {
|
|
|
4665
4866
|
if (adj === void 0 || adj.groupCode !== groupCode) break;
|
|
4666
4867
|
parts.push(
|
|
4667
4868
|
ctx.esc(adj.reasonCode),
|
|
4668
|
-
|
|
4669
|
-
adj.quantity === void 0 ? "" :
|
|
4869
|
+
escDec2(adj.amount, ctx.esc),
|
|
4870
|
+
adj.quantity === void 0 ? "" : escDec2(adj.quantity, ctx.esc)
|
|
4670
4871
|
);
|
|
4671
4872
|
triples += 1;
|
|
4672
4873
|
i += 1;
|
|
@@ -4737,7 +4938,7 @@ function emitNote(note, body, ctx) {
|
|
|
4737
4938
|
body.push(ctx.seg(["NTE", ctx.esc(note.noteReferenceCode), ctx.esc(note.description)]));
|
|
4738
4939
|
}
|
|
4739
4940
|
function emitAmount(amt, body, ctx) {
|
|
4740
|
-
body.push(ctx.seg(["AMT", ctx.esc(amt.qualifier),
|
|
4941
|
+
body.push(ctx.seg(["AMT", ctx.esc(amt.qualifier), escDec2(amt.amount, ctx.esc)]));
|
|
4741
4942
|
}
|
|
4742
4943
|
function emitHi(hi, body, ctx) {
|
|
4743
4944
|
const composite = ctx.comp([
|
|
@@ -4745,8 +4946,10 @@ function emitHi(hi, body, ctx) {
|
|
|
4745
4946
|
hi.code,
|
|
4746
4947
|
hi.dateQualifier ?? "",
|
|
4747
4948
|
hi.date ?? "",
|
|
4748
|
-
|
|
4749
|
-
|
|
4949
|
+
// `decStr`, not `escDec`: `ctx.comp` maps `esc` over every component, so
|
|
4950
|
+
// escaping here would double-release an active delimiter.
|
|
4951
|
+
hi.monetaryAmount === void 0 ? "" : decStr(hi.monetaryAmount),
|
|
4952
|
+
hi.quantity === void 0 ? "" : decStr(hi.quantity),
|
|
4750
4953
|
hi.versionId ?? "",
|
|
4751
4954
|
"",
|
|
4752
4955
|
hi.poaIndicator ?? ""
|
|
@@ -5058,6 +5261,7 @@ function get271Eligibility(delimiters, tx) {
|
|
|
5058
5261
|
const seg = body[i];
|
|
5059
5262
|
if (seg === void 0) continue;
|
|
5060
5263
|
const position = { segmentIndex: i + 1, transactionIndex: 0 };
|
|
5264
|
+
const sink = { warnings, position };
|
|
5061
5265
|
switch (seg.id) {
|
|
5062
5266
|
case "HL": {
|
|
5063
5267
|
const hl = decodeHl2(seg, delimiters);
|
|
@@ -5161,7 +5365,7 @@ function get271Eligibility(delimiters, tx) {
|
|
|
5161
5365
|
case "EB": {
|
|
5162
5366
|
flushBenefit();
|
|
5163
5367
|
if (currentSubscriber === void 0 && currentDependent === void 0) break;
|
|
5164
|
-
currentBenefit = openBenefit(seg, delimiters);
|
|
5368
|
+
currentBenefit = openBenefit(seg, delimiters, sink);
|
|
5165
5369
|
break;
|
|
5166
5370
|
}
|
|
5167
5371
|
case "MSG": {
|
|
@@ -5258,7 +5462,7 @@ function decodeDtp2(seg, delimiters) {
|
|
|
5258
5462
|
value
|
|
5259
5463
|
});
|
|
5260
5464
|
}
|
|
5261
|
-
function openBenefit(seg, delimiters) {
|
|
5465
|
+
function openBenefit(seg, delimiters, sink) {
|
|
5262
5466
|
const serviceTypeCodes = [];
|
|
5263
5467
|
for (const code of getAllSegmentValues(seg, "03", delimiters)) {
|
|
5264
5468
|
if (code === "") continue;
|
|
@@ -5273,10 +5477,10 @@ function openBenefit(seg, delimiters) {
|
|
|
5273
5477
|
insuranceTypeCode: elementOptional(seg, 4, delimiters),
|
|
5274
5478
|
planCoverageDescription: elementOptional(seg, 5, delimiters),
|
|
5275
5479
|
timePeriodQualifier: elementOptional(seg, 6, delimiters),
|
|
5276
|
-
monetaryAmount: elementDecimal(seg, 7, delimiters),
|
|
5277
|
-
percent: elementDecimal(seg, 8, delimiters),
|
|
5480
|
+
monetaryAmount: elementDecimal(seg, 7, delimiters, sink),
|
|
5481
|
+
percent: elementDecimal(seg, 8, delimiters, sink),
|
|
5278
5482
|
quantityQualifier: elementOptional(seg, 9, delimiters),
|
|
5279
|
-
quantity: elementDecimal(seg, 10, delimiters),
|
|
5483
|
+
quantity: elementDecimal(seg, 10, delimiters, sink),
|
|
5280
5484
|
authorizationRequired: elementOptional(seg, 11, delimiters),
|
|
5281
5485
|
inPlanNetwork: elementOptional(seg, 12, delimiters),
|
|
5282
5486
|
references: [],
|
|
@@ -5379,6 +5583,9 @@ function refuseSpec3(message) {
|
|
|
5379
5583
|
message
|
|
5380
5584
|
);
|
|
5381
5585
|
}
|
|
5586
|
+
function escDec3(value, esc) {
|
|
5587
|
+
return esc(requireCallerDecimal(value, "build271", refuseSpec3).toString());
|
|
5588
|
+
}
|
|
5382
5589
|
var X279A1_VERSION_RELEASE = "005010X279A1";
|
|
5383
5590
|
var X12_271_FUNCTIONAL_ID = "HB";
|
|
5384
5591
|
var X12_AGENCY_CODE3 = "X";
|
|
@@ -5398,6 +5605,7 @@ function build271(spec) {
|
|
|
5398
5605
|
};
|
|
5399
5606
|
const esc = makeCallerEscaper(delimiters, "build271", refuseSpec3);
|
|
5400
5607
|
const seg = (parts) => {
|
|
5608
|
+
requireCallerSegment(parts, "build271", refuseSpec3);
|
|
5401
5609
|
let end = parts.length;
|
|
5402
5610
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
5403
5611
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -5435,8 +5643,8 @@ function build271(spec) {
|
|
|
5435
5643
|
X12_271_FUNCTIONAL_ID,
|
|
5436
5644
|
esc(applicationSenderCode),
|
|
5437
5645
|
esc(applicationReceiverCode),
|
|
5438
|
-
groupDate,
|
|
5439
|
-
groupTime,
|
|
5646
|
+
esc(groupDate),
|
|
5647
|
+
esc(groupTime),
|
|
5440
5648
|
esc(envelope.groupControlNumber),
|
|
5441
5649
|
X12_AGENCY_CODE3,
|
|
5442
5650
|
X279A1_VERSION_RELEASE
|
|
@@ -5606,10 +5814,10 @@ function emitBenefit(benefit, body, ctx) {
|
|
|
5606
5814
|
ctx.esc(benefit.insuranceTypeCode ?? ""),
|
|
5607
5815
|
ctx.esc(benefit.planCoverageDescription ?? ""),
|
|
5608
5816
|
ctx.esc(benefit.timePeriodQualifier ?? ""),
|
|
5609
|
-
benefit.monetaryAmount === void 0 ? "" :
|
|
5610
|
-
benefit.percent === void 0 ? "" :
|
|
5817
|
+
benefit.monetaryAmount === void 0 ? "" : escDec3(benefit.monetaryAmount, ctx.esc),
|
|
5818
|
+
benefit.percent === void 0 ? "" : escDec3(benefit.percent, ctx.esc),
|
|
5611
5819
|
ctx.esc(benefit.quantityQualifier ?? ""),
|
|
5612
|
-
benefit.quantity === void 0 ? "" :
|
|
5820
|
+
benefit.quantity === void 0 ? "" : escDec3(benefit.quantity, ctx.esc),
|
|
5613
5821
|
ctx.esc(benefit.authorizationRequired ?? ""),
|
|
5614
5822
|
ctx.esc(benefit.inPlanNetwork ?? "")
|
|
5615
5823
|
])
|
|
@@ -5816,6 +6024,7 @@ function walk277(delimiters, tx) {
|
|
|
5816
6024
|
const seg = body[i];
|
|
5817
6025
|
if (seg === void 0) continue;
|
|
5818
6026
|
const position = { segmentIndex: i + 1, transactionIndex: 0 };
|
|
6027
|
+
const sink = { warnings, position };
|
|
5819
6028
|
switch (seg.id) {
|
|
5820
6029
|
case "HL": {
|
|
5821
6030
|
flushClaim();
|
|
@@ -5893,7 +6102,7 @@ function walk277(delimiters, tx) {
|
|
|
5893
6102
|
case "SVC": {
|
|
5894
6103
|
flushServiceLine();
|
|
5895
6104
|
if (currentClaim === void 0) currentClaim = openClaim3();
|
|
5896
|
-
currentServiceLine = openServiceLine3(seg, delimiters);
|
|
6105
|
+
currentServiceLine = openServiceLine3(seg, delimiters, sink);
|
|
5897
6106
|
break;
|
|
5898
6107
|
}
|
|
5899
6108
|
case "REF": {
|
|
@@ -5967,6 +6176,7 @@ function decodeDtp3(seg, delimiters) {
|
|
|
5967
6176
|
});
|
|
5968
6177
|
}
|
|
5969
6178
|
function decodeStc(seg, delimiters, warnings, position) {
|
|
6179
|
+
const sink = { warnings, position };
|
|
5970
6180
|
const statuses = [];
|
|
5971
6181
|
for (const elementIndex of [1, 10, 11]) {
|
|
5972
6182
|
const code = decodeStatusComposite(seg, elementIndex, delimiters, warnings, position);
|
|
@@ -5975,8 +6185,8 @@ function decodeStc(seg, delimiters, warnings, position) {
|
|
|
5975
6185
|
return Object.freeze({
|
|
5976
6186
|
statusEffectiveDate: elementOptional(seg, 2, delimiters),
|
|
5977
6187
|
actionCode: elementOptional(seg, 3, delimiters),
|
|
5978
|
-
totalChargeAmount: elementDecimal(seg, 4, delimiters),
|
|
5979
|
-
paymentAmount: elementDecimal(seg, 5, delimiters),
|
|
6188
|
+
totalChargeAmount: elementDecimal(seg, 4, delimiters, sink),
|
|
6189
|
+
paymentAmount: elementDecimal(seg, 5, delimiters, sink),
|
|
5980
6190
|
adjudicationDate: elementOptional(seg, 6, delimiters),
|
|
5981
6191
|
message: elementOptional(seg, 12, delimiters),
|
|
5982
6192
|
statuses: Object.freeze(statuses)
|
|
@@ -6003,7 +6213,7 @@ function decodeStatusComposite(seg, n, delimiters, warnings, position) {
|
|
|
6003
6213
|
entityCode
|
|
6004
6214
|
});
|
|
6005
6215
|
}
|
|
6006
|
-
function openServiceLine3(seg, delimiters) {
|
|
6216
|
+
function openServiceLine3(seg, delimiters, sink) {
|
|
6007
6217
|
const modifiers = [];
|
|
6008
6218
|
for (let comp = 3; comp <= 6; comp += 1) {
|
|
6009
6219
|
const m = componentOptional(seg, 1, comp, delimiters);
|
|
@@ -6013,9 +6223,13 @@ function openServiceLine3(seg, delimiters) {
|
|
|
6013
6223
|
serviceIdQualifier: componentOptional(seg, 1, 1, delimiters),
|
|
6014
6224
|
procedureCode: componentOptional(seg, 1, 2, delimiters),
|
|
6015
6225
|
modifiers,
|
|
6016
|
-
lineChargeAmount: elementDecimal(seg, 2, delimiters),
|
|
6017
|
-
linePaymentAmount: elementDecimal(seg, 3, delimiters),
|
|
6226
|
+
lineChargeAmount: elementDecimal(seg, 2, delimiters, sink),
|
|
6227
|
+
linePaymentAmount: elementDecimal(seg, 3, delimiters, sink),
|
|
6018
6228
|
revenueCode: elementOptional(seg, 4, delimiters),
|
|
6229
|
+
// SVC-07. SVC-05 (Quantity) and SVC-06 (a second composite) are NOT USED
|
|
6230
|
+
// in both X212 and X214, so they are deliberately left unread rather than
|
|
6231
|
+
// decoded "for symmetry" with the 835, whose SVC-05 IS the paid count.
|
|
6232
|
+
unitsOfService: elementDecimal(seg, 7, delimiters, sink),
|
|
6019
6233
|
statuses: [],
|
|
6020
6234
|
references: [],
|
|
6021
6235
|
dates: []
|
|
@@ -6029,6 +6243,7 @@ function freezeServiceLine3(acc) {
|
|
|
6029
6243
|
lineChargeAmount: acc.lineChargeAmount,
|
|
6030
6244
|
linePaymentAmount: acc.linePaymentAmount,
|
|
6031
6245
|
revenueCode: acc.revenueCode,
|
|
6246
|
+
unitsOfService: acc.unitsOfService,
|
|
6032
6247
|
statuses: Object.freeze(acc.statuses.slice()),
|
|
6033
6248
|
references: Object.freeze(acc.references.slice()),
|
|
6034
6249
|
dates: Object.freeze(acc.dates.slice())
|
|
@@ -6077,6 +6292,9 @@ function refuseSpec4(message) {
|
|
|
6077
6292
|
message
|
|
6078
6293
|
);
|
|
6079
6294
|
}
|
|
6295
|
+
function escDec4(value, esc) {
|
|
6296
|
+
return esc(requireCallerDecimal(value, "build277", refuseSpec4).toString());
|
|
6297
|
+
}
|
|
6080
6298
|
var X12_277_FUNCTIONAL_ID = "HN";
|
|
6081
6299
|
var X12_AGENCY_CODE4 = "X";
|
|
6082
6300
|
var HL_LEVEL3 = {
|
|
@@ -6094,7 +6312,7 @@ function build277CA(spec) {
|
|
|
6094
6312
|
}
|
|
6095
6313
|
function buildClaimStatus(version, spec) {
|
|
6096
6314
|
const { envelope } = spec;
|
|
6097
|
-
enforceStructuralSpec4(spec);
|
|
6315
|
+
enforceStructuralSpec4(version, spec);
|
|
6098
6316
|
const elementSeparator = envelope.elementSeparator ?? "*";
|
|
6099
6317
|
const repetitionSeparator = envelope.repetitionSeparator ?? "^";
|
|
6100
6318
|
const componentSeparator = envelope.componentSeparator ?? ":";
|
|
@@ -6107,6 +6325,7 @@ function buildClaimStatus(version, spec) {
|
|
|
6107
6325
|
};
|
|
6108
6326
|
const esc = makeCallerEscaper(delimiters, "build277", refuseSpec4);
|
|
6109
6327
|
const seg = (parts) => {
|
|
6328
|
+
requireCallerSegment(parts, "build277", refuseSpec4);
|
|
6110
6329
|
let end = parts.length;
|
|
6111
6330
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
6112
6331
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -6150,8 +6369,8 @@ function buildClaimStatus(version, spec) {
|
|
|
6150
6369
|
X12_277_FUNCTIONAL_ID,
|
|
6151
6370
|
esc(applicationSenderCode),
|
|
6152
6371
|
esc(applicationReceiverCode),
|
|
6153
|
-
groupDate,
|
|
6154
|
-
groupTime,
|
|
6372
|
+
esc(groupDate),
|
|
6373
|
+
esc(groupTime),
|
|
6155
6374
|
esc(envelope.groupControlNumber),
|
|
6156
6375
|
X12_AGENCY_CODE4,
|
|
6157
6376
|
version
|
|
@@ -6170,7 +6389,7 @@ function buildClaimStatus(version, spec) {
|
|
|
6170
6389
|
const raw = isa + gs + st + body.join("") + se + ge + iea;
|
|
6171
6390
|
return parseX12(raw);
|
|
6172
6391
|
}
|
|
6173
|
-
function enforceStructuralSpec4(spec) {
|
|
6392
|
+
function enforceStructuralSpec4(version, spec) {
|
|
6174
6393
|
const sources = requireCallerArray(
|
|
6175
6394
|
spec.informationSources,
|
|
6176
6395
|
"build277: spec.informationSources",
|
|
@@ -6228,13 +6447,13 @@ function enforceStructuralSpec4(spec) {
|
|
|
6228
6447
|
for (let u = 0; u < subscribers.length; u += 1) {
|
|
6229
6448
|
const subscriber = subscribers[u];
|
|
6230
6449
|
if (subscriber === void 0) continue;
|
|
6231
|
-
enforceSubscriber(subscriber, `${locator}.subscriber[${String(u)}]`);
|
|
6450
|
+
enforceSubscriber(version, subscriber, `${locator}.subscriber[${String(u)}]`);
|
|
6232
6451
|
}
|
|
6233
6452
|
}
|
|
6234
6453
|
}
|
|
6235
6454
|
}
|
|
6236
6455
|
}
|
|
6237
|
-
function enforceSubscriber(subscriber, locator) {
|
|
6456
|
+
function enforceSubscriber(version, subscriber, locator) {
|
|
6238
6457
|
const claims = requireCallerArray(
|
|
6239
6458
|
subscriber.claims,
|
|
6240
6459
|
`build277: subscriber at ${locator}: claims`,
|
|
@@ -6253,7 +6472,8 @@ function enforceSubscriber(subscriber, locator) {
|
|
|
6253
6472
|
}
|
|
6254
6473
|
for (let c = 0; c < claims.length; c += 1) {
|
|
6255
6474
|
const claim = claims[c];
|
|
6256
|
-
if (claim !== void 0)
|
|
6475
|
+
if (claim !== void 0)
|
|
6476
|
+
enforceClaim2(version, claim, `${locator}.claim[${String(c)}]`, c === 0);
|
|
6257
6477
|
}
|
|
6258
6478
|
for (let d = 0; d < dependents.length; d += 1) {
|
|
6259
6479
|
const dependent = dependents[d];
|
|
@@ -6272,11 +6492,12 @@ function enforceSubscriber(subscriber, locator) {
|
|
|
6272
6492
|
}
|
|
6273
6493
|
for (let c = 0; c < depClaims.length; c += 1) {
|
|
6274
6494
|
const claim = depClaims[c];
|
|
6275
|
-
if (claim !== void 0)
|
|
6495
|
+
if (claim !== void 0)
|
|
6496
|
+
enforceClaim2(version, claim, `${depLocator}.claim[${String(c)}]`, c === 0);
|
|
6276
6497
|
}
|
|
6277
6498
|
}
|
|
6278
6499
|
}
|
|
6279
|
-
function enforceClaim2(claim, locator, isFirst) {
|
|
6500
|
+
function enforceClaim2(version, claim, locator, isFirst) {
|
|
6280
6501
|
const statuses = requireCallerArray(
|
|
6281
6502
|
claim.statuses,
|
|
6282
6503
|
`build277: claim at ${locator}: statuses`,
|
|
@@ -6305,6 +6526,12 @@ function enforceClaim2(claim, locator, isFirst) {
|
|
|
6305
6526
|
for (let l = 0; l < serviceLines.length; l += 1) {
|
|
6306
6527
|
const line = serviceLines[l];
|
|
6307
6528
|
if (line === void 0) continue;
|
|
6529
|
+
if (version === "005010X212" && line.unitsOfService === void 0) {
|
|
6530
|
+
throw new ClaimStatus277BuildError(
|
|
6531
|
+
CLAIM_STATUS_277_BUILD_ERROR_CODES.X12_277_BUILD_INVALID_SPEC,
|
|
6532
|
+
`build277: service line at ${locator}.line[${String(l)}] has no unitsOfService, and SVC-07 is a required element in 005010X212. Supply the submitted count; it is never defaulted. In 005010X214 it is situational, so build277CA accepts the same line.`
|
|
6533
|
+
);
|
|
6534
|
+
}
|
|
6308
6535
|
const lineStatuses = requireCallerArray(
|
|
6309
6536
|
line.statuses,
|
|
6310
6537
|
`build277: claim at ${locator}.line[${String(l)}]: statuses`,
|
|
@@ -6398,9 +6625,12 @@ function emitServiceLine3(line, body, ctx) {
|
|
|
6398
6625
|
ctx.seg([
|
|
6399
6626
|
"SVC",
|
|
6400
6627
|
svc01,
|
|
6401
|
-
line.lineChargeAmount === void 0 ? "" :
|
|
6402
|
-
line.linePaymentAmount === void 0 ? "" :
|
|
6403
|
-
ctx.esc(line.revenueCode ?? "")
|
|
6628
|
+
line.lineChargeAmount === void 0 ? "" : escDec4(line.lineChargeAmount, ctx.esc),
|
|
6629
|
+
line.linePaymentAmount === void 0 ? "" : escDec4(line.linePaymentAmount, ctx.esc),
|
|
6630
|
+
ctx.esc(line.revenueCode ?? ""),
|
|
6631
|
+
"",
|
|
6632
|
+
"",
|
|
6633
|
+
line.unitsOfService === void 0 ? "" : escDec4(line.unitsOfService, ctx.esc)
|
|
6404
6634
|
])
|
|
6405
6635
|
);
|
|
6406
6636
|
for (const status of line.statuses ?? []) emitStatus(status, body, ctx);
|
|
@@ -6419,8 +6649,8 @@ function emitStatus(status, body, ctx) {
|
|
|
6419
6649
|
composite(0),
|
|
6420
6650
|
ctx.esc(status.statusEffectiveDate ?? ""),
|
|
6421
6651
|
ctx.esc(status.actionCode ?? ""),
|
|
6422
|
-
status.totalChargeAmount === void 0 ? "" :
|
|
6423
|
-
status.paymentAmount === void 0 ? "" :
|
|
6652
|
+
status.totalChargeAmount === void 0 ? "" : escDec4(status.totalChargeAmount, ctx.esc),
|
|
6653
|
+
status.paymentAmount === void 0 ? "" : escDec4(status.paymentAmount, ctx.esc),
|
|
6424
6654
|
ctx.esc(status.adjudicationDate ?? ""),
|
|
6425
6655
|
"",
|
|
6426
6656
|
"",
|
|
@@ -6590,9 +6820,11 @@ function get820Payments(delimiters, tx) {
|
|
|
6590
6820
|
for (let i = 0; i < body.length; i += 1) {
|
|
6591
6821
|
const seg = body[i];
|
|
6592
6822
|
if (seg === void 0) continue;
|
|
6823
|
+
const position = { segmentIndex: i + 1, transactionIndex: 0 };
|
|
6824
|
+
const sink = { warnings, position };
|
|
6593
6825
|
switch (seg.id) {
|
|
6594
6826
|
case "BPR": {
|
|
6595
|
-
payment = decodeBpr2(seg, delimiters);
|
|
6827
|
+
payment = decodeBpr2(seg, delimiters, sink);
|
|
6596
6828
|
break;
|
|
6597
6829
|
}
|
|
6598
6830
|
case "TRN": {
|
|
@@ -6659,13 +6891,13 @@ function get820Payments(delimiters, tx) {
|
|
|
6659
6891
|
}
|
|
6660
6892
|
case "RMR": {
|
|
6661
6893
|
if (current === void 0) break;
|
|
6662
|
-
const item = decodeRmr(seg, delimiters);
|
|
6894
|
+
const item = decodeRmr(seg, delimiters, sink);
|
|
6663
6895
|
if (item !== void 0) current.openItems.push(item);
|
|
6664
6896
|
break;
|
|
6665
6897
|
}
|
|
6666
6898
|
case "ADX": {
|
|
6667
6899
|
if (current === void 0) break;
|
|
6668
|
-
const adjustment = decodeAdx(seg, delimiters);
|
|
6900
|
+
const adjustment = decodeAdx(seg, delimiters, sink);
|
|
6669
6901
|
if (adjustment !== void 0) current.adjustments.push(adjustment);
|
|
6670
6902
|
break;
|
|
6671
6903
|
}
|
|
@@ -6717,10 +6949,10 @@ function freezeRemittance(acc) {
|
|
|
6717
6949
|
adjustments: Object.freeze(acc.adjustments.slice())
|
|
6718
6950
|
});
|
|
6719
6951
|
}
|
|
6720
|
-
function decodeBpr2(seg, delimiters) {
|
|
6952
|
+
function decodeBpr2(seg, delimiters, sink) {
|
|
6721
6953
|
return Object.freeze({
|
|
6722
6954
|
transactionHandlingCode: elementValue(seg, 1, delimiters),
|
|
6723
|
-
totalPremiumAmount: elementDecimalOrZero(seg, 2, delimiters),
|
|
6955
|
+
totalPremiumAmount: elementDecimalOrZero(seg, 2, delimiters, sink),
|
|
6724
6956
|
creditDebitFlag: elementValue(seg, 3, delimiters),
|
|
6725
6957
|
method: elementValue(seg, 4, delimiters),
|
|
6726
6958
|
paymentFormatCode: elementOptional(seg, 5, delimiters),
|
|
@@ -6788,7 +7020,7 @@ function decodeNm13(seg, delimiters) {
|
|
|
6788
7020
|
idCode: elementOptional(seg, 9, delimiters)
|
|
6789
7021
|
});
|
|
6790
7022
|
}
|
|
6791
|
-
function decodeRmr(seg, delimiters) {
|
|
7023
|
+
function decodeRmr(seg, delimiters, sink) {
|
|
6792
7024
|
const qualifier = elementValue(seg, 1, delimiters);
|
|
6793
7025
|
const referenceId = elementValue(seg, 2, delimiters);
|
|
6794
7026
|
if (qualifier === "" && referenceId === "") return void 0;
|
|
@@ -6796,12 +7028,12 @@ function decodeRmr(seg, delimiters) {
|
|
|
6796
7028
|
qualifier,
|
|
6797
7029
|
referenceId,
|
|
6798
7030
|
paymentActionCode: elementOptional(seg, 3, delimiters),
|
|
6799
|
-
amountPaid: elementDecimalOrZero(seg, 4, delimiters),
|
|
6800
|
-
amountDue: elementDecimal(seg, 5, delimiters)
|
|
7031
|
+
amountPaid: elementDecimalOrZero(seg, 4, delimiters, sink),
|
|
7032
|
+
amountDue: elementDecimal(seg, 5, delimiters, sink)
|
|
6801
7033
|
});
|
|
6802
7034
|
}
|
|
6803
|
-
function decodeAdx(seg, delimiters) {
|
|
6804
|
-
const amount = elementDecimal(seg, 1, delimiters);
|
|
7035
|
+
function decodeAdx(seg, delimiters, sink) {
|
|
7036
|
+
const amount = elementDecimal(seg, 1, delimiters, sink);
|
|
6805
7037
|
if (amount === void 0) return void 0;
|
|
6806
7038
|
return Object.freeze({
|
|
6807
7039
|
amount,
|
|
@@ -6862,6 +7094,9 @@ var Premium820BuildError = class extends Error {
|
|
|
6862
7094
|
function refuseSpec5(message) {
|
|
6863
7095
|
throw new Premium820BuildError(PREMIUM_820_BUILD_ERROR_CODES.X12_820_BUILD_INVALID_SPEC, message);
|
|
6864
7096
|
}
|
|
7097
|
+
function escDec5(value, esc) {
|
|
7098
|
+
return esc(requireCallerDecimal(value, "build820", refuseSpec5).toString());
|
|
7099
|
+
}
|
|
6865
7100
|
var X218_VERSION_RELEASE = "005010X218";
|
|
6866
7101
|
var X12_820_FUNCTIONAL_ID = "RA";
|
|
6867
7102
|
var X12_AGENCY_CODE5 = "X";
|
|
@@ -6880,6 +7115,7 @@ function build820(spec) {
|
|
|
6880
7115
|
};
|
|
6881
7116
|
const esc = makeCallerEscaper(delimiters, "build820", refuseSpec5);
|
|
6882
7117
|
const seg = (parts) => {
|
|
7118
|
+
requireCallerSegment(parts, "build820", refuseSpec5);
|
|
6883
7119
|
let end = parts.length;
|
|
6884
7120
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
6885
7121
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -6935,9 +7171,9 @@ function build820(spec) {
|
|
|
6935
7171
|
// GS-02
|
|
6936
7172
|
esc(applicationReceiverCode),
|
|
6937
7173
|
// GS-03
|
|
6938
|
-
groupDate,
|
|
7174
|
+
esc(groupDate),
|
|
6939
7175
|
// GS-04 - CCYYMMDD
|
|
6940
|
-
groupTime,
|
|
7176
|
+
esc(groupTime),
|
|
6941
7177
|
// GS-05 - HHMM
|
|
6942
7178
|
esc(envelope.groupControlNumber),
|
|
6943
7179
|
// GS-06
|
|
@@ -6953,7 +7189,7 @@ function build820(spec) {
|
|
|
6953
7189
|
seg([
|
|
6954
7190
|
"BPR",
|
|
6955
7191
|
esc(spec.payment.transactionHandlingCode),
|
|
6956
|
-
|
|
7192
|
+
escDec5(spec.payment.totalPremiumAmount, esc),
|
|
6957
7193
|
esc(spec.payment.creditDebitFlag),
|
|
6958
7194
|
esc(spec.payment.method),
|
|
6959
7195
|
esc(spec.payment.paymentFormatCode ?? ""),
|
|
@@ -7110,7 +7346,7 @@ function emitRemittance(remittance, body, seg, esc) {
|
|
|
7110
7346
|
body.push(
|
|
7111
7347
|
seg([
|
|
7112
7348
|
"ADX",
|
|
7113
|
-
|
|
7349
|
+
escDec5(adjustment.amount, esc),
|
|
7114
7350
|
esc(adjustment.reasonCode),
|
|
7115
7351
|
esc(adjustment.referenceQualifier ?? ""),
|
|
7116
7352
|
esc(adjustment.referenceId ?? "")
|
|
@@ -7140,8 +7376,8 @@ function emitOpenItem(item, seg, esc) {
|
|
|
7140
7376
|
esc(item.qualifier),
|
|
7141
7377
|
esc(item.referenceId),
|
|
7142
7378
|
esc(item.paymentActionCode ?? ""),
|
|
7143
|
-
|
|
7144
|
-
item.amountDue === void 0 ? "" :
|
|
7379
|
+
escDec5(item.amountPaid, esc),
|
|
7380
|
+
item.amountDue === void 0 ? "" : escDec5(item.amountDue, esc)
|
|
7145
7381
|
]);
|
|
7146
7382
|
}
|
|
7147
7383
|
function emitRef5(ref, seg, esc) {
|
|
@@ -7372,7 +7608,8 @@ async function* get834Enrollments(delimiters, tx) {
|
|
|
7372
7608
|
}
|
|
7373
7609
|
case "AMT": {
|
|
7374
7610
|
if (currentCoverage === void 0) break;
|
|
7375
|
-
const
|
|
7611
|
+
const sink = { warnings: current.warnings, position };
|
|
7612
|
+
const amount = decodeAmt3(seg, delimiters, sink);
|
|
7376
7613
|
if (amount !== void 0) currentCoverage.amounts.push(amount);
|
|
7377
7614
|
break;
|
|
7378
7615
|
}
|
|
@@ -7498,8 +7735,8 @@ function decodeDtp4(seg, delimiters) {
|
|
|
7498
7735
|
value
|
|
7499
7736
|
});
|
|
7500
7737
|
}
|
|
7501
|
-
function decodeAmt3(seg, delimiters) {
|
|
7502
|
-
const amount = elementDecimal(seg, 2, delimiters);
|
|
7738
|
+
function decodeAmt3(seg, delimiters, sink) {
|
|
7739
|
+
const amount = elementDecimal(seg, 2, delimiters, sink);
|
|
7503
7740
|
if (amount === void 0) return void 0;
|
|
7504
7741
|
return Object.freeze({
|
|
7505
7742
|
qualifier: elementValue(seg, 1, delimiters),
|
|
@@ -7561,6 +7798,9 @@ function refuseSpec6(message) {
|
|
|
7561
7798
|
message
|
|
7562
7799
|
);
|
|
7563
7800
|
}
|
|
7801
|
+
function escDec6(value, esc) {
|
|
7802
|
+
return esc(requireCallerDecimal(value, "build834", refuseSpec6).toString());
|
|
7803
|
+
}
|
|
7564
7804
|
var X220A1_VERSION_RELEASE = "005010X220A1";
|
|
7565
7805
|
var X12_834_FUNCTIONAL_ID = "BE";
|
|
7566
7806
|
var X12_AGENCY_CODE6 = "X";
|
|
@@ -7581,6 +7821,7 @@ function build834(spec) {
|
|
|
7581
7821
|
};
|
|
7582
7822
|
const esc = makeCallerEscaper(delimiters, "build834", refuseSpec6);
|
|
7583
7823
|
const seg = (parts) => {
|
|
7824
|
+
requireCallerSegment(parts, "build834", refuseSpec6);
|
|
7584
7825
|
let end = parts.length;
|
|
7585
7826
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
7586
7827
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -7636,9 +7877,9 @@ function build834(spec) {
|
|
|
7636
7877
|
// GS-02
|
|
7637
7878
|
esc(applicationReceiverCode),
|
|
7638
7879
|
// GS-03
|
|
7639
|
-
groupDate,
|
|
7880
|
+
esc(groupDate),
|
|
7640
7881
|
// GS-04 - CCYYMMDD
|
|
7641
|
-
groupTime,
|
|
7882
|
+
esc(groupTime),
|
|
7642
7883
|
// GS-05 - HHMM
|
|
7643
7884
|
esc(envelope.groupControlNumber),
|
|
7644
7885
|
// GS-06
|
|
@@ -7819,7 +8060,7 @@ function emitCoverage(coverage, body, seg, esc) {
|
|
|
7819
8060
|
);
|
|
7820
8061
|
for (const date of coverage.dates ?? []) body.push(emitDate4(date, seg, esc));
|
|
7821
8062
|
for (const amount of coverage.amounts ?? []) {
|
|
7822
|
-
body.push(seg(["AMT", esc(amount.qualifier),
|
|
8063
|
+
body.push(seg(["AMT", esc(amount.qualifier), escDec6(amount.amount, esc)]));
|
|
7823
8064
|
}
|
|
7824
8065
|
}
|
|
7825
8066
|
function emitRef6(ref, seg, esc) {
|
|
@@ -8227,6 +8468,7 @@ var HL_LEVEL4 = {
|
|
|
8227
8468
|
DEPENDENT: "23"
|
|
8228
8469
|
};
|
|
8229
8470
|
var DEFAULT_REVIEW_LEVEL = "EV";
|
|
8471
|
+
var REVIEW_LEVEL_CODES = Object.freeze(["EV", "SS"]);
|
|
8230
8472
|
function build278Request(spec) {
|
|
8231
8473
|
return buildServicesReview("005010X217", "request", spec);
|
|
8232
8474
|
}
|
|
@@ -8248,6 +8490,7 @@ function buildServicesReview(version, direction, spec) {
|
|
|
8248
8490
|
};
|
|
8249
8491
|
const esc = makeCallerEscaper(delimiters, "build278", refuseSpec7);
|
|
8250
8492
|
const seg = (parts) => {
|
|
8493
|
+
requireCallerSegment(parts, "build278", refuseSpec7);
|
|
8251
8494
|
let end = parts.length;
|
|
8252
8495
|
while (end > 1 && parts[end - 1] === "") end -= 1;
|
|
8253
8496
|
return parts.slice(0, end).join(elementSeparator) + segmentTerminator;
|
|
@@ -8291,8 +8534,8 @@ function buildServicesReview(version, direction, spec) {
|
|
|
8291
8534
|
X12_278_FUNCTIONAL_ID,
|
|
8292
8535
|
esc(applicationSenderCode),
|
|
8293
8536
|
esc(applicationReceiverCode),
|
|
8294
|
-
groupDate,
|
|
8295
|
-
groupTime,
|
|
8537
|
+
esc(groupDate),
|
|
8538
|
+
esc(groupTime),
|
|
8296
8539
|
esc(envelope.groupControlNumber),
|
|
8297
8540
|
X12_AGENCY_CODE7,
|
|
8298
8541
|
version
|
|
@@ -8364,6 +8607,13 @@ function enforceStructuralSpec7(spec, direction) {
|
|
|
8364
8607
|
}
|
|
8365
8608
|
}
|
|
8366
8609
|
function enforceReview(review, locator, direction) {
|
|
8610
|
+
const resolvedLevel = review.levelCode ?? DEFAULT_REVIEW_LEVEL;
|
|
8611
|
+
if (!REVIEW_LEVEL_CODES.includes(resolvedLevel)) {
|
|
8612
|
+
throw new ServicesReview278BuildError(
|
|
8613
|
+
AUTH_278_BUILD_ERROR_CODES.X12_278_BUILD_INVALID_SPEC,
|
|
8614
|
+
`build278: review at ${locator} has HL-03 level code ${renderCallerValue(resolvedLevel)}; a review level must be "EV" (patient event) or "SS" (service). A level outside those two emits a well-formed document whose review loop no reader opens, so the review and its HCR-01 certification decision would not decode.`
|
|
8615
|
+
);
|
|
8616
|
+
}
|
|
8367
8617
|
if (review.requestCategoryCode === "") {
|
|
8368
8618
|
throw new ServicesReview278BuildError(
|
|
8369
8619
|
AUTH_278_BUILD_ERROR_CODES.X12_278_BUILD_INVALID_SPEC,
|
|
@@ -8421,7 +8671,7 @@ function emitReview(review, parentHlId, direction, body, ctx, counter) {
|
|
|
8421
8671
|
const nested = review.reviews ?? [];
|
|
8422
8672
|
const hasChild = nested.length > 0 ? "1" : "0";
|
|
8423
8673
|
const levelCode = review.levelCode ?? DEFAULT_REVIEW_LEVEL;
|
|
8424
|
-
body.push(ctx.seg(["HL", hlId, parentHlId, levelCode, hasChild]));
|
|
8674
|
+
body.push(ctx.seg(["HL", hlId, parentHlId, ctx.esc(levelCode), hasChild]));
|
|
8425
8675
|
for (const trace of review.traces ?? []) {
|
|
8426
8676
|
body.push(
|
|
8427
8677
|
ctx.seg([
|
|
@@ -9068,13 +9318,13 @@ function build999(spec) {
|
|
|
9068
9318
|
// GS-02
|
|
9069
9319
|
esc(envelope.receiverId),
|
|
9070
9320
|
// GS-03
|
|
9071
|
-
groupDate,
|
|
9321
|
+
esc(groupDate),
|
|
9072
9322
|
// GS-04 - CCYYMMDD
|
|
9073
|
-
groupTime,
|
|
9323
|
+
esc(groupTime),
|
|
9074
9324
|
// GS-05 - HHMM
|
|
9075
|
-
envelope.groupControlNumber,
|
|
9325
|
+
esc(envelope.groupControlNumber),
|
|
9076
9326
|
// GS-06
|
|
9077
|
-
groupResponsibleAgency,
|
|
9327
|
+
esc(groupResponsibleAgency),
|
|
9078
9328
|
// GS-07
|
|
9079
9329
|
X231A1_VERSION_RELEASE
|
|
9080
9330
|
// GS-08 - the 999 TR3
|
|
@@ -9084,7 +9334,7 @@ function build999(spec) {
|
|
|
9084
9334
|
);
|
|
9085
9335
|
const stControlNumber = envelope.transactionSetControlNumber;
|
|
9086
9336
|
const st = joinSeg(
|
|
9087
|
-
["ST", "999", stControlNumber, X231A1_VERSION_RELEASE],
|
|
9337
|
+
["ST", "999", esc(stControlNumber), X231A1_VERSION_RELEASE],
|
|
9088
9338
|
elementSeparator,
|
|
9089
9339
|
segmentTerminator
|
|
9090
9340
|
);
|
|
@@ -9117,8 +9367,16 @@ function build999(spec) {
|
|
|
9117
9367
|
const ak9 = buildAk9(functionalGroup, esc, elementSeparator, segmentTerminator);
|
|
9118
9368
|
const bodySegments = [st, ak1, ...responseSegments, ak9];
|
|
9119
9369
|
const seCount = bodySegments.length + 1;
|
|
9120
|
-
const se = joinSeg(
|
|
9121
|
-
|
|
9370
|
+
const se = joinSeg(
|
|
9371
|
+
["SE", String(seCount), esc(stControlNumber)],
|
|
9372
|
+
elementSeparator,
|
|
9373
|
+
segmentTerminator
|
|
9374
|
+
);
|
|
9375
|
+
const ge = joinSeg(
|
|
9376
|
+
["GE", "1", esc(envelope.groupControlNumber)],
|
|
9377
|
+
elementSeparator,
|
|
9378
|
+
segmentTerminator
|
|
9379
|
+
);
|
|
9122
9380
|
const iea = joinSeg(["IEA", "1", interchangeControlNumber], elementSeparator, segmentTerminator);
|
|
9123
9381
|
const raw = isa + gs + bodySegments.join("") + se + ge + iea;
|
|
9124
9382
|
return parseX12(raw);
|
|
@@ -9240,7 +9498,7 @@ function buildIk4(elemError, esc, componentSeparator, elementSeparator, segmentT
|
|
|
9240
9498
|
return joinSeg(parts, elementSeparator, segmentTerminator);
|
|
9241
9499
|
}
|
|
9242
9500
|
function buildIk5(response, esc, elementSeparator, segmentTerminator) {
|
|
9243
|
-
const parts = ["IK5", response.disposition];
|
|
9501
|
+
const parts = ["IK5", esc(response.disposition)];
|
|
9244
9502
|
const codes = response.syntaxErrorCodes ?? [];
|
|
9245
9503
|
if (codes.length > 5) {
|
|
9246
9504
|
throw new AckBuildError(
|
|
@@ -9254,7 +9512,7 @@ function buildIk5(response, esc, elementSeparator, segmentTerminator) {
|
|
|
9254
9512
|
function buildAk9(group, esc, elementSeparator, segmentTerminator) {
|
|
9255
9513
|
const parts = [
|
|
9256
9514
|
"AK9",
|
|
9257
|
-
group.disposition,
|
|
9515
|
+
esc(group.disposition),
|
|
9258
9516
|
String(group.numberOfTransactionSets),
|
|
9259
9517
|
String(group.numberOfReceivedTransactionSets),
|
|
9260
9518
|
String(group.numberOfAcceptedTransactionSets)
|
|
@@ -9270,6 +9528,7 @@ function buildAk9(group, esc, elementSeparator, segmentTerminator) {
|
|
|
9270
9528
|
return joinSeg(parts, elementSeparator, segmentTerminator);
|
|
9271
9529
|
}
|
|
9272
9530
|
function joinSeg(parts, elementSeparator, segmentTerminator) {
|
|
9531
|
+
requireCallerSegment(parts, "build999", refuseSpec8);
|
|
9273
9532
|
return parts.join(elementSeparator) + segmentTerminator;
|
|
9274
9533
|
}
|
|
9275
9534
|
function pad8(value, width) {
|
|
@@ -9624,6 +9883,7 @@ function buildTransaction(tx, esc, elementSeparator, segmentTerminator) {
|
|
|
9624
9883
|
return st + bodySegments + se;
|
|
9625
9884
|
}
|
|
9626
9885
|
function joinSeg2(parts, elementSeparator, segmentTerminator) {
|
|
9886
|
+
requireCallerSegment(parts, "buildInterchange", refuseSpec9);
|
|
9627
9887
|
return parts.join(elementSeparator) + segmentTerminator;
|
|
9628
9888
|
}
|
|
9629
9889
|
function pad9(value, width) {
|
|
@@ -9932,7 +10192,7 @@ var profiles = Object.freeze({
|
|
|
9932
10192
|
});
|
|
9933
10193
|
|
|
9934
10194
|
// src/index.ts
|
|
9935
|
-
var VERSION = "0.0.
|
|
10195
|
+
var VERSION = "0.0.11";
|
|
9936
10196
|
|
|
9937
10197
|
exports.ACK_BUILD_ERROR_CODES = ACK_BUILD_ERROR_CODES;
|
|
9938
10198
|
exports.ALL_WARNING_MESSAGES = ALL_WARNING_MESSAGES;
|
|
@@ -10069,6 +10329,7 @@ exports.elementDecimal = elementDecimal;
|
|
|
10069
10329
|
exports.elementDecimalOrZero = elementDecimalOrZero;
|
|
10070
10330
|
exports.elementOptional = elementOptional;
|
|
10071
10331
|
exports.elementValue = elementValue;
|
|
10332
|
+
exports.entitySegmentDiscardedAfterLx = entitySegmentDiscardedAfterLx;
|
|
10072
10333
|
exports.escapeRelease = escapeRelease;
|
|
10073
10334
|
exports.get271Eligibility = get271Eligibility;
|
|
10074
10335
|
exports.get277CADisposition = get277CADisposition;
|
|
@@ -10107,11 +10368,15 @@ exports.parseX12 = parseX12;
|
|
|
10107
10368
|
exports.partitionWarnings = partitionWarnings;
|
|
10108
10369
|
exports.pre005010 = pre005010;
|
|
10109
10370
|
exports.profiles = profiles;
|
|
10371
|
+
exports.readElementDecimal = readElementDecimal;
|
|
10110
10372
|
exports.remitBalanceMismatch = remitBalanceMismatch;
|
|
10111
10373
|
exports.renderCallerValue = renderCallerValue;
|
|
10112
10374
|
exports.resolveHiQualifier = resolveHiQualifier;
|
|
10113
10375
|
exports.segmentCountMismatch = segmentCountMismatch;
|
|
10114
10376
|
exports.serializeX12 = serializeX12;
|
|
10377
|
+
exports.serviceLineDropped = serviceLineDropped;
|
|
10378
|
+
exports.serviceLineNotDecoded = serviceLineNotDecoded;
|
|
10379
|
+
exports.serviceSegmentWithoutLx = serviceSegmentWithoutLx;
|
|
10115
10380
|
exports.setDefaultProfile = setDefaultProfile;
|
|
10116
10381
|
exports.trailingGarbage = trailingGarbage;
|
|
10117
10382
|
exports.transactionCountMismatch = transactionCountMismatch;
|
|
@@ -10124,5 +10389,6 @@ exports.unknownClaimStatusCategory = unknownClaimStatusCategory;
|
|
|
10124
10389
|
exports.unknownHiQualifier = unknownHiQualifier;
|
|
10125
10390
|
exports.unknownMaintenanceType = unknownMaintenanceType;
|
|
10126
10391
|
exports.unknownRarc = unknownRarc;
|
|
10392
|
+
exports.unparseableDecimal = unparseableDecimal;
|
|
10127
10393
|
//# sourceMappingURL=index.cjs.map
|
|
10128
10394
|
//# sourceMappingURL=index.cjs.map
|