feat: show collection balance in billing widget (#7454)
[openemr.git] / ccdaservice / serveccda.js
blob919be01eb0b7aa0e3a6fd7cf45acf90e31f48060
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-2022 Jerry Padgett <sjpadgett@gmail.com>
7  * @license   https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
8  */
10 "use strict";
12 const enableDebug = true;
14 const net = require('net');
15 const server = net.createServer();
16 const to_json = require('xmljson').to_json;
17 const bbg = require(__dirname + '/oe-blue-button-generate');
18 const fs = require('fs');
19 const { DataStack } = require('./data-stack/data-stack');
20 const { cleanCode } = require('./utils/clean-code/clean-code');
21 const { safeTrim } = require('./utils/safe-trim/safe-trim');
22 const { headReplace } = require('./utils/head-replace/head-replace');
23 const { fDate, templateDate } = require('./utils/date/date');
24 const { countEntities } = require('./utils/count-entities/count-entities');
25 const { populateTimezones } = require('./utils/timezones/timezones');
26 const {
27     getNpiFacility,
28     populateDemographics,
29 } = require('./utils/demographics/populate-demographics');
30 const { populateProvider } = require('./utils/providers/providers');
32 var conn = ''; // make our connection scope global to script
33 var oidFacility = "";
34 var all = "";
35 var npiProvider = "";
36 var npiFacility = "";
37 var webRoot = "";
38 var authorDateTime = '';
39 var documentLocation = '';
41 function populateProviders(all) {
42     let providerArray = [];
43     // primary provider
44     let provider = populateProvider(all.primary_care_provider.provider, all);
45     providerArray.push(provider);
46     let count = countEntities(all.care_team.provider);
47     if (count === 1) {
48         provider = populateProvider(all.care_team.provider, all);
49         providerArray.push(provider);
50     } else if (count > 1) {
51         for (let i in all.care_team.provider) {
52             provider = populateProvider(all.care_team.provider[i], all);
53             providerArray.push(provider);
54         }
55     }
56     return {
57         "providers":
58             {
59                 "date_time": {
60                     "low": {
61                         "date": fDate(all.time_start) || fDate(""),
62                         "precision": "tz"
63                     },
64                     "high": {
65                         "date": fDate(all.time_end) || fDate(""),
66                         "precision": "tz"
67                     }
68                 },
69                 "code": {
70                     "name": all.primary_diagnosis.text || "",
71                     "code": cleanCode(all.primary_diagnosis.code || ""),
72                     "code_system_name": all.primary_diagnosis.code_type || ""
73                 },
74                 "provider": providerArray,
75             }
76     }
80 function populateCareTeamMember(provider) {
81     return {
82         //"function_code": provider.physician_type ? "PP" : "",
83         "function_code": {
84             "xmlns": "urn:hl7-org:sdtc",
85             "name": provider.taxonomy_description || "",
86             "code": cleanCode(provider.taxonomy) || "",
87             "code_system": "2.16.840.1.113883.6.101",
88             "code_system_name": "NUCC Health Care Provider Taxonomy"
89         },
90         "status": "active",
91         "date_time": {
92             "low": {
93                 "date": fDate(provider.provider_since) || fDate(""),
94                 "precision": "tz"
95             }
96         },
97         "identifiers": [
98             {
99                 "identifier": provider.npi ? "2.16.840.1.113883.4.6" : oidFacility,
100                 "extension": provider.npi || provider.table_id
101             }
102         ],
103         "full_name": provider.fname + " " + provider.lname,
104         "name": {
105             "last": provider.lname || "",
106             "first": provider.fname || ""
107         },
108         "address": {
109             "street_lines": [
110                 provider.street
111             ],
112             "city": provider.city,
113             "state": provider.state,
114             "zip": provider.zip,
115             "country": all.encounter_provider.facility_country_code || "US"
116         },
117         "phone": [
118             {
119                 "number": provider.telecom,
120                 "type": "work place"
121             }
122         ]
123     }
126 function populateAuthorFromAuthorContainer(pd) {
127     let author = pd.author || {};
128     return {
129         "code": {
130             "name": author.physician_type || '',
131             "code": author.physician_type_code || '',
132             "code_system": author.physician_type_system,
133             "code_system_name": author.physician_type_system_name
134         },
135         "date_time": {
136             "point": {
137                 "date": fDate(author.time),
138                 "precision": "tz"
139             }
140         },
141         "identifiers": [
142             {
143                 "identifier": author.npi ? "2.16.840.1.113883.4.6" : author.id,
144                 "extension": author.npi ? author.npi : 'NI'
145             }
146         ],
147         "name": [
148             {
149                 "last": author.lname || "",
150                 "first": author.fname || ""
151             }
152         ],
153         "organization": [
154             {
155                 "identity": [
156                     {
157                         "root": author.facility_oid || "2.16.840.1.113883.4.6",
158                         "extension": author.facility_npi || "NI"
159                     }
160                 ],
161                 "name": [
162                     author.facility_name || ""
163                 ]
164             }
165         ]
166     };
169 function populateCareTeamMembers(pd) {
170     let providerArray = [];
171     // primary provider
172     let primaryCareProvider = pd.primary_care_provider || {provider: {}};
173     let providerSince = fDate(primaryCareProvider.provider.provider_since || '');
174     if (pd.primary_care_provider) {
175         let provider = populateCareTeamMember(pd.primary_care_provider.provider);
176         providerArray.push(provider);
177         let count = countEntities(pd.care_team.provider);
178         if (count === 1) {
179             provider = populateCareTeamMember(pd.care_team.provider);
180             providerSince = providerSince || fDate(provider.provider_since);
181             providerArray.push(provider);
182         } else if (count > 1) {
183             for (let i in pd.care_team.provider) {
184                 provider = populateCareTeamMember(pd.care_team.provider[i]);
185                 providerSince = providerSince || fDate(provider.provider_since);
186                 providerArray.push(provider);
187             }
188         }
189     }
190     return {
191         "providers":
192             {
193                 "provider": providerArray,
194             },
195         "status": "active",
196         "date_time": {
197             "low": {
198                 "date": providerSince || fDate(""),
199                 "precision": "tz"
200             }
201         },
202         // we treat this author a bit differently since we are working at the main pd object instead of the sub pd.care_team
203         "author": populateAuthorFromAuthorContainer(pd.care_team)
204     }
207 function populateMedication(pd) {
208     pd.status = 'Completed'; //@todo invoke prescribed
209     return {
210         "date_time": {
211             "low": {
212                 "date": fDate(pd.start_date),
213                 "precision": "tz"
214             }/*,
215             "high": {
216                 "date": fDate(pd.end_date),
217                 "precision": "day"
218             }*/
219         },
220         "identifiers": [{
221             "identifier": pd.sha_extension,
222             "extension": pd.extension || ""
223         }],
224         "status": pd.status,
225         "sig": pd.direction,
226         "product": {
227             "identifiers": [{
228                 "identifier": pd.sha_extension || "2a620155-9d11-439e-92b3-5d9815ff4ee8",
229                 "extension": pd.extension + 1 || ""
230             }],
231             "unencoded_name": pd.drug,
232             "product": {
233                 "name": pd.drug,
234                 "code": cleanCode(pd.rxnorm),
235                 "code_system_name": "RXNORM"
236                 /*"translations": [{
237                     "name": pd.drug,
238                     "code": pd.rxnorm,
239                     "code_system_name": "RXNORM"
240                 }],*/
241             },
242             //"manufacturer": ""
243         },
244         "author": {
245             "code": {
246                 "name": pd.author.physician_type || '',
247                 "code": pd.author.physician_type_code || '',
248                 "code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
249             },
250             "date_time": {
251                 "point": {
252                     "date": fDate(pd.author.time),
253                     "precision": "tz"
254                 }
255             },
256             "identifiers": [
257                 {
258                     "identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
259                     "extension": pd.author.npi ? pd.author.npi : 'NI'
260                 }
261             ],
262             "name": [
263                 {
264                     "last": pd.author.lname,
265                     "first": pd.author.fname
266                 }
267             ],
268             "organization": [
269                 {
270                     "identity": [
271                         {
272                             "root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
273                             "extension": pd.author.facility_npi || "NI"
274                         }
275                     ],
276                     "name": [
277                         pd.author.facility_name
278                     ]
279                 }
280             ]
281         },
282         "supply": {
283             "date_time": {
284                 "low": {
285                     "date": fDate(pd.start_date),
286                     "precision": "day"
287                 },
288                 "high": {
289                     "date": fDate(pd.end_date),
290                     "precision": "day"
291                 }
292             },
293             "repeatNumber": "0",
294             "quantity": "0",
295             "product": {
296                 "identifiers": [{
297                     "identifier": pd.sha_extension || "2a620155-9d11-439e-92b3-5d9815ff4ee8",
298                     "extension": pd.extension + 1 || ""
299                 }],
300                 "unencoded_name": pd.drug,
301                 "product": {
302                     "name": pd.drug,
303                     "code": cleanCode(pd.rxnorm),
304                     /*"translations": [{
305                         "name": pd.drug,
306                         "code": pd.rxnorm,
307                         "code_system_name": "RXNORM"
308                     }],*/
309                     "code_system_name": "RXNORM"
310                 },
311                 //"manufacturer": ""
312             },
313             "author": {
314                 "code": {
315                     "name": all.author.physician_type || '',
316                     "code": all.author.physician_type_code || '',
317                     "code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
318                 },
319                 "date_time": {
320                     "point": {
321                         "date": authorDateTime,
322                         "precision": "tz"
323                     }
324                 },
325                 "identifiers": [
326                     {
327                         "identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
328                         "extension": all.author.npi ? all.author.npi : 'NI'
329                     }
330                 ],
331                 "name": [
332                     {
333                         "last": all.author.lname,
334                         "first": all.author.fname
335                     }
336                 ],
337                 "organization": [
338                     {
339                         "identity": [
340                             {
341                                 "root": oidFacility || "2.16.840.1.113883.4.6",
342                                 "extension": npiFacility || ""
343                             }
344                         ],
345                         "name": [
346                             all.encounter_provider.facility_name
347                         ]
348                     }
349                 ]
350             },
351             "instructions": {
352                 "code": {
353                     "name": "instruction",
354                     "code": "409073007",
355                     "code_system_name": "SNOMED CT"
356                 },
357                 "free_text": pd.instructions || "No Instructions"
358             },
359         },
360         "administration": {
361             "route": {
362                 "name": pd.route || "",
363                 "code": cleanCode(pd.route_code) || "",
364                 "code_system_name": "Medication Route FDA"
365             },
366             "form": {
367                 "name": pd.form,
368                 "code": cleanCode(pd.form_code),
369                 "code_system_name": "Medication Route FDA"
370             },
371             "dose": {
372                 "value": parseFloat(pd.size),
373                 "unit": pd.unit,
374             },
375             /*"rate": {
376                 "value": parseFloat(pd.dosage),
377                 "unit": ""
378             },*/
379             "interval": {
380                 "period": {
381                     "value": parseFloat(pd.dosage),
382                     "unit": pd.interval
383                 },
384                 "frequency": true
385             }
386         },
387         "performer": {
388             "identifiers": [{
389                 "identifier": "2.16.840.1.113883.4.6",
390                 "extension": pd.npi || ""
391             }],
392             "organization": [{
393                 "identifiers": [{
394                     "identifier": pd.sha_extension,
395                     "extension": pd.extension || ""
396                 }],
397                 "name": [pd.performer_name]
398             }]
399         },
400         "drug_vehicle": {
401             "name": pd.form,
402             "code": cleanCode(pd.form_code),
403             "code_system_name": "RXNORM"
404         },
405         /*"precondition": {
406             "code": {
407                 "code": "ASSERTION",
408                 "code_system_name": "ActCode"
409             },
410             "value": {
411                 "name": "none",
412                 "code": "none",
413                 "code_system_name": "SNOMED CT"
414             }
415         },
416         "indication": {
417             "identifiers": [{
418                 "identifier": "db734647-fc99-424c-a864-7e3cda82e703",
419                 "extension": "45665"
420             }],
421             "code": {
422                 "name": "Finding",
423                 "code": "404684003",
424                 "code_system_name": "SNOMED CT"
425             },
426             "date_time": {
427                 "low": {
428                     "date": fDate(pd.start_date),
429                     "precision": "day"
430                 }
431             },
432             "value": {
433                 "name": pd.indications,
434                 "code": pd.indications_code,
435                 "code_system_name": "SNOMED CT"
436             }
437         },
438         "dispense": {
439             "identifiers": [{
440                 "identifier": "1.2.3.4.56789.1",
441                 "extension": "cb734647-fc99-424c-a864-7e3cda82e704"
442             }],
443             "performer": {
444                 "identifiers": [{
445                     "identifier": "2.16.840.1.113883.19.5.9999.456",
446                     "extension": "2981823"
447                 }],
448                 "address": [{
449                     "street_lines": [pd.address],
450                     "city": pd.city,
451                     "state": pd.state,
452                     "zip": pd.zip,
453                     "country": "US"
454                 }],
455                 "organization": [{
456                     "identifiers": [{
457                         "identifier": "2.16.840.1.113883.19.5.9999.1393"
458                     }],
459                     "name": [pd.performer_name]
460                 }]
461             },
462             "product": {
463                 "identifiers": [{
464                     "identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8"
465                 }],
466                 "unencoded_name": pd.drug,
467                 "product": {
468                     "name": pd.drug,
469                     "code": pd.rxnorm,
470                     "translations": [{
471                         "name": pd.drug,
472                         "code": pd.rxnorm,
473                         "code_system_name": "RXNORM"
474                     }],
475                     "code_system_name": "RXNORM"
476                 },
477                 "manufacturer": ""
478             }
479         }*/
480     };
483 function getFinding(pd, problem) {
484     const finding = {
485         "identifiers": [{
486             "identifier": pd.sha_extension,
487             "extension": ''
488         }],
489         "value": {
490             "name": '',
491             "code": '',
492             "code_system_name": ''
493         },
494         "date_time": {
495             "low": {
496                 "date": '',
497                 "precision": "day"
498             }
499         },
500         "status": '',
501         "reason": pd.encounter_reason,
502         "author": {
503             "code": {
504                 "name": all.author.physician_type || '',
505                 "code": all.author.physician_type_code || '',
506                 "code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
507             },
508             "date_time": {
509                 "point": {
510                     "date": authorDateTime,
511                     "precision": "tz"
512                 }
513             },
514             "identifiers": [
515                 {
516                     "identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
517                     "extension": all.author.npi ? all.author.npi : 'UNK'
518                 }
519             ],
520             "name": [
521                 {
522                     "last": all.author.lname,
523                     "first": all.author.fname
524                 }
525             ],
526             "organization": [
527                 {
528                     "identity": [
529                         {
530                             "root": oidFacility || "2.16.840.1.113883.4.6",
531                             "extension": npiFacility || ""
532                         }
533                     ],
534                     "name": [
535                         all.encounter_provider.facility_name
536                     ]
537                 }
538             ]
539         },
540     };
542     finding.identifiers["0"].extension = problem.extension;
543     finding.date_time.low.date = fDate(problem.date);
544     finding.value.name = problem.text;
545     finding.value.code = cleanCode(problem.code);
546     finding.value.code_system_name = problem.code_type;
547     finding.status = problem.status;
548     return finding;
551 function populateEncounter(pd) {
552     // just to get diagnosis. for findings..
553     let findingObj = [];
554     let theone = {};
555     let count = 0;
556     try {
557         count = countEntities(pd.encounter_problems.problem);
558     } catch (e) {
559         count = 0;
560     }
561     if (count > 1) {
562         for (let i in pd.encounter_problems.problem) {
563             theone[i] = getFinding(pd, pd.encounter_problems.problem[i]);
564             findingObj.push(theone[i]);
565         }
566     } else if (count !== 0 && pd.encounter_problems.problem.code > '') {
567         let finding = getFinding(pd, pd.encounter_problems.problem);
568         findingObj.push(finding);
569     }
571     return {
572         "encounter": {
573             "name": pd.visit_category ? (pd.visit_category + " | " + pd.encounter_reason) : pd.code_description,
574             "code": pd.code || "185347001",
575             //"code_system": "2.16.840.1.113883.6.96",
576             "code_system_name": pd.code_type || "SNOMED CT",
577             "translations": [{
578                 "name": "Ambulatory",
579                 "code": "AMB",
580                 "code_system_name": "ActCode"
581             }]
582         },
583         "identifiers": [{
584             "identifier": pd.sha_extension,
585             "extension": pd.extension
586         }],
587         "date_time": {
588             "point": {
589                 "date": fDate(pd.date),
590                 "precision": "tz"
591             }
592         },
593         "performers": [{
594             "identifiers": [{
595                 "identifier": "2.16.840.1.113883.4.6",
596                 "extension": pd.npi || ""
597             }],
598             "code": [{
599                 "name": pd.physician_type,
600                 "code": cleanCode(pd.physician_type_code),
601                 "code_system_name": pd.physician_code_type
602             }],
603             "name": [
604                 {
605                     "last": pd.lname || "",
606                     "first": pd.fname || ""
607                 }
608             ],
609             "phone": [
610                 {
611                     "number": pd.work_phone,
612                     "type": "work place"
613                 }
614             ]
615         }],
616         "locations": [{
617             "name": pd.location,
618             "location_type": {
619                 "name": pd.location_details,
620                 "code": "1160-1",
621                 "code_system_name": "HealthcareServiceLocation"
622             },
623             "address": [{
624                 "street_lines": [pd.facility_address],
625                 "city": pd.facility_city,
626                 "state": pd.facility_state,
627                 "zip": pd.facility_zip,
628                 "country": pd.facility_country || "US"
629             }],
630             "phone": [
631                 {
632                     "number": pd.facility_phone,
633                     "type": "work place"
634                 }
635             ]
636         }],
637         "findings": findingObj
638     };
641 function populateAllergy(pd) {
643     if (!pd) {
644         return {
645             "no_know_allergies": "No Known Allergies",
646             "date_time": {
647                 "low": templateDate("", "day"),
648                 //"high": templateDate(pd.enddate, "day")
649             }
650         }
651     }
652     let allergyAuthor = {
653         "code": {
654             "name": pd.author.physician_type || '',
655             "code": pd.author.physician_type_code || '',
656             "code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
657         },
658         "date_time": {
659             "point": {
660                 "date": fDate(pd.author.time),
661                 "precision": "tz"
662             }
663         },
664         "identifiers": [
665             {
666                 "identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
667                 "extension": pd.author.npi ? pd.author.npi : 'NI'
668             }
669         ],
670         "name": [
671             {
672                 "last": pd.author.lname,
673                 "first": pd.author.fname
674             }
675         ],
676         "organization": [
677             {
678                 "identity": [
679                     {
680                         "root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
681                         "extension": pd.author.facility_npi || "NI"
682                     }
683                 ],
684                 "name": [
685                     pd.author.facility_name
686                 ]
687             }
688         ]
689     };
691     return {
692         "identifiers": [{
693             "identifier": pd.sha_id,
694             "extension": pd.id || ""
695         }],
696         "date_time": {
697             "low": templateDate(pd.startdate, "day"),
698             //"high": templateDate(pd.enddate, "day")
699         },
700         "author": allergyAuthor,
701         "observation": {
702             "identifiers": [{
703                 "identifier": pd.sha_extension || "2a620155-9d11-439e-92b3-5d9815ff4ee8",
704                 "extension": pd.id + 1 || ""
705             }],
706             "author": allergyAuthor,
707             "allergen": {
708                 "name": pd.title || "",
709                 "code": pd.rxnorm_code_text ? cleanCode(pd.rxnorm_code) : pd.snomed_code_text ? cleanCode(pd.snomed_code) : cleanCode(""),
710                 "code_system_name": pd.rxnorm_code_text ? "RXNORM" : pd.snomed_code_text ? "SNOMED CT" : ""
711             },
712             "date_time": {
713                 "low": {
714                     "date": fDate(pd.startdate) || fDate(""),
715                     "precision": "day"
716                 }
717             },
718             "intolerance": {
719                 "name": "Propensity to adverse reactions to drug",
720                 "code": "420134006",
721                 "code_system_name": "SNOMED CT"
722             },
723             "severity": {
724                 "code": {
725                     "name": pd.outcome || "",
726                     "code": cleanCode(pd.outcome_code) || "",
727                     "code_system_name": "SNOMED CT"
728                 }
729             },
730             "status": {
731                 "name": pd.status_table || "",
732                 "code": cleanCode(pd.status_code),
733                 "code_system_name": "SNOMED CT"
734             },
735             "reactions": [{
736                 "identifiers": [{
737                     "identifier": "4adc1020-7b14-11db-9fe1-0800200c9a64"
738                 }],
739                 "date_time": {
740                     "low": templateDate(pd.startdate, "day"),
741                     "high": templateDate(pd.enddate, "day")
742                 },
743                 "reaction": {
744                     "name": pd.reaction_text,
745                     "code": cleanCode(pd.reaction_code) || "",
746                     "code_system_name": pd.reaction_code_type || "SNOMED CT"
747                 },
748                 "severity": {
749                     "code": {
750                         "name": pd.outcome || "",
751                         "code": cleanCode(pd.outcome_code),
752                         "code_system_name": "SNOMED CT"
753                     }
754                 }
755             }]
756         }
757     }
760 function populateProblem(pd) {
761     let primary_care_provider = all.primary_care_provider || {provider: {}};
762     return {
763         "date_time": {
764             "low": {
765                 "date": fDate(pd.start_date_table),
766                 "precision": "day"
767             },
768             /*"high": {
769                 "date": fDate(pd.end_date),
770                 "precision": "day"
771             }*/
772         },
773         "identifiers": [{
774             "identifier": pd.sha_extension,
775             "extension": pd.extension || ""
776         }],
777         "translations": [{
778             "name": "Condition",
779             "code": "75323-6",
780             "code_system_name": "LOINC"
781         }],
782         "problem": {
783             "code": {
784                 "name": safeTrim(pd.title),
785                 "code": cleanCode(pd.code),
786                 "code_system_name": safeTrim(pd.code_type)
787             },
788             "date_time": {
789                 "low": {
790                     "date": fDate(pd.start_date),
791                     "precision": "day"
792                 },
793                 /*"high": {
794                     "date": fDate(pd.end_date),
795                     "precision": getPrecision()
796                 }*/
797             }
798         },
799         "author": {
800             "code": {
801                 "name": pd.author.physician_type || '',
802                 "code": pd.author.physician_type_code || '',
803                 "code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
804             },
805             "date_time": {
806                 "point": {
807                     "date": fDate(pd.author.time),
808                     "precision": "tz"
809                 }
810             },
811             "identifiers": [
812                 {
813                     "identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
814                     "extension": pd.author.npi ? pd.author.npi : 'NI'
815                 }
816             ],
817             "name": [
818                 {
819                     "last": pd.author.lname,
820                     "first": pd.author.fname
821                 }
822             ],
823             "organization": [
824                 {
825                     "identity": [
826                         {
827                             "root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
828                             "extension": pd.author.facility_npi || "NI"
829                         }
830                     ],
831                     "name": [
832                         pd.author.facility_name
833                     ]
834                 }
835             ]
836         },
837         "performer": [
838             {
839                 "identifiers": [
840                     {
841                         "identifier": "2.16.840.1.113883.4.6",
842                         "extension": primary_care_provider.provider.npi || ""
843                     }
844                 ],
845                 "name": [
846                     {
847                         "last": primary_care_provider.provider.lname || "",
848                         "first": primary_care_provider.provider.fname || ""
849                     }
850                 ]
851             }],
852         "onset_age": pd.age,
853         "onset_age_unit": "Year",
854         "status": {
855             "name": pd.status_table,
856             "date_time": {
857                 "low": {
858                     "date": fDate(pd.start_date),
859                     "precision": "day"
860                 },
861                 /*"high": {
862                     "date": fDate(pd.end_date),
863                     "precision": getPrecision()
864                 }*/
865             }
866         },
867         "patient_status": pd.observation,
868         "source_list_identifiers": [{
869             "identifier": pd.sha_extension,
870             "extension": pd.extension || ""
871         }]
872     };
876 function populateProcedure(pd) {
877     return {
878         "procedure": {
879             "name": pd.description,
880             "code": cleanCode(pd.code),
881             //"code_system": "2.16.840.1.113883.6.12",
882             "code_system_name": pd.code_type
883         },
884         "identifiers": [{
885             "identifier": "d68b7e32-7810-4f5b-9cc2-acd54b0fd85d",
886             "extension": pd.extension
887         }],
888         "status": "completed",
889         "date_time": {
890             "point": {
891                 "date": fDate(pd.date),
892                 "precision": "day"
893             }
894         },
895         /*"body_sites": [{
896             "name": "",
897             "code": "",
898             "code_system_name": ""
899         }],
900         "specimen": {
901             "identifiers": [{
902                 "identifier": "c2ee9ee9-ae31-4628-a919-fec1cbb58683"
903             }],
904             "code": {
905                 "name": "",
906                 "code": "",
907                 "code_system_name": "SNOMED CT"
908             }
909         },*/
910         "performers": [{
911             "identifiers": [{
912                 "identifier": "2.16.840.1.113883.4.6",
913                 "extension": pd.npi || ""
914             }],
915             "address": [{
916                 "street_lines": [pd.address],
917                 "city": pd.city,
918                 "state": pd.state,
919                 "zip": pd.zip,
920                 "country": "US"
921             }],
922             "phone": [{
923                 "number": pd.work_phone,
924                 "type": "work place"
925             }],
926             "organization": [{
927                 "identifiers": [{
928                     "identifier": pd.facility_sha_extension,
929                     "extension": pd.facility_extension
930                 }],
931                 "name": [pd.facility_name],
932                 "address": [{
933                     "street_lines": [pd.facility_address],
934                     "city": pd.facility_city,
935                     "state": pd.facility_state,
936                     "zip": pd.facility_zip,
937                     "country": pd.facility_country || "US"
938                 }],
939                 "phone": [{
940                     "number": pd.facility_phone,
941                     "type": "work place"
942                 }]
943             }]
944         }],
945         "author": populateAuthorFromAuthorContainer(pd),
946         "procedure_type": "procedure"
947     };
950 function populateMedicalDevice(pd) {
951     return {
952         "identifiers": [{
953             "identifier": pd.sha_extension,
954             "extension": pd.extension
955         }],
956         "date_time": {
957             "low": {
958                 "date": fDate(pd.start_date),
959                 "precision": "day"
960             }/*,
961         "high": {
962             "date": fDate(pd.end_date),
963             "precision": "day"
964         }*/
965         },
966         "device_type": "UDI",
967         "device": {
968             "name": pd.code_text,
969             "code": cleanCode(pd.code),
970             "code_system_name": "SNOMED CT",
971             "identifiers": [{
972                 "identifier": "2.16.840.1.113883.3.3719",
973                 "extension": pd.udi
974             }],
975             "status": "completed",
976             "body_sites": [{
977                 "name": "",
978                 "code": "",
979                 "code_system_name": ""
980             }],
981             "udi": pd.udi
982         },
983         "author": {
984             "code": {
985                 "name": pd.author.physician_type || '',
986                 "code": pd.author.physician_type_code || '',
987                 "code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
988             },
989             "date_time": {
990                 "point": {
991                     "date": fDate(pd.author.time),
992                     "precision": "tz"
993                 }
994             },
995             "identifiers": [
996                 {
997                     "identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
998                     "extension": pd.author.npi ? pd.author.npi : 'NI'
999                 }
1000             ],
1001             "name": [
1002                 {
1003                     "last": pd.author.lname,
1004                     "first": pd.author.fname
1005                 }
1006             ],
1007             "organization": [
1008                 {
1009                     "identity": [
1010                         {
1011                             "root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
1012                             "extension": pd.author.facility_npi || "NI"
1013                         }
1014                     ],
1015                     "name": [
1016                         pd.author.facility_name
1017                     ]
1018                 }
1019             ]
1020         }
1021     }
1024 function populateResult(pd) {
1025     let icode = pd.subtest.abnormal_flag;
1026     let value = parseFloat(pd.subtest.result_value) || pd.subtest.result_value || "";
1027     let type = isNaN(value) ? "ST" : "PQ";
1028     type = !pd.subtest.unit ? "ST" : type;
1029     value += "";
1030     let range_type = pd.subtest.range.toUpperCase() == "NEGATIVE" ? "CO" : type;
1031     type = value.toUpperCase() == "NEGATIVE" ? "CO" : type;
1033     switch (pd.subtest.abnormal_flag.toUpperCase()) {
1034         case "NO":
1035             icode = "Normal";
1036             break;
1037         case "YES":
1038             icode = "Abnormal";
1039             break;
1040         case "":
1041             icode = "";
1042             break;
1043     }
1044     let result = {
1045         "identifiers": [{
1046             "identifier": pd.subtest.root,
1047             "extension": pd.subtest.extension
1048         }],
1049         "result": {
1050             "name": pd.title,
1051             "code": cleanCode(pd.subtest.result_code) || "",
1052             "code_system_name": "LOINC"
1053         },
1054         "date_time": {
1055             "point": {
1056                 "date": fDate(pd.date_ordered),
1057                 "precision": "day"
1058             }
1059         },
1060         "status": pd.order_status,
1061         "reference_range": {
1062             "low": pd.subtest.low,
1063             "high": pd.subtest.high,
1064             "unit": pd.subtest.unit,
1065             "type": type,
1066             "range_type": range_type
1067         },
1068         "value": value + "",
1069         "unit": pd.subtest.unit,
1070         "type": type,
1071         "range": pd.subtest.range,
1072         "range_type": range_type
1073     };
1074     // interpretation cannot be an empty value so we skip it if it is
1075     // empty as Observation.interpretationCode is [0..*]
1076     if (icode !== "") {
1077         result["interpretations"] = [icode];
1078     }
1079     return result;
1082 function getResultSet(results) {
1084     if (!results) return '';
1086     // not sure if the result set should be grouped better on the backend as the author information needs to be more nuanced here
1087     let tResult = results.result[0] || results.result;
1088     let resultSet = {
1089         "identifiers": [{
1090             "identifier": tResult.root,
1091             "extension": tResult.extension
1092         }],
1093         "author": populateAuthorFromAuthorContainer(tResult),
1094         "result_set": {
1095             "name": tResult.test_name,
1096             "code": cleanCode(tResult.test_code),
1097             "code_system_name": "LOINC"
1098         }
1099     };
1100     let rs = [];
1101     let many = [];
1102     let theone = {};
1103     let count = 0;
1104     many.results = [];
1105     try {
1106         count = countEntities(results.result);
1107     } catch (e) {
1108         count = 0;
1109     }
1110     if (count > 1) {
1111         for (let i in results.result) {
1112             theone[i] = populateResult(results.result[i]);
1113             many.results.push(theone[i]);
1114         }
1115     } else if (count !== 0) {
1116         theone = populateResult(results.result);
1117         many.results.push(theone);
1118     }
1119     rs.results = Object.assign(resultSet);
1120     rs.results.results = Object.assign(many.results);
1121     return rs;
1124 function getPlanOfCare(pd) {
1125     let name = '';
1126     let code = '';
1127     let code_system_name = "";
1128     let status = "Active";
1129     let one = true;
1130     let encounter;
1132     let planType = "observation";
1133     switch (pd.care_plan_type) {
1134         case 'plan_of_care':
1135             planType = "observation"; // mood code INT. sets code in template
1136             break;
1137         case 'test_or_order':
1138             planType = "observation"; // mood code RQO
1139             break;
1140         case 'procedure':
1141             planType = "procedure";
1142             break;
1143         case 'appointments':
1144             planType = "encounter";
1145             break;
1146         case 'instructions':
1147             planType = "instructions";
1148             break;
1149         case 'referral':
1150             planType = ""; // for now exclude. unsure how to template.
1151             break;
1152         default:
1153             planType = "observation";
1154     }
1155     if (pd.code_type === 'RXCUI') {
1156         pd.code_type = 'RXNORM';
1157     }
1158     if (pd.code_type === 'RXNORM') {
1159         planType = "substanceAdministration";
1160     }
1161     if (planType === "") {
1162         return false;
1163     }
1165     for (let key in all.encounter_list.encounter) {
1166         // skip loop if the property is from prototype
1167         if (!Object.prototype.hasOwnProperty.call(all.encounter_list.encounter, key)) {
1168             continue;
1169         }
1170         encounter = all.encounter_list.encounter[key];
1171         if (pd.encounter == encounter.encounter_id) {
1172             one = false;
1173             name = encounter.encounter_diagnosis.text;
1174             code = cleanCode(encounter.encounter_diagnosis.code);
1175             code_system_name = encounter.encounter_diagnosis.code_type;
1176             status = encounter.encounter_diagnosis.status;
1177             encounter = all.encounter_list.encounter[key]; // to be sure.
1178             break;
1179         }
1180     }
1181     if (one) {
1182         let value = "";
1183         if (all.encounter_list && all.encounter_list.encounter && all.encounter_list.encounter.encounter_diagnosis) {
1184             value = all.encounter_list.encounter.encounter_diagnosis;
1185         }
1186         name = value.text;
1187         code = cleanCode(value.code);
1188         code_system_name = value.code_type;
1189         status = value.status;
1190         encounter = all.encounter_list.encounter;
1191     }
1193     return {
1194         "plan": {
1195             "name": pd.code_text || "",
1196             "code": cleanCode(pd.code) || "",
1197             "code_system_name": pd.code_type || "SNOMED CT"
1198         },
1199         "identifiers": [{
1200             "identifier": pd.sha_extension,
1201             "extension": pd.extension || ""
1202         }],
1203         "goal": {
1204             "code": cleanCode(pd.code) || "",
1205             "name": safeTrim(pd.description) || ""
1206         },
1207         "date_time": {
1208             "point": {
1209                 "date": fDate(pd.date),
1210                 "precision": "day"
1211             }
1212         },
1213         "type": planType,
1214         "status": {
1215             "code": cleanCode(pd.status)
1216         },
1217         "author": populateAuthorFromAuthorContainer(pd),
1218         "performers": [{
1219             "identifiers": [{
1220                 "identifier": "2.16.840.1.113883.4.6",
1221                 "extension": encounter.npi || ""
1222             }],
1223             "code": [{
1224                 "name": encounter.physician_type,
1225                 "code": cleanCode(encounter.physician_type_code),
1226                 "code_system_name": "SNOMED CT"
1227             }],
1228             "name": [
1229                 {
1230                     "last": encounter.lname || "",
1231                     "first": encounter.fname || ""
1232                 }
1233             ],
1234             "phone": [
1235                 {
1236                     "number": encounter.work_phone,
1237                     "type": "work place"
1238                 }
1239             ]
1240         }],
1241         "locations": [{
1242             "name": encounter.location,
1243             "location_type": {
1244                 "name": encounter.location_details,
1245                 "code": "1160-1",
1246                 "code_system_name": "HealthcareServiceLocation"
1247             },
1248             "address": [{
1249                 "street_lines": [encounter.facility_address],
1250                 "city": encounter.facility_city,
1251                 "state": encounter.facility_state,
1252                 "zip": encounter.facility_zip,
1253                 "country": encounter.facility_country || "US"
1254             }],
1255             "phone": [
1256                 {
1257                     "number": encounter.facility_phone,
1258                     "type": "work place"
1259                 }
1260             ]
1261         }],
1262         "findings": [{
1263             "identifiers": [{
1264                 "identifier": encounter.sha_extension,
1265                 "extension": encounter.extension
1266             }],
1267             "value": {
1268                 "name": name,
1269                 "code": code,
1270                 "code_system_name": code_system_name
1271             },
1272             "date_time": {
1273                 "low": {
1274                     "date": fDate(encounter.date),
1275                     "precision": "day"
1276                 }
1277             },
1278             "status": status,
1279             "reason": encounter.encounter_reason
1280         }],
1281         "name": safeTrim(pd.description),
1282         "mood_code": pd.moodCode
1283     };
1286 function getGoals(pd) {
1287     return {
1288         "goal_code": {
1289             "name": pd.code_text !== "NULL" ? pd.code_text : "",
1290             "code": cleanCode(pd.code) || "",
1291             "code_system_name": pd.code_type || ""
1292         },
1293         "identifiers": [{
1294             "identifier": pd.sha_extension,
1295             "extension": pd.extension,
1296         }],
1297         "date_time": {
1298             "point": {
1299                 "date": fDate(pd.date),
1300                 "precision": "day"
1301             }
1302         },
1303         "type": "observation",
1304         "status": {
1305             "code": "active", //cleanCode(pd.status)
1306         },
1307         "author": populateAuthorFromAuthorContainer(pd),
1308         "name": pd.description
1309     };
1312 function getFunctionalStatus(pd) {
1313     let functionalStatusAuthor = {
1314         "code": {
1315             "name": all.author.physician_type || '',
1316             "code": all.author.physician_type_code || '',
1317             "code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
1318         },
1319         "date_time": {
1320             "point": {
1321                 "date": authorDateTime,
1322                 "precision": "tz"
1323             }
1324         },
1325         "identifiers": [
1326             {
1327                 "identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
1328                 "extension": all.author.npi ? all.author.npi : 'NI'
1329             }
1330         ],
1331         "name": [
1332             {
1333                 "last": all.author.lname,
1334                 "first": all.author.fname
1335             }
1336         ],
1337         "organization": [
1338             {
1339                 "identity": [
1340                     {
1341                         "root": oidFacility || "2.16.840.1.113883.4.6",
1342                         "extension": npiFacility || ""
1343                     }
1344                 ],
1345                 "name": [
1346                     all.encounter_provider.facility_name
1347                 ]
1348             }
1349         ]
1350     };
1352     return {
1353         "status": "completed",
1354         "author": functionalStatusAuthor,
1355         "identifiers": [{
1356             "identifier": "9a6d1bac-17d3-4195-89a4-1121bc809000",
1357             "extension": pd.extension || '',
1358         }],
1360         "observation": {
1361             "value": {
1362                 "name": pd.code_text !== "NULL" ? safeTrim(pd.code_text) : "",
1363                 "code": cleanCode(pd.code) || "",
1364                 "code_system_name": pd.code_type || "SNOMED-CT"
1365             },
1366             "identifiers": [{
1367                 "identifier": "9a6d1bac-17d3-4195-89a4-1121bc8090ab",
1368                 "extension": pd.extension || '',
1369             }],
1370             "date_time": {
1371                 "point": {
1372                     "date": fDate(pd.date),
1373                     "precision": "day"
1374                 }
1375             },
1376             "status": "completed",
1377             "author": functionalStatusAuthor
1378         }
1379     };
1382 function getMentalStatus(pd) {
1383     return {
1384         "value": {
1385             "name": pd.code_text !== "NULL" ? pd.code_text : "",
1386             "code": cleanCode(pd.code) || "",
1387             "code_system_name": pd.code_type || ""
1388         },
1389         "identifiers": [{
1390             "identifier": "9a6d1bac-17d3-4195-89a4-1121bc809ccc",
1391             "extension": pd.extension,
1392         }],
1393         "note": safeTrim(pd.description),
1394         "date_time": {
1395             "low": templateDate(pd.date, "day")
1396             //"high": templateDate(pd.date, "day")
1397         },
1398         "author": {
1399             "code": {
1400                 "name": all.author.physician_type || '',
1401                 "code": all.author.physician_type_code || '',
1402                 "code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
1403             },
1404             "date_time": {
1405                 "point": {
1406                     "date": authorDateTime,
1407                     "precision": "tz"
1408                 }
1409             },
1410             "identifiers": [
1411                 {
1412                     "identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
1413                     "extension": all.author.npi ? all.author.npi : 'NI'
1414                 }
1415             ],
1416             "name": [
1417                 {
1418                     "last": all.author.lname,
1419                     "first": all.author.fname
1420                 }
1421             ],
1422             "organization": [
1423                 {
1424                     "identity": [
1425                         {
1426                             "root": oidFacility || "2.16.840.1.113883.4.6",
1427                             "extension": npiFacility || ""
1428                         }
1429                     ],
1430                     "name": [
1431                         all.encounter_provider.facility_name
1432                     ]
1433                 }
1434             ]
1435         }
1436     };
1439 function getAssessments(pd) {
1440     return {
1441         "description": safeTrim(pd.description),
1442         "author": populateAuthorFromAuthorContainer(pd)
1443     };
1446 function getHealthConcerns(pd) {
1447     let one = true;
1448     let issue_uuid;
1449     let problems = [], problem = {};
1450     if (countEntities(pd.issues.issue_uuid) !== 0) {
1451         for (let key in pd.issues.issue_uuid) {
1452             issue_uuid = pd.issues.issue_uuid[key];
1453             if (issue_uuid) {
1454                 one = false;
1455             }
1456             problem = {
1457                 "identifiers": [{
1458                     "identifier": issue_uuid
1459                 }]
1460             };
1461             problems.push(problem);
1462         }
1463     }
1464     if (one) {
1465         if (pd.issues.issue_uuid) {
1466             problem = {
1467                 "identifiers": [{
1468                     "identifier": pd.issues.issue_uuid
1469                 }]
1470             };
1471             problems.push(problem);
1472         }
1473     }
1474     return {
1475         // todo need to make array of health concerns
1476         "type": "act",
1477         "text": safeTrim(pd.text),
1478         "value": {
1479             "name": pd.code_text || "",
1480             "code": cleanCode(pd.code) || "",
1481             "code_system_name": pd.code_type || "SNOMED CT"
1482         },
1483         "author": populateAuthorFromAuthorContainer(pd),
1484         "identifiers": [{
1485             "identifier": pd.sha_extension,
1486             "extension": pd.extension,
1487         }],
1488         problems: problems
1489     }
1492 function getReferralReason(pd) {
1493     return {
1494         "reason": safeTrim(pd.text),
1495         "author": populateAuthorFromAuthorContainer(pd)
1496     };
1499 function populateVital(pd) {
1500     return {
1501         "identifiers": [{
1502             "identifier": pd.sha_extension,
1503             "extension": pd.extension
1504         }],
1505         "status": "completed",
1506         "date_time": {
1507             "point": {
1508                 "date": fDate(pd.effectivetime),
1509                 "precision": "day"
1510             }
1511         },
1512         // our list of vitals per organizer.
1513         "vital_list": [{
1514             "identifiers": [{
1515                 "identifier": pd.sha_extension,
1516                 "extension": pd.extension_bps
1517             }],
1518             "vital": {
1519                 "name": "Blood Pressure Systolic",
1520                 "code": "8480-6",
1521                 "code_system_name": "LOINC"
1522             },
1523             "status": "completed",
1524             "date_time": {
1525                 "point": {
1526                     "date": fDate(pd.effectivetime),
1527                     "precision": "day"
1528                 }
1529             },
1530             "interpretations": ["Normal"],
1531             "value": parseFloat(pd.bps) || pd.bps,
1532             "unit": "mm[Hg]",
1533             "author": populateAuthorFromAuthorContainer(pd),
1534         }, {
1535             "identifiers": [{
1536                 "identifier": pd.sha_extension,
1537                 "extension": pd.extension_bpd
1538             }],
1539             "vital": {
1540                 "name": "Blood Pressure Diastolic",
1541                 "code": "8462-4",
1542                 "code_system_name": "LOINC"
1543             },
1544             "status": "completed",
1545             "date_time": {
1546                 "point": {
1547                     "date": fDate(pd.effectivetime),
1548                     "precision": "day"
1549                 }
1550             },
1551             "interpretations": ["Normal"],
1552             "value": parseFloat(pd.bpd) || pd.bpd,
1553             "unit": "mm[Hg]",
1554             "author": populateAuthorFromAuthorContainer(pd),
1555         }, {
1556             "identifiers": [{
1557                 "identifier": pd.sha_extension,
1558                 "extension": pd.extension_height
1559             }],
1560             "vital": {
1561                 "name": "Height",
1562                 "code": "8302-2",
1563                 "code_system_name": "LOINC"
1564             },
1565             "status": "completed",
1566             "date_time": {
1567                 "point": {
1568                     "date": fDate(pd.effectivetime),
1569                     "precision": "day"
1570                 }
1571             },
1572             "interpretations": ["Normal"],
1573             "value": parseFloat(pd.height) || pd.height,
1574             "unit": pd.unit_height,
1575             "author": populateAuthorFromAuthorContainer(pd),
1576         }, {
1577             "identifiers": [{
1578                 "identifier": pd.sha_extension,
1579                 "extension": pd.extension_weight
1580             }],
1581             "vital": {
1582                 "name": "Weight Measured",
1583                 "code": "29463-7",
1584                 "code_system_name": "LOINC"
1585             },
1586             "status": "completed",
1587             "date_time": {
1588                 "point": {
1589                     "date": fDate(pd.effectivetime),
1590                     "precision": "day"
1591                 }
1592             },
1593             "interpretations": ["Normal"],
1594             "value": parseFloat(pd.weight) || "",
1595             "unit": pd.unit_weight,
1596             "author": populateAuthorFromAuthorContainer(pd),
1597         }, {
1598             "identifiers": [{
1599                 "identifier": pd.sha_extension,
1600                 "extension": pd.extension_BMI
1601             }],
1602             "vital": {
1603                 "name": "BMI (Body Mass Index)",
1604                 "code": "39156-5",
1605                 "code_system_name": "LOINC"
1606             },
1607             "status": "completed",
1608             "date_time": {
1609                 "point": {
1610                     "date": fDate(pd.effectivetime),
1611                     "precision": "day"
1612                 }
1613             },
1614             "interpretations": [pd.BMI_status == 'Overweight' ? 'High' : pd.BMI_status == 'Overweight' ? 'Low' : 'Normal'],
1615             "value": parseFloat(pd.BMI) || "",
1616             "unit": "kg/m2",
1617             "author": populateAuthorFromAuthorContainer(pd),
1618         }, {
1619             "identifiers": [{
1620                 "identifier": pd.sha_extension,
1621                 "extension": pd.extension_pulse
1622             }],
1623             "vital": {
1624                 "name": "Heart Rate",
1625                 "code": "8867-4",
1626                 "code_system_name": "LOINC"
1627             },
1628             "status": "completed",
1629             "date_time": {
1630                 "point": {
1631                     "date": fDate(pd.effectivetime),
1632                     "precision": "day"
1633                 }
1634             },
1635             "interpretations": ["Normal"],
1636             "value": parseFloat(pd.pulse) || "",
1637             "unit": "/min",
1638             "author": populateAuthorFromAuthorContainer(pd),
1639         }, {
1640             "identifiers": [{
1641                 "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.2",
1642                 "extension": pd.extension_breath
1643             }],
1644             "vital": {
1645                 "name": "Respiratory Rate",
1646                 "code": "9279-1",
1647                 "code_system_name": "LOINC"
1648             },
1649             "status": "completed",
1650             "date_time": {
1651                 "point": {
1652                     "date": fDate(pd.effectivetime),
1653                     "precision": "day"
1654                 }
1655             },
1656             "interpretations": ["Normal"],
1657             "value": parseFloat(pd.breath) || "",
1658             "unit": "/min",
1659             "author": populateAuthorFromAuthorContainer(pd),
1660         }, {
1661             "identifiers": [{
1662                 "identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.3",
1663                 "extension": pd.extension_temperature
1664             }],
1665             "vital": {
1666                 "name": "Body Temperature",
1667                 "code": "8310-5",
1668                 "code_system_name": "LOINC"
1669             },
1670             "status": "completed",
1671             "date_time": {
1672                 "point": {
1673                     "date": fDate(pd.effectivetime),
1674                     "precision": "day"
1675                 }
1676             },
1677             "interpretations": ["Normal"],
1678             "value": parseFloat(pd.temperature) || "",
1679             "unit": pd.unit_temperature,
1680             "author": populateAuthorFromAuthorContainer(pd),
1681         }, {
1682             "identifiers": [{
1683                 "identifier": pd.sha_extension,
1684                 "extension": pd.extension_oxygen_saturation
1685             }],
1686             "vital": {
1687                 "name": "O2 % BldC Oximetry",
1688                 "code": "59408-5",
1689                 "code_system_name": "LOINC"
1690             },
1691             "status": "completed",
1692             "date_time": {
1693                 "point": {
1694                     "date": fDate(pd.effectivetime),
1695                     "precision": "day"
1696                 }
1697             },
1698             "interpretations": ["Normal"],
1699             "value": parseFloat(pd.oxygen_saturation) || "",
1700             "unit": "%",
1701             "author": populateAuthorFromAuthorContainer(pd),
1702         }, {
1703             "identifiers": [{
1704                 "identifier": pd.sha_extension,
1705                 "extension": pd.extension_ped_weight_height
1706             }],
1707             "vital": { // --------------------------------------------------------------------------------
1708                 "name": "Weight for Height Percentile",
1709                 "code": "77606-2",
1710                 "code_system_name": "LOINC"
1711             },
1712             "status": "completed",
1713             "date_time": {
1714                 "point": {
1715                     "date": fDate(pd.effectivetime),
1716                     "precision": "day"
1717                 }
1718             },
1719             "interpretations": ["Normal"],
1720             "value": parseFloat(pd.ped_weight_height) || "",
1721             "unit": "%",
1722             "author": populateAuthorFromAuthorContainer(pd),
1723         }, {
1724             "identifiers": [{
1725                 "identifier": pd.sha_extension,
1726                 "extension": pd.extension_inhaled_oxygen_concentration
1727             }],
1728             "vital": {
1729                 "name": "Inhaled Oxygen Concentration",
1730                 "code": "3150-0",
1731                 "code_system_name": "LOINC"
1732             },
1733             "status": "completed",
1734             "date_time": {
1735                 "point": {
1736                     "date": fDate(pd.effectivetime),
1737                     "precision": "day"
1738                 }
1739             },
1740             "interpretations": ["Normal"],
1741             "value": parseFloat(pd.inhaled_oxygen_concentration) || "",
1742             "unit": "%",
1743             "author": populateAuthorFromAuthorContainer(pd),
1744         }, {
1745             "identifiers": [{
1746                 "identifier": pd.sha_extension,
1747                 "extension": pd.extension_ped_bmi
1748             }],
1749             "vital": {
1750                 "name": "BMI Percentile",
1751                 "code": "59576-9",
1752                 "code_system_name": "LOINC"
1753             },
1754             "status": "completed",
1755             "date_time": {
1756                 "point": {
1757                     "date": fDate(pd.effectivetime),
1758                     "precision": "day"
1759                 }
1760             },
1761             "interpretations": ["Normal"],
1762             "value": parseFloat(pd.ped_bmi) || "",
1763             "unit": "%",
1764             "author": populateAuthorFromAuthorContainer(pd),
1765         }, {
1766             "identifiers": [{
1767                 "identifier": pd.sha_extension,
1768                 "extension": pd.extension_ped_head_circ
1769             }],
1770             "vital": {
1771                 "name": "Head Occipital-frontal Circumference Percentile",
1772                 "code": "8289-1",
1773                 "code_system_name": "LOINC"
1774             },
1775             "status": "completed",
1776             "date_time": {
1777                 "point": {
1778                     "date": fDate(pd.effectivetime),
1779                     "precision": "day"
1780                 }
1781             },
1782             "interpretations": ["Normal"],
1783             "value": parseFloat(pd.ped_head_circ) || "",
1784             "unit": "%",
1785             "author": populateAuthorFromAuthorContainer(pd),
1786         }
1787         ]
1788     }
1791 function populateSocialHistory(pd) {
1792     return {
1793         "date_time": {
1794             "low": templateDate(pd.date, "day")
1795             //"high": templateDate(pd.date, "day")
1796         },
1797         "identifiers": [{
1798             "identifier": pd.sha_extension,
1799             "extension": pd.extension
1800         }],
1801         "code": {
1802             "name": pd.code
1803         },
1804         "element": pd.element,
1805         "value": pd.description,
1806         "gender": all.patient.gender,
1807         "author": {
1808             "code": {
1809                 "name": pd.author.physician_type || '',
1810                 "code": pd.author.physician_type_code || '',
1811                 "code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
1812             },
1813             "date_time": {
1814                 "point": {
1815                     "date": fDate(pd.author.time),
1816                     "precision": "tz"
1817                 }
1818             },
1819             "identifiers": [
1820                 {
1821                     "identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
1822                     "extension": pd.author.npi ? pd.author.npi : 'NI'
1823                 }
1824             ],
1825             "name": [
1826                 {
1827                     "last": pd.author.lname,
1828                     "first": pd.author.fname
1829                 }
1830             ],
1831             "organization": [
1832                 {
1833                     "identity": [
1834                         {
1835                             "root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
1836                             "extension": pd.author.facility_npi || "NI"
1837                         }
1838                     ],
1839                     "name": [
1840                         pd.author.facility_name
1841                     ]
1842                 }
1843             ]
1844         }
1845         , "gender_author": {
1846             "code": {
1847                 "name": all.patient.author.physician_type || '',
1848                 "code": all.patient.author.physician_type_code || '',
1849                 "code_system": all.patient.author.physician_type_system, "code_system_name": all.patient.author.physician_type_system_name
1850             },
1851             "date_time": {
1852                 "point": {
1853                     "date": fDate(all.patient.author.time),
1854                     "precision": "tz"
1855                 }
1856             },
1857             "identifiers": [
1858                 {
1859                     "identifier": all.patient.author.npi ? "2.16.840.1.113883.4.6" : all.patient.author.id,
1860                     "extension": all.patient.author.npi ? all.patient.author.npi : 'NI'
1861                 }
1862             ],
1863             "name": [
1864                 {
1865                     "last": all.patient.author.lname,
1866                     "first": all.patient.author.fname
1867                 }
1868             ],
1869             "organization": [
1870                 {
1871                     "identity": [
1872                         {
1873                             "root": all.patient.author.facility_oid || "2.16.840.1.113883.4.6",
1874                             "extension": all.patient.author.facility_npi || "NI"
1875                         }
1876                     ],
1877                     "name": [
1878                         all.patient.author.facility_name
1879                     ]
1880                 }
1881             ]
1882         }
1883     };
1886 function populateImmunization(pd) {
1887     return {
1888         "date_time": {
1889             "low": {
1890                 "date": fDate(pd.administered_on),
1891                 "precision": "day"
1892             }
1893         },
1894         "identifiers": [{
1895             "identifier": pd.sha_extension,
1896             "extension": pd.extension || ""
1897         }],
1898         "status": "complete",
1899         "product": {
1900             "product": {
1901                 "name": pd.code_text,
1902                 "code": cleanCode(pd.cvx_code),
1903                 "code_system_name": "CVX"
1904                 /*"translations": [{
1905                     "name": "",
1906                     "code": "",
1907                     "code_system_name": "CVX"
1908                 }]*/
1909             },
1910             "lot_number": "",
1911             "manufacturer": ""
1912         },
1913         "administration": {
1914             "route": {
1915                 "name": pd.route_of_administration,
1916                 "code": cleanCode(pd.route_code) || "",
1917                 "code_system_name": "Medication Route FDA"
1918             }/*,
1919         "dose": {
1920             "value": 50,
1921             "unit": "mcg"
1922         }*/
1923         },
1924         "performer": {
1925             "identifiers": [{
1926                 "identifier": "2.16.840.1.113883.4.6",
1927                 "extension": pd.npi || ""
1928             }],
1929             "name": [{
1930                 "last": pd.lname,
1931                 "first": pd.fname
1932             }],
1933             "address": [{
1934                 "street_lines": [pd.address],
1935                 "city": pd.city,
1936                 "state": pd.state,
1937                 "zip": pd.zip,
1938                 "country": "US"
1939             }],
1940             "organization": [{
1941                 "identifiers": [{
1942                     "identifier": "2.16.840.1.113883.4.6",
1943                     "extension": npiFacility || ""
1944                 }],
1945                 "name": [pd.facility_name]
1946             }]
1947         },
1948         "instructions": {
1949             "code": {
1950                 "name": "immunization education",
1951                 "code": "171044003",
1952                 "code_system_name": "SNOMED CT"
1953             },
1954             "free_text": "Needs Attention for more data."
1955         },
1956         "author": {
1957             "code": {
1958                 "name": pd.author.physician_type || '',
1959                 "code": pd.author.physician_type_code || '',
1960                 "code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
1961             },
1962             "date_time": {
1963                 "point": {
1964                     "date": fDate(pd.author.time),
1965                     "precision": "tz"
1966                 }
1967             },
1968             "identifiers": [
1969                 {
1970                     "identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
1971                     "extension": pd.author.npi ? pd.author.npi : 'NI'
1972                 }
1973             ],
1974             "name": [
1975                 {
1976                     "last": pd.author.lname,
1977                     "first": pd.author.fname
1978                 }
1979             ],
1980             "organization": [
1981                 {
1982                     "identity": [
1983                         {
1984                             "root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
1985                             "extension": pd.author.facility_npi || "NI"
1986                         }
1987                     ],
1988                     "name": [
1989                         pd.author.facility_name
1990                     ]
1991                 }
1992             ]
1993         }
1994     };
1997 function populatePayer(pd) {
1998     return {
1999         "identifiers": [{
2000             "identifier": "1fe2cdd0-7aad-11db-9fe1-0800200c9a66"
2001         }],
2002         "policy": {
2003             "identifiers": [{
2004                 "identifier": "3e676a50-7aac-11db-9fe1-0800200c9a66"
2005             }],
2006             "code": {
2007                 "code": "SELF",
2008                 "code_system_name": "HL7 RoleCode"
2009             },
2010             "insurance": {
2011                 "code": {
2012                     "code": "PAYOR",
2013                     "code_system_name": "HL7 RoleCode"
2014                 },
2015                 "performer": {
2016                     "identifiers": [{
2017                         "identifier": "2.16.840.1.113883.19"
2018                     }],
2019                     "address": [{
2020                         "street_lines": ["123 Insurance Road"],
2021                         "city": "Blue Bell",
2022                         "state": "MA",
2023                         "zip": "02368",
2024                         "country": "US",
2025                         "use": "work place"
2026                     }],
2027                     "phone": [{
2028                         "number": "(781)555-1515",
2029                         "type": "work place"
2030                     }],
2031                     "organization": [{
2032                         "name": ["Good Health Insurance"],
2033                         "address": [{
2034                             "street_lines": ["123 Insurance Road"],
2035                             "city": "Blue Bell",
2036                             "state": "MA",
2037                             "zip": "02368",
2038                             "country": "US",
2039                             "use": "work place"
2040                         }],
2041                         "phone": [{
2042                             "number": "(781)555-1515",
2043                             "type": "work place"
2044                         }]
2045                     }],
2046                     "code": [{
2047                         "code": "PAYOR",
2048                         "code_system_name": "HL7 RoleCode"
2049                     }]
2050                 }
2051             }
2052         },
2053         "guarantor": {
2054             "code": {
2055                 "code": "GUAR",
2056                 "code_system_name": "HL7 Role"
2057             },
2058             "identifiers": [{
2059                 "identifier": "329fcdf0-7ab3-11db-9fe1-0800200c9a66"
2060             }],
2061             "name": [{
2062                 "prefix": "Mr.",
2063                 "middle": ["Frankie"],
2064                 "last": "Everyman",
2065                 "first": "Adam"
2066             }],
2067             "address": [{
2068                 "street_lines": ["17 Daws Rd."],
2069                 "city": "Blue Bell",
2070                 "state": "MA",
2071                 "zip": "02368",
2072                 "country": "US",
2073                 "use": "primary home"
2074             }],
2075             "phone": [{
2076                 "number": "(781)555-1212",
2077                 "type": "primary home"
2078             }]
2079         },
2080         "participant": {
2081             "code": {
2082                 "name": "Self",
2083                 "code": "SELF",
2084                 "code_system_name": "HL7 Role"
2085             },
2086             "performer": {
2087                 "identifiers": [{
2088                     "identifier": "14d4a520-7aae-11db-9fe1-0800200c9a66",
2089                     "extension": "1138345"
2090                 }],
2091                 "address": [{
2092                     "street_lines": ["17 Daws Rd."],
2093                     "city": "Blue Bell",
2094                     "state": "MA",
2095                     "zip": "02368",
2096                     "country": "US",
2097                     "use": "primary home"
2098                 }],
2099                 "code": [{
2100                     "name": "Self",
2101                     "code": "SELF",
2102                     "code_system_name": "HL7 Role"
2103                 }]
2104             },
2105             "name": [{
2106                 "prefix": "Mr.",
2107                 "middle": ["A."],
2108                 "last": "Everyman",
2109                 "first": "Frank"
2110             }]
2111         },
2112         "policy_holder": {
2113             "performer": {
2114                 "identifiers": [{
2115                     "identifier": "2.16.840.1.113883.19",
2116                     "extension": "1138345"
2117                 }],
2118                 "address": [{
2119                     "street_lines": ["17 Daws Rd."],
2120                     "city": "Blue Bell",
2121                     "state": "MA",
2122                     "zip": "02368",
2123                     "country": "US",
2124                     "use": "primary home"
2125                 }]
2126             }
2127         },
2128         "authorization": {
2129             "identifiers": [{
2130                 "identifier": "f4dce790-8328-11db-9fe1-0800200c9a66"
2131             }],
2132             "procedure": {
2133                 "code": {
2134                     "name": "Colonoscopy",
2135                     "code": "73761001",
2136                     "code_system_name": "SNOMED CT"
2137                 }
2138             }
2139         }
2140     };
2143 function populateNote(pd) {
2144     return {
2145         "date_time": {
2146             "point": {
2147                 "date": fDate(pd.date),
2148                 "precision": "day"
2149             }
2150         },
2151         "translations": {
2152             code_system: "2.16.840.1.113883.6.1",
2153             code_system_name: "LOINC",
2154             code: cleanCode(pd.code),
2155             name: pd.code_text || ""
2156         },
2157         "author": populateAuthorFromAuthorContainer(pd),
2158         "note": safeTrim(pd.description),
2159     };
2162 function populateParticipant(participant) {
2163     return {
2164         "name": {
2165             "prefix": participant.prefix || "",
2166             "suffix": participant.suffix || "",
2167             "middle": [participant.mname] || "",
2168             "last": participant.lname || "",
2169             "first": participant.fname || ""
2170         },
2171         "typeCode": participant.type || "",
2172         "classCode": "ASSIGNED",
2173         "code": {
2174             "name": participant.organization_taxonomy_description || "",
2175             "code": cleanCode(participant.organization_taxonomy) || "",
2176             "code_system": "2.16.840.1.113883.6.101",
2177             "code_system_name": "NUCC Health Care Provider Taxonomy"
2178         },
2179         "identifiers": [{
2180             "identifier": participant.organization_npi ? "2.16.840.1.113883.4.6" : participant.organization_id,
2181             "extension": participant.organization_npi ? participant.organization_npi : ''
2182         }],
2183         "date_time": {
2184             "point": {
2185                 "date": participant.date_time,
2186                 "precision": "tz"
2187             }
2188         },
2189         "phone": [
2190             {
2191                 "number": participant.phonew1 || "",
2192                 "type": "WP"
2193             }
2194         ],
2195         "address": [
2196             {
2197                 "street_lines": [
2198                     participant.street
2199                 ],
2200                 "city": participant.city,
2201                 "state": participant.state,
2202                 "zip": participant.postalCode,
2203                 "country": participant.country || "US",
2204                 "use": participant.address_use || "WP"
2205             }
2206         ],
2207     }
2210 function populateHeader(pd) {
2211     // default doc type ToC CCD
2212     let name = "Summarization of Episode Note";
2213     let docCode = "34133-9";
2214     let docOid = "2.16.840.1.113883.10.20.22.1.2";
2215     if (pd.doc_type == 'referral') {
2216         name = "Referral Note";
2217         docCode = "57133-1";
2218         docOid = "2.16.840.1.113883.10.20.22.1.14";
2219     }
2221     if (pd.doc_type == 'unstructured') {
2222         name = "Patient Documents";
2223         docCode = "34133-9";
2224         docOid = "2.16.840.1.113883.10.20.22.1.10";
2225     }
2227     const head = {
2228         "identifiers": [
2229             {
2230                 "identifier": oidFacility,
2231                 "extension": "123456"
2232             }
2233         ],
2234         "code": {
2235             "name": name,
2236             "code": docCode,
2237             "code_system_name": "LOINC"
2238         },
2239         "template": {
2240             "root": docOid,
2241             "extension": "2015-08-01"
2242         },
2243         "title": name,
2244         "date_time": {
2245             "point": {
2246                 "date": fDate(pd.created_time_timezone),
2247                 "precision": "tz"
2248             }
2249         },
2250         "author": {
2251             "code": {
2252                 "name": all.author.physician_type || '',
2253                 "code": all.author.physician_type_code || '',
2254                 "code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
2255             },
2256             "date_time": {
2257                 "point": {
2258                     "date": authorDateTime,
2259                     "precision": "tz"
2260                 }
2261             },
2262             "identifiers": [
2263                 {
2264                     "identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
2265                     "extension": all.author.npi ? all.author.npi : 'NI'
2266                 }
2267             ],
2268             "name": [
2269                 {
2270                     "last": all.author.lname,
2271                     "first": all.author.fname
2272                 }
2273             ],
2274             "address": [
2275                 {
2276                     "street_lines": [
2277                         all.author.streetAddressLine
2278                     ],
2279                     "city": all.author.city,
2280                     "state": all.author.state,
2281                     "zip": all.author.postalCode,
2282                     "country": all.author.country || "US",
2283                     "use": "work place"
2284                 }
2285             ],
2286             "phone": [
2287                 {
2288                     "number": all.author.telecom || "",
2289                     "type": "WP"
2290                 }
2291             ],
2292             "organization": [
2293                 {
2294                     "identity": [
2295                         {
2296                             "root": oidFacility || "2.16.840.1.113883.4.6",
2297                             "extension": npiFacility || ""
2298                         }
2299                     ],
2300                     "name": [
2301                         all.encounter_provider.facility_name
2302                     ],
2303                     "address": [
2304                         {
2305                             "street_lines": [
2306                                 all.encounter_provider.facility_street
2307                             ],
2308                             "city": all.encounter_provider.facility_city,
2309                             "state": all.encounter_provider.facility_state,
2310                             "zip": all.encounter_provider.facility_postal_code,
2311                             "country": all.encounter_provider.facility_country_code || "US",
2312                             "use": "work place"
2313                         }
2314                     ],
2315                     "phone": [
2316                         {
2317                             "number": all.encounter_provider.facility_phone,
2318                             "type": "work primary"
2319                         }
2320                     ]
2321                 }
2322             ]
2323         },
2324         "custodian": {
2325             "identity": [
2326                 {
2327                     "root": "2.16.840.1.113883.4.6",
2328                     "extension": npiFacility || ""
2329                 }
2330             ],
2331             "name": [
2332                 pd.custodian.organization || pd.custodian.name
2333             ],
2334             "address": [
2335                 {
2336                     "street_lines": [
2337                         pd.custodian.streetAddressLine
2338                     ],
2339                     "city": pd.custodian.city,
2340                     "state": pd.custodian.state,
2341                     "zip": pd.custodian.postalCode,
2342                     "country": pd.custodian.country || "US"
2343                 }
2344             ],
2345             "phone": [
2346                 {
2347                     "number": pd.custodian.telecom,
2348                     "type": "work primary"
2349                 }
2350             ]
2351         },
2352         "information_recipient": {
2353             "name": {
2354                 "prefix": pd.information_recipient.prefix || "",
2355                 "suffix": pd.information_recipient.suffix || "",
2356                 "middle": [pd.information_recipient.mname] || "",
2357                 "last": pd.information_recipient.lname || "",
2358                 "first": pd.information_recipient.fname || ""
2359             },
2360             "organization": {
2361                 "name": pd.information_recipient.organization || "org"
2362             },
2363         }
2364     };
2365     let participants = [];
2366     let docParticipants = pd.document_participants || {participant: []};
2367     let count = 0;
2368     try {
2369         count = countEntities(docParticipants.participant);
2370     } catch (e) {
2371         count = 0
2372     }
2373     if (count === 1) {
2374         participants = [populateParticipant(docParticipants.participant)];
2375     } else {
2376         // grab the values of our object
2377         participants = Object.values(docParticipants.participant).filter(pcpt => pcpt.type).map(pcpt => populateParticipant(pcpt));
2378     }
2379     if (participants.length) {
2380         head.participants = participants;
2381     }
2383     if (countEntities(all.encounter_list.encounter) === 1) {
2384         let primary_care_provider = pd.primary_care_provider || {provider: {}};
2385         head.component_of = {
2386             "identifiers": [
2387                 {
2388                     "identifier": oidFacility || "",
2389                     "extension": "PT-" + (pd.patient.id || "")
2390                 }
2391             ],
2392             "code": {
2393                 "name": pd.primary_diagnosis.text || "",
2394                 "code": pd.primary_diagnosis.code || "",
2395                 "code_system_name": pd.primary_diagnosis.code_type || ""
2396             },
2397             "date_time": {
2398                 "low": {
2399                     "date": pd.primary_diagnosis.encounter_date || "",
2400                     "precision": "tz"
2401                 },
2402                 "high": {
2403                     "date": pd.primary_diagnosis.encounter_end_date || "",
2404                     "precision": "tz"
2405                 }
2406             },
2407             "responsible_party": {
2408                 "root": oidFacility,
2409                 "name": {
2410                     "last": pd.author.lname,
2411                     "first": pd.author.fname
2412                 },
2413             },
2414             "encounter_participant": {
2415                 "root": oidFacility,
2416                 "name": {
2417                     "last": primary_care_provider.provider.lname || "",
2418                     "first": primary_care_provider.provider.fname || ""
2419                 },
2420                 "address": [
2421                     {
2422                         "street_lines": [
2423                             pd.encounter_provider.facility_street
2424                         ],
2425                         "city": pd.encounter_provider.facility_city,
2426                         "state": pd.encounter_provider.facility_state,
2427                         "zip": pd.encounter_provider.facility_postal_code,
2428                         "country": pd.encounter_provider.facility_country_code || "US",
2429                         "use": "work place"
2430                     }
2431                 ],
2432                 "phone": [
2433                     {
2434                         "number": pd.encounter_provider.facility_phone,
2435                         "type": "work primary"
2436                     }
2437                 ]
2438             }
2439         }
2440     }
2442     return head;
2445 function getMeta(pd) {
2446     let meta = {};
2447     meta = {
2448         "type": pd.doc_type,
2449         "identifiers": [
2450             {
2451                 "identifier": oidFacility || "NI",
2452                 "extension": "TT988"
2453             }
2454         ],
2455         "confidentiality": "Normal",
2456         "set_id": {
2457             "identifier": oidFacility || "NI",
2458             "extension": "sTT988"
2459         }
2460     }
2461     return meta;
2465  / * function generateCcda
2466  /* The main document builder
2467  /* pd array the xml parsed array of data sent from CCM.
2468  */
2469 function generateCcda(pd) {
2470     let doc = {};
2471     let data = {};
2472     let count = 0;
2473     let many = [];
2474     let theone = {};
2475     all = pd;
2476     let primary_care_provider = all.primary_care_provider || {};
2477     npiProvider = primary_care_provider.provider ? primary_care_provider.provider.npi : "NI";
2478     oidFacility = all.encounter_provider.facility_oid ? all.encounter_provider.facility_oid : "2.16.840.1.113883.19.5.99999.1";
2479     npiFacility = getNpiFacility(pd, false);
2480     webRoot = all.serverRoot;
2481     documentLocation = all.document_location;
2483     authorDateTime = pd.created_time_timezone;
2484     if (pd.author.time.length > 7) {
2485         authorDateTime = pd.author.time;
2486     } else if (all.encounter_list && all.encounter_list.encounter) {
2487         if (countEntities(all.encounter_list.encounter) === 1) {
2488             authorDateTime = all.encounter_list.encounter.date;
2489         } else {
2490             authorDateTime = all.encounter_list.encounter[0].date;
2491         }
2492     }
2494     authorDateTime = fDate(authorDateTime);
2495     // Demographics
2496     let demographic = populateDemographics(pd, npiFacility);
2497 // This populates documentationOf. We are using providerOrganization also.
2498     if (pd.primary_care_provider) {
2499         Object.assign(demographic, populateProviders(pd));
2500     }
2501     data.demographics = Object.assign(demographic);
2502 // Encounters
2503     let encs = [];
2504     let enc = {};
2505     encs.encounters = [];
2506     try {
2507         count = countEntities(pd.encounter_list.encounter);
2508     } catch (e) {
2509         count = 0
2510     }
2511     if (count > 1) {
2512         for (let i in pd.encounter_list.encounter) {
2513             enc[i] = populateEncounter(pd.encounter_list.encounter[i]);
2514             encs.encounters.push(enc[i]);
2515         }
2516     } else if (count !== 0) {
2517         enc = populateEncounter(pd.encounter_list.encounter);
2518         encs.encounters.push(enc);
2519     }
2520     if (count !== 0) {
2521         data.encounters = Object.assign(encs.encounters);
2522     }
2523 // vitals
2524     let vitals = [];
2525     let vital = {};
2526     vitals.vitals = [];
2527     try {
2528         count = countEntities(pd.history_physical.vitals_list.vitals);
2529     } catch (e) {
2530         count = 0
2531     }
2532     if (count > 1) {
2533         for (let i in pd.history_physical.vitals_list.vitals) {
2534             vitals[i] = populateVital(pd.history_physical.vitals_list.vitals[i]);
2535             vitals.vitals.push(vitals[i]);
2536         }
2537     } else if (count !== 0) {
2538         vital = populateVital(pd.history_physical.vitals_list.vitals);
2539         vitals.vitals.push(vital);
2540     }
2541     if (count !== 0) {
2542         data.vitals = Object.assign(vitals.vitals);
2543     }
2544 // Medications
2545     let meds = [];
2546     let m = {};
2547     meds.medications = [];
2548     try {
2549         count = countEntities(pd.medications.medication);
2550     } catch (e) {
2551         count = 0
2552     }
2553     if (count > 1) {
2554         for (let i in pd.medications.medication) {
2555             m[i] = populateMedication(pd.medications.medication[i]);
2556             meds.medications.push(m[i]);
2557         }
2558     } else if (count !== 0) {
2559         m = populateMedication(pd.medications.medication);
2560         meds.medications.push(m);
2561     }
2562     if (count !== 0) {
2563         data.medications = Object.assign(meds.medications);
2564     }
2565 // Allergies
2566     let allergies = [];
2567     let allergy = {};
2568     allergies.allergies = [];
2569     try {
2570         count = countEntities(pd.allergies.allergy);
2571     } catch (e) {
2572         count = 0
2573     }
2574     if (count > 1) {
2575         for (let i in pd.allergies.allergy) {
2576             allergy[i] = populateAllergy(pd.allergies.allergy[i]);
2577             allergies.allergies.push(allergy[i]);
2578         }
2579     } else if (count <= 1) {
2580         allergy = populateAllergy(pd.allergies.allergy);
2581         allergies.allergies.push(allergy);
2582         count = 1;
2583     }
2584     if (count !== 0) {
2585         data.allergies = Object.assign(allergies.allergies);
2586     }
2587 // Problems
2588     let problems = [];
2589     let problem = {};
2590     problems.problems = [];
2591     try {
2592         count = countEntities(pd.problem_lists.problem);
2593     } catch (e) {
2594         count = 0
2595     }
2596     if (count > 1) {
2597         for (let i in pd.problem_lists.problem) {
2598             problem[i] = populateProblem(pd.problem_lists.problem[i], pd);
2599             problems.problems.push(problem[i]);
2600         }
2601     } else if (count !== 0) {
2602         problem = populateProblem(pd.problem_lists.problem);
2603         problems.problems.push(problem);
2604     }
2605     if (count !== 0) {
2606         data.problems = Object.assign(problems.problems);
2607     }
2608 // Procedures
2609     many = [];
2610     theone = {};
2611     many.procedures = [];
2612     try {
2613         count = countEntities(pd.procedures.procedure);
2614     } catch (e) {
2615         count = 0
2616     }
2617     if (count > 1) {
2618         for (let i in pd.procedures.procedure) {
2619             theone[i] = populateProcedure(pd.procedures.procedure[i]);
2620             many.procedures.push(theone[i]);
2621         }
2622     } else if (count !== 0) {
2623         theone = populateProcedure(pd.procedures.procedure);
2624         many.procedures.push(theone);
2625     }
2626     if (count !== 0) {
2627         data.procedures = Object.assign(many.procedures);
2628     }
2629 // Medical Devices
2630     many = [];
2631     theone = {};
2632     many.medical_devices = [];
2633     try {
2634         count = countEntities(pd.medical_devices.device);
2635     } catch (e) {
2636         count = 0
2637     }
2638     if (count > 1) {
2639         for (let i in pd.medical_devices.device) {
2640             theone[i] = populateMedicalDevice(pd.medical_devices.device[i]);
2641             many.medical_devices.push(theone[i]);
2642         }
2643     } else if (count !== 0) {
2644         theone = populateMedicalDevice(pd.medical_devices.device);
2645         many.medical_devices.push(theone);
2646     }
2647     if (count !== 0) {
2648         data.medical_devices = Object.assign(many.medical_devices);
2649     }
2650 // Results
2651     if (pd.results) {
2652         data.results = Object.assign(getResultSet(pd.results, pd)['results']);
2653     }
2655 // Referral TODO sjp I'm not happy with this.
2656     // different referral sources. 1st is dynamic with doc gen from CCM.
2657     // 2nd is the latest referral from transactions.
2658     if (pd.referral_reason[0].text !== "") {
2659         data.referral_reason = Object.assign(getReferralReason(pd.referral_reason[0], pd));
2660     } else if (pd.referral_reason[1].text !== "" && typeof pd.referral_reason[1].text !== 'undefined') {
2661         data.referral_reason = Object.assign(getReferralReason(pd.referral_reason[1], pd));
2662     } else {
2663         data.referral_reason = {}; // leave as empty so we can get our null flavor section.
2664     }
2665 // Health Concerns
2666     many = [];
2667     theone = {};
2668     many.health_concerns = [];
2669     try {
2670         count = countEntities(pd.health_concerns.concern);
2671     } catch (e) {
2672         count = 0
2673     }
2674     if (count > 1) {
2675         for (let i in pd.health_concerns.concern) {
2676             theone[i] = getHealthConcerns(pd.health_concerns.concern[i]);
2677             many.health_concerns.push(theone[i]);
2678             break;
2679         }
2680     } else if (count !== 0) {
2681         theone = getHealthConcerns(pd.health_concerns.concern);
2682         many.health_concerns.push(theone);
2683     }
2684     if (count !== 0) {
2685         data.health_concerns = Object.assign(many.health_concerns);
2686     } else {
2687         data.health_concerns = {"type": "act"}; // leave it as an empty section that we'll null flavor
2688     }
2689 // Immunizations
2690     many = [];
2691     theone = {};
2692     many.immunizations = [];
2693     try {
2694         count = countEntities(pd.immunizations.immunization);
2695     } catch (e) {
2696         count = 0;
2697     }
2698     if (count > 1) {
2699         for (let i in pd.immunizations.immunization) {
2700             theone[i] = populateImmunization(pd.immunizations.immunization[i]);
2701             many.immunizations.push(theone[i]);
2702         }
2703     } else if (count !== 0) {
2704         theone = populateImmunization(pd.immunizations.immunization);
2705         many.immunizations.push(theone);
2706     }
2707     if (count !== 0) {
2708         data.immunizations = Object.assign(many.immunizations);
2709     }
2710 // Plan of Care
2711     many = [];
2712     theone = {};
2713     many.plan_of_care = [];
2714     try {
2715         count = countEntities(pd.planofcare.item);
2716     } catch (e) {
2717         count = 0
2718     }
2719     if (count > 1) {
2720         for (let i in pd.planofcare.item) {
2721             if (cleanCode(pd.planofcare.item[i].date) === '') {
2722                 i--;
2723                 continue;
2724             }
2725             theone[i] = getPlanOfCare(pd.planofcare.item[i]);
2726             if (theone[i]) {
2727                 many.plan_of_care.push(theone[i]);
2728             }
2729         }
2730     } else if (count !== 0) {
2731         theone = getPlanOfCare(pd.planofcare.item);
2732         if (theone) {
2733             many.plan_of_care.push(theone);
2734         }
2735     }
2736     if (count !== 0) {
2737         data.plan_of_care = Object.assign(many.plan_of_care);
2738     }
2739 // Goals
2740     many = [];
2741     theone = {};
2742     many.goals = [];
2743     try {
2744         count = countEntities(pd.goals.item);
2745     } catch (e) {
2746         count = 0
2747     }
2748     if (count > 1) {
2749         for (let i in pd.goals.item) {
2750             theone[i] = getGoals(pd.goals.item[i]);
2751             many.goals.push(theone[i]);
2752         }
2753     } else if (count !== 0) {
2754         theone = getGoals(pd.goals.item);
2755         many.goals.push(theone);
2756     }
2757     if (count !== 0) {
2758         data.goals = Object.assign(many.goals);
2759     }
2760 // Assessments.
2761     many = [];
2762     theone = {};
2763     many.clinicalNoteAssessments = [];
2764     try {
2765         count = countEntities(pd.clinical_notes.evaluation_note);
2766     } catch (e) {
2767         count = 0
2768     }
2769     if (count > 1) {
2770         for (let i in pd.clinical_notes.evaluation_note) {
2771             theone[i] = getAssessments(pd.clinical_notes.evaluation_note[i]);
2772             many.clinicalNoteAssessments.push(theone[i]);
2773             break; // for now only one assessment. @todo concat notes to one.
2774         }
2775     } else if (count !== 0) {
2776         theone = getAssessments(pd.clinical_notes.evaluation_note);
2777         many.clinicalNoteAssessments.push(theone);
2778     }
2779     if (count !== 0) {
2780         data.clinicalNoteAssessments = Object.assign(many.clinicalNoteAssessments);
2781     }
2783 // Functional Status.
2784     many = [];
2785     theone = {};
2786     many.functional_status = [];
2787     try {
2788         count = countEntities(pd.functional_status.item);
2789     } catch (e) {
2790         count = 0
2791     }
2792     if (count > 1) {
2793         for (let i in pd.functional_status.item) {
2794             theone[i] = getFunctionalStatus(pd.functional_status.item[i]);
2795             many.functional_status.push(theone[i]);
2796         }
2797     } else if (count !== 0) {
2798         theone = getFunctionalStatus(pd.functional_status.item);
2799         many.functional_status.push(theone);
2800     }
2801     if (count !== 0) {
2802         data.functional_status = Object.assign(many.functional_status);
2803     }
2805 // Mental Status.
2806     many = [];
2807     theone = {};
2808     many.mental_status = [];
2809     try {
2810         count = countEntities(pd.mental_status.item);
2811     } catch (e) {
2812         count = 0
2813     }
2814     if (count > 1) {
2815         for (let i in pd.mental_status.item) {
2816             theone[i] = getMentalStatus(pd.mental_status.item[i]);
2817             many.mental_status.push(theone[i]);
2818         }
2819     } else if (count !== 0) {
2820         theone = getMentalStatus(pd.mental_status.item);
2821         many.mental_status.push(theone);
2822     }
2823     if (count !== 0) {
2824         data.mental_status = Object.assign(many.mental_status);
2825     }
2827 // Social History
2828     many = [];
2829     theone = {};
2830     many.social_history = [];
2831     try {
2832         count = countEntities(pd.history_physical.social_history.history_element);
2833     } catch (e) {
2834         count = 0
2835     }
2836     if (count > 1) {
2837         for (let i in pd.history_physical.social_history.history_element) {
2838             if (i > 0) break;
2839             theone[i] = populateSocialHistory(pd.history_physical.social_history.history_element[i]);
2840             many.social_history.push(theone[i]);
2841         }
2842     } else if (count !== 0) {
2843         theone = populateSocialHistory(pd.history_physical.social_history.history_element);
2844         many.social_history.push(theone);
2845     }
2846     if (count !== 0) {
2847         data.social_history = Object.assign(many.social_history);
2848     }
2849 // Notes
2850     for (let currentNote in pd.clinical_notes) {
2851         many = [];
2852         theone = {};
2853         switch (pd.clinical_notes[currentNote].clinical_notes_type) {
2854             case 'evaluation_note':
2855                 continue;
2856             case 'progress_note':
2857                 break;
2858             case 'history_physical':
2859                 pd.clinical_notes[currentNote].code_text = "History and Physical";
2860                 break;
2861             case 'nurse_note':
2862                 break;
2863             case 'general_note':
2864                 break;
2865             case 'discharge_summary':
2866                 break;
2867             case 'procedure_note':
2868                 break;
2869             case 'consultation_note':
2870                 break;
2871             case 'imaging_narrative':
2872                 break;
2873             case 'laboratory_report_narrative':
2874                 break;
2875             case 'pathology_report_narrative':
2876                 break;
2877             default:
2878                 continue;
2879         }
2880         try {
2881             count = countEntities(pd.clinical_notes[currentNote]);
2882         } catch (e) {
2883             count = 0
2884         }
2885         if (count > 1) {
2886             for (let i in pd.clinical_notes[currentNote]) {
2887                 theone[i] = populateNote(pd.clinical_notes[currentNote]);
2888                 many.push(theone[i]);
2889             }
2890         } else if (count !== 0) {
2891             theone = populateNote(pd.clinical_notes[currentNote]);
2892             many.push(theone);
2893         }
2894         if (count !== 0) {
2895             data[currentNote] = Object.assign(many);
2896         }
2897     }
2898 // Care Team and members
2899     if (pd.care_team.is_active == 'active') {
2900         data.care_team = Object.assign(populateCareTeamMembers(pd));
2901     }
2903 // ------------------------------------------ End Sections ---------------------------------------- //
2905     // sections data objects
2906     doc.data = Object.assign(data);
2907     // document meta data and header objects
2908     let meta = getMeta(pd);
2909     let header = populateHeader(pd);
2910     meta.ccda_header = Object.assign(header);
2911     doc.meta = Object.assign(meta);
2913     if (pd.timezone_local_offset) {
2914         populateTimezones(doc, pd.timezone_local_offset, 0);
2915     }
2916     // build to cda
2917     let xml = bbg.generateCCD(doc);
2919     /* Debug */
2920     if (enableDebug === true) {
2921         let place = documentLocation + "/documents/temp/";
2922         if (fs.existsSync(place)) {
2923             fs.writeFile(place + "ccda.json", JSON.stringify(all, null, 4), function (err) {
2924                 if (err) {
2925                     return console.log(err);
2926                 }
2927             });
2928             fs.writeFile(place + "ccda.xml", xml, function (err) {
2929                 if (err) {
2930                     return console.log(err);
2931                 }
2932             });
2933         }
2934     }
2936     return xml;
2939 let unstructuredTemplate = null;
2941 function generateUnstructured(pd) {
2942     let doc = {};
2943     let data = {};
2944     let count = 0;
2945     let many = [];
2946     let theone = {};
2947     // include unstructured document type oid in header
2948     pd.doc_type = 'unstructured';
2949     all = pd;
2950     let primary_care_provider = all.primary_care_provider || {};
2951     npiProvider = primary_care_provider.provider ? primary_care_provider.provider.npi : "NI";
2952     oidFacility = all.encounter_provider.facility_oid ? all.encounter_provider.facility_oid : "2.16.840.1.113883.19.5.99999.1";
2953     npiFacility = getNpiFacility(pd, true);
2954     webRoot = all.serverRoot;
2955     documentLocation = all.document_location;
2956     authorDateTime = pd.created_time_timezone;
2957     if (pd.author.time.length > 7) {
2958         authorDateTime = pd.author.time;
2959     } else if (all.encounter_list && all.encounter_list.encounter) {
2960         if (countEntities(all.encounter_list.encounter) === 1) {
2961             authorDateTime = all.encounter_list.encounter.date;
2962         } else {
2963             authorDateTime = all.encounter_list.encounter[0].date;
2964         }
2965     }
2966     authorDateTime = fDate(authorDateTime);
2967 // Demographics is needed in unstructured
2968     let demographic = populateDemographics(pd, npiFacility);
2969     data.demographics = Object.assign(demographic);
2971     if (pd.primary_care_provider) {
2972         Object.assign(demographic, populateProviders(pd));
2973     }
2974     doc.data = Object.assign(data);
2976     // document meta data and header objects
2977     let meta = getMeta(pd);
2978     let header = populateHeader(pd);
2979     meta.ccda_header = Object.assign(header);
2980     doc.meta = Object.assign(meta);
2982     // set TZ offset for moment
2983     if (pd.timezone_local_offset) {
2984         populateTimezones(doc, pd.timezone_local_offset, 0);
2985     }
2986     // build to cda
2987     let xml = bbg.generateCCD(doc);
2988     unstructuredTemplate = unstructuredTemplate.trim();
2989     xml = xml.replace(/<\/ClinicalDocument>/g, unstructuredTemplate);
2990     xml += "</ClinicalDocument>" + "\n";
2992     /* Debug */
2993     if (enableDebug === true) {
2994         let place = documentLocation + "/documents/temp/";
2995         if (fs.existsSync(place)) {
2996             fs.writeFile(place + "unstructured.xml", xml, function (err) {
2997                 if (err) {
2998                     return console.log(err);
2999                 }
3000             });
3001         }
3002     }
3004     return xml;
3007 function processConnection(connection) {
3008     conn = connection; // make it global
3009     let remoteAddress = conn.remoteAddress + ':' + conn.remotePort;
3010     conn.setEncoding('utf8');
3011     //console.log('server remote address ', remoteAddress);
3012     let xml_complete = "";
3014     function eventData(xml) {
3015         xml_complete = xml.toString();
3016         // ensure we have an array start and end
3017         if (xml_complete.match(/^<CCDA/g) && xml_complete.match(/<\/CCDA>$/g)) {
3018             let doc = "";
3019             let xslUrl = "";
3020             /* eslint-disable-next-line no-control-regex */
3021             xml_complete = xml_complete.replace(/(\u000b\u001c)/gm, "").trim();
3022             xml_complete = xml_complete.replace(/\t\s+/g, " ").trim();
3023             // convert xml data set for document to json array
3024             to_json(xml_complete, function (error, data) {
3025                 if (error) {
3026                     console.log(
3027                         "toJson error: " + error + "Len: " + xml_complete.length
3028                     );
3029                     return "ERROR: Failed json build";
3030                 }
3031                 let unstructured = "";
3032                 let isUnstruturedData = !!data.CCDA.patient_files;
3033                 // extract unstructured documents file component templates. One per file.
3034                 if (isUnstruturedData) {
3035                     unstructuredTemplate = xml_complete.substring(
3036                         xml_complete.lastIndexOf("<patient_files>") + 15,
3037                         xml_complete.lastIndexOf("</patient_files>")
3038                     );
3039                 }
3040                 // create doc_type document i.e. CCD Referral etc.
3041                 if (data.CCDA.doc_type !== "unstructured") {
3042                     doc = generateCcda(data.CCDA);
3043                     if (data.CCDA.xslUrl) {
3044                         xslUrl = data.CCDA.xslUrl || "";
3045                     }
3046                     doc = headReplace(doc, xslUrl);
3047                 } else {
3048                     unstructured = generateUnstructured(data.CCDA);
3049                     if (data.CCDA.xslUrl) {
3050                         xslUrl = data.CCDA.xslUrl || "";
3051                     }
3052                     doc = headReplace(unstructured, xslUrl);
3053                     // combine the two documents to send back all at once.
3054                     doc += unstructured;
3055                 }
3056                 // auto build an Unstructured document of supplied embedded files.
3057                 if (
3058                     data.CCDA.doc_type !== "unstructured" &&
3059                     isUnstruturedData
3060                 ) {
3061                     unstructured = generateUnstructured(data.CCDA);
3062                     unstructured = headReplace(unstructured, xslUrl);
3063                     // combine the two documents to send back all at once.
3064                     doc += unstructured;
3065                 }
3066             });
3067             // send results back to eagerly awaiting CCM for disposal.
3068             doc = doc
3069                 .toString()
3070                 /* eslint-disable-next-line no-control-regex */
3071                 .replace(/(\u000b\u001c|\r)/gm, "")
3072                 .trim();
3073             let chunk = "";
3074             let numChunks = Math.ceil(doc.length / 1024);
3075             for (let i = 0, o = 0; i < numChunks; ++i, o += 1024) {
3076                 chunk = doc.substring(o, o + 1024);
3077                 conn.write(chunk);
3078             }
3079             conn.write(String.fromCharCode(28) + "\r\r" + "");
3080             conn.end();
3081         }
3082     }
3084     function eventCloseConn() {
3085         //console.log('connection from %s closed', remoteAddress);
3086     }
3088     function eventErrorConn(err) {
3089         console.log('Connection %s error: %s', remoteAddress, err.message);
3090         console.log(err.stack);
3091         conn.destroy();
3092     }
3094 // Connection Events //
3095     // CCM will send one File Separator characters to mark end of array.
3096     let received = new DataStack(String.fromCharCode(28));
3097     conn.on("data", data => {
3098         received.push(data);
3099         while (!received.endOfCcda() && data.length > 0) {
3100             data = "";
3101             eventData(received.returnData());
3102         }
3103     });
3105     conn.once('close', eventCloseConn);
3106     conn.on('error', eventErrorConn);
3109 function setUp(server) {
3110     server.on('connection', processConnection);
3111     server.listen(6661, '127.0.0.1', function () { // never change port!
3112         //console.log('server listening to ', server.address());
3113     });
3116 // start up listener for requests from CCM or others.
3117 setUp(server);
3119 /* ---------------------------------For future use in header. Do not remove!-------------------------------------------- */
3120 /*"data_enterer": {
3121     "identifiers": [
3122         {
3123             "identifier": "2.16.840.1.113883.4.6",
3124             "extension": "999999943252"
3125         }
3126     ],
3127     "name": [
3128         {
3129             "last": pd.data_enterer.lname,
3130             "first": pd.data_enterer.fname
3131         }
3132     ],
3133     "address": [
3134         {
3135             "street_lines": [
3136                 pd.data_enterer.streetAddressLine
3137             ],
3138             "city": pd.data_enterer.city,
3139             "state": pd.data_enterer.state,
3140             "zip": pd.data_enterer.postalCode,
3141             "country": pd.data_enterer.country
3142         }
3143     ],
3144     "phone": [
3145         {
3146             "number": pd.data_enterer.telecom,
3147             "type": "work place"
3148         }
3149     ]
3151 "informant": {
3152     "identifiers": [
3153         {
3154             "identifier": "2.16.840.1.113883.19.5",
3155             "extension": "KP00017"
3156         }
3157     ],
3158     "name": [
3159         {
3160             "last": pd.informer.lname || "",
3161             "first": pd.informer.fname || ""
3162         }
3163     ],
3164     "address": [
3165         {
3166             "street_lines": [
3167                 pd.informer.streetAddressLine || ""
3168             ],
3169             "city": pd.informer.city,
3170             "state": pd.informer.state,
3171             "zip": pd.informer.postalCode,
3172             "country": pd.informer.country
3173         }
3174     ],
3175     "phone": [
3176         {
3177             "number": pd.informer.telecom || "",
3178             "type": "work place"
3179         }
3180     ]
3181 },*/
3182 /*"service_event": {
3183     "code": {
3184         "name": "",
3185         "code": "",
3186         "code_system_name": "SNOMED CT"
3187     },
3188     "date_time": {
3189         "low": {
3190             "date": "2021-03-11",
3191             "precision": "day"
3192         },
3193         "high": {
3194             "date": pd.created_time,
3195             "precision": "day"
3196         }
3197     },
3198     "performer": [
3199         {
3200             "performer": [
3201                 {
3202                     "identifiers": [
3203                         {
3204                             "identifier": "2.16.840.1.113883.4.6",
3205                             "extension": npiProvider
3206                         }
3207                     ],
3208                     "name": [
3209                         {
3210                             "last": pd.information_recipient.lname || "DAH",
3211                             "first": pd.information_recipient.fname || "DAH"
3212                         }
3213                     ],
3214                     "address": [
3215                         {
3216                             "street_lines": [
3217                                 pd.information_recipient.streetAddressLine
3218                             ],
3219                             "city": pd.information_recipient.city,
3220                             "state": pd.information_recipient.state,
3221                             "zip": pd.information_recipient.postalCode,
3222                             "country": pd.information_recipient.country || "US"
3223                         }
3224                     ],
3225                     "phone": [
3226                         {
3227                             "number": pd.information_recipient.telecom,
3228                             "type": "work place"
3229                         }
3230                     ],
3231                     "organization": [
3232                         {
3233                             "identifiers": [
3234                                 {
3235                                     "identifier": "2.16.840.1.113883.19.5.9999.1393"
3236                                 }
3237                             ],
3238                             "name": [
3239                                 pd.encounter_provider.facility_name
3240                             ],
3241                             "address": [
3242                                 {
3243                                     "street_lines": [
3244                                         pd.encounter_provider.facility_street
3245                                     ],
3246                                     "city": pd.encounter_provider.facility_city,
3247                                     "state": pd.encounter_provider.facility_state,
3248                                     "zip": pd.encounter_provider.facility_postal_code,
3249                                     "country": pd.encounter_provider.facility_country_code || "US"
3250                                 }
3251                             ],
3252                             "phone": [
3253                                 {
3254                                     "number": pd.encounter_provider.facility_phone,
3255                                     "type": "primary work"
3256                                 }
3257                             ]
3258                         }
3259                     ],
3260                     "code": [
3261                         {
3262                             "name": "",
3263                             "code": "",
3264                             "code_system_name": "Provider Codes"
3265                         }
3266                     ]
3267                 }
3268             ],
3269             "code": {
3270                 "name": "Primary Performer",
3271                 "code": "PP",
3272                 "code_system_name": "Provider Role"
3273             }
3274         }
3275     ]