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