CCDA and Other (#4382)
[openemr.git] / ccdaservice / serveccda.js
blob9286668d10e0eb0acdf15040dbc2614737f3d3ac
1 /**
2  * @package   OpenEMR CCDAServer
3  * @link      http://www.open-emr.org
4  *
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
8  */
10 "use strict";
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
18 var oidFacility = "";
19 var all = "";
20 var npiProvider = "";
21 var npiFacility = "";
23 function trim(s) {
24     if (typeof s === 'string') return s.trim();
25     return s;
28 function fDate(str, lim8=false) {
29     str = String(str);
30     if (lim8) {
31         let rtn = str.substring(0, 8);
32         return rtn;
33     }
34     if (Number(str) === 0) {
35         return (new Date()).toISOString().slice(0, 10).replace(/-/g, "");
36     }
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
45     }
47     return str;
50 function getPrecision(str) {
51     str = String(str);
52     let pflg = "day";
54     if (Number(str) === 0) {
55         return "day";
56     }
57     if (str.length > 8) {
58         pflg = "minute";
59     }
60     if (str.length > 12) {
61         pflg = "second";
62     }
64     return pflg;
67 function templateDate(date, precision) {
68     return {'date': fDate(date), 'precision': precision}
71 function cleanCode(code) {
72     if (code.length < 2) {
73         code = "";
74     }
75     return code.replace(/[.#]/, "");
78 function isOne(who) {
79     try {
80         if (who !== null && typeof who === 'object') {
81             return (who.hasOwnProperty('extension') || who.hasOwnProperty('id') || who.hasOwnProperty('date')) ? 1 : Object.keys(who).length;
82         }
83     } catch (e) {
84         return false;
85     }
86     return 0;
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));
92     return r;
95 function populateDemographic(pd, g) {
96     let guardian = [{
97         "relation": g.relation,
98         "addresses": [{
99             "street_lines": [g.address],
100             "city": g.city,
101             "state": g.state,
102             "zip": g.postalCode,
103             "country": g.country || "US",
104             "use": "primary home"
105         }],
106         "names": [{
107             "last": g.display_name, //@todo parse first/last
108             "first": g.display_name
109         }],
110         "phone": [{
111             "number": g.telecom,
112             "type": "primary home"
113         }]
114     }];
116     return {
117         "name": {
118             "middle": [pd.mname],
119             "last": pd.lname,
120             "first": pd.fname
121         },
122         "birth_name": {
123             "middle": pd.birth_mname || pd.mname,
124             "last": pd.birth_lname || pd.lname,
125             "first": pd.birth_fname || pd.fname
126         },
127         "dob": {
128             "point": {
129                 "date": fDate(pd.dob),
130                 "precision": "day"
131             }
132         },
133         "gender": pd.gender.toUpperCase(),
134         "identifiers": [{
135             "identifier": oidFacility,
136             "extension": "PT-" + pd.id
137         }],
138         "marital_status": pd.status.toUpperCase(),
139         "addresses": [{
140             "street_lines": [pd.street],
141             "city": pd.city,
142             "state": pd.state,
143             "zip": pd.postalCode,
144             "country": pd.country || "US",
145             "use": "primary home"
146         }],
147         "phone": [
148             {
149                 "number": pd.phone_home,
150                 "type": "primary home"
151             }, {
152                 "number": pd.phone_mobile,
153                 "type": "primary mobile"
154             }
155         ],
156         "ethnicity": pd.ethnicity || "",
157         "race": pd.race || "",
158         "race_additional": pd.race == "White" ? "European" : "African",
159         "languages": [{
160             "language": pd.language === 'English' ? "en-US" : pd.language === 'Spanish' ? "sp-US" : 'en-US',
161             "preferred": true,
162             "mode": "Expressed spoken",
163             "proficiency": "Good"
164         }],
165         //"religion": pd.religion.toUpperCase() || "UNK",
166         /*"birthplace":'', {
167             "city": "",
168             "state": "",
169             "zip": "",
170             "country": ""
171         },*/
172         "attributed_provider": {
173             "identity": [
174                 {
175                     "root": "2.16.840.1.113883.4.6",
176                     "extension": npiFacility || "UNK"
177                 }
178             ],
179             "phone": [{
180                 "number": all.encounter_provider.facility_phone || "UNK",
181             }],
182             "name": [
183                 {
184                     "full": all.encounter_provider.facility_name || "UNK"
185                 }
186             ],
187             "address": [
188                 {
189                     "street_lines": [
190                         all.encounter_provider.facility_street
191                     ],
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",
196                     "use": "work place"
197                 }
198             ],
199         },
200         //"guardians": g.display_name ? guardian : '' //not required
201     }
205 function populateProviders() {
206     return {
207         "providers": [
208             {
209                 "code": {
210                     "name": "UNK",
211                     "code": "UNK",
212                     "code_system_name": "SNOMED CT"
213                 },
214                 "date_time": {
215                     "low": {
216                         "date": fDate(""),
217                         "precision": "day"
218                     },
219                     "high": {
220                         "date": fDate(""),
221                         "precision": "day"
222                     }
223                 },
224                 "identity": [
225                     {
226                         "root": "2.16.840.1.113883.4.6",
227                         "extension": all.primary_care_provider.provider[0].npi || "UNK"
228                     }
229                 ],
230                 "type": [
231                     {
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"
235                     }
236                 ],
237                 "name": [
238                     {
239                         "last": all.primary_care_provider.provider[0].lname || "UNK",
240                         "first": all.primary_care_provider.provider[0].fname || "UNK"
241                     }
242                 ],
243                 "address": [
244                     {
245                         "street_lines": [
246                             all.encounter_provider.facility_street
247                         ],
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"
252                     }
253                 ],
254                 "phone": [
255                     {
256                         "value": {
257                             "number": all.encounter_provider.facility_phone || "",
259                         }
260                     }],
261                 "organization": [
262                     {
263                         "identifiers": [
264                             {
265                                 "identifier": "2.16.840.1.113883.19.5.9999.1393" //@todo need facility oid
266                             }
267                         ],
268                         "name": [
269                             all.encounter_provider.facility_name
270                         ],
271                         "address": [
272                             {
273                                 "street_lines": [
274                                     all.encounter_provider.facility_street
275                                 ],
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"
280                             }
281                         ],
282                         "phone": [
283                             {
284                                 "number": all.encounter_provider.facility_phone,
285                                 "type": "primary work"
286                             }
287                         ]
288                     }
289                 ]
291             }
292         ]
293     }
296 function populateMedication(pd) {
297     pd.status = 'Completed'; //@todo invoke prescribed
298     return {
299         "date_time": {
300             "low": {
301                 "date": fDate(pd.start_date),
302                 "precision": "day"
303             },
304             "high": {
305                 "date": fDate(pd.end_date),
306                 "precision": "day"
307             }
308         },
309         "identifiers": [{
310             "identifier": pd.sha_extension,
311             "extension": pd.extension || "UNK"
312         }],
313         "status": pd.status,
314         "sig": pd.direction,
315         "product": {
316             "identifiers": [{
317                 "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8",
318                 "extension": "UNK"
319             }],
320             "unencoded_name": pd.drug,
321             "product": {
322                 "name": pd.drug,
323                 "code": cleanCode(pd.rxnorm),
324                 /*"translations": [{
325                     "name": pd.drug,
326                     "code": pd.rxnorm,
327                     "code_system_name": "RXNORM"
328                 }],*/
329                 "code_system_name": "RXNORM"
330             },
331             //"manufacturer": ""
332         },
333         "supply": {
334             "date_time": {
335                 "low": {
336                     "date": fDate(pd.start_date),
337                     "precision": "day"
338                 },
339                 "high": {
340                     "date": fDate(pd.end_date),
341                     "precision": "day"
342                 }
343             },
344             "repeatNumber": "0",
345             "quantity": "0",
346             "product": {
347                 "identifiers": [{
348                     "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8",
349                     "extension": "UNK"
350                 }],
351                 "unencoded_name": pd.drug,
352                 "product": {
353                     "name": pd.drug,
354                     "code": cleanCode(pd.rxnorm),
355                     /*"translations": [{
356                         "name": pd.drug,
357                         "code": pd.rxnorm,
358                         "code_system_name": "RXNORM"
359                     }],*/
360                     "code_system_name": "RXNORM"
361                 },
362                 //"manufacturer": ""
363             },
364             "author": {
365                 "date_time": {
366                     "point": {
367                         "date": fDate(pd.start_date),
368                         "precision": getPrecision(fDate(pd.start_date))
369                     }
370                 },
371                 "identifiers": [{
372                     "identifier": "2.16.840.1.113883.4.6",
373                     "extension": pd.npi || "UNK"
374                 }],
375                 "name": {
376                     "prefix": pd.title,
377                     "last": pd.lname,
378                     "first": pd.fname
379                 }
380             },
381             "instructions": {
382                 "code": {
383                     "name": "instruction",
384                     "code": "409073007",
385                     "code_system_name": "SNOMED CT"
386                 },
387                 "free_text": pd.instructions || "No Instructions"
388             },
389         },
390         "administration": {
391             "route": {
392                 "name": pd.route || "",
393                 "code": cleanCode(pd.route_code) || "UNK",
394                 "code_system_name": "Medication Route FDA"
395             },
396             "form": {
397                 "name": pd.form,
398                 "code": cleanCode(pd.form_code),
399                 "code_system_name": "Medication Route FDA"
400             },
401             "dose": {
402                 "value": parseFloat(pd.size),
403                 "unit": pd.unit,
404             },
405             /*"rate": {
406                 "value": parseFloat(pd.dosage),
407                 "unit": ""
408             },*/
409             "interval": {
410                 "period": {
411                     "value": parseFloat(pd.dosage),
412                     "unit": pd.interval
413                 },
414                 "frequency": true
415             }
416         },
417         "performer": {
418             "identifiers": [{
419                 "identifier": "2.16.840.1.113883.4.6",
420                 "extension": pd.npi || "UNK"
421             }],
422             "organization": [{
423                 "identifiers": [{
424                     "identifier": pd.sha_extension,
425                     "extension": pd.extension || "UNK"
426                 }],
427                 "name": [pd.performer_name]
428             }]
429         },
430         "drug_vehicle": {
431             "name": pd.form,
432             "code": cleanCode(pd.form_code),
433             "code_system_name": "RXNORM"
434         },
435         /*"precondition": {
436             "code": {
437                 "code": "ASSERTION",
438                 "code_system_name": "ActCode"
439             },
440             "value": {
441                 "name": "none",
442                 "code": "none",
443                 "code_system_name": "SNOMED CT"
444             }
445         },
446         "indication": {
447             "identifiers": [{
448                 "identifier": "db734647-fc99-424c-a864-7e3cda82e703",
449                 "extension": "45665"
450             }],
451             "code": {
452                 "name": "Finding",
453                 "code": "404684003",
454                 "code_system_name": "SNOMED CT"
455             },
456             "date_time": {
457                 "low": {
458                     "date": fDate(pd.start_date),
459                     "precision": "day"
460                 }
461             },
462             "value": {
463                 "name": pd.indications,
464                 "code": pd.indications_code,
465                 "code_system_name": "SNOMED CT"
466             }
467         },*/
468         /*"dispense": {
469             "identifiers": [{
470                 "identifier": "1.2.3.4.56789.1",
471                 "extension": "cb734647-fc99-424c-a864-7e3cda82e704"
472             }],
473             "performer": {
474                 "identifiers": [{
475                     "identifier": "2.16.840.1.113883.19.5.9999.456",
476                     "extension": "2981823"
477                 }],
478                 "address": [{
479                     "street_lines": [pd.address],
480                     "city": pd.city,
481                     "state": pd.state,
482                     "zip": pd.zip,
483                     "country": "US"
484                 }],
485                 "organization": [{
486                     "identifiers": [{
487                         "identifier": "2.16.840.1.113883.19.5.9999.1393"
488                     }],
489                     "name": [pd.performer_name]
490                 }]
491             },
492             "product": {
493                 "identifiers": [{
494                     "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8"
495                 }],
496                 "unencoded_name": pd.drug,
497                 "product": {
498                     "name": pd.drug,
499                     "code": pd.rxnorm,
500                     "translations": [{
501                         "name": pd.drug,
502                         "code": pd.rxnorm,
503                         "code_system_name": "RXNORM"
504                     }],
505                     "code_system_name": "RXNORM"
506                 },
507                 "manufacturer": ""
508             }
509         }*/
510     };
513 function populateEncounter(pd) {
514     return {
515         "encounter": {
516             "name": pd.visit_category ? pd.visit_category : 'UNK',
517             "code": "185347001",
518             "code_system": "2.16.840.1.113883.6.96",
519             "code_system_name": "SNOMED CT",
520             "translations": [{
521                 "name": "Ambulatory",
522                 "code": "AMB",
523                 "code_system_name": "ActCode"
524             }]
525         },
526         "identifiers": [{
527             "identifier": pd.sha_extension,
528             "extension": pd.extension
529         }],
530         "date_time": {
531             "point": {
532                 "date": fDate(pd.date),
533                 "precision": "second" //getPrecision(fDate(pd.date_formatted))
534             }
535         },
536         "performers": [{
537             "identifiers": [{
538                 "identifier": "2.16.840.1.113883.4.6",
539                 "extension": pd.npi || "UNK"
540             }],
541             "code": [{
542                 "name": pd.physician_type,
543                 "code": cleanCode(pd.physician_type_code),
544                 "code_system_name": "SNOMED CT"
545             }],
546             "name": [
547                 {
548                     "last": pd.lname || "UNK",
549                     "first": pd.fname || "UNK"
550                 }
551             ],
552             "phone": [
553                 {
554                     "number": pd.work_phone,
555                     "type": "work place"
556                 }
557             ]
558         }],
559         "locations": [{
560             "name": pd.location,
561             "location_type": {
562                 "name": pd.location_details,
563                 "code": "1160-1",
564                 "code_system_name": "HealthcareServiceLocation"
565             },
566             "address": [{
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"
572             }],
573             "phone": [
574                 {
575                     "number": pd.facility_phone,
576                     "type": "work place"
577                 }
578             ]
579         }],
580         "findings": [{
581             "identifiers": [{
582                 "identifier": pd.sha_extension,
583                 "extension": pd.extension
584             }],
585             "value": {
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"
589             },
590             "date_time": {
591                 "low": {
592                     "date": fDate(pd.date),
593                     "precision": "day"
594                 }
595             },
596             //"status": pd.encounter_procedures.procedures.status
597         }]
598     };
601 function populateAllergy(pd) {
602     return {
603         "identifiers": [{
604             "identifier": pd.sha_id,
605             "extension": pd.id || "UNK"
606         }],
607         "date_time": {
608             "low": templateDate(pd.startdate, "day"),
609             //"high": templateDate(pd.enddate, "day")
610         },
611         "observation": {
612             "identifiers": [{
613                 "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a66",
614                 "extension": pd.extension || "UNK"
615             }],
616             "allergen": {
617                 "name": pd.title,
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"
620             },
621             "date_time": {
622                 "low": {
623                     "date": fDate(pd.startdate),
624                     "precision": "day"
625                 }
626             },
627             "intolerance": {
628                 "name": "Propensity to adverse reactions to drug",
629                 "code": "420134006",
630                 "code_system_name": "SNOMED CT"
631             },
632             "severity": {
633                 "code": {
634                     "name": pd.outcome,
635                     "code": cleanCode(pd.outcome_code) || "UNK",
636                     "code_system_name": "SNOMED CT"
637                 }
638             },
639             "status": {
640                 "name": pd.status_table,
641                 "code": cleanCode(pd.status_code) || "UNK",
642                 "code_system_name": "SNOMED CT"
643             },
644             "reactions": [{
645                 "identifiers": [{
646                     "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a64"
647                 }],
648                 "date_time": {
649                     "low": templateDate(pd.startdate, "day"),
650                     "high": templateDate(pd.enddate, "day")
651                 },
652                 "reaction": {
653                     "name": pd.reaction_text,
654                     "code": cleanCode(pd.reaction_code) || "UNK",
655                     "code_system_name": pd.reaction_code_type || "SNOMED CT"
656                 },
657                 "severity": {
658                     "code": {
659                         "name": pd.outcome,
660                         "code": cleanCode(pd.outcome_code) || "UNK",
661                         "code_system_name": "SNOMED CT"
662                     }
663                 }
664             }]
665         }
666     }
669 function populateProblem(pd) {
670     return {
671         "date_time": {
672             "low": {
673                 "date": fDate(pd.start_date_table),
674                 "precision": "day"
675             },
676             /*"high": {
677                 "date": fDate(pd.end_date),
678                 "precision": "day"
679             }*/
680         },
681         "identifiers": [{
682             "identifier": pd.sha_extension,
683             "extension": pd.extension || "UNK"
684         }],
685         "translations": [{
686             "name": "Condition",
687             "code": "75323-6",
688             "code_system_name": "LOINC"
689         }],
690         "problem": {
691             "code": {
692                 "name": trim(pd.title),
693                 "code": cleanCode(pd.code),
694                 "code_system_name": trim(pd.code_type)
695             },
696             "date_time": {
697                 "low": {
698                     "date": fDate(pd.start_date),
699                     "precision": "day"
700                 },
701                 /*"high": {
702                     "date": fDate(pd.end_date),
703                     "precision": getPrecision()
704                 }*/
705             }
706         },
707         "performer": [
708             {
709                 "identifiers": [
710                     {
711                         "identifier": "2.16.840.1.113883.4.6",
712                         "extension": all.primary_care_provider.provider[0].npi || "UNK"
713                     }
714                 ],
715                 "name": [
716                     {
717                         "last": all.primary_care_provider.provider[0].lname || "",
718                         "first": all.primary_care_provider.provider[0].fname || ""
719                     }
720                 ]
721             }],
722         "onset_age": pd.age,
723         "onset_age_unit": "Year",
724         "status": {
725             "name": pd.status_table,
726             "date_time": {
727                 "low": {
728                     "date": fDate(pd.start_date),
729                     "precision": "day"
730                 },
731                 /*"high": {
732                     "date": fDate(pd.end_date),
733                     "precision": getPrecision()
734                 }*/
735             }
736         },
737         "patient_status": pd.observation,
738         "source_list_identifiers": [{
739             "identifier": pd.sha_extension,
740             "extension": pd.extension || "UNK"
741         }]
742     };
746 function populateProcedure(pd) {
747     return {
748         "procedure": {
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"
753         },
754         "identifiers": [{
755             "identifier": "d68b7e32-7810-4f5b-9cc2-acd54b0fd85d",
756             "extension": pd.extension
757         }],
758         "status": "completed",
759         "date_time": {
760             "point": {
761                 "date": fDate(pd.date),
762                 "precision": "day"
763             }
764         },
765         /*"body_sites": [{
766             "name": "",
767             "code": "",
768             "code_system_name": ""
769         }],
770         "specimen": {
771             "identifiers": [{
772                 "identifier": "c2ee9ee9-ae31-4628-a919-fec1cbb58683"
773             }],
774             "code": {
775                 "name": "",
776                 "code": "",
777                 "code_system_name": "SNOMED CT"
778             }
779         },*/
780         "performers": [{
781             "identifiers": [{
782                 "identifier": "2.16.840.1.113883.4.6",
783                 "extension": pd.npi || "UNK"
784             }],
785             "address": [{
786                 "street_lines": [pd.address],
787                 "city": pd.city,
788                 "state": pd.state,
789                 "zip": pd.zip,
790                 "country": "US"
791             }],
792             "phone": [{
793                 "number": pd.work_phone,
794                 "type": "work place"
795             }],
796             "organization": [{
797                 "identifiers": [{
798                     "identifier": pd.facility_sha_extension,
799                     "extension": pd.facility_extension
800                 }],
801                 "name": [pd.facility_name],
802                 "address": [{
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"
808                 }],
809                 "phone": [{
810                     "number": pd.facility_phone,
811                     "type": "work place"
812                 }]
813             }]
814         }],
815         "procedure_type": "procedure"
816     };
819 function populateMedicalDevice(pd) {
820     return {
821         "identifiers": [{
822             "identifier": pd.sha_extension,
823             "extension": pd.extension
824         }],
825         "date_time": {
826             "low": {
827                 "date": fDate(pd.start_date),
828                 "precision": "day"
829             }/*,
830             "high": {
831                 "date": fDate(pd.end_date),
832                 "precision": "day"
833             }*/
834         },
835         "device_type": "UDI",
836         "device": {
837             "name": pd.code_text,
838             "code": cleanCode(pd.code),
839             "code_system_name": "SNOMED CT",
840             "identifiers": [{
841                 "identifier": "2.16.840.1.113883.3.3719",
842                 "extension": pd.udi
843             }],
844             "status": "completed",
845             "body_sites": [{
846                 "name": "",
847                 "code": "",
848                 "code_system_name": ""
849             }],
850             "udi": pd.udi
851         }
852     }
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;
861     value += "";
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()) {
866         case "NO":
867             icode = "Normal";
868             break;
869         case "YES":
870             icode = "Abnormal";
871             break;
872         case "":
873             icode = "UNK";
874             break;
875     }
876     return {
877         "identifiers": [{
878             "identifier": pd.subtest.root,
879             "extension": pd.subtest.extension
880         }],
881         "result": {
882             "name": pd.title,
883             "code": cleanCode(pd.subtest.result_code) || "UNK",
884             "code_system_name": "LOINC"
885         },
886         "date_time": {
887             "point": {
888                 "date": fDate(pd.date_ordered),
889                 "precision": "day"
890             }
891         },
892         "status": pd.order_status,
893         "reference_range": {
894             "low": pd.subtest.low,
895             "high": pd.subtest.high,
896             "unit": pd.subtest.unit,
897             "type": type,
898             "range_type": range_type
899         },
900         "interpretations": [icode],
901         "value": value + "",
902         "unit": pd.subtest.unit,
903         "type": type,
904         "range": pd.subtest.range,
905         "range_type": range_type
906     };
909 function getResultSet(results) {
911     if (!results) return '';
913     let tResult = results.result[0] || results.result;
914     var resultSet = {
915         "identifiers": [{
916             "identifier": tResult.root,
917             "extension": tResult.extension
918         }],
919         "author": [
920             {
921                 "date_time": {
922                     "point": {
923                         "date": fDate(tResult.date_ordered),
924                         "precision": getPrecision(fDate(tResult.date_ordered))
925                     }
926                 },
927                 "identifiers": [
928                     {
929                         "identifier": "2.16.840.1.113883.4.6",
930                         "extension": all.primary_care_provider.provider[0].npi || "UNK"
931                     }
932                 ],
933                 "name": [
934                     {
935                         "last": all.primary_care_provider.provider[0].lname || "",
936                         "first": all.primary_care_provider.provider[0].fname || ""
937                     }
938                 ]
939             }],
940         "result_set": {
941             "name": tResult.test_name,
942             "code": cleanCode(tResult.test_code),
943             "code_system_name": "LOINC"
944         }
945     };
946     var rs = [];
947     var many = [];
948     var theone = {};
949     var count = 0;
950     many.results = [];
951     try {
952         count = isOne(results.result);
953     } catch (e) {
954         count = 0;
955     }
956     if (count > 1) {
957         for (let i in results.result) {
958             theone[i] = populateResult(results.result[i]);
959             many.results.push(theone[i]);
960         }
961     } else if (count !== 0) {
962         theone = populateResult(results.result);
963         many.results.push(theone);
964     }
965     rs.results = Object.assign(resultSet);
966     rs.results.results = Object.assign(many.results);
967     return rs;
970 function getPlanOfCare(pd) {
971     return {
972         "plan": {
973             "name": pd.code_text || "UNK",
974             "code": cleanCode(pd.code) || "UNK",
975             "code_system_name": pd.code_type || "SNOMED CT"
976         },
977         "identifiers": [{
978             "identifier": "9a6d1bac-17d3-4195-89a4-1121bc809b4a"
979         }],
980         "goal": {
981             "code": cleanCode(pd.code) || "UNK",
982             "name": pd.description || "UNK"
983         },
984         "date_time": {
985             "center": {
986                 "date": fDate(pd.date_formatted),
987                 "precision": "day"
988             }
989         },
990         "type": "observation",
991         "status": {
992             "code": cleanCode(pd.status)
993         },
994         "name": pd.description
995     };
998 function populateVital(pd) {
999     return {
1000         "identifiers": [{
1001             "identifier": pd.sha_extension,
1002             "extension": pd.extension
1003         }],
1004         "status": "completed",
1005         "date_time": {
1006             "point": {
1007                 "date": fDate(pd.effectivetime),
1008                 "precision": getPrecision(fDate(pd.effectivetime))
1009             }
1010         },
1011         // our list of vitals per organizer.
1012         "vital_list": [{
1013             "identifiers": [{
1014                 "identifier": pd.sha_extension,
1015                 "extension": pd.extension_bps
1016             }],
1017             "vital": {
1018                 "name": "Blood Pressure Systolic",
1019                 "code": "8480-6",
1020                 "code_system_name": "LOINC"
1021             },
1022             "status": "completed",
1023             "date_time": {
1024                 "point": {
1025                     "date": fDate(pd.effectivetime),
1026                     "precision": getPrecision(fDate(pd.effectivetime))
1027                 }
1028             },
1029             "interpretations": ["Normal"],
1030             "value": parseFloat(pd.bps),
1031             "unit": "mm[Hg]"
1032         }, {
1033             "identifiers": [{
1034                 "identifier": pd.sha_extension,
1035                 "extension": pd.extension_bpd
1036             }],
1037             "vital": {
1038                 "name": "Blood Pressure Diastolic",
1039                 "code": "8462-4",
1040                 "code_system_name": "LOINC"
1041             },
1042             "status": "completed",
1043             "date_time": {
1044                 "point": {
1045                     "date": fDate(pd.effectivetime),
1046                     "precision": getPrecision(fDate(pd.effectivetime))
1047                 }
1048             },
1049             "interpretations": ["Normal"],
1050             "value": parseFloat(pd.bpd),
1051             "unit": "mm[Hg]"
1052         }, {
1053             "identifiers": [{
1054                 "identifier": pd.sha_extension,
1055                 "extension": pd.extension_pulse
1056             }],
1057             "vital": {
1058                 "name": "Heart Rate",
1059                 "code": "8867-4",
1060                 "code_system_name": "LOINC"
1061             },
1062             "status": "completed",
1063             "date_time": {
1064                 "point": {
1065                     "date": fDate(pd.effectivetime),
1066                     "precision": getPrecision(fDate(pd.effectivetime))
1067                 }
1068             },
1069             "interpretations": ["Normal"],
1070             "value": parseFloat(pd.pulse),
1071             "unit": "/min"
1072         }, {
1073             "identifiers": [{
1074                 "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.2",
1075                 "extension": pd.extension_breath
1076             }],
1077             "vital": {
1078                 "name": "Respiratory Rate",
1079                 "code": "9279-1",
1080                 "code_system_name": "LOINC"
1081             },
1082             "status": "completed",
1083             "date_time": {
1084                 "point": {
1085                     "date": fDate(pd.effectivetime),
1086                     "precision": getPrecision(fDate(pd.effectivetime))
1087                 }
1088             },
1089             "interpretations": ["Normal"],
1090             "value": parseFloat(pd.breath),
1091             "unit": "/min"
1092         }, {
1093             "identifiers": [{
1094                 "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.3",
1095                 "extension": pd.extension_temperature
1096             }],
1097             "vital": {
1098                 "name": "Body Temperature",
1099                 "code": "8310-5",
1100                 "code_system_name": "LOINC"
1101             },
1102             "status": "completed",
1103             "date_time": {
1104                 "point": {
1105                     "date": fDate(pd.effectivetime),
1106                     "precision": getPrecision(fDate(pd.effectivetime))
1107                 }
1108             },
1109             "interpretations": ["Normal"],
1110             "value": parseFloat(pd.temperature),
1111             "unit": pd.unit_temperature
1112         },
1113             {
1114                 "identifiers": [{
1115                     "identifier": pd.sha_extension,
1116                     "extension": pd.extension_height
1117                 }],
1118                 "vital": {
1119                     "name": "Height",
1120                     "code": "8302-2",
1121                     "code_system_name": "LOINC"
1122                 },
1123                 "status": "completed",
1124                 "date_time": {
1125                     "point": {
1126                         "date": fDate(pd.effectivetime),
1127                         "precision": getPrecision(fDate(pd.effectivetime))
1128                     }
1129                 },
1130                 "interpretations": ["Normal"],
1131                 "value": parseFloat(pd.height),
1132                 "unit": pd.unit_height
1133             }, {
1134                 "identifiers": [{
1135                     "identifier": pd.sha_extension,
1136                     "extension": pd.extension_weight
1137                 }],
1138                 "vital": {
1139                     "name": "Weight Measured",
1140                     "code": "29463-7",
1141                     "code_system_name": "LOINC"
1142                 },
1143                 "status": "completed",
1144                 "date_time": {
1145                     "point": {
1146                         "date": fDate(pd.effectivetime),
1147                         "precision": getPrecision(fDate(pd.effectivetime))
1148                     }
1149                 },
1150                 "interpretations": ["Normal"],
1151                 "value": parseFloat(pd.weight),
1152                 "unit": pd.unit_weight
1153             }, {
1154                 "identifiers": [{
1155                     "identifier": pd.sha_extension,
1156                     "extension": pd.extension_BMI
1157                 }],
1158                 "vital": {
1159                     "name": "BMI (Body Mass Index)",
1160                     "code": "39156-5",
1161                     "code_system_name": "LOINC"
1162                 },
1163                 "status": "completed",
1164                 "date_time": {
1165                     "point": {
1166                         "date": fDate(pd.effectivetime),
1167                         "precision": getPrecision(fDate(pd.effectivetime))
1168                     }
1169                 },
1170                 "interpretations": ["Normal"],
1171                 "value": parseFloat(pd.BMI),
1172                 "unit": "kg/m2"
1173             }, {
1174                 "identifiers": [{
1175                     "identifier": pd.sha_extension,
1176                     "extension": pd.extension_oxygen_saturation
1177                 }],
1178                 "vital": {
1179                     "name": "O2 % BldC Oximetry",
1180                     "code": "59408-5",
1181                     "code_system_name": "LOINC"
1182                 },
1183                 "status": "completed",
1184                 "date_time": {
1185                     "point": {
1186                         "date": fDate(pd.effectivetime),
1187                         "precision": getPrecision(fDate(pd.effectivetime))
1188                     }
1189                 },
1190                 "interpretations": ["Normal"],
1191                 "value": parseFloat(pd.oxygen_saturation),
1192                 "unit": "%"
1193             }
1194         ]
1195     }
1198 function populateSocialHistory(pd) {
1199     return {
1200         "date_time": {
1201             "low": templateDate(pd.date_formatted, "day")
1202             //"high": templateDate(pd.date, "day")
1203         },
1204         "identifiers": [{
1205             "identifier": pd.sha_extension,
1206             "extension": pd.extension
1207         }],
1208         "code": {
1209             "name": pd.element
1210         },
1211         "value": pd.description,
1212         "gender": all.patient.gender
1213     };
1216 function populateImmunization(pd) {
1217     return {
1218         "date_time": {
1219             "point": {
1220                 "date": fDate(pd.administered_on),
1221                 "precision": "month"
1222             }
1223         },
1224         "identifiers": [{
1225             "identifier": "e6f1ba43-c0ed-4b9b-9f12-f435d8ad8f92",
1226             "extension": pd.extension || "UNK"
1227         }],
1228         "status": "complete",
1229         "product": {
1230             "product": {
1231                 "name": pd.code_text,
1232                 "code": cleanCode(pd.cvx_code),
1233                 "code_system_name": "CVX"
1234                 /*"translations": [{
1235                     "name": "",
1236                     "code": "",
1237                     "code_system_name": "CVX"
1238                 }]*/
1239             },
1240             "lot_number": "UNK",
1241             "manufacturer": "UNK"
1242         },
1243         "administration": {
1244             "route": {
1245                 "name": pd.route_of_administration,
1246                 "code": cleanCode(pd.route_code) || "UNK",
1247                 "code_system_name": "Medication Route FDA"
1248             }/*,
1249             "dose": {
1250                 "value": 50,
1251                 "unit": "mcg"
1252             }*/
1253         },
1254         "performer": {
1255             "identifiers": [{
1256                 "identifier": "2.16.840.1.113883.4.6",
1257                 "extension": npiProvider || "UNK"
1258             }],
1259             "name": [{
1260                 "last": pd.lname,
1261                 "first": pd.fname
1262             }],
1263             "address": [{
1264                 "street_lines": [pd.address],
1265                 "city": pd.city,
1266                 "state": pd.state,
1267                 "zip": pd.zip,
1268                 "country": "US"
1269             }],
1270             "organization": [{
1271                 "identifiers": [{
1272                     "identifier": "2.16.840.1.113883.4.6",
1273                     "extension": npiFacility || "UNK"
1274                 }],
1275                 "name": [pd.facility_name]
1276             }]
1277         },
1278         "instructions": {
1279             "code": {
1280                 "name": "immunization education",
1281                 "code": "171044003",
1282                 "code_system_name": "SNOMED CT"
1283             },
1284             "free_text": "Needs Attention for more data."
1285         }
1286     };
1289 function populatePayer(pd) {
1290     return {
1291         "identifiers": [{
1292             "identifier": "1fe2cdd0-7aad-11db-9fe1-0800200c9a66"
1293         }],
1294         "policy": {
1295             "identifiers": [{
1296                 "identifier": "3e676a50-7aac-11db-9fe1-0800200c9a66"
1297             }],
1298             "code": {
1299                 "code": "SELF",
1300                 "code_system_name": "HL7 RoleCode"
1301             },
1302             "insurance": {
1303                 "code": {
1304                     "code": "PAYOR",
1305                     "code_system_name": "HL7 RoleCode"
1306                 },
1307                 "performer": {
1308                     "identifiers": [{
1309                         "identifier": "2.16.840.1.113883.19"
1310                     }],
1311                     "address": [{
1312                         "street_lines": ["123 Insurance Road"],
1313                         "city": "Blue Bell",
1314                         "state": "MA",
1315                         "zip": "02368",
1316                         "country": "US",
1317                         "use": "work place"
1318                     }],
1319                     "phone": [{
1320                         "number": "(781)555-1515",
1321                         "type": "work place"
1322                     }],
1323                     "organization": [{
1324                         "name": ["Good Health Insurance"],
1325                         "address": [{
1326                             "street_lines": ["123 Insurance Road"],
1327                             "city": "Blue Bell",
1328                             "state": "MA",
1329                             "zip": "02368",
1330                             "country": "US",
1331                             "use": "work place"
1332                         }],
1333                         "phone": [{
1334                             "number": "(781)555-1515",
1335                             "type": "work place"
1336                         }]
1337                     }],
1338                     "code": [{
1339                         "code": "PAYOR",
1340                         "code_system_name": "HL7 RoleCode"
1341                     }]
1342                 }
1343             }
1344         },
1345         "guarantor": {
1346             "code": {
1347                 "code": "GUAR",
1348                 "code_system_name": "HL7 Role"
1349             },
1350             "identifiers": [{
1351                 "identifier": "329fcdf0-7ab3-11db-9fe1-0800200c9a66"
1352             }],
1353             "name": [{
1354                 "prefix": "Mr.",
1355                 "middle": ["Frankie"],
1356                 "last": "Everyman",
1357                 "first": "Adam"
1358             }],
1359             "address": [{
1360                 "street_lines": ["17 Daws Rd."],
1361                 "city": "Blue Bell",
1362                 "state": "MA",
1363                 "zip": "02368",
1364                 "country": "US",
1365                 "use": "primary home"
1366             }],
1367             "phone": [{
1368                 "number": "(781)555-1212",
1369                 "type": "primary home"
1370             }]
1371         },
1372         "participant": {
1373             "code": {
1374                 "name": "Self",
1375                 "code": "SELF",
1376                 "code_system_name": "HL7 Role"
1377             },
1378             "performer": {
1379                 "identifiers": [{
1380                     "identifier": "14d4a520-7aae-11db-9fe1-0800200c9a66",
1381                     "extension": "1138345"
1382                 }],
1383                 "address": [{
1384                     "street_lines": ["17 Daws Rd."],
1385                     "city": "Blue Bell",
1386                     "state": "MA",
1387                     "zip": "02368",
1388                     "country": "US",
1389                     "use": "primary home"
1390                 }],
1391                 "code": [{
1392                     "name": "Self",
1393                     "code": "SELF",
1394                     "code_system_name": "HL7 Role"
1395                 }]
1396             },
1397             "name": [{
1398                 "prefix": "Mr.",
1399                 "middle": ["A."],
1400                 "last": "Everyman",
1401                 "first": "Frank"
1402             }]
1403         },
1404         "policy_holder": {
1405             "performer": {
1406                 "identifiers": [{
1407                     "identifier": "2.16.840.1.113883.19",
1408                     "extension": "1138345"
1409                 }],
1410                 "address": [{
1411                     "street_lines": ["17 Daws Rd."],
1412                     "city": "Blue Bell",
1413                     "state": "MA",
1414                     "zip": "02368",
1415                     "country": "US",
1416                     "use": "primary home"
1417                 }]
1418             }
1419         },
1420         "authorization": {
1421             "identifiers": [{
1422                 "identifier": "f4dce790-8328-11db-9fe1-0800200c9a66"
1423             }],
1424             "procedure": {
1425                 "code": {
1426                     "name": "Colonoscopy",
1427                     "code": "73761001",
1428                     "code_system_name": "SNOMED CT"
1429                 }
1430             }
1431         }
1432     };
1435 function populateHeader(pd) {
1436     var head = {
1437         "identifiers": [
1438             {
1439                 "identifier": oidFacility,
1440                 "extension": "TT988"
1441             }
1442         ],
1443         "code": {
1444             "name": "Continuity of Care Document", //change to toc w/code
1445             "code": "34133-9",
1446             "code_system_name": "LOINC"
1447         },
1448         "template": [
1449             "2.16.840.1.113883.10.20.22.1.1",
1450             "2.16.840.1.113883.10.20.22.1.2"
1451         ],
1452         "title": "OpenEMR Transitions of Care : Consolidated CDA",
1453         "date_time": {
1454             "date": pd.created_time_timezone,
1455             "precision": "none"
1456         },
1457         "author": {
1458             "author": [
1459                 {
1460                     "time": pd.created_time_timezone,
1461                     "identifiers": [
1462                         {
1463                             "identifier": "2.16.840.1.113883.4.6",
1464                             "extension": pd.author.npi || "UNK"
1465                         }
1466                     ],
1467                     "name": [
1468                         {
1469                             "last": pd.author.lname,
1470                             "first": pd.author.fname
1471                         }
1472                     ],
1473                     "address": [
1474                         {
1475                             "street_lines": [
1476                                 pd.author.streetAddressLine
1477                             ],
1478                             "city": pd.author.city,
1479                             "state": pd.author.state,
1480                             "zip": pd.author.postalCode,
1481                             "country": pd.author.country || "US",
1482                             "use": "work place"
1483                         }
1484                     ],
1485                     "phone": [
1486                         {
1487                             "number": pd.author.telecom || "UNK",
1488                             "type": "WP"
1489                         }
1490                     ],
1491                     "organization": [
1492                         {
1493                             "identity": [
1494                                 {
1495                                     "root": "2.16.840.1.113883.4.6",
1496                                     "extension": npiFacility || "UNK"
1497                                 }
1498                             ],
1499                             "name": [
1500                                 pd.encounter_provider.facility_name
1501                             ],
1502                             "address": [
1503                                 {
1504                                     "street_lines": [
1505                                         pd.encounter_provider.facility_street
1506                                     ],
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",
1511                                     "use": "work place"
1512                                 }
1513                             ],
1514                             "phone": [
1515                                 {
1516                                     "number": pd.encounter_provider.facility_phone,
1517                                     "type": "work primary"
1518                                 }
1519                             ]
1520                         }
1521                     ]
1522                 }
1523             ]
1524         },
1525         "custodian": {
1526             "identity": [
1527                 {
1528                     "root": "2.16.840.1.113883.4.6",
1529                     "extension": npiFacility || "UNK"
1530                 }
1531             ],
1532             "name": [
1533                 pd.encounter_provider.facility_name
1534             ],
1535             "address": [
1536                 {
1537                     "street_lines": [
1538                         pd.encounter_provider.facility_street
1539                     ],
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"
1544                 }
1545             ],
1546             "phone": [
1547                 {
1548                     "number": pd.encounter_provider.facility_phone,
1549                     "type": "work primary"
1550                 }
1551             ]
1552         },
1553         /*"data_enterer": {
1554             "identifiers": [
1555                 {
1556                     "identifier": "2.16.840.1.113883.4.6",
1557                     "extension": "999999943252"
1558                 }
1559             ],
1560             "name": [
1561                 {
1562                     "last": pd.data_enterer.lname,
1563                     "first": pd.data_enterer.fname
1564                 }
1565             ],
1566             "address": [
1567                 {
1568                     "street_lines": [
1569                         pd.data_enterer.streetAddressLine
1570                     ],
1571                     "city": pd.data_enterer.city,
1572                     "state": pd.data_enterer.state,
1573                     "zip": pd.data_enterer.postalCode,
1574                     "country": pd.data_enterer.country
1575                 }
1576             ],
1577             "phone": [
1578                 {
1579                     "number": pd.data_enterer.telecom,
1580                     "type": "work place"
1581                 }
1582             ]
1583         },
1584         "informant": {
1585             "identifiers": [
1586                 {
1587                     "identifier": "2.16.840.1.113883.19.5",
1588                     "extension": "KP00017"
1589                 }
1590             ],
1591             "name": [
1592                 {
1593                     "last": pd.informer.lname || "",
1594                     "first": pd.informer.fname || ""
1595                 }
1596             ],
1597             "address": [
1598                 {
1599                     "street_lines": [
1600                         pd.informer.streetAddressLine || ""
1601                     ],
1602                     "city": pd.informer.city,
1603                     "state": pd.informer.state,
1604                     "zip": pd.informer.postalCode,
1605                     "country": pd.informer.country
1606                 }
1607             ],
1608             "phone": [
1609                 {
1610                     "number": pd.informer.telecom || "",
1611                     "type": "work place"
1612                 }
1613             ]
1614         },*/
1615         /*"service_event": {
1616             "code": {
1617                 "name": "UNK",
1618                 "code": "UNK",
1619                 "code_system_name": "SNOMED CT"
1620             },
1621             "date_time": {
1622                 "low": {
1623                     "date": "2021-03-11",
1624                     "precision": "day"
1625                 },
1626                 "high": {
1627                     "date": pd.created_time,
1628                     "precision": "day"
1629                 }
1630             },
1631             "performer": [
1632                 {
1633                     "performer": [
1634                         {
1635                             "identifiers": [
1636                                 {
1637                                     "identifier": "2.16.840.1.113883.4.6",
1638                                     "extension": npiProvider
1639                                 }
1640                             ],
1641                             "name": [
1642                                 {
1643                                     "last": pd.information_recipient.lname || "DAH",
1644                                     "first": pd.information_recipient.fname || "DAH"
1645                                 }
1646                             ],
1647                             "address": [
1648                                 {
1649                                     "street_lines": [
1650                                         pd.information_recipient.streetAddressLine
1651                                     ],
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"
1656                                 }
1657                             ],
1658                             "phone": [
1659                                 {
1660                                     "number": pd.information_recipient.telecom,
1661                                     "type": "work place"
1662                                 }
1663                             ],
1664                             "organization": [
1665                                 {
1666                                     "identifiers": [
1667                                         {
1668                                             "identifier": "2.16.840.1.113883.19.5.9999.1393"
1669                                         }
1670                                     ],
1671                                     "name": [
1672                                         pd.encounter_provider.facility_name
1673                                     ],
1674                                     "address": [
1675                                         {
1676                                             "street_lines": [
1677                                                 pd.encounter_provider.facility_street
1678                                             ],
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"
1683                                         }
1684                                     ],
1685                                     "phone": [
1686                                         {
1687                                             "number": pd.encounter_provider.facility_phone,
1688                                             "type": "primary work"
1689                                         }
1690                                     ]
1691                                 }
1692                             ],
1693                             "code": [
1694                                 {
1695                                     "name": "UNK",
1696                                     "code": "",
1697                                     "code_system_name": "Provider Codes"
1698                                 }
1699                             ]
1700                         }
1701                     ],
1702                     "code": {
1703                         "name": "Primary Performer",
1704                         "code": "PP",
1705                         "code_system_name": "Provider Role"
1706                     }
1707                 }
1708             ]
1709         }*/
1710     };
1711     return head;
1714 function getMeta(pd) {
1715     var meta = {};
1716     meta = {
1717         "type": "CCDA",
1718         "identifiers": [
1719             {
1720                 "identifier": oidFacility || "UNK",
1721                 "extension": "TT988"
1722             }
1723         ],
1724         "confidentiality": "Normal",
1725         "set_id": {
1726             "identifier": oidFacility + ".1" || "UNK",
1727             "extension": "sTT988"
1728         }
1729     }
1730     return meta;
1733 function genCcda(pd) {
1734     var doc = {};
1735     var data = {};
1736     var count = 0;
1737     var many = [];
1738     var theone = {};
1740     all = 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;
1745 // Demographics
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);
1752 // vitals
1753     many.vitals = [];
1754     try {
1755         count = isOne(pd.history_physical.vitals_list.vitals);
1756     } catch (e) {
1757         count = 0
1758     }
1759     /*if (count > 1) {
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);
1763         }
1764     } else if (count === 1) {
1765         theone = populateVital(pd.history_physical.vitals_list.vitals);
1766         many.vitals.push(theone);
1767     }
1768     data.vitals = Object.assign(many.vitals);*/
1769     if (count !== 0) {
1770         data.vitals = Object.assign(populateVital(pd.history_physical.vitals_list.vitals));
1771     }
1772 // Medications
1773     let meds = [];
1774     let m = {};
1775     meds.medications = [];
1776     try {
1777         count = isOne(pd.medications.medication);
1778     } catch (e) {
1779         count = 0
1780     }
1781     if (count > 1) {
1782         for (let i in pd.medications.medication) {
1783             m[i] = populateMedication(pd.medications.medication[i]);
1784             meds.medications.push(m[i]);
1785         }
1786     } else if (count !== 0) {
1787         m = populateMedication(pd.medications.medication);
1788         meds.medications.push(m);
1789     }
1790     data.medications = Object.assign(meds.medications);
1791 // Encounters
1792     let encs = [];
1793     let enc = {};
1794     encs.encounters = [];
1795     try {
1796         count = isOne(pd.encounter_list.encounter);
1797     } catch (e) {
1798         count = 0
1799     }
1800     if (count > 1) {
1801         for (let i in pd.encounter_list.encounter) {
1802             enc[i] = populateEncounter(pd.encounter_list.encounter[i]);
1803             encs.encounters.push(enc[i]);
1804         }
1805     } else if (count !== 0) {
1806         enc = populateEncounter(pd.encounter_list.encounter);
1807         encs.encounters.push(enc);
1808     }
1809     data.encounters = Object.assign(encs.encounters);
1811 // Allergies
1812     let allergies = [];
1813     let allergy = {};
1814     allergies.allergies = [];
1815     try {
1816         count = isOne(pd.allergies.allergy);
1817     } catch (e) {
1818         count = 0
1819     }
1820     if (count > 1) {
1821         for (let i in pd.allergies.allergy) {
1822             allergy[i] = populateAllergy(pd.allergies.allergy[i]);
1823             allergies.allergies.push(allergy[i]);
1824         }
1825     } else if (count !== 0) {
1826         allergy = populateAllergy(pd.allergies.allergy);
1827         allergies.allergies.push(allergy);
1828     }
1829     data.allergies = Object.assign(allergies.allergies);
1831 // Problems
1832     let problems = [];
1833     let problem = {};
1834     problems.problems = [];
1835     try {
1836         count = isOne(pd.problem_lists.problem);
1837     } catch (e) {
1838         count = 0
1839     }
1840     if (count > 1) {
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]);
1844         }
1845     } else if (count !== 0) {
1846         problem = populateProblem(pd.problem_lists.problem);
1847         problems.problems.push(problem);
1848     }
1849     data.problems = Object.assign(problems.problems);
1850 // Procedures
1851     many = [];
1852     theone = {};
1853     many.procedures = [];
1854     try {
1855         count = isOne(pd.procedures.procedure);
1856     } catch (e) {
1857         count = 0
1858     }
1859     if (count > 1) {
1860         for (let i in pd.procedures.procedure) {
1861             theone[i] = populateProcedure(pd.procedures.procedure[i]);
1862             many.procedures.push(theone[i]);
1863         }
1864     } else if (count !== 0) {
1865         theone = populateProcedure(pd.procedures.procedure);
1866         many.procedures.push(theone);
1867     }
1868     data.procedures = Object.assign(many.procedures);
1869 // Medical Devices
1870     many = [];
1871     theone = {};
1872     many.medical_devices = [];
1873     try {
1874         count = isOne(pd.medical_devices.device);
1875     } catch (e) {
1876         count = 0
1877     }
1878     if (count > 1) {
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]);
1882         }
1883     } else if (count !== 0) {
1884         theone = populateMedicalDevice(pd.medical_devices.device);
1885         many.medical_devices.push(theone);
1886     }
1887     data.medical_devices = Object.assign(many.medical_devices);
1889 // Results
1890     if (pd.results) {
1891         data.results = Object.assign(getResultSet(pd.results, pd)['results']);
1892     }
1893 // Immunizations
1894     many = [];
1895     theone = {};
1896     many.immunizations = [];
1897     try {
1898         count = isOne(pd.immunizations.immunization);
1899     } catch (e) {
1900         count = 0;
1901     }
1902     if (count > 1) {
1903         for (let i in pd.immunizations.immunization) {
1904             theone[i] = populateImmunization(pd.immunizations.immunization[i]);
1905             many.immunizations.push(theone[i]);
1906         }
1907     } else if (count !== 0) {
1908         theone = populateImmunization(pd.immunizations.immunization);
1909         many.immunizations.push(theone);
1910     }
1911     data.immunizations = Object.assign(many.immunizations);
1912 // Plan of Care
1913     many = [];
1914     theone = {};
1915     many.plan_of_care = [];
1916     try {
1917         count = isOne(pd.planofcare.item);
1918     } catch (e) {
1919         count = 0
1920     }
1921     if (count > 1) {
1922         for (let i in pd.planofcare.item) {
1923             if (cleanCode(pd.planofcare.item[i].code) === '') {
1924                 i--;
1925                 continue;
1926             }
1927             theone[i] = getPlanOfCare(pd.planofcare.item[i]);
1928             many.plan_of_care.push(theone[i]);
1929         }
1930     } else if (count !== 0) {
1931         theone = getPlanOfCare(pd.planofcare.item);
1932         many.plan_of_care.push(theone);
1933     }
1935     data.plan_of_care = Object.assign(many.plan_of_care);
1936     // Social History
1937     many = [];
1938     theone = {};
1939     many.social_history = [];
1940     try {
1941         count = isOne(pd.history_physical.social_history.history_element);
1942     } catch (e) {
1943         count = 0
1944     }
1945     if (count > 1) {
1946         for (let i in pd.history_physical.social_history.history_element) {
1947             if (i > 0) break;
1948             theone[i] = populateSocialHistory(pd.history_physical.social_history.history_element[i]);
1949             many.social_history.push(theone[i]);
1950         }
1951     } else if (count !== 0) {
1952         theone = populateSocialHistory(pd.history_physical.social_history.history_element);
1953         many.social_history.push(theone);
1954     }
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);
1968     // Debug
1969     fs.writeFile("ccda.json", JSON.stringify(all, null, 4), function (err) {
1970         if (err) {
1971             return console.log(err);
1972         }
1973         console.log("Json saved!");
1974     });
1975     fs.writeFile("ccda.xml", xml, function (err) {
1976         if (err) {
1977             return console.log(err);
1978         }
1979         console.log("Xml saved!");
1980     });
1982     return xml;
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");
1998             conn.end('');
1999             return;
2000         }
2001         xml_complete += xml.toString();
2002         if (xml.toString().match(/\<\/CCDA\>$/g)) {
2003             // ---------------------start--------------------------------
2004             let doc = "";
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);
2011                     return;
2012                 }
2013                 doc = genCcda(data.CCDA);
2014             });
2016             doc = headReplace(doc);
2017             doc = doc.toString().replace(/(\u000b|\u001c|\r)/gm, "").trim();
2018             //console.log(doc);
2019             let chunk = "";
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);
2023                 conn.write(chunk);
2024             }
2025             conn.write(String.fromCharCode(28) + "\r\r" + '');
2026             conn.end();
2027         }
2028     }
2030     function eventCloseConn() {
2031         //console.log('connection from %s closed', remoteAddress);
2032     }
2034     function eventErrorConn(err) {
2035         //console.log('Connection %s error: %s', remoteAddress, err.message);
2036     }
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());
2048     });
2051 setUp(server);