@imranq2/fhirpatientsummary 1.0.23 → 1.0.25
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/dist/index.cjs +478 -9
- package/dist/index.js +478 -9
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -155,7 +155,9 @@ var IPSSectionSummaryCompositionFilter = {
|
|
|
155
155
|
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "vital_summary_document"),
|
|
156
156
|
["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "careplan_summary_document"),
|
|
157
157
|
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
|
|
158
|
-
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document")
|
|
158
|
+
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document"),
|
|
159
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && ["lab_summary_document", "diagnosticreportlab_summary_document"].includes(c.code)),
|
|
160
|
+
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "procedure_summary_document")
|
|
159
161
|
};
|
|
160
162
|
var IPSSectionResourceHelper = class {
|
|
161
163
|
static getResourceFilterForSection(section) {
|
|
@@ -1324,6 +1326,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1324
1326
|
*/
|
|
1325
1327
|
generateSummaryNarrative(resources, timezone) {
|
|
1326
1328
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1329
|
+
let isSummaryCreated = false;
|
|
1327
1330
|
let html = `
|
|
1328
1331
|
<div>
|
|
1329
1332
|
<table>
|
|
@@ -1353,6 +1356,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1353
1356
|
break;
|
|
1354
1357
|
}
|
|
1355
1358
|
}
|
|
1359
|
+
isSummaryCreated = true;
|
|
1356
1360
|
html += `
|
|
1357
1361
|
<tr>
|
|
1358
1362
|
<td>${data["allergen"] ?? "-"}</td>
|
|
@@ -1365,7 +1369,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1365
1369
|
</tbody>
|
|
1366
1370
|
</table>
|
|
1367
1371
|
</div>`;
|
|
1368
|
-
return html;
|
|
1372
|
+
return isSummaryCreated ? html : void 0;
|
|
1369
1373
|
}
|
|
1370
1374
|
/**
|
|
1371
1375
|
* Internal static implementation that actually generates the narrative
|
|
@@ -1511,6 +1515,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1511
1515
|
*/
|
|
1512
1516
|
generateSummaryNarrative(resources, timezone) {
|
|
1513
1517
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1518
|
+
let isSummaryCreated = false;
|
|
1514
1519
|
let html = `
|
|
1515
1520
|
<div>
|
|
1516
1521
|
<table>
|
|
@@ -1555,6 +1560,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1555
1560
|
}
|
|
1556
1561
|
}
|
|
1557
1562
|
if (data["status"] === "active") {
|
|
1563
|
+
isSummaryCreated = true;
|
|
1558
1564
|
html += `
|
|
1559
1565
|
<tr>
|
|
1560
1566
|
<td>${data["medication"]}</td>
|
|
@@ -1570,7 +1576,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1570
1576
|
</tbody>
|
|
1571
1577
|
</table>
|
|
1572
1578
|
</div>`;
|
|
1573
|
-
return html;
|
|
1579
|
+
return isSummaryCreated ? html : void 0;
|
|
1574
1580
|
}
|
|
1575
1581
|
/**
|
|
1576
1582
|
* Safely parse a date string and return a valid Date object or null
|
|
@@ -1766,6 +1772,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1766
1772
|
*/
|
|
1767
1773
|
generateSummaryNarrative(resources, timezone) {
|
|
1768
1774
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1775
|
+
let isSummaryCreated = false;
|
|
1769
1776
|
let html = `
|
|
1770
1777
|
<div>
|
|
1771
1778
|
<table>
|
|
@@ -1796,6 +1803,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1796
1803
|
}
|
|
1797
1804
|
}
|
|
1798
1805
|
if (data["status"] === "completed") {
|
|
1806
|
+
isSummaryCreated = true;
|
|
1799
1807
|
html += `
|
|
1800
1808
|
<tr>
|
|
1801
1809
|
<td>${data["immunization"] ?? "-"}</td>
|
|
@@ -1809,7 +1817,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1809
1817
|
</tbody>
|
|
1810
1818
|
</table>
|
|
1811
1819
|
</div>`;
|
|
1812
|
-
return html;
|
|
1820
|
+
return isSummaryCreated ? html : void 0;
|
|
1813
1821
|
}
|
|
1814
1822
|
/**
|
|
1815
1823
|
* Internal static implementation that actually generates the narrative
|
|
@@ -1925,6 +1933,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1925
1933
|
*/
|
|
1926
1934
|
generateSummaryNarrative(resources, timezone) {
|
|
1927
1935
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1936
|
+
let isSummaryCreated = false;
|
|
1928
1937
|
let html = `
|
|
1929
1938
|
<div>
|
|
1930
1939
|
<table>
|
|
@@ -1964,6 +1973,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1964
1973
|
data[columnTitle] = columnData.text?.div ?? "";
|
|
1965
1974
|
}
|
|
1966
1975
|
}
|
|
1976
|
+
isSummaryCreated = true;
|
|
1967
1977
|
html += `
|
|
1968
1978
|
<tr>
|
|
1969
1979
|
<td>${data["Vital Name"] ?? "-"}</td>
|
|
@@ -1977,7 +1987,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1977
1987
|
</tbody>
|
|
1978
1988
|
</table>
|
|
1979
1989
|
</div>`;
|
|
1980
|
-
return html;
|
|
1990
|
+
return isSummaryCreated ? html : void 0;
|
|
1981
1991
|
}
|
|
1982
1992
|
/**
|
|
1983
1993
|
* Internal static implementation that actually generates the narrative
|
|
@@ -2088,6 +2098,400 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2088
2098
|
generateNarrative(resources, timezone) {
|
|
2089
2099
|
return _DiagnosticResultsTemplate.generateStaticNarrative(resources, timezone);
|
|
2090
2100
|
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Helper function to format observation data fields
|
|
2103
|
+
* @param obsData - Record containing observation data fields
|
|
2104
|
+
*/
|
|
2105
|
+
formatSummaryObservationData(obsData) {
|
|
2106
|
+
const valueType = obsData["valueType"];
|
|
2107
|
+
switch (valueType) {
|
|
2108
|
+
case "valueQuantity":
|
|
2109
|
+
if (obsData["value"] && obsData["unit"]) {
|
|
2110
|
+
obsData["formattedValue"] = `${obsData["value"]} ${obsData["unit"]}`;
|
|
2111
|
+
} else if (obsData["value"]) {
|
|
2112
|
+
obsData["formattedValue"] = obsData["value"];
|
|
2113
|
+
}
|
|
2114
|
+
break;
|
|
2115
|
+
case "valueCodeableConcept":
|
|
2116
|
+
case "valueString":
|
|
2117
|
+
case "valueBoolean":
|
|
2118
|
+
case "valueInteger":
|
|
2119
|
+
case "valueDateTime":
|
|
2120
|
+
case "valueTime":
|
|
2121
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2122
|
+
break;
|
|
2123
|
+
case "valuePeriod":
|
|
2124
|
+
if (obsData["valuePeriodStart"] && obsData["valuePeriodEnd"]) {
|
|
2125
|
+
obsData["formattedValue"] = `${obsData["valuePeriodStart"]} - ${obsData["valuePeriodEnd"]}`;
|
|
2126
|
+
} else if (obsData["valuePeriodStart"]) {
|
|
2127
|
+
obsData["formattedValue"] = `From ${obsData["valuePeriodStart"]}`;
|
|
2128
|
+
} else if (obsData["valuePeriodEnd"]) {
|
|
2129
|
+
obsData["formattedValue"] = `Until ${obsData["valuePeriodEnd"]}`;
|
|
2130
|
+
}
|
|
2131
|
+
break;
|
|
2132
|
+
case "valueSampledData": {
|
|
2133
|
+
const sampledParts = [];
|
|
2134
|
+
if (obsData["sampledDataOriginValue"]) {
|
|
2135
|
+
sampledParts.push(`Origin: ${obsData["sampledDataOriginValue"]}${obsData["sampledDataOriginUnit"] ? " " + obsData["sampledDataOriginUnit"] : ""}`);
|
|
2136
|
+
}
|
|
2137
|
+
if (obsData["sampledDataPeriod"]) {
|
|
2138
|
+
sampledParts.push(`Period: ${obsData["sampledDataPeriod"]}`);
|
|
2139
|
+
}
|
|
2140
|
+
if (obsData["sampledDataFactor"]) {
|
|
2141
|
+
sampledParts.push(`Factor: ${obsData["sampledDataFactor"]}`);
|
|
2142
|
+
}
|
|
2143
|
+
if (obsData["sampledDataLowerLimit"]) {
|
|
2144
|
+
sampledParts.push(`Lower: ${obsData["sampledDataLowerLimit"]}`);
|
|
2145
|
+
}
|
|
2146
|
+
if (obsData["sampledDataUpperLimit"]) {
|
|
2147
|
+
sampledParts.push(`Upper: ${obsData["sampledDataUpperLimit"]}`);
|
|
2148
|
+
}
|
|
2149
|
+
if (obsData["sampledDataData"]) {
|
|
2150
|
+
sampledParts.push(`Data: ${obsData["sampledDataData"]}`);
|
|
2151
|
+
}
|
|
2152
|
+
obsData["formattedValue"] = sampledParts.join(", ");
|
|
2153
|
+
break;
|
|
2154
|
+
}
|
|
2155
|
+
case "valueRange": {
|
|
2156
|
+
const rangeParts = [];
|
|
2157
|
+
if (obsData["valueRangeLowValue"]) {
|
|
2158
|
+
rangeParts.push(`${obsData["valueRangeLowValue"]}${obsData["valueRangeLowUnit"] ? " " + obsData["valueRangeLowUnit"] : ""}`);
|
|
2159
|
+
}
|
|
2160
|
+
if (obsData["valueRangeHighValue"]) {
|
|
2161
|
+
rangeParts.push(`${obsData["valueRangeHighValue"]}${obsData["valueRangeHighUnit"] ? " " + obsData["valueRangeHighUnit"] : ""}`);
|
|
2162
|
+
}
|
|
2163
|
+
obsData["formattedValue"] = rangeParts.join(" - ");
|
|
2164
|
+
break;
|
|
2165
|
+
}
|
|
2166
|
+
case "valueRatio": {
|
|
2167
|
+
const numerator = obsData["valueRatioNumeratorValue"] ? `${obsData["valueRatioNumeratorValue"]}${obsData["valueRatioNumeratorUnit"] ? " " + obsData["valueRatioNumeratorUnit"] : ""}` : "";
|
|
2168
|
+
const denominator = obsData["valueRatioDenominatorValue"] ? `${obsData["valueRatioDenominatorValue"]}${obsData["valueRatioDenominatorUnit"] ? " " + obsData["valueRatioDenominatorUnit"] : ""}` : "";
|
|
2169
|
+
if (numerator && denominator) {
|
|
2170
|
+
obsData["formattedValue"] = `${numerator} / ${denominator}`;
|
|
2171
|
+
} else if (numerator) {
|
|
2172
|
+
obsData["formattedValue"] = numerator;
|
|
2173
|
+
}
|
|
2174
|
+
break;
|
|
2175
|
+
}
|
|
2176
|
+
default:
|
|
2177
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2178
|
+
break;
|
|
2179
|
+
}
|
|
2180
|
+
if (obsData["referenceRangeLow"]) {
|
|
2181
|
+
obsData["referenceRange"] = obsData["referenceRangeLow"] + " " + obsData["referenceRangeLowUnit"];
|
|
2182
|
+
}
|
|
2183
|
+
if (obsData["referenceRangeHigh"]) {
|
|
2184
|
+
if (obsData["referenceRange"]) {
|
|
2185
|
+
obsData["referenceRange"] += " - ";
|
|
2186
|
+
} else {
|
|
2187
|
+
obsData["referenceRange"] = "";
|
|
2188
|
+
}
|
|
2189
|
+
obsData["referenceRange"] += obsData["referenceRangeHigh"] + " " + obsData["referenceRangeHighUnit"];
|
|
2190
|
+
}
|
|
2191
|
+
if (obsData["referenceRangeAgeLowValue"] || obsData["referenceRangeAgeHighValue"]) {
|
|
2192
|
+
const ageParts = [];
|
|
2193
|
+
if (obsData["referenceRangeAgeLowValue"]) {
|
|
2194
|
+
ageParts.push(`${obsData["referenceRangeAgeLowValue"]}${obsData["referenceRangeAgeLowUnit"] ? " " + obsData["referenceRangeAgeLowUnit"] : ""}`);
|
|
2195
|
+
}
|
|
2196
|
+
if (obsData["referenceRangeAgeHighValue"]) {
|
|
2197
|
+
ageParts.push(`${obsData["referenceRangeAgeHighValue"]}${obsData["referenceRangeAgeHighUnit"] ? " " + obsData["referenceRangeAgeHighUnit"] : ""}`);
|
|
2198
|
+
}
|
|
2199
|
+
if (obsData["referenceRange"]) {
|
|
2200
|
+
obsData["referenceRange"] += ` (Age: ${ageParts.join(" - ")})`;
|
|
2201
|
+
} else {
|
|
2202
|
+
obsData["referenceRange"] = `Age: ${ageParts.join(" - ")}`;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Helper function to extract observation field data
|
|
2208
|
+
* @param column - Column data from the summary
|
|
2209
|
+
* @param targetData - Record to populate with extracted data
|
|
2210
|
+
*/
|
|
2211
|
+
extractSummaryObservationFields(column, targetData) {
|
|
2212
|
+
switch (column.title) {
|
|
2213
|
+
case "Labs Name":
|
|
2214
|
+
targetData["code"] = column.text?.div ?? "";
|
|
2215
|
+
break;
|
|
2216
|
+
case "effectiveDateTime":
|
|
2217
|
+
targetData["effectiveDateTime"] = column.text?.div ?? "";
|
|
2218
|
+
break;
|
|
2219
|
+
case "effectivePeriod.start":
|
|
2220
|
+
targetData["effectivePeriodStart"] = column.text?.div ?? "";
|
|
2221
|
+
break;
|
|
2222
|
+
case "effectivePeriod.end":
|
|
2223
|
+
targetData["effectivePeriodEnd"] = column.text?.div ?? "";
|
|
2224
|
+
break;
|
|
2225
|
+
// valueQuantity
|
|
2226
|
+
case "valueQuantity.value":
|
|
2227
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2228
|
+
targetData["valueType"] = "valueQuantity";
|
|
2229
|
+
break;
|
|
2230
|
+
case "valueQuantity.unit":
|
|
2231
|
+
targetData["unit"] = column.text?.div ?? "";
|
|
2232
|
+
break;
|
|
2233
|
+
// valueCodeableConcept
|
|
2234
|
+
case "valueCodeableConcept.text":
|
|
2235
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2236
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2237
|
+
break;
|
|
2238
|
+
case "valueCodeableConcept.coding.display":
|
|
2239
|
+
if (!targetData["value"]) {
|
|
2240
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2241
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2242
|
+
}
|
|
2243
|
+
break;
|
|
2244
|
+
// valueString
|
|
2245
|
+
case "valueString":
|
|
2246
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2247
|
+
targetData["valueType"] = "valueString";
|
|
2248
|
+
break;
|
|
2249
|
+
// valueBoolean
|
|
2250
|
+
case "valueBoolean":
|
|
2251
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2252
|
+
targetData["valueType"] = "valueBoolean";
|
|
2253
|
+
break;
|
|
2254
|
+
// valueInteger
|
|
2255
|
+
case "valueInteger":
|
|
2256
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2257
|
+
targetData["valueType"] = "valueInteger";
|
|
2258
|
+
break;
|
|
2259
|
+
// valueDateTime
|
|
2260
|
+
case "valueDateTime":
|
|
2261
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2262
|
+
targetData["valueType"] = "valueDateTime";
|
|
2263
|
+
break;
|
|
2264
|
+
// valuePeriod
|
|
2265
|
+
case "valuePeriod.start":
|
|
2266
|
+
targetData["valuePeriodStart"] = column.text?.div ?? "";
|
|
2267
|
+
targetData["valueType"] = "valuePeriod";
|
|
2268
|
+
break;
|
|
2269
|
+
case "valuePeriod.end":
|
|
2270
|
+
targetData["valuePeriodEnd"] = column.text?.div ?? "";
|
|
2271
|
+
targetData["valueType"] = "valuePeriod";
|
|
2272
|
+
break;
|
|
2273
|
+
// valueTime
|
|
2274
|
+
case "valueTime":
|
|
2275
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2276
|
+
targetData["valueType"] = "valueTime";
|
|
2277
|
+
break;
|
|
2278
|
+
// valueSampledData
|
|
2279
|
+
case "valueSampledData.origin.value":
|
|
2280
|
+
targetData["sampledDataOriginValue"] = column.text?.div ?? "";
|
|
2281
|
+
targetData["valueType"] = "valueSampledData";
|
|
2282
|
+
break;
|
|
2283
|
+
case "valueSampledData.origin.unit":
|
|
2284
|
+
targetData["sampledDataOriginUnit"] = column.text?.div ?? "";
|
|
2285
|
+
break;
|
|
2286
|
+
case "valueSampledData.period":
|
|
2287
|
+
targetData["sampledDataPeriod"] = column.text?.div ?? "";
|
|
2288
|
+
break;
|
|
2289
|
+
case "valueSampledData.factor":
|
|
2290
|
+
targetData["sampledDataFactor"] = column.text?.div ?? "";
|
|
2291
|
+
break;
|
|
2292
|
+
case "valueSampledData.lowerLimit":
|
|
2293
|
+
targetData["sampledDataLowerLimit"] = column.text?.div ?? "";
|
|
2294
|
+
break;
|
|
2295
|
+
case "valueSampledData.upperLimit":
|
|
2296
|
+
targetData["sampledDataUpperLimit"] = column.text?.div ?? "";
|
|
2297
|
+
break;
|
|
2298
|
+
case "valueSampledData.data":
|
|
2299
|
+
targetData["sampledDataData"] = column.text?.div ?? "";
|
|
2300
|
+
break;
|
|
2301
|
+
// valueRange
|
|
2302
|
+
case "valueRange.low.value":
|
|
2303
|
+
targetData["valueRangeLowValue"] = column.text?.div ?? "";
|
|
2304
|
+
targetData["valueType"] = "valueRange";
|
|
2305
|
+
break;
|
|
2306
|
+
case "valueRange.low.unit":
|
|
2307
|
+
targetData["valueRangeLowUnit"] = column.text?.div ?? "";
|
|
2308
|
+
break;
|
|
2309
|
+
case "valueRange.high.value":
|
|
2310
|
+
targetData["valueRangeHighValue"] = column.text?.div ?? "";
|
|
2311
|
+
break;
|
|
2312
|
+
case "valueRange.high.unit":
|
|
2313
|
+
targetData["valueRangeHighUnit"] = column.text?.div ?? "";
|
|
2314
|
+
break;
|
|
2315
|
+
// valueRatio
|
|
2316
|
+
case "valueRatio.numerator.value":
|
|
2317
|
+
targetData["valueRatioNumeratorValue"] = column.text?.div ?? "";
|
|
2318
|
+
targetData["valueType"] = "valueRatio";
|
|
2319
|
+
break;
|
|
2320
|
+
case "valueRatio.numerator.unit":
|
|
2321
|
+
targetData["valueRatioNumeratorUnit"] = column.text?.div ?? "";
|
|
2322
|
+
break;
|
|
2323
|
+
case "valueRatio.denominator.value":
|
|
2324
|
+
targetData["valueRatioDenominatorValue"] = column.text?.div ?? "";
|
|
2325
|
+
break;
|
|
2326
|
+
case "valueRatio.denominator.unit":
|
|
2327
|
+
targetData["valueRatioDenominatorUnit"] = column.text?.div ?? "";
|
|
2328
|
+
break;
|
|
2329
|
+
// referenceRange
|
|
2330
|
+
case "referenceRange.low.value":
|
|
2331
|
+
targetData["referenceRangeLow"] = column.text?.div ?? "";
|
|
2332
|
+
break;
|
|
2333
|
+
case "referenceRange.low.unit":
|
|
2334
|
+
targetData["referenceRangeLowUnit"] = column.text?.div ?? "";
|
|
2335
|
+
break;
|
|
2336
|
+
case "referenceRange.high.value":
|
|
2337
|
+
targetData["referenceRangeHigh"] = column.text?.div ?? "";
|
|
2338
|
+
break;
|
|
2339
|
+
case "referenceRange.high.unit":
|
|
2340
|
+
targetData["referenceRangeHighUnit"] = column.text?.div ?? "";
|
|
2341
|
+
break;
|
|
2342
|
+
case "referenceRange.age.low.value":
|
|
2343
|
+
targetData["referenceRangeAgeLowValue"] = column.text?.div ?? "";
|
|
2344
|
+
break;
|
|
2345
|
+
case "referenceRange.age.low.unit":
|
|
2346
|
+
targetData["referenceRangeAgeLowUnit"] = column.text?.div ?? "";
|
|
2347
|
+
break;
|
|
2348
|
+
case "referenceRange.age.high.value":
|
|
2349
|
+
targetData["referenceRangeAgeHighValue"] = column.text?.div ?? "";
|
|
2350
|
+
break;
|
|
2351
|
+
case "referenceRange.age.high.unit":
|
|
2352
|
+
targetData["referenceRangeAgeHighUnit"] = column.text?.div ?? "";
|
|
2353
|
+
break;
|
|
2354
|
+
default:
|
|
2355
|
+
break;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Generate HTML narrative for Diagnostic Results & Observation resources using summary
|
|
2360
|
+
* @param resources - FHIR Composition resources
|
|
2361
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2362
|
+
* @returns HTML string for rendering
|
|
2363
|
+
*/
|
|
2364
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2365
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2366
|
+
let html = `
|
|
2367
|
+
<div>`;
|
|
2368
|
+
let observationhtml = `
|
|
2369
|
+
<div>
|
|
2370
|
+
<h3>Observations</h3>
|
|
2371
|
+
<table>
|
|
2372
|
+
<thead>
|
|
2373
|
+
<tr>
|
|
2374
|
+
<th>Code</th>
|
|
2375
|
+
<th>Result</th>
|
|
2376
|
+
<th>Reference Range</th>
|
|
2377
|
+
<th>Date</th>
|
|
2378
|
+
</tr>
|
|
2379
|
+
</thead>
|
|
2380
|
+
<tbody>`;
|
|
2381
|
+
let diagnosticReporthtml = `
|
|
2382
|
+
<div>
|
|
2383
|
+
<h3>Diagnostic Reports</h3>
|
|
2384
|
+
<table>
|
|
2385
|
+
<thead>
|
|
2386
|
+
<tr>
|
|
2387
|
+
<th>Report</th>
|
|
2388
|
+
<th>Performer</th>
|
|
2389
|
+
<th>Issued</th>
|
|
2390
|
+
</tr>
|
|
2391
|
+
</thead>
|
|
2392
|
+
<tbody>`;
|
|
2393
|
+
let observationExists = false;
|
|
2394
|
+
let diagnosticReportExists = false;
|
|
2395
|
+
for (const resourceItem of resources) {
|
|
2396
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2397
|
+
const data = {};
|
|
2398
|
+
const components = [];
|
|
2399
|
+
for (const columnData of rowData.section ?? []) {
|
|
2400
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2401
|
+
if (columnData.text?.div === "Observation.component" && columnData.section) {
|
|
2402
|
+
for (const componentSection of columnData.section) {
|
|
2403
|
+
const componentData = {};
|
|
2404
|
+
for (const nestedColumn of componentSection.section ?? []) {
|
|
2405
|
+
this.extractSummaryObservationFields(nestedColumn, componentData);
|
|
2406
|
+
}
|
|
2407
|
+
if (Object.keys(componentData).length > 0) {
|
|
2408
|
+
components.push(componentData);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
} else {
|
|
2412
|
+
this.extractSummaryObservationFields(columnData, data);
|
|
2413
|
+
}
|
|
2414
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2415
|
+
switch (columnData.title) {
|
|
2416
|
+
case "Diagnostic Report Name":
|
|
2417
|
+
data["report"] = columnData.text?.div ?? "";
|
|
2418
|
+
break;
|
|
2419
|
+
case "Performer":
|
|
2420
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2421
|
+
break;
|
|
2422
|
+
case "Issued Date":
|
|
2423
|
+
data["issued"] = columnData.text?.div ?? "";
|
|
2424
|
+
break;
|
|
2425
|
+
case "Status":
|
|
2426
|
+
data["status"] = columnData.text?.div ?? "";
|
|
2427
|
+
break;
|
|
2428
|
+
default:
|
|
2429
|
+
break;
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2434
|
+
observationExists = true;
|
|
2435
|
+
let date = data["effectiveDateTime"] ? templateUtilities.renderTime(data["effectiveDateTime"], timezone) : "";
|
|
2436
|
+
if (!date && data["effectivePeriodStart"]) {
|
|
2437
|
+
date = templateUtilities.renderTime(data["effectivePeriodStart"], timezone);
|
|
2438
|
+
if (data["effectivePeriodEnd"]) {
|
|
2439
|
+
date += " - " + templateUtilities.renderTime(data["effectivePeriodEnd"], timezone);
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
if (components.length > 0) {
|
|
2443
|
+
const groupName = data["code"] ?? "";
|
|
2444
|
+
for (const component of components) {
|
|
2445
|
+
this.formatSummaryObservationData(component);
|
|
2446
|
+
observationhtml += `
|
|
2447
|
+
<tr>
|
|
2448
|
+
<td>${groupName ? groupName + " - " : ""}${component["code"] ?? "-"}</td>
|
|
2449
|
+
<td>${component["formattedValue"] ?? "-"}</td>
|
|
2450
|
+
<td>${component["referenceRange"]?.trim() ?? "-"}</td>
|
|
2451
|
+
<td>${date ?? "-"}</td>
|
|
2452
|
+
</tr>`;
|
|
2453
|
+
}
|
|
2454
|
+
} else {
|
|
2455
|
+
this.formatSummaryObservationData(data);
|
|
2456
|
+
observationhtml += `
|
|
2457
|
+
<tr>
|
|
2458
|
+
<td>${data["code"] ?? "-"}</td>
|
|
2459
|
+
<td>${data["formattedValue"] ?? "-"}</td>
|
|
2460
|
+
<td>${data["referenceRange"]?.trim() ?? "-"}</td>
|
|
2461
|
+
<td>${date ?? "-"}</td>
|
|
2462
|
+
</tr>`;
|
|
2463
|
+
}
|
|
2464
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2465
|
+
if (data["status"] === "final") {
|
|
2466
|
+
diagnosticReportExists = true;
|
|
2467
|
+
diagnosticReporthtml += `
|
|
2468
|
+
<tr>
|
|
2469
|
+
<td>${data["report"] ?? "-"}</td>
|
|
2470
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2471
|
+
<td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
|
|
2472
|
+
</tr>`;
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
if (observationExists) {
|
|
2478
|
+
html += observationhtml;
|
|
2479
|
+
html += `
|
|
2480
|
+
</tbody>
|
|
2481
|
+
</table>
|
|
2482
|
+
</div>`;
|
|
2483
|
+
}
|
|
2484
|
+
if (diagnosticReportExists) {
|
|
2485
|
+
html += diagnosticReporthtml;
|
|
2486
|
+
html += `
|
|
2487
|
+
</tbody>
|
|
2488
|
+
</table>
|
|
2489
|
+
</div>`;
|
|
2490
|
+
}
|
|
2491
|
+
html += `
|
|
2492
|
+
</div>`;
|
|
2493
|
+
return observationExists || diagnosticReportExists ? html : void 0;
|
|
2494
|
+
}
|
|
2091
2495
|
/**
|
|
2092
2496
|
* Internal static implementation that actually generates the narrative
|
|
2093
2497
|
* @param resources - FHIR resources array containing Observation and DiagnosticReport resources
|
|
@@ -2229,6 +2633,59 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
|
|
|
2229
2633
|
});
|
|
2230
2634
|
return _HistoryOfProceduresTemplate.generateStaticNarrative(resources, timezone);
|
|
2231
2635
|
}
|
|
2636
|
+
/**
|
|
2637
|
+
* Generate HTML narrative for Procedure resources using summary
|
|
2638
|
+
* @param resources - FHIR Composition resources
|
|
2639
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2640
|
+
* @returns HTML string for rendering
|
|
2641
|
+
*/
|
|
2642
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2643
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2644
|
+
let isSummaryCreated = false;
|
|
2645
|
+
let html = `
|
|
2646
|
+
<div>
|
|
2647
|
+
<table>
|
|
2648
|
+
<thead>
|
|
2649
|
+
<tr>
|
|
2650
|
+
<th>Procedure</th>
|
|
2651
|
+
<th>Performer</th>
|
|
2652
|
+
<th>Date</th>
|
|
2653
|
+
</tr>
|
|
2654
|
+
</thead>
|
|
2655
|
+
<tbody>`;
|
|
2656
|
+
for (const resourceItem of resources) {
|
|
2657
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2658
|
+
const data = {};
|
|
2659
|
+
for (const columnData of rowData.section ?? []) {
|
|
2660
|
+
switch (columnData.title) {
|
|
2661
|
+
case "Procedure Name":
|
|
2662
|
+
data["procedure"] = columnData.text?.div ?? "";
|
|
2663
|
+
break;
|
|
2664
|
+
case "Performer":
|
|
2665
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2666
|
+
break;
|
|
2667
|
+
case "Performed Date":
|
|
2668
|
+
data["date"] = columnData.text?.div ?? "";
|
|
2669
|
+
break;
|
|
2670
|
+
default:
|
|
2671
|
+
break;
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
isSummaryCreated = true;
|
|
2675
|
+
html += `
|
|
2676
|
+
<tr>
|
|
2677
|
+
<td>${data["procedure"] ?? "-"}</td>
|
|
2678
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2679
|
+
<td>${templateUtilities.renderTime(data["date"], timezone) ?? "-"}</td>
|
|
2680
|
+
</tr>`;
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
html += `
|
|
2684
|
+
</tbody>
|
|
2685
|
+
</table>
|
|
2686
|
+
</div>`;
|
|
2687
|
+
return isSummaryCreated ? html : void 0;
|
|
2688
|
+
}
|
|
2232
2689
|
/**
|
|
2233
2690
|
* Internal static implementation that actually generates the narrative
|
|
2234
2691
|
* @param resources - FHIR Procedure resources
|
|
@@ -2411,6 +2868,7 @@ var PlanOfCareTemplate = class {
|
|
|
2411
2868
|
*/
|
|
2412
2869
|
generateSummaryNarrative(resources, timezone) {
|
|
2413
2870
|
const templateUtilities = new TemplateUtilities(resources);
|
|
2871
|
+
let isSummaryCreated = false;
|
|
2414
2872
|
let html = `
|
|
2415
2873
|
<div>
|
|
2416
2874
|
<table>
|
|
@@ -2434,6 +2892,7 @@ var PlanOfCareTemplate = class {
|
|
|
2434
2892
|
if (data["status"] !== "active") {
|
|
2435
2893
|
continue;
|
|
2436
2894
|
}
|
|
2895
|
+
isSummaryCreated = true;
|
|
2437
2896
|
html += `
|
|
2438
2897
|
<tr>
|
|
2439
2898
|
<td>${data["CarePlan Name"] ?? "-"}</td>
|
|
@@ -2447,7 +2906,7 @@ var PlanOfCareTemplate = class {
|
|
|
2447
2906
|
</tbody>
|
|
2448
2907
|
</table>
|
|
2449
2908
|
</div>`;
|
|
2450
|
-
return html;
|
|
2909
|
+
return isSummaryCreated ? html : void 0;
|
|
2451
2910
|
}
|
|
2452
2911
|
};
|
|
2453
2912
|
|
|
@@ -2900,11 +3359,13 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2900
3359
|
timezone,
|
|
2901
3360
|
true
|
|
2902
3361
|
);
|
|
2903
|
-
}
|
|
3362
|
+
}
|
|
3363
|
+
if (!narrative && sectionType in IPSMandatorySections) {
|
|
2904
3364
|
narrative = await NarrativeGenerator.createNarrativeAsync(
|
|
2905
3365
|
IPSMissingMandatorySectionContent[sectionType]
|
|
2906
3366
|
);
|
|
2907
|
-
}
|
|
3367
|
+
}
|
|
3368
|
+
if (!narrative) {
|
|
2908
3369
|
return this;
|
|
2909
3370
|
}
|
|
2910
3371
|
this.addSectionAsync(narrative, sectionType, validResources);
|
|
@@ -2922,13 +3383,21 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2922
3383
|
}
|
|
2923
3384
|
});
|
|
2924
3385
|
}
|
|
2925
|
-
|
|
3386
|
+
let narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
2926
3387
|
sectionType,
|
|
2927
3388
|
summaryCompositions,
|
|
2928
3389
|
timezone,
|
|
2929
3390
|
true,
|
|
2930
3391
|
true
|
|
2931
3392
|
);
|
|
3393
|
+
if (!narrative && sectionType in IPSMandatorySections) {
|
|
3394
|
+
narrative = await NarrativeGenerator.createNarrativeAsync(
|
|
3395
|
+
IPSMissingMandatorySectionContent[sectionType]
|
|
3396
|
+
);
|
|
3397
|
+
}
|
|
3398
|
+
if (!narrative) {
|
|
3399
|
+
return this;
|
|
3400
|
+
}
|
|
2932
3401
|
this.addSectionAsync(narrative, sectionType, sectionResources);
|
|
2933
3402
|
return this;
|
|
2934
3403
|
}
|
package/dist/index.js
CHANGED
|
@@ -127,7 +127,9 @@ var IPSSectionSummaryCompositionFilter = {
|
|
|
127
127
|
["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "vital_summary_document"),
|
|
128
128
|
["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "careplan_summary_document"),
|
|
129
129
|
["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "immunization_summary_document"),
|
|
130
|
-
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document")
|
|
130
|
+
["MedicationSummarySection" /* MEDICATIONS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "medication_summary_document"),
|
|
131
|
+
["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && ["lab_summary_document", "diagnosticreportlab_summary_document"].includes(c.code)),
|
|
132
|
+
["HistoryOfProceduresSection" /* PROCEDURES */]: (resource) => resource.resourceType === "Composition" && resource.type?.coding?.some((c) => c.system === IPS_SUMMARY_COMPOSITION_TYPE_SYSTEM && c.code === "procedure_summary_document")
|
|
131
133
|
};
|
|
132
134
|
var IPSSectionResourceHelper = class {
|
|
133
135
|
static getResourceFilterForSection(section) {
|
|
@@ -1296,6 +1298,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1296
1298
|
*/
|
|
1297
1299
|
generateSummaryNarrative(resources, timezone) {
|
|
1298
1300
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1301
|
+
let isSummaryCreated = false;
|
|
1299
1302
|
let html = `
|
|
1300
1303
|
<div>
|
|
1301
1304
|
<table>
|
|
@@ -1325,6 +1328,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1325
1328
|
break;
|
|
1326
1329
|
}
|
|
1327
1330
|
}
|
|
1331
|
+
isSummaryCreated = true;
|
|
1328
1332
|
html += `
|
|
1329
1333
|
<tr>
|
|
1330
1334
|
<td>${data["allergen"] ?? "-"}</td>
|
|
@@ -1337,7 +1341,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
|
|
|
1337
1341
|
</tbody>
|
|
1338
1342
|
</table>
|
|
1339
1343
|
</div>`;
|
|
1340
|
-
return html;
|
|
1344
|
+
return isSummaryCreated ? html : void 0;
|
|
1341
1345
|
}
|
|
1342
1346
|
/**
|
|
1343
1347
|
* Internal static implementation that actually generates the narrative
|
|
@@ -1483,6 +1487,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1483
1487
|
*/
|
|
1484
1488
|
generateSummaryNarrative(resources, timezone) {
|
|
1485
1489
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1490
|
+
let isSummaryCreated = false;
|
|
1486
1491
|
let html = `
|
|
1487
1492
|
<div>
|
|
1488
1493
|
<table>
|
|
@@ -1527,6 +1532,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1527
1532
|
}
|
|
1528
1533
|
}
|
|
1529
1534
|
if (data["status"] === "active") {
|
|
1535
|
+
isSummaryCreated = true;
|
|
1530
1536
|
html += `
|
|
1531
1537
|
<tr>
|
|
1532
1538
|
<td>${data["medication"]}</td>
|
|
@@ -1542,7 +1548,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
|
|
|
1542
1548
|
</tbody>
|
|
1543
1549
|
</table>
|
|
1544
1550
|
</div>`;
|
|
1545
|
-
return html;
|
|
1551
|
+
return isSummaryCreated ? html : void 0;
|
|
1546
1552
|
}
|
|
1547
1553
|
/**
|
|
1548
1554
|
* Safely parse a date string and return a valid Date object or null
|
|
@@ -1738,6 +1744,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1738
1744
|
*/
|
|
1739
1745
|
generateSummaryNarrative(resources, timezone) {
|
|
1740
1746
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1747
|
+
let isSummaryCreated = false;
|
|
1741
1748
|
let html = `
|
|
1742
1749
|
<div>
|
|
1743
1750
|
<table>
|
|
@@ -1768,6 +1775,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1768
1775
|
}
|
|
1769
1776
|
}
|
|
1770
1777
|
if (data["status"] === "completed") {
|
|
1778
|
+
isSummaryCreated = true;
|
|
1771
1779
|
html += `
|
|
1772
1780
|
<tr>
|
|
1773
1781
|
<td>${data["immunization"] ?? "-"}</td>
|
|
@@ -1781,7 +1789,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
|
|
|
1781
1789
|
</tbody>
|
|
1782
1790
|
</table>
|
|
1783
1791
|
</div>`;
|
|
1784
|
-
return html;
|
|
1792
|
+
return isSummaryCreated ? html : void 0;
|
|
1785
1793
|
}
|
|
1786
1794
|
/**
|
|
1787
1795
|
* Internal static implementation that actually generates the narrative
|
|
@@ -1897,6 +1905,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1897
1905
|
*/
|
|
1898
1906
|
generateSummaryNarrative(resources, timezone) {
|
|
1899
1907
|
const templateUtilities = new TemplateUtilities(resources);
|
|
1908
|
+
let isSummaryCreated = false;
|
|
1900
1909
|
let html = `
|
|
1901
1910
|
<div>
|
|
1902
1911
|
<table>
|
|
@@ -1936,6 +1945,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1936
1945
|
data[columnTitle] = columnData.text?.div ?? "";
|
|
1937
1946
|
}
|
|
1938
1947
|
}
|
|
1948
|
+
isSummaryCreated = true;
|
|
1939
1949
|
html += `
|
|
1940
1950
|
<tr>
|
|
1941
1951
|
<td>${data["Vital Name"] ?? "-"}</td>
|
|
@@ -1949,7 +1959,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
|
|
|
1949
1959
|
</tbody>
|
|
1950
1960
|
</table>
|
|
1951
1961
|
</div>`;
|
|
1952
|
-
return html;
|
|
1962
|
+
return isSummaryCreated ? html : void 0;
|
|
1953
1963
|
}
|
|
1954
1964
|
/**
|
|
1955
1965
|
* Internal static implementation that actually generates the narrative
|
|
@@ -2060,6 +2070,400 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
|
|
|
2060
2070
|
generateNarrative(resources, timezone) {
|
|
2061
2071
|
return _DiagnosticResultsTemplate.generateStaticNarrative(resources, timezone);
|
|
2062
2072
|
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Helper function to format observation data fields
|
|
2075
|
+
* @param obsData - Record containing observation data fields
|
|
2076
|
+
*/
|
|
2077
|
+
formatSummaryObservationData(obsData) {
|
|
2078
|
+
const valueType = obsData["valueType"];
|
|
2079
|
+
switch (valueType) {
|
|
2080
|
+
case "valueQuantity":
|
|
2081
|
+
if (obsData["value"] && obsData["unit"]) {
|
|
2082
|
+
obsData["formattedValue"] = `${obsData["value"]} ${obsData["unit"]}`;
|
|
2083
|
+
} else if (obsData["value"]) {
|
|
2084
|
+
obsData["formattedValue"] = obsData["value"];
|
|
2085
|
+
}
|
|
2086
|
+
break;
|
|
2087
|
+
case "valueCodeableConcept":
|
|
2088
|
+
case "valueString":
|
|
2089
|
+
case "valueBoolean":
|
|
2090
|
+
case "valueInteger":
|
|
2091
|
+
case "valueDateTime":
|
|
2092
|
+
case "valueTime":
|
|
2093
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2094
|
+
break;
|
|
2095
|
+
case "valuePeriod":
|
|
2096
|
+
if (obsData["valuePeriodStart"] && obsData["valuePeriodEnd"]) {
|
|
2097
|
+
obsData["formattedValue"] = `${obsData["valuePeriodStart"]} - ${obsData["valuePeriodEnd"]}`;
|
|
2098
|
+
} else if (obsData["valuePeriodStart"]) {
|
|
2099
|
+
obsData["formattedValue"] = `From ${obsData["valuePeriodStart"]}`;
|
|
2100
|
+
} else if (obsData["valuePeriodEnd"]) {
|
|
2101
|
+
obsData["formattedValue"] = `Until ${obsData["valuePeriodEnd"]}`;
|
|
2102
|
+
}
|
|
2103
|
+
break;
|
|
2104
|
+
case "valueSampledData": {
|
|
2105
|
+
const sampledParts = [];
|
|
2106
|
+
if (obsData["sampledDataOriginValue"]) {
|
|
2107
|
+
sampledParts.push(`Origin: ${obsData["sampledDataOriginValue"]}${obsData["sampledDataOriginUnit"] ? " " + obsData["sampledDataOriginUnit"] : ""}`);
|
|
2108
|
+
}
|
|
2109
|
+
if (obsData["sampledDataPeriod"]) {
|
|
2110
|
+
sampledParts.push(`Period: ${obsData["sampledDataPeriod"]}`);
|
|
2111
|
+
}
|
|
2112
|
+
if (obsData["sampledDataFactor"]) {
|
|
2113
|
+
sampledParts.push(`Factor: ${obsData["sampledDataFactor"]}`);
|
|
2114
|
+
}
|
|
2115
|
+
if (obsData["sampledDataLowerLimit"]) {
|
|
2116
|
+
sampledParts.push(`Lower: ${obsData["sampledDataLowerLimit"]}`);
|
|
2117
|
+
}
|
|
2118
|
+
if (obsData["sampledDataUpperLimit"]) {
|
|
2119
|
+
sampledParts.push(`Upper: ${obsData["sampledDataUpperLimit"]}`);
|
|
2120
|
+
}
|
|
2121
|
+
if (obsData["sampledDataData"]) {
|
|
2122
|
+
sampledParts.push(`Data: ${obsData["sampledDataData"]}`);
|
|
2123
|
+
}
|
|
2124
|
+
obsData["formattedValue"] = sampledParts.join(", ");
|
|
2125
|
+
break;
|
|
2126
|
+
}
|
|
2127
|
+
case "valueRange": {
|
|
2128
|
+
const rangeParts = [];
|
|
2129
|
+
if (obsData["valueRangeLowValue"]) {
|
|
2130
|
+
rangeParts.push(`${obsData["valueRangeLowValue"]}${obsData["valueRangeLowUnit"] ? " " + obsData["valueRangeLowUnit"] : ""}`);
|
|
2131
|
+
}
|
|
2132
|
+
if (obsData["valueRangeHighValue"]) {
|
|
2133
|
+
rangeParts.push(`${obsData["valueRangeHighValue"]}${obsData["valueRangeHighUnit"] ? " " + obsData["valueRangeHighUnit"] : ""}`);
|
|
2134
|
+
}
|
|
2135
|
+
obsData["formattedValue"] = rangeParts.join(" - ");
|
|
2136
|
+
break;
|
|
2137
|
+
}
|
|
2138
|
+
case "valueRatio": {
|
|
2139
|
+
const numerator = obsData["valueRatioNumeratorValue"] ? `${obsData["valueRatioNumeratorValue"]}${obsData["valueRatioNumeratorUnit"] ? " " + obsData["valueRatioNumeratorUnit"] : ""}` : "";
|
|
2140
|
+
const denominator = obsData["valueRatioDenominatorValue"] ? `${obsData["valueRatioDenominatorValue"]}${obsData["valueRatioDenominatorUnit"] ? " " + obsData["valueRatioDenominatorUnit"] : ""}` : "";
|
|
2141
|
+
if (numerator && denominator) {
|
|
2142
|
+
obsData["formattedValue"] = `${numerator} / ${denominator}`;
|
|
2143
|
+
} else if (numerator) {
|
|
2144
|
+
obsData["formattedValue"] = numerator;
|
|
2145
|
+
}
|
|
2146
|
+
break;
|
|
2147
|
+
}
|
|
2148
|
+
default:
|
|
2149
|
+
obsData["formattedValue"] = obsData["value"] ?? "";
|
|
2150
|
+
break;
|
|
2151
|
+
}
|
|
2152
|
+
if (obsData["referenceRangeLow"]) {
|
|
2153
|
+
obsData["referenceRange"] = obsData["referenceRangeLow"] + " " + obsData["referenceRangeLowUnit"];
|
|
2154
|
+
}
|
|
2155
|
+
if (obsData["referenceRangeHigh"]) {
|
|
2156
|
+
if (obsData["referenceRange"]) {
|
|
2157
|
+
obsData["referenceRange"] += " - ";
|
|
2158
|
+
} else {
|
|
2159
|
+
obsData["referenceRange"] = "";
|
|
2160
|
+
}
|
|
2161
|
+
obsData["referenceRange"] += obsData["referenceRangeHigh"] + " " + obsData["referenceRangeHighUnit"];
|
|
2162
|
+
}
|
|
2163
|
+
if (obsData["referenceRangeAgeLowValue"] || obsData["referenceRangeAgeHighValue"]) {
|
|
2164
|
+
const ageParts = [];
|
|
2165
|
+
if (obsData["referenceRangeAgeLowValue"]) {
|
|
2166
|
+
ageParts.push(`${obsData["referenceRangeAgeLowValue"]}${obsData["referenceRangeAgeLowUnit"] ? " " + obsData["referenceRangeAgeLowUnit"] : ""}`);
|
|
2167
|
+
}
|
|
2168
|
+
if (obsData["referenceRangeAgeHighValue"]) {
|
|
2169
|
+
ageParts.push(`${obsData["referenceRangeAgeHighValue"]}${obsData["referenceRangeAgeHighUnit"] ? " " + obsData["referenceRangeAgeHighUnit"] : ""}`);
|
|
2170
|
+
}
|
|
2171
|
+
if (obsData["referenceRange"]) {
|
|
2172
|
+
obsData["referenceRange"] += ` (Age: ${ageParts.join(" - ")})`;
|
|
2173
|
+
} else {
|
|
2174
|
+
obsData["referenceRange"] = `Age: ${ageParts.join(" - ")}`;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* Helper function to extract observation field data
|
|
2180
|
+
* @param column - Column data from the summary
|
|
2181
|
+
* @param targetData - Record to populate with extracted data
|
|
2182
|
+
*/
|
|
2183
|
+
extractSummaryObservationFields(column, targetData) {
|
|
2184
|
+
switch (column.title) {
|
|
2185
|
+
case "Labs Name":
|
|
2186
|
+
targetData["code"] = column.text?.div ?? "";
|
|
2187
|
+
break;
|
|
2188
|
+
case "effectiveDateTime":
|
|
2189
|
+
targetData["effectiveDateTime"] = column.text?.div ?? "";
|
|
2190
|
+
break;
|
|
2191
|
+
case "effectivePeriod.start":
|
|
2192
|
+
targetData["effectivePeriodStart"] = column.text?.div ?? "";
|
|
2193
|
+
break;
|
|
2194
|
+
case "effectivePeriod.end":
|
|
2195
|
+
targetData["effectivePeriodEnd"] = column.text?.div ?? "";
|
|
2196
|
+
break;
|
|
2197
|
+
// valueQuantity
|
|
2198
|
+
case "valueQuantity.value":
|
|
2199
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2200
|
+
targetData["valueType"] = "valueQuantity";
|
|
2201
|
+
break;
|
|
2202
|
+
case "valueQuantity.unit":
|
|
2203
|
+
targetData["unit"] = column.text?.div ?? "";
|
|
2204
|
+
break;
|
|
2205
|
+
// valueCodeableConcept
|
|
2206
|
+
case "valueCodeableConcept.text":
|
|
2207
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2208
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2209
|
+
break;
|
|
2210
|
+
case "valueCodeableConcept.coding.display":
|
|
2211
|
+
if (!targetData["value"]) {
|
|
2212
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2213
|
+
targetData["valueType"] = "valueCodeableConcept";
|
|
2214
|
+
}
|
|
2215
|
+
break;
|
|
2216
|
+
// valueString
|
|
2217
|
+
case "valueString":
|
|
2218
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2219
|
+
targetData["valueType"] = "valueString";
|
|
2220
|
+
break;
|
|
2221
|
+
// valueBoolean
|
|
2222
|
+
case "valueBoolean":
|
|
2223
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2224
|
+
targetData["valueType"] = "valueBoolean";
|
|
2225
|
+
break;
|
|
2226
|
+
// valueInteger
|
|
2227
|
+
case "valueInteger":
|
|
2228
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2229
|
+
targetData["valueType"] = "valueInteger";
|
|
2230
|
+
break;
|
|
2231
|
+
// valueDateTime
|
|
2232
|
+
case "valueDateTime":
|
|
2233
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2234
|
+
targetData["valueType"] = "valueDateTime";
|
|
2235
|
+
break;
|
|
2236
|
+
// valuePeriod
|
|
2237
|
+
case "valuePeriod.start":
|
|
2238
|
+
targetData["valuePeriodStart"] = column.text?.div ?? "";
|
|
2239
|
+
targetData["valueType"] = "valuePeriod";
|
|
2240
|
+
break;
|
|
2241
|
+
case "valuePeriod.end":
|
|
2242
|
+
targetData["valuePeriodEnd"] = column.text?.div ?? "";
|
|
2243
|
+
targetData["valueType"] = "valuePeriod";
|
|
2244
|
+
break;
|
|
2245
|
+
// valueTime
|
|
2246
|
+
case "valueTime":
|
|
2247
|
+
targetData["value"] = column.text?.div ?? "";
|
|
2248
|
+
targetData["valueType"] = "valueTime";
|
|
2249
|
+
break;
|
|
2250
|
+
// valueSampledData
|
|
2251
|
+
case "valueSampledData.origin.value":
|
|
2252
|
+
targetData["sampledDataOriginValue"] = column.text?.div ?? "";
|
|
2253
|
+
targetData["valueType"] = "valueSampledData";
|
|
2254
|
+
break;
|
|
2255
|
+
case "valueSampledData.origin.unit":
|
|
2256
|
+
targetData["sampledDataOriginUnit"] = column.text?.div ?? "";
|
|
2257
|
+
break;
|
|
2258
|
+
case "valueSampledData.period":
|
|
2259
|
+
targetData["sampledDataPeriod"] = column.text?.div ?? "";
|
|
2260
|
+
break;
|
|
2261
|
+
case "valueSampledData.factor":
|
|
2262
|
+
targetData["sampledDataFactor"] = column.text?.div ?? "";
|
|
2263
|
+
break;
|
|
2264
|
+
case "valueSampledData.lowerLimit":
|
|
2265
|
+
targetData["sampledDataLowerLimit"] = column.text?.div ?? "";
|
|
2266
|
+
break;
|
|
2267
|
+
case "valueSampledData.upperLimit":
|
|
2268
|
+
targetData["sampledDataUpperLimit"] = column.text?.div ?? "";
|
|
2269
|
+
break;
|
|
2270
|
+
case "valueSampledData.data":
|
|
2271
|
+
targetData["sampledDataData"] = column.text?.div ?? "";
|
|
2272
|
+
break;
|
|
2273
|
+
// valueRange
|
|
2274
|
+
case "valueRange.low.value":
|
|
2275
|
+
targetData["valueRangeLowValue"] = column.text?.div ?? "";
|
|
2276
|
+
targetData["valueType"] = "valueRange";
|
|
2277
|
+
break;
|
|
2278
|
+
case "valueRange.low.unit":
|
|
2279
|
+
targetData["valueRangeLowUnit"] = column.text?.div ?? "";
|
|
2280
|
+
break;
|
|
2281
|
+
case "valueRange.high.value":
|
|
2282
|
+
targetData["valueRangeHighValue"] = column.text?.div ?? "";
|
|
2283
|
+
break;
|
|
2284
|
+
case "valueRange.high.unit":
|
|
2285
|
+
targetData["valueRangeHighUnit"] = column.text?.div ?? "";
|
|
2286
|
+
break;
|
|
2287
|
+
// valueRatio
|
|
2288
|
+
case "valueRatio.numerator.value":
|
|
2289
|
+
targetData["valueRatioNumeratorValue"] = column.text?.div ?? "";
|
|
2290
|
+
targetData["valueType"] = "valueRatio";
|
|
2291
|
+
break;
|
|
2292
|
+
case "valueRatio.numerator.unit":
|
|
2293
|
+
targetData["valueRatioNumeratorUnit"] = column.text?.div ?? "";
|
|
2294
|
+
break;
|
|
2295
|
+
case "valueRatio.denominator.value":
|
|
2296
|
+
targetData["valueRatioDenominatorValue"] = column.text?.div ?? "";
|
|
2297
|
+
break;
|
|
2298
|
+
case "valueRatio.denominator.unit":
|
|
2299
|
+
targetData["valueRatioDenominatorUnit"] = column.text?.div ?? "";
|
|
2300
|
+
break;
|
|
2301
|
+
// referenceRange
|
|
2302
|
+
case "referenceRange.low.value":
|
|
2303
|
+
targetData["referenceRangeLow"] = column.text?.div ?? "";
|
|
2304
|
+
break;
|
|
2305
|
+
case "referenceRange.low.unit":
|
|
2306
|
+
targetData["referenceRangeLowUnit"] = column.text?.div ?? "";
|
|
2307
|
+
break;
|
|
2308
|
+
case "referenceRange.high.value":
|
|
2309
|
+
targetData["referenceRangeHigh"] = column.text?.div ?? "";
|
|
2310
|
+
break;
|
|
2311
|
+
case "referenceRange.high.unit":
|
|
2312
|
+
targetData["referenceRangeHighUnit"] = column.text?.div ?? "";
|
|
2313
|
+
break;
|
|
2314
|
+
case "referenceRange.age.low.value":
|
|
2315
|
+
targetData["referenceRangeAgeLowValue"] = column.text?.div ?? "";
|
|
2316
|
+
break;
|
|
2317
|
+
case "referenceRange.age.low.unit":
|
|
2318
|
+
targetData["referenceRangeAgeLowUnit"] = column.text?.div ?? "";
|
|
2319
|
+
break;
|
|
2320
|
+
case "referenceRange.age.high.value":
|
|
2321
|
+
targetData["referenceRangeAgeHighValue"] = column.text?.div ?? "";
|
|
2322
|
+
break;
|
|
2323
|
+
case "referenceRange.age.high.unit":
|
|
2324
|
+
targetData["referenceRangeAgeHighUnit"] = column.text?.div ?? "";
|
|
2325
|
+
break;
|
|
2326
|
+
default:
|
|
2327
|
+
break;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
/**
|
|
2331
|
+
* Generate HTML narrative for Diagnostic Results & Observation resources using summary
|
|
2332
|
+
* @param resources - FHIR Composition resources
|
|
2333
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2334
|
+
* @returns HTML string for rendering
|
|
2335
|
+
*/
|
|
2336
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2337
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2338
|
+
let html = `
|
|
2339
|
+
<div>`;
|
|
2340
|
+
let observationhtml = `
|
|
2341
|
+
<div>
|
|
2342
|
+
<h3>Observations</h3>
|
|
2343
|
+
<table>
|
|
2344
|
+
<thead>
|
|
2345
|
+
<tr>
|
|
2346
|
+
<th>Code</th>
|
|
2347
|
+
<th>Result</th>
|
|
2348
|
+
<th>Reference Range</th>
|
|
2349
|
+
<th>Date</th>
|
|
2350
|
+
</tr>
|
|
2351
|
+
</thead>
|
|
2352
|
+
<tbody>`;
|
|
2353
|
+
let diagnosticReporthtml = `
|
|
2354
|
+
<div>
|
|
2355
|
+
<h3>Diagnostic Reports</h3>
|
|
2356
|
+
<table>
|
|
2357
|
+
<thead>
|
|
2358
|
+
<tr>
|
|
2359
|
+
<th>Report</th>
|
|
2360
|
+
<th>Performer</th>
|
|
2361
|
+
<th>Issued</th>
|
|
2362
|
+
</tr>
|
|
2363
|
+
</thead>
|
|
2364
|
+
<tbody>`;
|
|
2365
|
+
let observationExists = false;
|
|
2366
|
+
let diagnosticReportExists = false;
|
|
2367
|
+
for (const resourceItem of resources) {
|
|
2368
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2369
|
+
const data = {};
|
|
2370
|
+
const components = [];
|
|
2371
|
+
for (const columnData of rowData.section ?? []) {
|
|
2372
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2373
|
+
if (columnData.text?.div === "Observation.component" && columnData.section) {
|
|
2374
|
+
for (const componentSection of columnData.section) {
|
|
2375
|
+
const componentData = {};
|
|
2376
|
+
for (const nestedColumn of componentSection.section ?? []) {
|
|
2377
|
+
this.extractSummaryObservationFields(nestedColumn, componentData);
|
|
2378
|
+
}
|
|
2379
|
+
if (Object.keys(componentData).length > 0) {
|
|
2380
|
+
components.push(componentData);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
} else {
|
|
2384
|
+
this.extractSummaryObservationFields(columnData, data);
|
|
2385
|
+
}
|
|
2386
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2387
|
+
switch (columnData.title) {
|
|
2388
|
+
case "Diagnostic Report Name":
|
|
2389
|
+
data["report"] = columnData.text?.div ?? "";
|
|
2390
|
+
break;
|
|
2391
|
+
case "Performer":
|
|
2392
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2393
|
+
break;
|
|
2394
|
+
case "Issued Date":
|
|
2395
|
+
data["issued"] = columnData.text?.div ?? "";
|
|
2396
|
+
break;
|
|
2397
|
+
case "Status":
|
|
2398
|
+
data["status"] = columnData.text?.div ?? "";
|
|
2399
|
+
break;
|
|
2400
|
+
default:
|
|
2401
|
+
break;
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
|
|
2406
|
+
observationExists = true;
|
|
2407
|
+
let date = data["effectiveDateTime"] ? templateUtilities.renderTime(data["effectiveDateTime"], timezone) : "";
|
|
2408
|
+
if (!date && data["effectivePeriodStart"]) {
|
|
2409
|
+
date = templateUtilities.renderTime(data["effectivePeriodStart"], timezone);
|
|
2410
|
+
if (data["effectivePeriodEnd"]) {
|
|
2411
|
+
date += " - " + templateUtilities.renderTime(data["effectivePeriodEnd"], timezone);
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
if (components.length > 0) {
|
|
2415
|
+
const groupName = data["code"] ?? "";
|
|
2416
|
+
for (const component of components) {
|
|
2417
|
+
this.formatSummaryObservationData(component);
|
|
2418
|
+
observationhtml += `
|
|
2419
|
+
<tr>
|
|
2420
|
+
<td>${groupName ? groupName + " - " : ""}${component["code"] ?? "-"}</td>
|
|
2421
|
+
<td>${component["formattedValue"] ?? "-"}</td>
|
|
2422
|
+
<td>${component["referenceRange"]?.trim() ?? "-"}</td>
|
|
2423
|
+
<td>${date ?? "-"}</td>
|
|
2424
|
+
</tr>`;
|
|
2425
|
+
}
|
|
2426
|
+
} else {
|
|
2427
|
+
this.formatSummaryObservationData(data);
|
|
2428
|
+
observationhtml += `
|
|
2429
|
+
<tr>
|
|
2430
|
+
<td>${data["code"] ?? "-"}</td>
|
|
2431
|
+
<td>${data["formattedValue"] ?? "-"}</td>
|
|
2432
|
+
<td>${data["referenceRange"]?.trim() ?? "-"}</td>
|
|
2433
|
+
<td>${date ?? "-"}</td>
|
|
2434
|
+
</tr>`;
|
|
2435
|
+
}
|
|
2436
|
+
} else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
|
|
2437
|
+
if (data["status"] === "final") {
|
|
2438
|
+
diagnosticReportExists = true;
|
|
2439
|
+
diagnosticReporthtml += `
|
|
2440
|
+
<tr>
|
|
2441
|
+
<td>${data["report"] ?? "-"}</td>
|
|
2442
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2443
|
+
<td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
|
|
2444
|
+
</tr>`;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
if (observationExists) {
|
|
2450
|
+
html += observationhtml;
|
|
2451
|
+
html += `
|
|
2452
|
+
</tbody>
|
|
2453
|
+
</table>
|
|
2454
|
+
</div>`;
|
|
2455
|
+
}
|
|
2456
|
+
if (diagnosticReportExists) {
|
|
2457
|
+
html += diagnosticReporthtml;
|
|
2458
|
+
html += `
|
|
2459
|
+
</tbody>
|
|
2460
|
+
</table>
|
|
2461
|
+
</div>`;
|
|
2462
|
+
}
|
|
2463
|
+
html += `
|
|
2464
|
+
</div>`;
|
|
2465
|
+
return observationExists || diagnosticReportExists ? html : void 0;
|
|
2466
|
+
}
|
|
2063
2467
|
/**
|
|
2064
2468
|
* Internal static implementation that actually generates the narrative
|
|
2065
2469
|
* @param resources - FHIR resources array containing Observation and DiagnosticReport resources
|
|
@@ -2201,6 +2605,59 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
|
|
|
2201
2605
|
});
|
|
2202
2606
|
return _HistoryOfProceduresTemplate.generateStaticNarrative(resources, timezone);
|
|
2203
2607
|
}
|
|
2608
|
+
/**
|
|
2609
|
+
* Generate HTML narrative for Procedure resources using summary
|
|
2610
|
+
* @param resources - FHIR Composition resources
|
|
2611
|
+
* @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
|
|
2612
|
+
* @returns HTML string for rendering
|
|
2613
|
+
*/
|
|
2614
|
+
generateSummaryNarrative(resources, timezone) {
|
|
2615
|
+
const templateUtilities = new TemplateUtilities(resources);
|
|
2616
|
+
let isSummaryCreated = false;
|
|
2617
|
+
let html = `
|
|
2618
|
+
<div>
|
|
2619
|
+
<table>
|
|
2620
|
+
<thead>
|
|
2621
|
+
<tr>
|
|
2622
|
+
<th>Procedure</th>
|
|
2623
|
+
<th>Performer</th>
|
|
2624
|
+
<th>Date</th>
|
|
2625
|
+
</tr>
|
|
2626
|
+
</thead>
|
|
2627
|
+
<tbody>`;
|
|
2628
|
+
for (const resourceItem of resources) {
|
|
2629
|
+
for (const rowData of resourceItem.section ?? []) {
|
|
2630
|
+
const data = {};
|
|
2631
|
+
for (const columnData of rowData.section ?? []) {
|
|
2632
|
+
switch (columnData.title) {
|
|
2633
|
+
case "Procedure Name":
|
|
2634
|
+
data["procedure"] = columnData.text?.div ?? "";
|
|
2635
|
+
break;
|
|
2636
|
+
case "Performer":
|
|
2637
|
+
data["performer"] = columnData.text?.div ?? "";
|
|
2638
|
+
break;
|
|
2639
|
+
case "Performed Date":
|
|
2640
|
+
data["date"] = columnData.text?.div ?? "";
|
|
2641
|
+
break;
|
|
2642
|
+
default:
|
|
2643
|
+
break;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
isSummaryCreated = true;
|
|
2647
|
+
html += `
|
|
2648
|
+
<tr>
|
|
2649
|
+
<td>${data["procedure"] ?? "-"}</td>
|
|
2650
|
+
<td>${data["performer"] ?? "-"}</td>
|
|
2651
|
+
<td>${templateUtilities.renderTime(data["date"], timezone) ?? "-"}</td>
|
|
2652
|
+
</tr>`;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
html += `
|
|
2656
|
+
</tbody>
|
|
2657
|
+
</table>
|
|
2658
|
+
</div>`;
|
|
2659
|
+
return isSummaryCreated ? html : void 0;
|
|
2660
|
+
}
|
|
2204
2661
|
/**
|
|
2205
2662
|
* Internal static implementation that actually generates the narrative
|
|
2206
2663
|
* @param resources - FHIR Procedure resources
|
|
@@ -2383,6 +2840,7 @@ var PlanOfCareTemplate = class {
|
|
|
2383
2840
|
*/
|
|
2384
2841
|
generateSummaryNarrative(resources, timezone) {
|
|
2385
2842
|
const templateUtilities = new TemplateUtilities(resources);
|
|
2843
|
+
let isSummaryCreated = false;
|
|
2386
2844
|
let html = `
|
|
2387
2845
|
<div>
|
|
2388
2846
|
<table>
|
|
@@ -2406,6 +2864,7 @@ var PlanOfCareTemplate = class {
|
|
|
2406
2864
|
if (data["status"] !== "active") {
|
|
2407
2865
|
continue;
|
|
2408
2866
|
}
|
|
2867
|
+
isSummaryCreated = true;
|
|
2409
2868
|
html += `
|
|
2410
2869
|
<tr>
|
|
2411
2870
|
<td>${data["CarePlan Name"] ?? "-"}</td>
|
|
@@ -2419,7 +2878,7 @@ var PlanOfCareTemplate = class {
|
|
|
2419
2878
|
</tbody>
|
|
2420
2879
|
</table>
|
|
2421
2880
|
</div>`;
|
|
2422
|
-
return html;
|
|
2881
|
+
return isSummaryCreated ? html : void 0;
|
|
2423
2882
|
}
|
|
2424
2883
|
};
|
|
2425
2884
|
|
|
@@ -2872,11 +3331,13 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2872
3331
|
timezone,
|
|
2873
3332
|
true
|
|
2874
3333
|
);
|
|
2875
|
-
}
|
|
3334
|
+
}
|
|
3335
|
+
if (!narrative && sectionType in IPSMandatorySections) {
|
|
2876
3336
|
narrative = await NarrativeGenerator.createNarrativeAsync(
|
|
2877
3337
|
IPSMissingMandatorySectionContent[sectionType]
|
|
2878
3338
|
);
|
|
2879
|
-
}
|
|
3339
|
+
}
|
|
3340
|
+
if (!narrative) {
|
|
2880
3341
|
return this;
|
|
2881
3342
|
}
|
|
2882
3343
|
this.addSectionAsync(narrative, sectionType, validResources);
|
|
@@ -2894,13 +3355,21 @@ var ComprehensiveIPSCompositionBuilder = class {
|
|
|
2894
3355
|
}
|
|
2895
3356
|
});
|
|
2896
3357
|
}
|
|
2897
|
-
|
|
3358
|
+
let narrative = await NarrativeGenerator.generateNarrativeAsync(
|
|
2898
3359
|
sectionType,
|
|
2899
3360
|
summaryCompositions,
|
|
2900
3361
|
timezone,
|
|
2901
3362
|
true,
|
|
2902
3363
|
true
|
|
2903
3364
|
);
|
|
3365
|
+
if (!narrative && sectionType in IPSMandatorySections) {
|
|
3366
|
+
narrative = await NarrativeGenerator.createNarrativeAsync(
|
|
3367
|
+
IPSMissingMandatorySectionContent[sectionType]
|
|
3368
|
+
);
|
|
3369
|
+
}
|
|
3370
|
+
if (!narrative) {
|
|
3371
|
+
return this;
|
|
3372
|
+
}
|
|
2904
3373
|
this.addSectionAsync(narrative, sectionType, sectionResources);
|
|
2905
3374
|
return this;
|
|
2906
3375
|
}
|