@imranq2/fhirpatientsummary 1.0.24 → 1.0.26

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.
Files changed (3) hide show
  1. package/dist/index.cjs +142 -91
  2. package/dist/index.js +142 -91
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -142,7 +142,7 @@ var IPSSectionResourceFilters = {
142
142
  // Only include pregnancy history Observations
143
143
  ["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Observation" && (resource.code?.coding?.some((c) => Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS).includes(c.code)) || resource.valueCodeableConcept?.coding?.some((c) => Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME).includes(c.code))),
144
144
  // Only include Conditions or completed ClinicalImpressions
145
- ["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Condition" || resource.resourceType === "ClinicalImpression" && resource.status === "completed",
145
+ ["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => !["inactive", "resolved"].includes(c.code)) || resource.resourceType === "ClinicalImpression" && resource.status === "completed",
146
146
  // Only include resolved medical history Conditions
147
147
  ["HistoryOfPastIllnessSection" /* MEDICAL_HISTORY */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => ["inactive", "resolved"].includes(c.code)),
148
148
  // Only include active care plans
@@ -1326,6 +1326,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1326
1326
  */
1327
1327
  generateSummaryNarrative(resources, timezone) {
1328
1328
  const templateUtilities = new TemplateUtilities(resources);
1329
+ let isSummaryCreated = false;
1329
1330
  let html = `
1330
1331
  <div>
1331
1332
  <table>
@@ -1355,6 +1356,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1355
1356
  break;
1356
1357
  }
1357
1358
  }
1359
+ isSummaryCreated = true;
1358
1360
  html += `
1359
1361
  <tr>
1360
1362
  <td>${data["allergen"] ?? "-"}</td>
@@ -1367,7 +1369,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1367
1369
  </tbody>
1368
1370
  </table>
1369
1371
  </div>`;
1370
- return html;
1372
+ return isSummaryCreated ? html : void 0;
1371
1373
  }
1372
1374
  /**
1373
1375
  * Internal static implementation that actually generates the narrative
@@ -1513,6 +1515,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1513
1515
  */
1514
1516
  generateSummaryNarrative(resources, timezone) {
1515
1517
  const templateUtilities = new TemplateUtilities(resources);
1518
+ let isSummaryCreated = false;
1516
1519
  let html = `
1517
1520
  <div>
1518
1521
  <table>
@@ -1557,6 +1560,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1557
1560
  }
1558
1561
  }
1559
1562
  if (data["status"] === "active") {
1563
+ isSummaryCreated = true;
1560
1564
  html += `
1561
1565
  <tr>
1562
1566
  <td>${data["medication"]}</td>
@@ -1572,7 +1576,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1572
1576
  </tbody>
1573
1577
  </table>
1574
1578
  </div>`;
1575
- return html;
1579
+ return isSummaryCreated ? html : void 0;
1576
1580
  }
1577
1581
  /**
1578
1582
  * Safely parse a date string and return a valid Date object or null
@@ -1768,6 +1772,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1768
1772
  */
1769
1773
  generateSummaryNarrative(resources, timezone) {
1770
1774
  const templateUtilities = new TemplateUtilities(resources);
1775
+ let isSummaryCreated = false;
1771
1776
  let html = `
1772
1777
  <div>
1773
1778
  <table>
@@ -1798,6 +1803,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1798
1803
  }
1799
1804
  }
1800
1805
  if (data["status"] === "completed") {
1806
+ isSummaryCreated = true;
1801
1807
  html += `
1802
1808
  <tr>
1803
1809
  <td>${data["immunization"] ?? "-"}</td>
@@ -1811,7 +1817,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1811
1817
  </tbody>
1812
1818
  </table>
1813
1819
  </div>`;
1814
- return html;
1820
+ return isSummaryCreated ? html : void 0;
1815
1821
  }
1816
1822
  /**
1817
1823
  * Internal static implementation that actually generates the narrative
@@ -1881,8 +1887,8 @@ var ProblemListTemplate = class _ProblemListTemplate {
1881
1887
  let html = ``;
1882
1888
  const activeConditions = resources.map((entry) => entry) || [];
1883
1889
  activeConditions.sort((a, b) => {
1884
- const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
1885
- const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
1890
+ const dateA = a.recordedDate ? new Date(a.recordedDate).getTime() : 0;
1891
+ const dateB = b.recordedDate ? new Date(b.recordedDate).getTime() : 0;
1886
1892
  return dateB - dateA;
1887
1893
  });
1888
1894
  html += `
@@ -1895,12 +1901,17 @@ var ProblemListTemplate = class _ProblemListTemplate {
1895
1901
  </tr>
1896
1902
  </thead>
1897
1903
  <tbody>`;
1904
+ const addedConditionCodes = /* @__PURE__ */ new Set();
1898
1905
  for (const cond of activeConditions) {
1899
- html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
1900
- <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
1901
- <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
1902
- <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
1903
- </tr>`;
1906
+ const conditionCode = templateUtilities.codeableConcept(cond.code);
1907
+ if (!addedConditionCodes.has(conditionCode)) {
1908
+ addedConditionCodes.add(conditionCode);
1909
+ html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
1910
+ <td class="Name">${conditionCode}</td>
1911
+ <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
1912
+ <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
1913
+ </tr>`;
1914
+ }
1904
1915
  }
1905
1916
  html += `</tbody>
1906
1917
  </table>`;
@@ -1927,6 +1938,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1927
1938
  */
1928
1939
  generateSummaryNarrative(resources, timezone) {
1929
1940
  const templateUtilities = new TemplateUtilities(resources);
1941
+ let isSummaryCreated = false;
1930
1942
  let html = `
1931
1943
  <div>
1932
1944
  <table>
@@ -1966,6 +1978,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1966
1978
  data[columnTitle] = columnData.text?.div ?? "";
1967
1979
  }
1968
1980
  }
1981
+ isSummaryCreated = true;
1969
1982
  html += `
1970
1983
  <tr>
1971
1984
  <td>${data["Vital Name"] ?? "-"}</td>
@@ -1979,7 +1992,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1979
1992
  </tbody>
1980
1993
  </table>
1981
1994
  </div>`;
1982
- return html;
1995
+ return isSummaryCreated ? html : void 0;
1983
1996
  }
1984
1997
  /**
1985
1998
  * Internal static implementation that actually generates the narrative
@@ -2382,8 +2395,8 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2382
2395
  </tr>
2383
2396
  </thead>
2384
2397
  <tbody>`;
2385
- let observationExists = false;
2386
- let diagnosticReportExists = false;
2398
+ const observationAdded = /* @__PURE__ */ new Set();
2399
+ const diagnosticReportAdded = /* @__PURE__ */ new Set();
2387
2400
  for (const resourceItem of resources) {
2388
2401
  for (const rowData of resourceItem.section ?? []) {
2389
2402
  const data = {};
@@ -2423,7 +2436,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2423
2436
  }
2424
2437
  }
2425
2438
  if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
2426
- observationExists = true;
2427
2439
  let date = data["effectiveDateTime"] ? templateUtilities.renderTime(data["effectiveDateTime"], timezone) : "";
2428
2440
  if (!date && data["effectivePeriodStart"]) {
2429
2441
  date = templateUtilities.renderTime(data["effectivePeriodStart"], timezone);
@@ -2432,48 +2444,59 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2432
2444
  }
2433
2445
  }
2434
2446
  if (components.length > 0) {
2435
- const groupName = data["code"] ?? "";
2447
+ const groupName = data["code"] ? `${data["code"]} - ` : "";
2436
2448
  for (const component of components) {
2437
- this.formatSummaryObservationData(component);
2438
- observationhtml += `
2439
- <tr>
2440
- <td>${groupName ? groupName + " - " : ""}${component["code"] ?? "-"}</td>
2441
- <td>${component["formattedValue"] ?? "-"}</td>
2442
- <td>${component["referenceRange"]?.trim() ?? "-"}</td>
2443
- <td>${date ?? "-"}</td>
2444
- </tr>`;
2449
+ const componentCode = `${groupName}${component["code"] ?? ""}`;
2450
+ if (componentCode && !observationAdded.has(componentCode)) {
2451
+ observationAdded.add(componentCode);
2452
+ this.formatSummaryObservationData(component);
2453
+ observationhtml += `
2454
+ <tr>
2455
+ <td>${componentCode}</td>
2456
+ <td>${component["formattedValue"] ?? "-"}</td>
2457
+ <td>${component["referenceRange"]?.trim() ?? "-"}</td>
2458
+ <td>${date ?? "-"}</td>
2459
+ </tr>`;
2460
+ }
2445
2461
  }
2446
2462
  } else {
2447
- this.formatSummaryObservationData(data);
2448
- observationhtml += `
2449
- <tr>
2450
- <td>${data["code"] ?? "-"}</td>
2451
- <td>${data["formattedValue"] ?? "-"}</td>
2452
- <td>${data["referenceRange"]?.trim() ?? "-"}</td>
2453
- <td>${date ?? "-"}</td>
2454
- </tr>`;
2463
+ const code = data["code"] ?? "";
2464
+ if (code && !observationAdded.has(code)) {
2465
+ observationAdded.add(code);
2466
+ this.formatSummaryObservationData(data);
2467
+ observationhtml += `
2468
+ <tr>
2469
+ <td>${data["code"] ?? "-"}</td>
2470
+ <td>${data["formattedValue"] ?? "-"}</td>
2471
+ <td>${data["referenceRange"]?.trim() ?? "-"}</td>
2472
+ <td>${date ?? "-"}</td>
2473
+ </tr>`;
2474
+ }
2455
2475
  }
2456
2476
  } else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
2457
2477
  if (data["status"] === "final") {
2458
- diagnosticReportExists = true;
2459
- diagnosticReporthtml += `
2460
- <tr>
2461
- <td>${data["report"] ?? "-"}</td>
2462
- <td>${data["performer"] ?? "-"}</td>
2463
- <td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
2464
- </tr>`;
2478
+ const reportName = data["report"] ?? "";
2479
+ if (reportName && !diagnosticReportAdded.has(reportName)) {
2480
+ diagnosticReportAdded.add(reportName);
2481
+ diagnosticReporthtml += `
2482
+ <tr>
2483
+ <td>${data["report"] ?? "-"}</td>
2484
+ <td>${data["performer"] ?? "-"}</td>
2485
+ <td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
2486
+ </tr>`;
2487
+ }
2465
2488
  }
2466
2489
  }
2467
2490
  }
2468
2491
  }
2469
- if (observationExists) {
2492
+ if (observationAdded.size > 0) {
2470
2493
  html += observationhtml;
2471
2494
  html += `
2472
2495
  </tbody>
2473
2496
  </table>
2474
2497
  </div>`;
2475
2498
  }
2476
- if (diagnosticReportExists) {
2499
+ if (diagnosticReportAdded.size > 0) {
2477
2500
  html += diagnosticReporthtml;
2478
2501
  html += `
2479
2502
  </tbody>
@@ -2482,7 +2505,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2482
2505
  }
2483
2506
  html += `
2484
2507
  </div>`;
2485
- return html;
2508
+ return observationAdded.size > 0 || diagnosticReportAdded.size > 0 ? html : void 0;
2486
2509
  }
2487
2510
  /**
2488
2511
  * Internal static implementation that actually generates the narrative
@@ -2496,8 +2519,8 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2496
2519
  const observations = this.getObservations(resources);
2497
2520
  if (observations.length > 0) {
2498
2521
  observations.sort((a, b) => {
2499
- const dateA = a.effectiveDateTime || a.effectivePeriod?.start;
2500
- const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
2522
+ const dateA = a.effectiveDateTime || a.effectivePeriod?.start || a.effectivePeriod?.end;
2523
+ const dateB = b.effectiveDateTime || b.effectivePeriod?.start || b.effectivePeriod?.end;
2501
2524
  return dateA && dateB ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
2502
2525
  });
2503
2526
  html += this.renderObservations(templateUtilities, observations, timezone);
@@ -2552,17 +2575,22 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2552
2575
  </tr>
2553
2576
  </thead>
2554
2577
  <tbody>`;
2578
+ const observationAdded = /* @__PURE__ */ new Set();
2555
2579
  for (const obs of observations) {
2556
- html += `
2557
- <tr id="${templateUtilities.narrativeLinkId(obs)}">
2558
- <td>${templateUtilities.codeableConcept(obs.code)}</td>
2559
- <td>${templateUtilities.extractObservationValue(obs)}</td>
2560
- <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
2561
- <td>${templateUtilities.firstFromCodeableConceptList(obs.interpretation)}</td>
2562
- <td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
2563
- <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
2564
- <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
2565
- </tr>`;
2580
+ const obsCode = templateUtilities.codeableConcept(obs.code);
2581
+ if (!observationAdded.has(obsCode)) {
2582
+ observationAdded.add(obsCode);
2583
+ html += `
2584
+ <tr id="${templateUtilities.narrativeLinkId(obs)}">
2585
+ <td>${obsCode}</td>
2586
+ <td>${templateUtilities.extractObservationValue(obs)}</td>
2587
+ <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
2588
+ <td>${templateUtilities.firstFromCodeableConceptList(obs.interpretation)}</td>
2589
+ <td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
2590
+ <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
2591
+ <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
2592
+ </tr>`;
2593
+ }
2566
2594
  }
2567
2595
  html += `
2568
2596
  </tbody>
@@ -2589,18 +2617,23 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2589
2617
  </tr>
2590
2618
  </thead>
2591
2619
  <tbody>`;
2620
+ const diagnosticReportAdded = /* @__PURE__ */ new Set();
2592
2621
  for (const report of reports) {
2593
- let resultCount = "";
2594
- if (report.result && Array.isArray(report.result)) {
2595
- resultCount = `${report.result.length} result${report.result.length !== 1 ? "s" : ""}`;
2622
+ const reportName = templateUtilities.codeableConcept(report.code);
2623
+ if (!diagnosticReportAdded.has(reportName)) {
2624
+ diagnosticReportAdded.add(reportName);
2625
+ let resultCount = "";
2626
+ if (report.result && Array.isArray(report.result)) {
2627
+ resultCount = `${report.result.length} result${report.result.length !== 1 ? "s" : ""}`;
2628
+ }
2629
+ html += `
2630
+ <tr id="${templateUtilities.narrativeLinkId(report)}">
2631
+ <td>${reportName}</td>
2632
+ <td>${templateUtilities.firstFromCodeableConceptList(report.category)}</td>
2633
+ <td>${resultCount}</td>
2634
+ <td>${report.issued ? templateUtilities.renderTime(report.issued, timezone) : ""}</td>
2635
+ </tr>`;
2596
2636
  }
2597
- html += `
2598
- <tr id="${templateUtilities.narrativeLinkId(report)}">
2599
- <td>${templateUtilities.codeableConcept(report.code)}</td>
2600
- <td>${templateUtilities.firstFromCodeableConceptList(report.category)}</td>
2601
- <td>${resultCount}</td>
2602
- <td>${report.issued ? templateUtilities.renderTime(report.issued, timezone) : ""}</td>
2603
- </tr>`;
2604
2637
  }
2605
2638
  html += `
2606
2639
  </tbody>
@@ -2633,6 +2666,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
2633
2666
  */
2634
2667
  generateSummaryNarrative(resources, timezone) {
2635
2668
  const templateUtilities = new TemplateUtilities(resources);
2669
+ let isSummaryCreated = false;
2636
2670
  let html = `
2637
2671
  <div>
2638
2672
  <table>
@@ -2662,6 +2696,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
2662
2696
  break;
2663
2697
  }
2664
2698
  }
2699
+ isSummaryCreated = true;
2665
2700
  html += `
2666
2701
  <tr>
2667
2702
  <td>${data["procedure"] ?? "-"}</td>
@@ -2674,7 +2709,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
2674
2709
  </tbody>
2675
2710
  </table>
2676
2711
  </div>`;
2677
- return html;
2712
+ return isSummaryCreated ? html : void 0;
2678
2713
  }
2679
2714
  /**
2680
2715
  * Internal static implementation that actually generates the narrative
@@ -2778,8 +2813,8 @@ var PastHistoryOfIllnessTemplate = class {
2778
2813
  let html = ``;
2779
2814
  const resolvedConditions = resources.map((entry) => entry) || [];
2780
2815
  resolvedConditions.sort((a, b) => {
2781
- const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
2782
- const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
2816
+ const dateA = a.recordedDate ? new Date(a.recordedDate).getTime() : 0;
2817
+ const dateB = b.recordedDate ? new Date(b.recordedDate).getTime() : 0;
2783
2818
  return dateB - dateA;
2784
2819
  });
2785
2820
  html += `
@@ -2793,13 +2828,18 @@ var PastHistoryOfIllnessTemplate = class {
2793
2828
  </tr>
2794
2829
  </thead>
2795
2830
  <tbody>`;
2831
+ const addedConditionCodes = /* @__PURE__ */ new Set();
2796
2832
  for (const cond of resolvedConditions) {
2797
- html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2798
- <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
2799
- <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2800
- <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2801
- <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
2802
- </tr>`;
2833
+ const conditionCode = templateUtilities.codeableConcept(cond.code);
2834
+ if (!addedConditionCodes.has(conditionCode)) {
2835
+ addedConditionCodes.add(conditionCode);
2836
+ html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2837
+ <td class="Name">${conditionCode}</td>
2838
+ <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2839
+ <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2840
+ <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
2841
+ </tr>`;
2842
+ }
2803
2843
  }
2804
2844
  html += `</tbody>
2805
2845
  </table>`;
@@ -2858,6 +2898,7 @@ var PlanOfCareTemplate = class {
2858
2898
  */
2859
2899
  generateSummaryNarrative(resources, timezone) {
2860
2900
  const templateUtilities = new TemplateUtilities(resources);
2901
+ let isSummaryCreated = false;
2861
2902
  let html = `
2862
2903
  <div>
2863
2904
  <table>
@@ -2881,6 +2922,7 @@ var PlanOfCareTemplate = class {
2881
2922
  if (data["status"] !== "active") {
2882
2923
  continue;
2883
2924
  }
2925
+ isSummaryCreated = true;
2884
2926
  html += `
2885
2927
  <tr>
2886
2928
  <td>${data["CarePlan Name"] ?? "-"}</td>
@@ -2894,7 +2936,7 @@ var PlanOfCareTemplate = class {
2894
2936
  </tbody>
2895
2937
  </table>
2896
2938
  </div>`;
2897
- return html;
2939
+ return isSummaryCreated ? html : void 0;
2898
2940
  }
2899
2941
  };
2900
2942
 
@@ -2922,20 +2964,14 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2922
2964
  const clinicalImpressions = [];
2923
2965
  for (const resourceItem of resources) {
2924
2966
  if (resourceItem.resourceType === "Condition") {
2925
- const cond = resourceItem;
2926
- const isResolved = cond.clinicalStatus?.coding?.some(
2927
- (c) => c.code === "resolved" || c.code === "inactive" || c.display?.toLowerCase().includes("resolved")
2928
- );
2929
- if (!isResolved) {
2930
- activeConditions.push(cond);
2931
- }
2967
+ activeConditions.push(resourceItem);
2932
2968
  } else if (resourceItem.resourceType === "ClinicalImpression") {
2933
2969
  clinicalImpressions.push(resourceItem);
2934
2970
  }
2935
2971
  }
2936
2972
  activeConditions.sort((a, b) => {
2937
- const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
2938
- const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
2973
+ const dateA = a.recordedDate ? new Date(a.recordedDate).getTime() : 0;
2974
+ const dateB = b.recordedDate ? new Date(b.recordedDate).getTime() : 0;
2939
2975
  return dateB - dateA;
2940
2976
  });
2941
2977
  clinicalImpressions.sort((a, b) => {
@@ -2954,12 +2990,17 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2954
2990
  </tr>
2955
2991
  </thead>
2956
2992
  <tbody>`;
2993
+ const addedConditionCodes = /* @__PURE__ */ new Set();
2957
2994
  for (const cond of activeConditions) {
2958
- html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2959
- <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
2960
- <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2961
- <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2962
- </tr>`;
2995
+ const conditionCode = templateUtilities.codeableConcept(cond.code);
2996
+ if (!addedConditionCodes.has(conditionCode)) {
2997
+ addedConditionCodes.add(conditionCode);
2998
+ html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2999
+ <td class="Name">${conditionCode}</td>
3000
+ <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
3001
+ <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
3002
+ </tr>`;
3003
+ }
2963
3004
  }
2964
3005
  html += `</tbody>
2965
3006
  </table>`;
@@ -3347,11 +3388,13 @@ var ComprehensiveIPSCompositionBuilder = class {
3347
3388
  timezone,
3348
3389
  true
3349
3390
  );
3350
- } else if (sectionType in IPSMandatorySections) {
3391
+ }
3392
+ if (!narrative && sectionType in IPSMandatorySections) {
3351
3393
  narrative = await NarrativeGenerator.createNarrativeAsync(
3352
3394
  IPSMissingMandatorySectionContent[sectionType]
3353
3395
  );
3354
- } else {
3396
+ }
3397
+ if (!narrative) {
3355
3398
  return this;
3356
3399
  }
3357
3400
  this.addSectionAsync(narrative, sectionType, validResources);
@@ -3369,13 +3412,21 @@ var ComprehensiveIPSCompositionBuilder = class {
3369
3412
  }
3370
3413
  });
3371
3414
  }
3372
- const narrative = await NarrativeGenerator.generateNarrativeAsync(
3415
+ let narrative = await NarrativeGenerator.generateNarrativeAsync(
3373
3416
  sectionType,
3374
3417
  summaryCompositions,
3375
3418
  timezone,
3376
3419
  true,
3377
3420
  true
3378
3421
  );
3422
+ if (!narrative && sectionType in IPSMandatorySections) {
3423
+ narrative = await NarrativeGenerator.createNarrativeAsync(
3424
+ IPSMissingMandatorySectionContent[sectionType]
3425
+ );
3426
+ }
3427
+ if (!narrative) {
3428
+ return this;
3429
+ }
3379
3430
  this.addSectionAsync(narrative, sectionType, sectionResources);
3380
3431
  return this;
3381
3432
  }
package/dist/index.js CHANGED
@@ -114,7 +114,7 @@ var IPSSectionResourceFilters = {
114
114
  // Only include pregnancy history Observations
115
115
  ["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: (resource) => resource.resourceType === "Observation" && (resource.code?.coding?.some((c) => Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_STATUS).includes(c.code)) || resource.valueCodeableConcept?.coding?.some((c) => Object.keys(PREGNANCY_LOINC_CODES.PREGNANCY_OUTCOME).includes(c.code))),
116
116
  // Only include Conditions or completed ClinicalImpressions
117
- ["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Condition" || resource.resourceType === "ClinicalImpression" && resource.status === "completed",
117
+ ["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => !["inactive", "resolved"].includes(c.code)) || resource.resourceType === "ClinicalImpression" && resource.status === "completed",
118
118
  // Only include resolved medical history Conditions
119
119
  ["HistoryOfPastIllnessSection" /* MEDICAL_HISTORY */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => ["inactive", "resolved"].includes(c.code)),
120
120
  // Only include active care plans
@@ -1298,6 +1298,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1298
1298
  */
1299
1299
  generateSummaryNarrative(resources, timezone) {
1300
1300
  const templateUtilities = new TemplateUtilities(resources);
1301
+ let isSummaryCreated = false;
1301
1302
  let html = `
1302
1303
  <div>
1303
1304
  <table>
@@ -1327,6 +1328,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1327
1328
  break;
1328
1329
  }
1329
1330
  }
1331
+ isSummaryCreated = true;
1330
1332
  html += `
1331
1333
  <tr>
1332
1334
  <td>${data["allergen"] ?? "-"}</td>
@@ -1339,7 +1341,7 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1339
1341
  </tbody>
1340
1342
  </table>
1341
1343
  </div>`;
1342
- return html;
1344
+ return isSummaryCreated ? html : void 0;
1343
1345
  }
1344
1346
  /**
1345
1347
  * Internal static implementation that actually generates the narrative
@@ -1485,6 +1487,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1485
1487
  */
1486
1488
  generateSummaryNarrative(resources, timezone) {
1487
1489
  const templateUtilities = new TemplateUtilities(resources);
1490
+ let isSummaryCreated = false;
1488
1491
  let html = `
1489
1492
  <div>
1490
1493
  <table>
@@ -1529,6 +1532,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1529
1532
  }
1530
1533
  }
1531
1534
  if (data["status"] === "active") {
1535
+ isSummaryCreated = true;
1532
1536
  html += `
1533
1537
  <tr>
1534
1538
  <td>${data["medication"]}</td>
@@ -1544,7 +1548,7 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1544
1548
  </tbody>
1545
1549
  </table>
1546
1550
  </div>`;
1547
- return html;
1551
+ return isSummaryCreated ? html : void 0;
1548
1552
  }
1549
1553
  /**
1550
1554
  * Safely parse a date string and return a valid Date object or null
@@ -1740,6 +1744,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1740
1744
  */
1741
1745
  generateSummaryNarrative(resources, timezone) {
1742
1746
  const templateUtilities = new TemplateUtilities(resources);
1747
+ let isSummaryCreated = false;
1743
1748
  let html = `
1744
1749
  <div>
1745
1750
  <table>
@@ -1770,6 +1775,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1770
1775
  }
1771
1776
  }
1772
1777
  if (data["status"] === "completed") {
1778
+ isSummaryCreated = true;
1773
1779
  html += `
1774
1780
  <tr>
1775
1781
  <td>${data["immunization"] ?? "-"}</td>
@@ -1783,7 +1789,7 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1783
1789
  </tbody>
1784
1790
  </table>
1785
1791
  </div>`;
1786
- return html;
1792
+ return isSummaryCreated ? html : void 0;
1787
1793
  }
1788
1794
  /**
1789
1795
  * Internal static implementation that actually generates the narrative
@@ -1853,8 +1859,8 @@ var ProblemListTemplate = class _ProblemListTemplate {
1853
1859
  let html = ``;
1854
1860
  const activeConditions = resources.map((entry) => entry) || [];
1855
1861
  activeConditions.sort((a, b) => {
1856
- const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
1857
- const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
1862
+ const dateA = a.recordedDate ? new Date(a.recordedDate).getTime() : 0;
1863
+ const dateB = b.recordedDate ? new Date(b.recordedDate).getTime() : 0;
1858
1864
  return dateB - dateA;
1859
1865
  });
1860
1866
  html += `
@@ -1867,12 +1873,17 @@ var ProblemListTemplate = class _ProblemListTemplate {
1867
1873
  </tr>
1868
1874
  </thead>
1869
1875
  <tbody>`;
1876
+ const addedConditionCodes = /* @__PURE__ */ new Set();
1870
1877
  for (const cond of activeConditions) {
1871
- html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
1872
- <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
1873
- <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
1874
- <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
1875
- </tr>`;
1878
+ const conditionCode = templateUtilities.codeableConcept(cond.code);
1879
+ if (!addedConditionCodes.has(conditionCode)) {
1880
+ addedConditionCodes.add(conditionCode);
1881
+ html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
1882
+ <td class="Name">${conditionCode}</td>
1883
+ <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
1884
+ <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
1885
+ </tr>`;
1886
+ }
1876
1887
  }
1877
1888
  html += `</tbody>
1878
1889
  </table>`;
@@ -1899,6 +1910,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1899
1910
  */
1900
1911
  generateSummaryNarrative(resources, timezone) {
1901
1912
  const templateUtilities = new TemplateUtilities(resources);
1913
+ let isSummaryCreated = false;
1902
1914
  let html = `
1903
1915
  <div>
1904
1916
  <table>
@@ -1938,6 +1950,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1938
1950
  data[columnTitle] = columnData.text?.div ?? "";
1939
1951
  }
1940
1952
  }
1953
+ isSummaryCreated = true;
1941
1954
  html += `
1942
1955
  <tr>
1943
1956
  <td>${data["Vital Name"] ?? "-"}</td>
@@ -1951,7 +1964,7 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1951
1964
  </tbody>
1952
1965
  </table>
1953
1966
  </div>`;
1954
- return html;
1967
+ return isSummaryCreated ? html : void 0;
1955
1968
  }
1956
1969
  /**
1957
1970
  * Internal static implementation that actually generates the narrative
@@ -2354,8 +2367,8 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2354
2367
  </tr>
2355
2368
  </thead>
2356
2369
  <tbody>`;
2357
- let observationExists = false;
2358
- let diagnosticReportExists = false;
2370
+ const observationAdded = /* @__PURE__ */ new Set();
2371
+ const diagnosticReportAdded = /* @__PURE__ */ new Set();
2359
2372
  for (const resourceItem of resources) {
2360
2373
  for (const rowData of resourceItem.section ?? []) {
2361
2374
  const data = {};
@@ -2395,7 +2408,6 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2395
2408
  }
2396
2409
  }
2397
2410
  if (resourceItem.title === "Observation|Labs Summary Grouped by Lab Code") {
2398
- observationExists = true;
2399
2411
  let date = data["effectiveDateTime"] ? templateUtilities.renderTime(data["effectiveDateTime"], timezone) : "";
2400
2412
  if (!date && data["effectivePeriodStart"]) {
2401
2413
  date = templateUtilities.renderTime(data["effectivePeriodStart"], timezone);
@@ -2404,48 +2416,59 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2404
2416
  }
2405
2417
  }
2406
2418
  if (components.length > 0) {
2407
- const groupName = data["code"] ?? "";
2419
+ const groupName = data["code"] ? `${data["code"]} - ` : "";
2408
2420
  for (const component of components) {
2409
- this.formatSummaryObservationData(component);
2410
- observationhtml += `
2411
- <tr>
2412
- <td>${groupName ? groupName + " - " : ""}${component["code"] ?? "-"}</td>
2413
- <td>${component["formattedValue"] ?? "-"}</td>
2414
- <td>${component["referenceRange"]?.trim() ?? "-"}</td>
2415
- <td>${date ?? "-"}</td>
2416
- </tr>`;
2421
+ const componentCode = `${groupName}${component["code"] ?? ""}`;
2422
+ if (componentCode && !observationAdded.has(componentCode)) {
2423
+ observationAdded.add(componentCode);
2424
+ this.formatSummaryObservationData(component);
2425
+ observationhtml += `
2426
+ <tr>
2427
+ <td>${componentCode}</td>
2428
+ <td>${component["formattedValue"] ?? "-"}</td>
2429
+ <td>${component["referenceRange"]?.trim() ?? "-"}</td>
2430
+ <td>${date ?? "-"}</td>
2431
+ </tr>`;
2432
+ }
2417
2433
  }
2418
2434
  } else {
2419
- this.formatSummaryObservationData(data);
2420
- observationhtml += `
2421
- <tr>
2422
- <td>${data["code"] ?? "-"}</td>
2423
- <td>${data["formattedValue"] ?? "-"}</td>
2424
- <td>${data["referenceRange"]?.trim() ?? "-"}</td>
2425
- <td>${date ?? "-"}</td>
2426
- </tr>`;
2435
+ const code = data["code"] ?? "";
2436
+ if (code && !observationAdded.has(code)) {
2437
+ observationAdded.add(code);
2438
+ this.formatSummaryObservationData(data);
2439
+ observationhtml += `
2440
+ <tr>
2441
+ <td>${data["code"] ?? "-"}</td>
2442
+ <td>${data["formattedValue"] ?? "-"}</td>
2443
+ <td>${data["referenceRange"]?.trim() ?? "-"}</td>
2444
+ <td>${date ?? "-"}</td>
2445
+ </tr>`;
2446
+ }
2427
2447
  }
2428
2448
  } else if (resourceItem.title === "DiagnosticReportLab Summary Grouped by DiagnosticReport|Lab Code") {
2429
2449
  if (data["status"] === "final") {
2430
- diagnosticReportExists = true;
2431
- diagnosticReporthtml += `
2432
- <tr>
2433
- <td>${data["report"] ?? "-"}</td>
2434
- <td>${data["performer"] ?? "-"}</td>
2435
- <td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
2436
- </tr>`;
2450
+ const reportName = data["report"] ?? "";
2451
+ if (reportName && !diagnosticReportAdded.has(reportName)) {
2452
+ diagnosticReportAdded.add(reportName);
2453
+ diagnosticReporthtml += `
2454
+ <tr>
2455
+ <td>${data["report"] ?? "-"}</td>
2456
+ <td>${data["performer"] ?? "-"}</td>
2457
+ <td>${templateUtilities.renderTime(data["issued"], timezone) ?? "-"}</td>
2458
+ </tr>`;
2459
+ }
2437
2460
  }
2438
2461
  }
2439
2462
  }
2440
2463
  }
2441
- if (observationExists) {
2464
+ if (observationAdded.size > 0) {
2442
2465
  html += observationhtml;
2443
2466
  html += `
2444
2467
  </tbody>
2445
2468
  </table>
2446
2469
  </div>`;
2447
2470
  }
2448
- if (diagnosticReportExists) {
2471
+ if (diagnosticReportAdded.size > 0) {
2449
2472
  html += diagnosticReporthtml;
2450
2473
  html += `
2451
2474
  </tbody>
@@ -2454,7 +2477,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2454
2477
  }
2455
2478
  html += `
2456
2479
  </div>`;
2457
- return html;
2480
+ return observationAdded.size > 0 || diagnosticReportAdded.size > 0 ? html : void 0;
2458
2481
  }
2459
2482
  /**
2460
2483
  * Internal static implementation that actually generates the narrative
@@ -2468,8 +2491,8 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2468
2491
  const observations = this.getObservations(resources);
2469
2492
  if (observations.length > 0) {
2470
2493
  observations.sort((a, b) => {
2471
- const dateA = a.effectiveDateTime || a.effectivePeriod?.start;
2472
- const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
2494
+ const dateA = a.effectiveDateTime || a.effectivePeriod?.start || a.effectivePeriod?.end;
2495
+ const dateB = b.effectiveDateTime || b.effectivePeriod?.start || b.effectivePeriod?.end;
2473
2496
  return dateA && dateB ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
2474
2497
  });
2475
2498
  html += this.renderObservations(templateUtilities, observations, timezone);
@@ -2524,17 +2547,22 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2524
2547
  </tr>
2525
2548
  </thead>
2526
2549
  <tbody>`;
2550
+ const observationAdded = /* @__PURE__ */ new Set();
2527
2551
  for (const obs of observations) {
2528
- html += `
2529
- <tr id="${templateUtilities.narrativeLinkId(obs)}">
2530
- <td>${templateUtilities.codeableConcept(obs.code)}</td>
2531
- <td>${templateUtilities.extractObservationValue(obs)}</td>
2532
- <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
2533
- <td>${templateUtilities.firstFromCodeableConceptList(obs.interpretation)}</td>
2534
- <td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
2535
- <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
2536
- <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
2537
- </tr>`;
2552
+ const obsCode = templateUtilities.codeableConcept(obs.code);
2553
+ if (!observationAdded.has(obsCode)) {
2554
+ observationAdded.add(obsCode);
2555
+ html += `
2556
+ <tr id="${templateUtilities.narrativeLinkId(obs)}">
2557
+ <td>${obsCode}</td>
2558
+ <td>${templateUtilities.extractObservationValue(obs)}</td>
2559
+ <td>${templateUtilities.extractObservationValueUnit(obs)}</td>
2560
+ <td>${templateUtilities.firstFromCodeableConceptList(obs.interpretation)}</td>
2561
+ <td>${templateUtilities.concatReferenceRange(obs.referenceRange)}</td>
2562
+ <td>${templateUtilities.renderNotes(obs.note, timezone)}</td>
2563
+ <td>${obs.effectiveDateTime ? templateUtilities.renderTime(obs.effectiveDateTime, timezone) : obs.effectivePeriod ? templateUtilities.renderPeriod(obs.effectivePeriod, timezone) : ""}</td>
2564
+ </tr>`;
2565
+ }
2538
2566
  }
2539
2567
  html += `
2540
2568
  </tbody>
@@ -2561,18 +2589,23 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
2561
2589
  </tr>
2562
2590
  </thead>
2563
2591
  <tbody>`;
2592
+ const diagnosticReportAdded = /* @__PURE__ */ new Set();
2564
2593
  for (const report of reports) {
2565
- let resultCount = "";
2566
- if (report.result && Array.isArray(report.result)) {
2567
- resultCount = `${report.result.length} result${report.result.length !== 1 ? "s" : ""}`;
2594
+ const reportName = templateUtilities.codeableConcept(report.code);
2595
+ if (!diagnosticReportAdded.has(reportName)) {
2596
+ diagnosticReportAdded.add(reportName);
2597
+ let resultCount = "";
2598
+ if (report.result && Array.isArray(report.result)) {
2599
+ resultCount = `${report.result.length} result${report.result.length !== 1 ? "s" : ""}`;
2600
+ }
2601
+ html += `
2602
+ <tr id="${templateUtilities.narrativeLinkId(report)}">
2603
+ <td>${reportName}</td>
2604
+ <td>${templateUtilities.firstFromCodeableConceptList(report.category)}</td>
2605
+ <td>${resultCount}</td>
2606
+ <td>${report.issued ? templateUtilities.renderTime(report.issued, timezone) : ""}</td>
2607
+ </tr>`;
2568
2608
  }
2569
- html += `
2570
- <tr id="${templateUtilities.narrativeLinkId(report)}">
2571
- <td>${templateUtilities.codeableConcept(report.code)}</td>
2572
- <td>${templateUtilities.firstFromCodeableConceptList(report.category)}</td>
2573
- <td>${resultCount}</td>
2574
- <td>${report.issued ? templateUtilities.renderTime(report.issued, timezone) : ""}</td>
2575
- </tr>`;
2576
2609
  }
2577
2610
  html += `
2578
2611
  </tbody>
@@ -2605,6 +2638,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
2605
2638
  */
2606
2639
  generateSummaryNarrative(resources, timezone) {
2607
2640
  const templateUtilities = new TemplateUtilities(resources);
2641
+ let isSummaryCreated = false;
2608
2642
  let html = `
2609
2643
  <div>
2610
2644
  <table>
@@ -2634,6 +2668,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
2634
2668
  break;
2635
2669
  }
2636
2670
  }
2671
+ isSummaryCreated = true;
2637
2672
  html += `
2638
2673
  <tr>
2639
2674
  <td>${data["procedure"] ?? "-"}</td>
@@ -2646,7 +2681,7 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
2646
2681
  </tbody>
2647
2682
  </table>
2648
2683
  </div>`;
2649
- return html;
2684
+ return isSummaryCreated ? html : void 0;
2650
2685
  }
2651
2686
  /**
2652
2687
  * Internal static implementation that actually generates the narrative
@@ -2750,8 +2785,8 @@ var PastHistoryOfIllnessTemplate = class {
2750
2785
  let html = ``;
2751
2786
  const resolvedConditions = resources.map((entry) => entry) || [];
2752
2787
  resolvedConditions.sort((a, b) => {
2753
- const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
2754
- const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
2788
+ const dateA = a.recordedDate ? new Date(a.recordedDate).getTime() : 0;
2789
+ const dateB = b.recordedDate ? new Date(b.recordedDate).getTime() : 0;
2755
2790
  return dateB - dateA;
2756
2791
  });
2757
2792
  html += `
@@ -2765,13 +2800,18 @@ var PastHistoryOfIllnessTemplate = class {
2765
2800
  </tr>
2766
2801
  </thead>
2767
2802
  <tbody>`;
2803
+ const addedConditionCodes = /* @__PURE__ */ new Set();
2768
2804
  for (const cond of resolvedConditions) {
2769
- html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2770
- <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
2771
- <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2772
- <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2773
- <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
2774
- </tr>`;
2805
+ const conditionCode = templateUtilities.codeableConcept(cond.code);
2806
+ if (!addedConditionCodes.has(conditionCode)) {
2807
+ addedConditionCodes.add(conditionCode);
2808
+ html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2809
+ <td class="Name">${conditionCode}</td>
2810
+ <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2811
+ <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2812
+ <td class="ResolvedDate">${templateUtilities.renderDate(cond.abatementDateTime)}</td>
2813
+ </tr>`;
2814
+ }
2775
2815
  }
2776
2816
  html += `</tbody>
2777
2817
  </table>`;
@@ -2830,6 +2870,7 @@ var PlanOfCareTemplate = class {
2830
2870
  */
2831
2871
  generateSummaryNarrative(resources, timezone) {
2832
2872
  const templateUtilities = new TemplateUtilities(resources);
2873
+ let isSummaryCreated = false;
2833
2874
  let html = `
2834
2875
  <div>
2835
2876
  <table>
@@ -2853,6 +2894,7 @@ var PlanOfCareTemplate = class {
2853
2894
  if (data["status"] !== "active") {
2854
2895
  continue;
2855
2896
  }
2897
+ isSummaryCreated = true;
2856
2898
  html += `
2857
2899
  <tr>
2858
2900
  <td>${data["CarePlan Name"] ?? "-"}</td>
@@ -2866,7 +2908,7 @@ var PlanOfCareTemplate = class {
2866
2908
  </tbody>
2867
2909
  </table>
2868
2910
  </div>`;
2869
- return html;
2911
+ return isSummaryCreated ? html : void 0;
2870
2912
  }
2871
2913
  };
2872
2914
 
@@ -2894,20 +2936,14 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2894
2936
  const clinicalImpressions = [];
2895
2937
  for (const resourceItem of resources) {
2896
2938
  if (resourceItem.resourceType === "Condition") {
2897
- const cond = resourceItem;
2898
- const isResolved = cond.clinicalStatus?.coding?.some(
2899
- (c) => c.code === "resolved" || c.code === "inactive" || c.display?.toLowerCase().includes("resolved")
2900
- );
2901
- if (!isResolved) {
2902
- activeConditions.push(cond);
2903
- }
2939
+ activeConditions.push(resourceItem);
2904
2940
  } else if (resourceItem.resourceType === "ClinicalImpression") {
2905
2941
  clinicalImpressions.push(resourceItem);
2906
2942
  }
2907
2943
  }
2908
2944
  activeConditions.sort((a, b) => {
2909
- const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
2910
- const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
2945
+ const dateA = a.recordedDate ? new Date(a.recordedDate).getTime() : 0;
2946
+ const dateB = b.recordedDate ? new Date(b.recordedDate).getTime() : 0;
2911
2947
  return dateB - dateA;
2912
2948
  });
2913
2949
  clinicalImpressions.sort((a, b) => {
@@ -2926,12 +2962,17 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2926
2962
  </tr>
2927
2963
  </thead>
2928
2964
  <tbody>`;
2965
+ const addedConditionCodes = /* @__PURE__ */ new Set();
2929
2966
  for (const cond of activeConditions) {
2930
- html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2931
- <td class="Name">${templateUtilities.codeableConcept(cond.code)}</td>
2932
- <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2933
- <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2934
- </tr>`;
2967
+ const conditionCode = templateUtilities.codeableConcept(cond.code);
2968
+ if (!addedConditionCodes.has(conditionCode)) {
2969
+ addedConditionCodes.add(conditionCode);
2970
+ html += `<tr id="${templateUtilities.narrativeLinkId(cond)}">
2971
+ <td class="Name">${conditionCode}</td>
2972
+ <td class="OnsetDate">${templateUtilities.renderDate(cond.onsetDateTime)}</td>
2973
+ <td class="RecordedDate">${templateUtilities.renderDate(cond.recordedDate)}</td>
2974
+ </tr>`;
2975
+ }
2935
2976
  }
2936
2977
  html += `</tbody>
2937
2978
  </table>`;
@@ -3319,11 +3360,13 @@ var ComprehensiveIPSCompositionBuilder = class {
3319
3360
  timezone,
3320
3361
  true
3321
3362
  );
3322
- } else if (sectionType in IPSMandatorySections) {
3363
+ }
3364
+ if (!narrative && sectionType in IPSMandatorySections) {
3323
3365
  narrative = await NarrativeGenerator.createNarrativeAsync(
3324
3366
  IPSMissingMandatorySectionContent[sectionType]
3325
3367
  );
3326
- } else {
3368
+ }
3369
+ if (!narrative) {
3327
3370
  return this;
3328
3371
  }
3329
3372
  this.addSectionAsync(narrative, sectionType, validResources);
@@ -3341,13 +3384,21 @@ var ComprehensiveIPSCompositionBuilder = class {
3341
3384
  }
3342
3385
  });
3343
3386
  }
3344
- const narrative = await NarrativeGenerator.generateNarrativeAsync(
3387
+ let narrative = await NarrativeGenerator.generateNarrativeAsync(
3345
3388
  sectionType,
3346
3389
  summaryCompositions,
3347
3390
  timezone,
3348
3391
  true,
3349
3392
  true
3350
3393
  );
3394
+ if (!narrative && sectionType in IPSMandatorySections) {
3395
+ narrative = await NarrativeGenerator.createNarrativeAsync(
3396
+ IPSMissingMandatorySectionContent[sectionType]
3397
+ );
3398
+ }
3399
+ if (!narrative) {
3400
+ return this;
3401
+ }
3351
3402
  this.addSectionAsync(narrative, sectionType, sectionResources);
3352
3403
  return this;
3353
3404
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imranq2/fhirpatientsummary",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "A template for creating npm packages using TypeScript and VSCode",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",