2 * @package OpenEMR CCDAServer
3 * @link http://www.open-emr.org
5 * @author Jerry Padgett <sjpadgett@gmail.com>
6 * @copyright Copyright (c) 2016-2021 Jerry Padgett <sjpadgett@gmail.com>
7 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
11 const net = require('net');
12 const server = net.createServer();
13 const to_json = require('xmljson').to_json;
14 const bbg = require(__dirname + '/oe-blue-button-generate');
15 const fs = require('fs');
17 var conn = ''; // make our connection scope global to script
24 if (typeof s === 'string') return s.trim();
28 function fDate(str, lim8=false) {
31 let rtn = str.substring(0, 8);
34 if (Number(str) === 0) {
35 return (new Date()).toISOString().slice(0, 10).replace(/-/g, "");
37 if (str.length === 1 || str === "0000-00-00") return (new Date()).toISOString().slice(0, 10).replace(/-/g, "");
38 if (str.length === 8 || (str.length === 14 && (1 * str.substring(12, 14)) === 0)) {
39 return [str.slice(0, 4), str.slice(4, 6), str.slice(6, 8)].join('-')
40 } else if (str.length === 10 && (1 * str.substring(0, 2)) <= 12) {
41 // case mm/dd/yyyy or mm-dd-yyyy
42 return [str.slice(6, 10), str.slice(0, 2), str.slice(3, 5)].join('-')
43 } else if (str.length === 14 && (1 * str.substring(12, 14)) > 0) {
44 // maybe a real time so parse
50 function getPrecision(str) {
54 if (Number(str) === 0) {
60 if (str.length > 12) {
67 function templateDate(date, precision) {
68 return {'date': fDate(date), 'precision': precision}
71 function cleanCode(code) {
72 if (code.length < 2) {
75 return code.replace(/[.#]/, "");
80 if (who !== null && typeof who === 'object') {
81 return (who.hasOwnProperty('extension') || who.hasOwnProperty('id') || who.hasOwnProperty('date')) ? 1 : Object.keys(who).length;
89 function headReplace(content) {
90 var r = '<?xml version="1.0" encoding="UTF-8"?>\n<?xml-stylesheet type="text/xsl" href="CDA.xsl"?>\n';
91 r += content.substr(content.search(/<ClinicalDocument/i));
95 function populateDemographic(pd, g) {
97 "relation": g.relation,
99 "street_lines": [g.address],
103 "country": g.country || "US",
104 "use": "primary home"
107 "last": g.display_name, //@todo parse first/last
108 "first": g.display_name
112 "type": "primary home"
118 "middle": [pd.mname],
123 "middle": pd.birth_mname || pd.mname,
124 "last": pd.birth_lname || pd.lname,
125 "first": pd.birth_fname || pd.fname
129 "date": fDate(pd.dob),
133 "gender": pd.gender.toUpperCase(),
135 "identifier": oidFacility,
136 "extension": "PT-" + pd.id
138 "marital_status": pd.status.toUpperCase(),
140 "street_lines": [pd.street],
143 "zip": pd.postalCode,
144 "country": pd.country || "US",
145 "use": "primary home"
149 "number": pd.phone_home,
150 "type": "primary home"
152 "number": pd.phone_mobile,
153 "type": "primary mobile"
156 "ethnicity": pd.ethnicity || "",
157 "race": pd.race || "",
158 "race_additional": pd.race == "White" ? "European" : "African",
160 "language": pd.language === 'English' ? "en-US" : pd.language === 'Spanish' ? "sp-US" : 'en-US',
162 "mode": "Expressed spoken",
163 "proficiency": "Good"
165 //"religion": pd.religion.toUpperCase() || "UNK",
172 "attributed_provider": {
175 "root": "2.16.840.1.113883.4.6",
176 "extension": npiFacility || "UNK"
180 "number": all.encounter_provider.facility_phone || "UNK",
184 "full": all.encounter_provider.facility_name || "UNK"
190 all.encounter_provider.facility_street
192 "city": all.encounter_provider.facility_city,
193 "state": all.encounter_provider.facility_state,
194 "zip": all.encounter_provider.facility_postal_code,
195 "country": all.encounter_provider.facility_country_code || "US",
200 //"guardians": g.display_name ? guardian : '' //not required
205 function populateProviders() {
212 "code_system_name": "SNOMED CT"
226 "root": "2.16.840.1.113883.4.6",
227 "extension": all.primary_care_provider.provider[0].npi || "UNK"
232 "name": all.primary_care_provider.provider[0].physician_type || "UNK",
233 "code": cleanCode(all.primary_care_provider.provider[0].physician_type_code) || "UNK",
234 "code_system_name": "Provider Codes"
239 "last": all.primary_care_provider.provider[0].lname || "UNK",
240 "first": all.primary_care_provider.provider[0].fname || "UNK"
246 all.encounter_provider.facility_street
248 "city": all.encounter_provider.facility_city,
249 "state": all.encounter_provider.facility_state,
250 "zip": all.encounter_provider.facility_postal_code,
251 "country": all.encounter_provider.facility_country_code || "US"
257 "number": all.encounter_provider.facility_phone || "",
265 "identifier": "2.16.840.1.113883.19.5.9999.1393" //@todo need facility oid
269 all.encounter_provider.facility_name
274 all.encounter_provider.facility_street
276 "city": all.encounter_provider.facility_city,
277 "state": all.encounter_provider.facility_state,
278 "zip": all.encounter_provider.facility_postal_code,
279 "country": all.encounter_provider.facility_country_code || "US"
284 "number": all.encounter_provider.facility_phone,
285 "type": "primary work"
296 function populateMedication(pd) {
297 pd.status = 'Completed'; //@todo invoke prescribed
301 "date": fDate(pd.start_date),
305 "date": fDate(pd.end_date),
310 "identifier": pd.sha_extension,
311 "extension": pd.extension || "UNK"
317 "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8",
320 "unencoded_name": pd.drug,
323 "code": cleanCode(pd.rxnorm),
327 "code_system_name": "RXNORM"
329 "code_system_name": "RXNORM"
336 "date": fDate(pd.start_date),
340 "date": fDate(pd.end_date),
348 "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8",
351 "unencoded_name": pd.drug,
354 "code": cleanCode(pd.rxnorm),
358 "code_system_name": "RXNORM"
360 "code_system_name": "RXNORM"
367 "date": fDate(pd.start_date),
368 "precision": getPrecision(fDate(pd.start_date))
372 "identifier": "2.16.840.1.113883.4.6",
373 "extension": pd.npi || "UNK"
383 "name": "instruction",
385 "code_system_name": "SNOMED CT"
387 "free_text": pd.instructions || "No Instructions"
392 "name": pd.route || "",
393 "code": cleanCode(pd.route_code) || "UNK",
394 "code_system_name": "Medication Route FDA"
398 "code": cleanCode(pd.form_code),
399 "code_system_name": "Medication Route FDA"
402 "value": parseFloat(pd.size),
406 "value": parseFloat(pd.dosage),
411 "value": parseFloat(pd.dosage),
419 "identifier": "2.16.840.1.113883.4.6",
420 "extension": pd.npi || "UNK"
424 "identifier": pd.sha_extension,
425 "extension": pd.extension || "UNK"
427 "name": [pd.performer_name]
432 "code": cleanCode(pd.form_code),
433 "code_system_name": "RXNORM"
438 "code_system_name": "ActCode"
443 "code_system_name": "SNOMED CT"
448 "identifier": "db734647-fc99-424c-a864-7e3cda82e703",
454 "code_system_name": "SNOMED CT"
458 "date": fDate(pd.start_date),
463 "name": pd.indications,
464 "code": pd.indications_code,
465 "code_system_name": "SNOMED CT"
470 "identifier": "1.2.3.4.56789.1",
471 "extension": "cb734647-fc99-424c-a864-7e3cda82e704"
475 "identifier": "2.16.840.1.113883.19.5.9999.456",
476 "extension": "2981823"
479 "street_lines": [pd.address],
487 "identifier": "2.16.840.1.113883.19.5.9999.1393"
489 "name": [pd.performer_name]
494 "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8"
496 "unencoded_name": pd.drug,
503 "code_system_name": "RXNORM"
505 "code_system_name": "RXNORM"
513 function populateEncounter(pd) {
516 "name": pd.visit_category ? pd.visit_category : 'UNK',
518 "code_system": "2.16.840.1.113883.6.96",
519 "code_system_name": "SNOMED CT",
521 "name": "Ambulatory",
523 "code_system_name": "ActCode"
527 "identifier": pd.sha_extension,
528 "extension": pd.extension
532 "date": fDate(pd.date),
533 "precision": "second" //getPrecision(fDate(pd.date_formatted))
538 "identifier": "2.16.840.1.113883.4.6",
539 "extension": pd.npi || "UNK"
542 "name": pd.physician_type,
543 "code": cleanCode(pd.physician_type_code),
544 "code_system_name": "SNOMED CT"
548 "last": pd.lname || "UNK",
549 "first": pd.fname || "UNK"
554 "number": pd.work_phone,
562 "name": pd.location_details,
564 "code_system_name": "HealthcareServiceLocation"
567 "street_lines": [pd.facility_address],
568 "city": pd.facility_city,
569 "state": pd.facility_state,
570 "zip": pd.facility_zip,
571 "country": pd.facility_country || "US"
575 "number": pd.facility_phone,
582 "identifier": pd.sha_extension,
583 "extension": pd.extension
586 "name": pd.encounter_procedures.procedures.text || encounter_reason,
587 "code": cleanCode(pd.encounter_procedures.procedures.code),
588 "code_system_name": pd.encounter_procedures.procedures.code_type || "ICD10" || "CPT4"
592 "date": fDate(pd.date),
596 //"status": pd.encounter_procedures.procedures.status
601 function populateAllergy(pd) {
604 "identifier": pd.sha_id,
605 "extension": pd.id || "UNK"
608 "low": templateDate(pd.startdate, "day"),
609 //"high": templateDate(pd.enddate, "day")
613 "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a66",
614 "extension": pd.extension || "UNK"
618 "code": cleanCode(pd.rxnorm_code) ? cleanCode(pd.rxnorm_code) : cleanCode(pd.snomed_code) ? cleanCode(pd.snomed_code) : cleanCode(pd.diagnosis_code),
619 "code_system_name": cleanCode(pd.rxnorm_code) ? "RXNORM" : cleanCode(pd.snomed_code) ? "SNOMED CT" : "ICD-10-CM"
623 "date": fDate(pd.startdate),
628 "name": "Propensity to adverse reactions to drug",
630 "code_system_name": "SNOMED CT"
635 "code": cleanCode(pd.outcome_code) || "UNK",
636 "code_system_name": "SNOMED CT"
640 "name": pd.status_table,
641 "code": cleanCode(pd.status_code) || "UNK",
642 "code_system_name": "SNOMED CT"
646 "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a64"
649 "low": templateDate(pd.startdate, "day"),
650 "high": templateDate(pd.enddate, "day")
653 "name": pd.reaction_text,
654 "code": cleanCode(pd.reaction_code) || "UNK",
655 "code_system_name": pd.reaction_code_type || "SNOMED CT"
660 "code": cleanCode(pd.outcome_code) || "UNK",
661 "code_system_name": "SNOMED CT"
669 function populateProblem(pd) {
673 "date": fDate(pd.start_date_table),
677 "date": fDate(pd.end_date),
682 "identifier": pd.sha_extension,
683 "extension": pd.extension || "UNK"
688 "code_system_name": "LOINC"
692 "name": trim(pd.title),
693 "code": cleanCode(pd.code),
694 "code_system_name": trim(pd.code_type)
698 "date": fDate(pd.start_date),
702 "date": fDate(pd.end_date),
703 "precision": getPrecision()
711 "identifier": "2.16.840.1.113883.4.6",
712 "extension": all.primary_care_provider.provider[0].npi || "UNK"
717 "last": all.primary_care_provider.provider[0].lname || "",
718 "first": all.primary_care_provider.provider[0].fname || ""
723 "onset_age_unit": "Year",
725 "name": pd.status_table,
728 "date": fDate(pd.start_date),
732 "date": fDate(pd.end_date),
733 "precision": getPrecision()
737 "patient_status": pd.observation,
738 "source_list_identifiers": [{
739 "identifier": pd.sha_extension,
740 "extension": pd.extension || "UNK"
746 function populateProcedure(pd) {
749 "name": pd.description,
750 "code": cleanCode(pd.code),
751 //"code_system": "2.16.840.1.113883.6.12",
752 "code_system_name": "SNOMED CT"
755 "identifier": "d68b7e32-7810-4f5b-9cc2-acd54b0fd85d",
756 "extension": pd.extension
758 "status": "completed",
761 "date": fDate(pd.date),
768 "code_system_name": ""
772 "identifier": "c2ee9ee9-ae31-4628-a919-fec1cbb58683"
777 "code_system_name": "SNOMED CT"
782 "identifier": "2.16.840.1.113883.4.6",
783 "extension": pd.npi || "UNK"
786 "street_lines": [pd.address],
793 "number": pd.work_phone,
798 "identifier": pd.facility_sha_extension,
799 "extension": pd.facility_extension
801 "name": [pd.facility_name],
803 "street_lines": [pd.facility_address],
804 "city": pd.facility_city,
805 "state": pd.facility_state,
806 "zip": pd.facility_zip,
807 "country": pd.facility_country || "US"
810 "number": pd.facility_phone,
815 "procedure_type": "procedure"
819 function populateMedicalDevice(pd) {
822 "identifier": pd.sha_extension,
823 "extension": pd.extension
827 "date": fDate(pd.start_date),
831 "date": fDate(pd.end_date),
835 "device_type": "UDI",
837 "name": pd.code_text,
838 "code": cleanCode(pd.code),
839 "code_system_name": "SNOMED CT",
841 "identifier": "2.16.840.1.113883.3.3719",
844 "status": "completed",
848 "code_system_name": ""
856 function populateResult(pd) {
857 let icode = pd.subtest.abnormal_flag;
858 let value = parseFloat(pd.subtest.result_value) || pd.subtest.result_value || "";
859 let type = isNaN(value) ? "ST" : "PQ";
860 type = !pd.subtest.unit ? "ST" : type;
862 let range_type = pd.subtest.range.toUpperCase() == "NEGATIVE" ? "CO" : type;
863 type = value.toUpperCase() == "NEGATIVE" ? "CO" : type;
865 switch (pd.subtest.abnormal_flag.toUpperCase()) {
878 "identifier": pd.subtest.root,
879 "extension": pd.subtest.extension
883 "code": cleanCode(pd.subtest.result_code) || "UNK",
884 "code_system_name": "LOINC"
888 "date": fDate(pd.date_ordered),
892 "status": pd.order_status,
894 "low": pd.subtest.low,
895 "high": pd.subtest.high,
896 "unit": pd.subtest.unit,
898 "range_type": range_type
900 "interpretations": [icode],
902 "unit": pd.subtest.unit,
904 "range": pd.subtest.range,
905 "range_type": range_type
909 function getResultSet(results) {
911 if (!results) return '';
913 let tResult = results.result[0] || results.result;
916 "identifier": tResult.root,
917 "extension": tResult.extension
923 "date": fDate(tResult.date_ordered),
924 "precision": getPrecision(fDate(tResult.date_ordered))
929 "identifier": "2.16.840.1.113883.4.6",
930 "extension": all.primary_care_provider.provider[0].npi || "UNK"
935 "last": all.primary_care_provider.provider[0].lname || "",
936 "first": all.primary_care_provider.provider[0].fname || ""
941 "name": tResult.test_name,
942 "code": cleanCode(tResult.test_code),
943 "code_system_name": "LOINC"
952 count = isOne(results.result);
957 for (let i in results.result) {
958 theone[i] = populateResult(results.result[i]);
959 many.results.push(theone[i]);
961 } else if (count !== 0) {
962 theone = populateResult(results.result);
963 many.results.push(theone);
965 rs.results = Object.assign(resultSet);
966 rs.results.results = Object.assign(many.results);
970 function getPlanOfCare(pd) {
973 "name": pd.code_text || "UNK",
974 "code": cleanCode(pd.code) || "UNK",
975 "code_system_name": pd.code_type || "SNOMED CT"
978 "identifier": "9a6d1bac-17d3-4195-89a4-1121bc809b4a"
981 "code": cleanCode(pd.code) || "UNK",
982 "name": pd.description || "UNK"
986 "date": fDate(pd.date_formatted),
990 "type": "observation",
992 "code": cleanCode(pd.status)
994 "name": pd.description
998 function populateVital(pd) {
1001 "identifier": pd.sha_extension,
1002 "extension": pd.extension
1004 "status": "completed",
1007 "date": fDate(pd.effectivetime),
1008 "precision": getPrecision(fDate(pd.effectivetime))
1011 // our list of vitals per organizer.
1014 "identifier": pd.sha_extension,
1015 "extension": pd.extension_bps
1018 "name": "Blood Pressure Systolic",
1020 "code_system_name": "LOINC"
1022 "status": "completed",
1025 "date": fDate(pd.effectivetime),
1026 "precision": getPrecision(fDate(pd.effectivetime))
1029 "interpretations": ["Normal"],
1030 "value": parseFloat(pd.bps),
1034 "identifier": pd.sha_extension,
1035 "extension": pd.extension_bpd
1038 "name": "Blood Pressure Diastolic",
1040 "code_system_name": "LOINC"
1042 "status": "completed",
1045 "date": fDate(pd.effectivetime),
1046 "precision": getPrecision(fDate(pd.effectivetime))
1049 "interpretations": ["Normal"],
1050 "value": parseFloat(pd.bpd),
1054 "identifier": pd.sha_extension,
1055 "extension": pd.extension_pulse
1058 "name": "Heart Rate",
1060 "code_system_name": "LOINC"
1062 "status": "completed",
1065 "date": fDate(pd.effectivetime),
1066 "precision": getPrecision(fDate(pd.effectivetime))
1069 "interpretations": ["Normal"],
1070 "value": parseFloat(pd.pulse),
1074 "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.2",
1075 "extension": pd.extension_breath
1078 "name": "Respiratory Rate",
1080 "code_system_name": "LOINC"
1082 "status": "completed",
1085 "date": fDate(pd.effectivetime),
1086 "precision": getPrecision(fDate(pd.effectivetime))
1089 "interpretations": ["Normal"],
1090 "value": parseFloat(pd.breath),
1094 "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.3",
1095 "extension": pd.extension_temperature
1098 "name": "Body Temperature",
1100 "code_system_name": "LOINC"
1102 "status": "completed",
1105 "date": fDate(pd.effectivetime),
1106 "precision": getPrecision(fDate(pd.effectivetime))
1109 "interpretations": ["Normal"],
1110 "value": parseFloat(pd.temperature),
1111 "unit": pd.unit_temperature
1115 "identifier": pd.sha_extension,
1116 "extension": pd.extension_height
1121 "code_system_name": "LOINC"
1123 "status": "completed",
1126 "date": fDate(pd.effectivetime),
1127 "precision": getPrecision(fDate(pd.effectivetime))
1130 "interpretations": ["Normal"],
1131 "value": parseFloat(pd.height),
1132 "unit": pd.unit_height
1135 "identifier": pd.sha_extension,
1136 "extension": pd.extension_weight
1139 "name": "Weight Measured",
1141 "code_system_name": "LOINC"
1143 "status": "completed",
1146 "date": fDate(pd.effectivetime),
1147 "precision": getPrecision(fDate(pd.effectivetime))
1150 "interpretations": ["Normal"],
1151 "value": parseFloat(pd.weight),
1152 "unit": pd.unit_weight
1155 "identifier": pd.sha_extension,
1156 "extension": pd.extension_BMI
1159 "name": "BMI (Body Mass Index)",
1161 "code_system_name": "LOINC"
1163 "status": "completed",
1166 "date": fDate(pd.effectivetime),
1167 "precision": getPrecision(fDate(pd.effectivetime))
1170 "interpretations": ["Normal"],
1171 "value": parseFloat(pd.BMI),
1175 "identifier": pd.sha_extension,
1176 "extension": pd.extension_oxygen_saturation
1179 "name": "O2 % BldC Oximetry",
1181 "code_system_name": "LOINC"
1183 "status": "completed",
1186 "date": fDate(pd.effectivetime),
1187 "precision": getPrecision(fDate(pd.effectivetime))
1190 "interpretations": ["Normal"],
1191 "value": parseFloat(pd.oxygen_saturation),
1198 function populateSocialHistory(pd) {
1201 "low": templateDate(pd.date_formatted, "day")
1202 //"high": templateDate(pd.date, "day")
1205 "identifier": pd.sha_extension,
1206 "extension": pd.extension
1211 "value": pd.description,
1212 "gender": all.patient.gender
1216 function populateImmunization(pd) {
1220 "date": fDate(pd.administered_on),
1221 "precision": "month"
1225 "identifier": "e6f1ba43-c0ed-4b9b-9f12-f435d8ad8f92",
1226 "extension": pd.extension || "UNK"
1228 "status": "complete",
1231 "name": pd.code_text,
1232 "code": cleanCode(pd.cvx_code),
1233 "code_system_name": "CVX"
1234 /*"translations": [{
1237 "code_system_name": "CVX"
1240 "lot_number": "UNK",
1241 "manufacturer": "UNK"
1245 "name": pd.route_of_administration,
1246 "code": cleanCode(pd.route_code) || "UNK",
1247 "code_system_name": "Medication Route FDA"
1256 "identifier": "2.16.840.1.113883.4.6",
1257 "extension": npiProvider || "UNK"
1264 "street_lines": [pd.address],
1272 "identifier": "2.16.840.1.113883.4.6",
1273 "extension": npiFacility || "UNK"
1275 "name": [pd.facility_name]
1280 "name": "immunization education",
1281 "code": "171044003",
1282 "code_system_name": "SNOMED CT"
1284 "free_text": "Needs Attention for more data."
1289 function populatePayer(pd) {
1292 "identifier": "1fe2cdd0-7aad-11db-9fe1-0800200c9a66"
1296 "identifier": "3e676a50-7aac-11db-9fe1-0800200c9a66"
1300 "code_system_name": "HL7 RoleCode"
1305 "code_system_name": "HL7 RoleCode"
1309 "identifier": "2.16.840.1.113883.19"
1312 "street_lines": ["123 Insurance Road"],
1313 "city": "Blue Bell",
1320 "number": "(781)555-1515",
1321 "type": "work place"
1324 "name": ["Good Health Insurance"],
1326 "street_lines": ["123 Insurance Road"],
1327 "city": "Blue Bell",
1334 "number": "(781)555-1515",
1335 "type": "work place"
1340 "code_system_name": "HL7 RoleCode"
1348 "code_system_name": "HL7 Role"
1351 "identifier": "329fcdf0-7ab3-11db-9fe1-0800200c9a66"
1355 "middle": ["Frankie"],
1360 "street_lines": ["17 Daws Rd."],
1361 "city": "Blue Bell",
1365 "use": "primary home"
1368 "number": "(781)555-1212",
1369 "type": "primary home"
1376 "code_system_name": "HL7 Role"
1380 "identifier": "14d4a520-7aae-11db-9fe1-0800200c9a66",
1381 "extension": "1138345"
1384 "street_lines": ["17 Daws Rd."],
1385 "city": "Blue Bell",
1389 "use": "primary home"
1394 "code_system_name": "HL7 Role"
1407 "identifier": "2.16.840.1.113883.19",
1408 "extension": "1138345"
1411 "street_lines": ["17 Daws Rd."],
1412 "city": "Blue Bell",
1416 "use": "primary home"
1422 "identifier": "f4dce790-8328-11db-9fe1-0800200c9a66"
1426 "name": "Colonoscopy",
1428 "code_system_name": "SNOMED CT"
1435 function populateHeader(pd) {
1439 "identifier": oidFacility,
1440 "extension": "TT988"
1444 "name": "Continuity of Care Document", //change to toc w/code
1446 "code_system_name": "LOINC"
1449 "2.16.840.1.113883.10.20.22.1.1",
1450 "2.16.840.1.113883.10.20.22.1.2"
1452 "title": "OpenEMR Transitions of Care : Consolidated CDA",
1454 "date": pd.created_time_timezone,
1460 "time": pd.created_time_timezone,
1463 "identifier": "2.16.840.1.113883.4.6",
1464 "extension": pd.author.npi || "UNK"
1469 "last": pd.author.lname,
1470 "first": pd.author.fname
1476 pd.author.streetAddressLine
1478 "city": pd.author.city,
1479 "state": pd.author.state,
1480 "zip": pd.author.postalCode,
1481 "country": pd.author.country || "US",
1487 "number": pd.author.telecom || "UNK",
1495 "root": "2.16.840.1.113883.4.6",
1496 "extension": npiFacility || "UNK"
1500 pd.encounter_provider.facility_name
1505 pd.encounter_provider.facility_street
1507 "city": pd.encounter_provider.facility_city,
1508 "state": pd.encounter_provider.facility_state,
1509 "zip": pd.encounter_provider.facility_postal_code,
1510 "country": pd.encounter_provider.facility_country_code || "US",
1516 "number": pd.encounter_provider.facility_phone,
1517 "type": "work primary"
1528 "root": "2.16.840.1.113883.4.6",
1529 "extension": npiFacility || "UNK"
1533 pd.encounter_provider.facility_name
1538 pd.encounter_provider.facility_street
1540 "city": pd.encounter_provider.facility_city,
1541 "state": pd.encounter_provider.facility_state,
1542 "zip": pd.encounter_provider.facility_postal_code,
1543 "country": pd.encounter_provider.facility_country_code || "US"
1548 "number": pd.encounter_provider.facility_phone,
1549 "type": "work primary"
1556 "identifier": "2.16.840.1.113883.4.6",
1557 "extension": "999999943252"
1562 "last": pd.data_enterer.lname,
1563 "first": pd.data_enterer.fname
1569 pd.data_enterer.streetAddressLine
1571 "city": pd.data_enterer.city,
1572 "state": pd.data_enterer.state,
1573 "zip": pd.data_enterer.postalCode,
1574 "country": pd.data_enterer.country
1579 "number": pd.data_enterer.telecom,
1580 "type": "work place"
1587 "identifier": "2.16.840.1.113883.19.5",
1588 "extension": "KP00017"
1593 "last": pd.informer.lname || "",
1594 "first": pd.informer.fname || ""
1600 pd.informer.streetAddressLine || ""
1602 "city": pd.informer.city,
1603 "state": pd.informer.state,
1604 "zip": pd.informer.postalCode,
1605 "country": pd.informer.country
1610 "number": pd.informer.telecom || "",
1611 "type": "work place"
1615 /*"service_event": {
1619 "code_system_name": "SNOMED CT"
1623 "date": "2021-03-11",
1627 "date": pd.created_time,
1637 "identifier": "2.16.840.1.113883.4.6",
1638 "extension": npiProvider
1643 "last": pd.information_recipient.lname || "DAH",
1644 "first": pd.information_recipient.fname || "DAH"
1650 pd.information_recipient.streetAddressLine
1652 "city": pd.information_recipient.city,
1653 "state": pd.information_recipient.state,
1654 "zip": pd.information_recipient.postalCode,
1655 "country": pd.information_recipient.country || "US"
1660 "number": pd.information_recipient.telecom,
1661 "type": "work place"
1668 "identifier": "2.16.840.1.113883.19.5.9999.1393"
1672 pd.encounter_provider.facility_name
1677 pd.encounter_provider.facility_street
1679 "city": pd.encounter_provider.facility_city,
1680 "state": pd.encounter_provider.facility_state,
1681 "zip": pd.encounter_provider.facility_postal_code,
1682 "country": pd.encounter_provider.facility_country_code || "US"
1687 "number": pd.encounter_provider.facility_phone,
1688 "type": "primary work"
1697 "code_system_name": "Provider Codes"
1703 "name": "Primary Performer",
1705 "code_system_name": "Provider Role"
1714 function getMeta(pd) {
1720 "identifier": oidFacility || "UNK",
1721 "extension": "TT988"
1724 "confidentiality": "Normal",
1726 "identifier": oidFacility + ".1" || "UNK",
1727 "extension": "sTT988"
1733 function genCcda(pd) {
1741 npiProvider = all.primary_care_provider.provider[0].npi;
1742 oidFacility = all.encounter_provider.facility_oid ? all.encounter_provider.facility_oid : "2.16.840.1.113883.3.8888.999999";
1743 npiFacility = all.encounter_provider.facility_npi;
1746 let demographic = populateDemographic(pd.patient, pd.guardian, pd);
1747 // This populates documentationOf. We are using providerOrganization also.
1748 Object.assign(demographic, populateProviders());
1750 data.demographics = Object.assign(demographic);
1755 count = isOne(pd.history_physical.vitals_list.vitals);
1760 for (let i in pd.history_physical.vitals_list.vitals) {
1761 theone = populateVital(pd.history_physical.vitals_list.vitals[i]);
1762 many.vitals.push.apply(many.vitals, theone);
1764 } else if (count === 1) {
1765 theone = populateVital(pd.history_physical.vitals_list.vitals);
1766 many.vitals.push(theone);
1768 data.vitals = Object.assign(many.vitals);*/
1770 data.vitals = Object.assign(populateVital(pd.history_physical.vitals_list.vitals));
1775 meds.medications = [];
1777 count = isOne(pd.medications.medication);
1782 for (let i in pd.medications.medication) {
1783 m[i] = populateMedication(pd.medications.medication[i]);
1784 meds.medications.push(m[i]);
1786 } else if (count !== 0) {
1787 m = populateMedication(pd.medications.medication);
1788 meds.medications.push(m);
1790 data.medications = Object.assign(meds.medications);
1794 encs.encounters = [];
1796 count = isOne(pd.encounter_list.encounter);
1801 for (let i in pd.encounter_list.encounter) {
1802 enc[i] = populateEncounter(pd.encounter_list.encounter[i]);
1803 encs.encounters.push(enc[i]);
1805 } else if (count !== 0) {
1806 enc = populateEncounter(pd.encounter_list.encounter);
1807 encs.encounters.push(enc);
1809 data.encounters = Object.assign(encs.encounters);
1814 allergies.allergies = [];
1816 count = isOne(pd.allergies.allergy);
1821 for (let i in pd.allergies.allergy) {
1822 allergy[i] = populateAllergy(pd.allergies.allergy[i]);
1823 allergies.allergies.push(allergy[i]);
1825 } else if (count !== 0) {
1826 allergy = populateAllergy(pd.allergies.allergy);
1827 allergies.allergies.push(allergy);
1829 data.allergies = Object.assign(allergies.allergies);
1834 problems.problems = [];
1836 count = isOne(pd.problem_lists.problem);
1841 for (let i in pd.problem_lists.problem) {
1842 problem[i] = populateProblem(pd.problem_lists.problem[i], pd);
1843 problems.problems.push(problem[i]);
1845 } else if (count !== 0) {
1846 problem = populateProblem(pd.problem_lists.problem);
1847 problems.problems.push(problem);
1849 data.problems = Object.assign(problems.problems);
1853 many.procedures = [];
1855 count = isOne(pd.procedures.procedure);
1860 for (let i in pd.procedures.procedure) {
1861 theone[i] = populateProcedure(pd.procedures.procedure[i]);
1862 many.procedures.push(theone[i]);
1864 } else if (count !== 0) {
1865 theone = populateProcedure(pd.procedures.procedure);
1866 many.procedures.push(theone);
1868 data.procedures = Object.assign(many.procedures);
1872 many.medical_devices = [];
1874 count = isOne(pd.medical_devices.device);
1879 for (let i in pd.medical_devices.device) {
1880 theone[i] = populateMedicalDevice(pd.medical_devices.device[i]);
1881 many.medical_devices.push(theone[i]);
1883 } else if (count !== 0) {
1884 theone = populateMedicalDevice(pd.medical_devices.device);
1885 many.medical_devices.push(theone);
1887 data.medical_devices = Object.assign(many.medical_devices);
1891 data.results = Object.assign(getResultSet(pd.results, pd)['results']);
1896 many.immunizations = [];
1898 count = isOne(pd.immunizations.immunization);
1903 for (let i in pd.immunizations.immunization) {
1904 theone[i] = populateImmunization(pd.immunizations.immunization[i]);
1905 many.immunizations.push(theone[i]);
1907 } else if (count !== 0) {
1908 theone = populateImmunization(pd.immunizations.immunization);
1909 many.immunizations.push(theone);
1911 data.immunizations = Object.assign(many.immunizations);
1915 many.plan_of_care = [];
1917 count = isOne(pd.planofcare.item);
1922 for (let i in pd.planofcare.item) {
1923 if (cleanCode(pd.planofcare.item[i].code) === '') {
1927 theone[i] = getPlanOfCare(pd.planofcare.item[i]);
1928 many.plan_of_care.push(theone[i]);
1930 } else if (count !== 0) {
1931 theone = getPlanOfCare(pd.planofcare.item);
1932 many.plan_of_care.push(theone);
1935 data.plan_of_care = Object.assign(many.plan_of_care);
1939 many.social_history = [];
1941 count = isOne(pd.history_physical.social_history.history_element);
1946 for (let i in pd.history_physical.social_history.history_element) {
1948 theone[i] = populateSocialHistory(pd.history_physical.social_history.history_element[i]);
1949 many.social_history.push(theone[i]);
1951 } else if (count !== 0) {
1952 theone = populateSocialHistory(pd.history_physical.social_history.history_element);
1953 many.social_history.push(theone);
1956 data.social_history = Object.assign(many.social_history);
1958 // ------------------------------------------ End Sections ----------------------------------------//
1960 doc.data = Object.assign(data);
1961 let meta = getMeta(pd);
1962 let header = populateHeader(pd);
1964 meta.ccda_header = Object.assign(header);
1965 doc.meta = Object.assign(meta);
1966 let xml = bbg.generateCCD(doc);
1969 fs.writeFile("ccda.json", JSON.stringify(all, null, 4), function (err) {
1971 return console.log(err);
1973 console.log("Json saved!");
1975 fs.writeFile("ccda.xml", xml, function (err) {
1977 return console.log(err);
1979 console.log("Xml saved!");
1985 function processConnection(connection) {
1986 conn = connection; // make it global
1987 var remoteAddress = conn.remoteAddress + ':' + conn.remotePort;
1988 //console.log(remoteAddress);
1989 conn.setEncoding('utf8');
1991 var xml_complete = "";
1993 function eventData(xml) {
1994 xml = xml.replace(/(\u000b|\u001c)/gm, "").trim();
1995 // Sanity check from service manager
1996 if (xml === 'status' || xml.length < 80) {
1997 conn.write("statusok" + String.fromCharCode(28) + "\r\r");
2001 xml_complete += xml.toString();
2002 if (xml.toString().match(/\<\/CCDA\>$/g)) {
2003 // ---------------------start--------------------------------
2005 xml_complete = xml_complete.replace(/\t\s+/g, ' ').trim();
2007 to_json(xml_complete, function (error, data) {
2008 // console.log(JSON.stringify(data, null, 4));
2009 if (error) { // need try catch
2010 console.log('toJson error: ' + error + 'Len: ' + xml_complete.length);
2013 doc = genCcda(data.CCDA);
2016 doc = headReplace(doc);
2017 doc = doc.toString().replace(/(\u000b|\u001c|\r)/gm, "").trim();
2020 let numChunks = Math.ceil(doc.length / 1024);
2021 for (let i = 0, o = 0; i < numChunks; ++i, o += 1024) {
2022 chunk = doc.substr(o, 1024);
2025 conn.write(String.fromCharCode(28) + "\r\r" + '');
2030 function eventCloseConn() {
2031 //console.log('connection from %s closed', remoteAddress);
2034 function eventErrorConn(err) {
2035 //console.log('Connection %s error: %s', remoteAddress, err.message);
2038 // Connection Events //
2039 conn.on('data', eventData);
2040 conn.once('close', eventCloseConn);
2041 conn.on('error', eventErrorConn);
2044 function setUp(server) {
2045 server.on('connection', processConnection);
2046 server.listen(6661, 'localhost', function () {
2047 //console.log('server listening to %j', server.address());