You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3540 lines
111 KiB
3540 lines
111 KiB
2 years ago
|
/**
|
||
|
* @package OpenEMR CCDAServer
|
||
|
* @link http://www.open-emr.org
|
||
|
*
|
||
|
* @author Jerry Padgett <sjpadgett@gmail.com>
|
||
|
* @copyright Copyright (c) 2016-2022 Jerry Padgett <sjpadgett@gmail.com>
|
||
|
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
|
||
|
*/
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
const enableDebug = true;
|
||
|
|
||
|
const net = require('net');
|
||
|
const server = net.createServer();
|
||
|
const to_json = require('xmljson').to_json;
|
||
|
const bbg = require(__dirname + '/oe-blue-button-generate');
|
||
|
const fs = require('fs');
|
||
|
|
||
|
var conn = ''; // make our connection scope global to script
|
||
|
var oidFacility = "";
|
||
|
var all = "";
|
||
|
var npiProvider = "";
|
||
|
var npiFacility = "";
|
||
|
var webRoot = "";
|
||
|
var authorDateTime = '';
|
||
|
var documentLocation = '';
|
||
|
|
||
|
class DataStack {
|
||
|
constructor(delimiter) {
|
||
|
this.delimiter = delimiter;
|
||
|
this.buffer = "";
|
||
|
}
|
||
|
|
||
|
endOfCcda() {
|
||
|
return this.buffer.length === 0 || this.buffer.indexOf(this.delimiter) === -1;
|
||
|
}
|
||
|
|
||
|
pushToStack(data) {
|
||
|
this.buffer += data;
|
||
|
}
|
||
|
|
||
|
fetchBuffer() {
|
||
|
const delimiterIndex = this.buffer.indexOf(this.delimiter);
|
||
|
if (delimiterIndex !== -1) {
|
||
|
const bufferMsg = this.buffer.slice(0, delimiterIndex);
|
||
|
this.buffer = this.buffer.replace(bufferMsg + this.delimiter, "");
|
||
|
return bufferMsg;
|
||
|
}
|
||
|
return null
|
||
|
}
|
||
|
|
||
|
returnData() {
|
||
|
return this.fetchBuffer();
|
||
|
}
|
||
|
|
||
|
clearStack() {
|
||
|
this.buffer = "";
|
||
|
}
|
||
|
|
||
|
readStackByDelimiter(delimiter) {
|
||
|
let backup = this.delimiter;
|
||
|
let part = '';
|
||
|
this.delimiter = delimiter;
|
||
|
part = this.fetchBuffer();
|
||
|
this.delimiter = backup;
|
||
|
return part;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function trim(s) {
|
||
|
if (typeof s === 'string') return s.trim();
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
function cleanText(s) {
|
||
|
if (typeof s === 'string') {
|
||
|
//s = s.replace(new RegExp('\r?\n','g'), '<br />');
|
||
|
return s.trim();
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
// do a recursive descent transformation of the node object populating the timezone offset value if we have
|
||
|
// a precision property (inside a date) with the value of timezone.
|
||
|
function populateTimezones(node, tzOffset, depthCheck) {
|
||
|
if (!node || typeof node !== 'object') {
|
||
|
return node;
|
||
|
}
|
||
|
// we should NEVER go farther than 25 recursive loops down in our heirarchy, if we do it means we have an infinite loop
|
||
|
if (depthCheck > 25) {
|
||
|
console.error("Max depth traversal reached. Potential infinite loop. Breaking out of loop")
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
if (node.hasOwnProperty('precision') && node.precision == 'tz' && !node.hasOwnProperty('timezoneOffset')) {
|
||
|
node.timezoneOffset = tzOffset;
|
||
|
} else {
|
||
|
for (const [key, value] of Object.entries(node)) {
|
||
|
node[key] = populateTimezones(value, tzOffset, depthCheck + 1);
|
||
|
}
|
||
|
}
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
function fDate(str, lim8 = false) {
|
||
|
str = String(str);
|
||
|
if (lim8) {
|
||
|
let rtn = str.substring(0, 8);
|
||
|
return rtn;
|
||
|
}
|
||
|
if (Number(str) === 0) {
|
||
|
return (new Date()).toISOString();
|
||
|
}
|
||
|
if (str.length === 1 || str === "0000-00-00") return (new Date()).toISOString();
|
||
|
if (str.length === 8 || (str.length === 14 && (1 * str.substring(12, 14)) === 0)) {
|
||
|
return [str.slice(0, 4), str.slice(4, 6), str.slice(6, 8)].join('-');
|
||
|
} else if (str.length === 10 && (1 * str.substring(0, 2)) <= 12) {
|
||
|
// case mm/dd/yyyy or mm-dd-yyyy
|
||
|
return [str.slice(6, 10), str.slice(0, 2), str.slice(3, 5)].join('-');
|
||
|
} else if (str.length === 17) {
|
||
|
str = str.split(' ');
|
||
|
str = [str[0].slice(0, 4), str[0].slice(4, 6), str[0].slice(6, 8)].join('-') + ' ' + str[1];
|
||
|
return str;
|
||
|
} else if (str.length === 19 && (str.substring(14, 15)) == '-') {
|
||
|
let strZone = str.split('-');
|
||
|
let strDate = [strZone[0].substring(0, 4), strZone[0].substring(4, 6), strZone[0].substring(6, 8)].join('-');
|
||
|
let strTime = [str.substring(8, 10), str.substring(10, 12), str.substring(12, 14)].join(':');
|
||
|
|
||
|
let str1 = strDate + ' ' + strTime + '-' + strZone[1];
|
||
|
return str1;
|
||
|
} else {
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
function getPrecision(str) {
|
||
|
str = String(str);
|
||
|
let pflg = "day";
|
||
|
|
||
|
if (Number(str) === 0) {
|
||
|
return "day";
|
||
|
}
|
||
|
if (str.length > 8) {
|
||
|
pflg = "day";
|
||
|
}
|
||
|
if (str.length > 12) {
|
||
|
pflg = "second";
|
||
|
}
|
||
|
if (str.length > 23) {
|
||
|
pflg = "tz";
|
||
|
}
|
||
|
|
||
|
return pflg;
|
||
|
}
|
||
|
|
||
|
function templateDate(date, precision) {
|
||
|
return {'date': fDate(date), 'precision': precision}
|
||
|
}
|
||
|
|
||
|
function cleanCode(code) {
|
||
|
if (typeof code === 'undefined') {
|
||
|
return "null_flavor";
|
||
|
}
|
||
|
if (code.length < 2) {
|
||
|
code = "null_flavor";
|
||
|
return code;
|
||
|
}
|
||
|
return code.replace(/[.#]/, "");
|
||
|
}
|
||
|
|
||
|
function isOne(who) {
|
||
|
try {
|
||
|
if (who !== null && typeof who === 'object') {
|
||
|
return (who.hasOwnProperty('npi')
|
||
|
|| who.hasOwnProperty('code')
|
||
|
|| who.hasOwnProperty('extension')
|
||
|
|| who.hasOwnProperty('id')
|
||
|
|| who.hasOwnProperty('date')
|
||
|
|| who.hasOwnProperty('use')
|
||
|
|| who.hasOwnProperty('type')
|
||
|
) ? 1 : Object.keys(who).length;
|
||
|
}
|
||
|
} catch (e) {
|
||
|
return false;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
function headReplace(content, xslUrl = "") {
|
||
|
|
||
|
let xsl = "CDA.xsl";
|
||
|
if (typeof xslUrl == "string" && xslUrl.trim() != "") {
|
||
|
xsl = xslUrl;
|
||
|
}
|
||
|
|
||
|
let r = '<?xml version="1.0" encoding="UTF-8"?>' + "\n" +
|
||
|
'<?xml-stylesheet type="text/xsl" href="' + xsl + '"?>';
|
||
|
r += "\n" + content.substring(content.search(/<ClinicalDocument/i));
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
function fetchPreviousAddresses(pd) {
|
||
|
let addressArray = [];
|
||
|
let pa = pd.previous_addresses.address;
|
||
|
let streetLine = [pd.street[0]];
|
||
|
if (pd.street[1].length > 0) {
|
||
|
streetLine = [pd.street[0], pd.street[1]];
|
||
|
}
|
||
|
addressArray.push({
|
||
|
"use": "HP",
|
||
|
"street_lines": streetLine,
|
||
|
"city": pd.city,
|
||
|
"state": pd.state,
|
||
|
"zip": pd.postalCode,
|
||
|
"country": pd.country || "US",
|
||
|
"date_time": {
|
||
|
// use current date for current residence
|
||
|
"low": {
|
||
|
"date": fDate(""),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
let count = isOne(pa);
|
||
|
// how do we ever get here where we just have one object?
|
||
|
if (count === 1) {
|
||
|
streetLine = [pa.street[0]];
|
||
|
if (pa.street[1].length > 0) {
|
||
|
streetLine = [pa.street[0], pa.street[1]];
|
||
|
}
|
||
|
addressArray.push({
|
||
|
"use": pa.use,
|
||
|
"street_lines": streetLine,
|
||
|
"city": pa.city,
|
||
|
"state": pa.state,
|
||
|
"zip": pa.postalCode,
|
||
|
"country": pa.country || "US",
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pa.period_start),
|
||
|
"precision": "day"
|
||
|
},
|
||
|
"high": {
|
||
|
"date": fDate(pa.period_end) || fDate(""),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
} else if (count > 1) {
|
||
|
for (let i in pa) {
|
||
|
streetLine = [pa[i].street[0]];
|
||
|
if (pa[i].street[1].length > 0) {
|
||
|
streetLine = [pa[i].street[0], pa[i].street[1]];
|
||
|
}
|
||
|
addressArray.push({
|
||
|
"use": pa[i].use,
|
||
|
"street_lines": streetLine,
|
||
|
"city": pa[i].city,
|
||
|
"state": pa[i].state,
|
||
|
"zip": pa[i].postalCode,
|
||
|
"country": pa[i].country || "US",
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pa[i].period_start),
|
||
|
"precision": "day"
|
||
|
},
|
||
|
"high": {
|
||
|
"date": fDate(pa[i].period_end) || fDate(""),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
return addressArray;
|
||
|
}
|
||
|
|
||
|
function populateDemographic(pd, g) {
|
||
|
let guardian = [{
|
||
|
"relation": g.relation,
|
||
|
"addresses": [{
|
||
|
"street_lines": [g.address],
|
||
|
"city": g.city,
|
||
|
"state": g.state,
|
||
|
"zip": g.postalCode,
|
||
|
"country": g.country || "US",
|
||
|
"use": "primary home"
|
||
|
}],
|
||
|
"names": [{
|
||
|
"last": g.display_name, //@todo parse first/last
|
||
|
"first": g.display_name
|
||
|
}],
|
||
|
"phone": [{
|
||
|
"number": g.telecom,
|
||
|
"type": "primary home"
|
||
|
}]
|
||
|
}];
|
||
|
if (pd.race === 'Declined To Specify' || pd.race === '') {
|
||
|
pd.race = "null_flavor";
|
||
|
}
|
||
|
if (pd.race_group === 'Declined To Specify' || pd.race_group === '') {
|
||
|
pd.race_group = "null_flavor";
|
||
|
}
|
||
|
if (pd.ethnicity === 'Declined To Specify' || pd.ethnicity === '') {
|
||
|
pd.ethnicity = "null_flavor";
|
||
|
}
|
||
|
let addressArray = fetchPreviousAddresses(pd);
|
||
|
return {
|
||
|
"name": {
|
||
|
"prefix": pd.prefix,
|
||
|
"suffix": pd.suffix,
|
||
|
"middle": [pd.mname] || "",
|
||
|
"last": pd.lname,
|
||
|
"first": pd.fname
|
||
|
},
|
||
|
"birth_name": {
|
||
|
"middle": pd.birth_mname || "",
|
||
|
"last": pd.birth_lname || "",
|
||
|
"first": pd.birth_fname || ""
|
||
|
},
|
||
|
"dob": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.dob),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"gender": pd.gender.toUpperCase() || "null_flavor",
|
||
|
"identifiers": [{
|
||
|
"identifier": oidFacility,
|
||
|
"extension": "PT-" + pd.id
|
||
|
}],
|
||
|
"marital_status": pd.status.toUpperCase(),
|
||
|
"addresses": addressArray,
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.phone_home,
|
||
|
"type": "primary home"
|
||
|
}, {
|
||
|
"number": pd.phone_mobile,
|
||
|
"type": "primary mobile"
|
||
|
}, {
|
||
|
"email": pd.email,
|
||
|
"type": "contact_email"
|
||
|
}
|
||
|
],
|
||
|
"ethnicity": pd.ethnicity || "",
|
||
|
"race": pd.race || "null_flavor",
|
||
|
"race_additional": pd.race_group || "null_flavor",
|
||
|
"languages": [{
|
||
|
"language": pd.language === 'English' ? "en-US" : pd.language === 'Spanish' ? "sp-US" : 'en-US',
|
||
|
"preferred": true,
|
||
|
"mode": "Expressed spoken",
|
||
|
"proficiency": "Good"
|
||
|
}],
|
||
|
//"religion": pd.religion.toUpperCase() || "",
|
||
|
/*"birthplace":'', {
|
||
|
"city": "",
|
||
|
"state": "",
|
||
|
"zip": "",
|
||
|
"country": ""
|
||
|
},*/
|
||
|
"attributed_provider": {
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"phone": [{
|
||
|
"number": all.encounter_provider.facility_phone || "",
|
||
|
}],
|
||
|
"name": [
|
||
|
{
|
||
|
"full": all.encounter_provider.facility_name || ""
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
all.encounter_provider.facility_street
|
||
|
],
|
||
|
"city": all.encounter_provider.facility_city,
|
||
|
"state": all.encounter_provider.facility_state,
|
||
|
"zip": all.encounter_provider.facility_postal_code,
|
||
|
"country": all.encounter_provider.facility_country_code || "US",
|
||
|
"use": "work place"
|
||
|
}
|
||
|
],
|
||
|
},
|
||
|
//"guardians": g.display_name ? guardian : '' //not required
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateProvider(provider) {
|
||
|
// The provider role is a maybe and will only be provided for physicians as a
|
||
|
// primary care role. All other team members will id via taxonomy only and if not physicians.
|
||
|
return {
|
||
|
"function_code": provider.physician_type ? "PP" : "",
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": provider.provider_since ? fDate(provider.provider_since) : fDate(""),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": provider.npi ? "2.16.840.1.113883.4.6" : oidFacility,
|
||
|
"extension": provider.npi || provider.table_id || ""
|
||
|
}
|
||
|
],
|
||
|
"type": [
|
||
|
{
|
||
|
"name": provider.taxonomy_description || "",
|
||
|
"code": cleanCode(provider.taxonomy) || "",
|
||
|
"code_system": "2.16.840.1.113883.6.101",
|
||
|
"code_system_name": "NUCC Health Care Provider Taxonomy"
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": provider.lname || "",
|
||
|
"first": provider.fname || ""
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
all.encounter_provider.facility_street
|
||
|
],
|
||
|
"city": all.encounter_provider.facility_city,
|
||
|
"state": all.encounter_provider.facility_state,
|
||
|
"zip": all.encounter_provider.facility_postal_code,
|
||
|
"country": all.encounter_provider.facility_country_code || "US"
|
||
|
}
|
||
|
],
|
||
|
|
||
|
"phone": [{
|
||
|
"number": all.encounter_provider.facility_phone || ""
|
||
|
}]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateProviders(all) {
|
||
|
let providerArray = [];
|
||
|
// primary provider
|
||
|
let provider = populateProvider(all.primary_care_provider.provider);
|
||
|
providerArray.push(provider);
|
||
|
let count = isOne(all.care_team.provider);
|
||
|
if (count === 1) {
|
||
|
provider = populateProvider(all.care_team.provider);
|
||
|
providerArray.push(provider);
|
||
|
} else if (count > 1) {
|
||
|
for (let i in all.care_team.provider) {
|
||
|
provider = populateProvider(all.care_team.provider[i]);
|
||
|
providerArray.push(provider);
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
"providers":
|
||
|
{
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(all.time_start) || fDate(""),
|
||
|
"precision": "tz"
|
||
|
},
|
||
|
"high": {
|
||
|
"date": fDate(all.time_end) || fDate(""),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"code": {
|
||
|
"name": all.primary_diagnosis.text || "",
|
||
|
"code": cleanCode(all.primary_diagnosis.code || ""),
|
||
|
"code_system_name": all.primary_diagnosis.code_type || ""
|
||
|
},
|
||
|
"provider": providerArray,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
function populateCareTeamMember(provider) {
|
||
|
return {
|
||
|
//"function_code": provider.physician_type ? "PP" : "",
|
||
|
"function_code": {
|
||
|
"xmlns": "urn:hl7-org:sdtc",
|
||
|
"name": provider.taxonomy_description || "",
|
||
|
"code": cleanCode(provider.taxonomy) || "",
|
||
|
"code_system": "2.16.840.1.113883.6.101",
|
||
|
"code_system_name": "NUCC Health Care Provider Taxonomy"
|
||
|
},
|
||
|
"status": "active",
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(provider.provider_since) || fDate(""),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": provider.npi ? "2.16.840.1.113883.4.6" : oidFacility,
|
||
|
"extension": provider.npi || provider.table_id
|
||
|
}
|
||
|
],
|
||
|
"full_name": provider.fname + " " + provider.lname,
|
||
|
"name": {
|
||
|
"last": provider.lname || "",
|
||
|
"first": provider.fname || ""
|
||
|
},
|
||
|
"address": {
|
||
|
"street_lines": [
|
||
|
provider.street
|
||
|
],
|
||
|
"city": provider.city,
|
||
|
"state": provider.state,
|
||
|
"zip": provider.zip,
|
||
|
"country": all.encounter_provider.facility_country_code || "US"
|
||
|
},
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": provider.telecom,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateAuthorFromAuthorContainer(pd) {
|
||
|
let author = pd.author || {};
|
||
|
return {
|
||
|
"code": {
|
||
|
"name": author.physician_type || '',
|
||
|
"code": author.physician_type_code || '',
|
||
|
"code_system": author.physician_type_system,
|
||
|
"code_system_name": author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": author.npi ? "2.16.840.1.113883.4.6" : author.id,
|
||
|
"extension": author.npi ? author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": author.lname || "",
|
||
|
"first": author.fname || ""
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
author.facility_name || ""
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateCareTeamMembers(pd) {
|
||
|
let providerArray = [];
|
||
|
// primary provider
|
||
|
let primaryCareProvider = pd.primary_care_provider || {provider: {}};
|
||
|
let providerSince = fDate(primaryCareProvider.provider.provider_since || '');
|
||
|
if (pd.primary_care_provider) {
|
||
|
let provider = populateCareTeamMember(pd.primary_care_provider.provider);
|
||
|
providerArray.push(provider);
|
||
|
let count = isOne(pd.care_team.provider);
|
||
|
if (count === 1) {
|
||
|
provider = populateCareTeamMember(pd.care_team.provider);
|
||
|
providerSince = providerSince || fDate(provider.provider_since);
|
||
|
providerArray.push(provider);
|
||
|
} else if (count > 1) {
|
||
|
for (let i in pd.care_team.provider) {
|
||
|
provider = populateCareTeamMember(pd.care_team.provider[i]);
|
||
|
providerSince = providerSince || fDate(provider.provider_since);
|
||
|
providerArray.push(provider);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
"providers":
|
||
|
{
|
||
|
"provider": providerArray,
|
||
|
},
|
||
|
"status": "active",
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": providerSince || fDate(""),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
// we treat this author a bit differently since we are working at the main pd object instead of the sub pd.care_team
|
||
|
"author": populateAuthorFromAuthorContainer(pd.care_team)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateMedication(pd) {
|
||
|
pd.status = 'Completed'; //@todo invoke prescribed
|
||
|
return {
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date),
|
||
|
"precision": "tz"
|
||
|
}/*,
|
||
|
"high": {
|
||
|
"date": fDate(pd.end_date),
|
||
|
"precision": "day"
|
||
|
}*/
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension || ""
|
||
|
}],
|
||
|
"status": pd.status,
|
||
|
"sig": pd.direction,
|
||
|
"product": {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension || "2a620155-9d11-439e-92b3-5d9815ff4ee8",
|
||
|
"extension": pd.extension + 1 || ""
|
||
|
}],
|
||
|
"unencoded_name": pd.drug,
|
||
|
"product": {
|
||
|
"name": pd.drug,
|
||
|
"code": cleanCode(pd.rxnorm),
|
||
|
"code_system_name": "RXNORM"
|
||
|
/*"translations": [{
|
||
|
"name": pd.drug,
|
||
|
"code": pd.rxnorm,
|
||
|
"code_system_name": "RXNORM"
|
||
|
}],*/
|
||
|
},
|
||
|
//"manufacturer": ""
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": pd.author.physician_type || '',
|
||
|
"code": pd.author.physician_type_code || '',
|
||
|
"code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
|
||
|
"extension": pd.author.npi ? pd.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"supply": {
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date),
|
||
|
"precision": "day"
|
||
|
},
|
||
|
"high": {
|
||
|
"date": fDate(pd.end_date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"repeatNumber": "0",
|
||
|
"quantity": "0",
|
||
|
"product": {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension || "2a620155-9d11-439e-92b3-5d9815ff4ee8",
|
||
|
"extension": pd.extension + 1 || ""
|
||
|
}],
|
||
|
"unencoded_name": pd.drug,
|
||
|
"product": {
|
||
|
"name": pd.drug,
|
||
|
"code": cleanCode(pd.rxnorm),
|
||
|
/*"translations": [{
|
||
|
"name": pd.drug,
|
||
|
"code": pd.rxnorm,
|
||
|
"code_system_name": "RXNORM"
|
||
|
}],*/
|
||
|
"code_system_name": "RXNORM"
|
||
|
},
|
||
|
//"manufacturer": ""
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": all.author.physician_type || '',
|
||
|
"code": all.author.physician_type_code || '',
|
||
|
"code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": authorDateTime,
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
|
||
|
"extension": all.author.npi ? all.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": all.author.lname,
|
||
|
"first": all.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": oidFacility || "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
all.encounter_provider.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"instructions": {
|
||
|
"code": {
|
||
|
"name": "instruction",
|
||
|
"code": "409073007",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"free_text": pd.instructions || "No Instructions"
|
||
|
},
|
||
|
},
|
||
|
"administration": {
|
||
|
"route": {
|
||
|
"name": pd.route || "",
|
||
|
"code": cleanCode(pd.route_code) || "",
|
||
|
"code_system_name": "Medication Route FDA"
|
||
|
},
|
||
|
"form": {
|
||
|
"name": pd.form,
|
||
|
"code": cleanCode(pd.form_code),
|
||
|
"code_system_name": "Medication Route FDA"
|
||
|
},
|
||
|
"dose": {
|
||
|
"value": parseFloat(pd.size),
|
||
|
"unit": pd.unit,
|
||
|
},
|
||
|
/*"rate": {
|
||
|
"value": parseFloat(pd.dosage),
|
||
|
"unit": ""
|
||
|
},*/
|
||
|
"interval": {
|
||
|
"period": {
|
||
|
"value": parseFloat(pd.dosage),
|
||
|
"unit": pd.interval
|
||
|
},
|
||
|
"frequency": true
|
||
|
}
|
||
|
},
|
||
|
"performer": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.npi || ""
|
||
|
}],
|
||
|
"organization": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension || ""
|
||
|
}],
|
||
|
"name": [pd.performer_name]
|
||
|
}]
|
||
|
},
|
||
|
"drug_vehicle": {
|
||
|
"name": pd.form,
|
||
|
"code": cleanCode(pd.form_code),
|
||
|
"code_system_name": "RXNORM"
|
||
|
},
|
||
|
/*"precondition": {
|
||
|
"code": {
|
||
|
"code": "ASSERTION",
|
||
|
"code_system_name": "ActCode"
|
||
|
},
|
||
|
"value": {
|
||
|
"name": "none",
|
||
|
"code": "none",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}
|
||
|
},
|
||
|
"indication": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "db734647-fc99-424c-a864-7e3cda82e703",
|
||
|
"extension": "45665"
|
||
|
}],
|
||
|
"code": {
|
||
|
"name": "Finding",
|
||
|
"code": "404684003",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"value": {
|
||
|
"name": pd.indications,
|
||
|
"code": pd.indications_code,
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}
|
||
|
},
|
||
|
"dispense": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "1.2.3.4.56789.1",
|
||
|
"extension": "cb734647-fc99-424c-a864-7e3cda82e704"
|
||
|
}],
|
||
|
"performer": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.19.5.9999.456",
|
||
|
"extension": "2981823"
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": [pd.address],
|
||
|
"city": pd.city,
|
||
|
"state": pd.state,
|
||
|
"zip": pd.zip,
|
||
|
"country": "US"
|
||
|
}],
|
||
|
"organization": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.19.5.9999.1393"
|
||
|
}],
|
||
|
"name": [pd.performer_name]
|
||
|
}]
|
||
|
},
|
||
|
"product": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2a620155-9d11-439e-92b3-5d9815ff4ee8"
|
||
|
}],
|
||
|
"unencoded_name": pd.drug,
|
||
|
"product": {
|
||
|
"name": pd.drug,
|
||
|
"code": pd.rxnorm,
|
||
|
"translations": [{
|
||
|
"name": pd.drug,
|
||
|
"code": pd.rxnorm,
|
||
|
"code_system_name": "RXNORM"
|
||
|
}],
|
||
|
"code_system_name": "RXNORM"
|
||
|
},
|
||
|
"manufacturer": ""
|
||
|
}
|
||
|
}*/
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateEncounter(pd) {
|
||
|
let name = '';
|
||
|
let code = '';
|
||
|
let code_system_name = "";
|
||
|
let status = "Active";
|
||
|
// just to get diagnosis. for findings..
|
||
|
if (typeof pd.encounter_diagnosis !== 'undefined') {
|
||
|
name = pd.encounter_diagnosis.text;
|
||
|
code = cleanCode(pd.encounter_diagnosis.code);
|
||
|
code_system_name = pd.encounter_diagnosis.code_type;
|
||
|
status = pd.encounter_diagnosis.status;
|
||
|
}
|
||
|
return {
|
||
|
"encounter": {
|
||
|
"name": pd.visit_category ? pd.visit_category : 'UNK',
|
||
|
"code": "185347001",
|
||
|
"code_system": "2.16.840.1.113883.6.96",
|
||
|
"code_system_name": "SNOMED CT",
|
||
|
"translations": [{
|
||
|
"name": "Ambulatory",
|
||
|
"code": "AMB",
|
||
|
"code_system_name": "ActCode"
|
||
|
}]
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"performers": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.npi || ""
|
||
|
}],
|
||
|
"code": [{
|
||
|
"name": pd.physician_type,
|
||
|
"code": cleanCode(pd.physician_type_code),
|
||
|
"code_system_name": pd.physician_code_type
|
||
|
}],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.lname || "",
|
||
|
"first": pd.fname || ""
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.work_phone,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
}],
|
||
|
"locations": [{
|
||
|
"name": pd.location,
|
||
|
"location_type": {
|
||
|
"name": pd.location_details,
|
||
|
"code": "1160-1",
|
||
|
"code_system_name": "HealthcareServiceLocation"
|
||
|
},
|
||
|
"address": [{
|
||
|
"street_lines": [pd.facility_address],
|
||
|
"city": pd.facility_city,
|
||
|
"state": pd.facility_state,
|
||
|
"zip": pd.facility_zip,
|
||
|
"country": pd.facility_country || "US"
|
||
|
}],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.facility_phone,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
}],
|
||
|
"findings": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension
|
||
|
}],
|
||
|
"value": {
|
||
|
"name": name,
|
||
|
"code": cleanCode(code),
|
||
|
"code_system_name": code_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"status": status,
|
||
|
"reason": pd.encounter_reason,
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": all.author.physician_type || '',
|
||
|
"code": all.author.physician_type_code || '',
|
||
|
"code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": authorDateTime,
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
|
||
|
"extension": all.author.npi ? all.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": all.author.lname,
|
||
|
"first": all.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": oidFacility || "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
all.encounter_provider.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
}]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateAllergy(pd) {
|
||
|
|
||
|
if (!pd) {
|
||
|
return {
|
||
|
"no_know_allergies": "No Known Allergies",
|
||
|
"date_time": {
|
||
|
"low": templateDate("", "day"),
|
||
|
//"high": templateDate(pd.enddate, "day")
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
let allergyAuthor = {
|
||
|
"code": {
|
||
|
"name": pd.author.physician_type || '',
|
||
|
"code": pd.author.physician_type_code || '',
|
||
|
"code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
|
||
|
"extension": pd.author.npi ? pd.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
};
|
||
|
|
||
|
return {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_id,
|
||
|
"extension": pd.id || ""
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"low": templateDate(pd.startdate, "day"),
|
||
|
//"high": templateDate(pd.enddate, "day")
|
||
|
},
|
||
|
"author": allergyAuthor,
|
||
|
"observation": {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension || "2a620155-9d11-439e-92b3-5d9815ff4ee8",
|
||
|
"extension": pd.id + 1 || ""
|
||
|
}],
|
||
|
"author": allergyAuthor,
|
||
|
"allergen": {
|
||
|
"name": pd.title || "",
|
||
|
"code": pd.rxnorm_code_text ? cleanCode(pd.rxnorm_code) : pd.snomed_code_text ? cleanCode(pd.snomed_code) : cleanCode(""),
|
||
|
"code_system_name": pd.rxnorm_code_text ? "RXNORM" : pd.snomed_code_text ? "SNOMED CT" : ""
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.startdate) || fDate(""),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"intolerance": {
|
||
|
"name": "Propensity to adverse reactions to drug",
|
||
|
"code": "420134006",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"severity": {
|
||
|
"code": {
|
||
|
"name": pd.outcome || "",
|
||
|
"code": cleanCode(pd.outcome_code) || "",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}
|
||
|
},
|
||
|
"status": {
|
||
|
"name": pd.status_table || "",
|
||
|
"code": cleanCode(pd.status_code),
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"reactions": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": "4adc1020-7b14-11db-9fe1-0800200c9a64"
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"low": templateDate(pd.startdate, "day"),
|
||
|
"high": templateDate(pd.enddate, "day")
|
||
|
},
|
||
|
"reaction": {
|
||
|
"name": pd.reaction_text,
|
||
|
"code": cleanCode(pd.reaction_code) || "",
|
||
|
"code_system_name": pd.reaction_code_type || "SNOMED CT"
|
||
|
},
|
||
|
"severity": {
|
||
|
"code": {
|
||
|
"name": pd.outcome || "",
|
||
|
"code": cleanCode(pd.outcome_code),
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}
|
||
|
}
|
||
|
}]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateProblem(pd) {
|
||
|
let primary_care_provider = all.primary_care_provider || {provider: {}};
|
||
|
return {
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date_table),
|
||
|
"precision": "day"
|
||
|
},
|
||
|
/*"high": {
|
||
|
"date": fDate(pd.end_date),
|
||
|
"precision": "day"
|
||
|
}*/
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension || ""
|
||
|
}],
|
||
|
"translations": [{
|
||
|
"name": "Condition",
|
||
|
"code": "75323-6",
|
||
|
"code_system_name": "LOINC"
|
||
|
}],
|
||
|
"problem": {
|
||
|
"code": {
|
||
|
"name": trim(pd.title),
|
||
|
"code": cleanCode(pd.code),
|
||
|
"code_system_name": trim(pd.code_type)
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date),
|
||
|
"precision": "day"
|
||
|
},
|
||
|
/*"high": {
|
||
|
"date": fDate(pd.end_date),
|
||
|
"precision": getPrecision()
|
||
|
}*/
|
||
|
}
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": pd.author.physician_type || '',
|
||
|
"code": pd.author.physician_type_code || '',
|
||
|
"code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
|
||
|
"extension": pd.author.npi ? pd.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"performer": [
|
||
|
{
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": primary_care_provider.provider.npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": primary_care_provider.provider.lname || "",
|
||
|
"first": primary_care_provider.provider.fname || ""
|
||
|
}
|
||
|
]
|
||
|
}],
|
||
|
"onset_age": pd.age,
|
||
|
"onset_age_unit": "Year",
|
||
|
"status": {
|
||
|
"name": pd.status_table,
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date),
|
||
|
"precision": "day"
|
||
|
},
|
||
|
/*"high": {
|
||
|
"date": fDate(pd.end_date),
|
||
|
"precision": getPrecision()
|
||
|
}*/
|
||
|
}
|
||
|
},
|
||
|
"patient_status": pd.observation,
|
||
|
"source_list_identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension || ""
|
||
|
}]
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
function populateProcedure(pd) {
|
||
|
return {
|
||
|
"procedure": {
|
||
|
"name": pd.description,
|
||
|
"code": cleanCode(pd.code),
|
||
|
//"code_system": "2.16.840.1.113883.6.12",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": "d68b7e32-7810-4f5b-9cc2-acd54b0fd85d",
|
||
|
"extension": pd.extension
|
||
|
}],
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
/*"body_sites": [{
|
||
|
"name": "",
|
||
|
"code": "",
|
||
|
"code_system_name": ""
|
||
|
}],
|
||
|
"specimen": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "c2ee9ee9-ae31-4628-a919-fec1cbb58683"
|
||
|
}],
|
||
|
"code": {
|
||
|
"name": "",
|
||
|
"code": "",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}
|
||
|
},*/
|
||
|
"performers": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.npi || ""
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": [pd.address],
|
||
|
"city": pd.city,
|
||
|
"state": pd.state,
|
||
|
"zip": pd.zip,
|
||
|
"country": "US"
|
||
|
}],
|
||
|
"phone": [{
|
||
|
"number": pd.work_phone,
|
||
|
"type": "work place"
|
||
|
}],
|
||
|
"organization": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.facility_sha_extension,
|
||
|
"extension": pd.facility_extension
|
||
|
}],
|
||
|
"name": [pd.facility_name],
|
||
|
"address": [{
|
||
|
"street_lines": [pd.facility_address],
|
||
|
"city": pd.facility_city,
|
||
|
"state": pd.facility_state,
|
||
|
"zip": pd.facility_zip,
|
||
|
"country": pd.facility_country || "US"
|
||
|
}],
|
||
|
"phone": [{
|
||
|
"number": pd.facility_phone,
|
||
|
"type": "work place"
|
||
|
}]
|
||
|
}]
|
||
|
}],
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
"procedure_type": "procedure"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateMedicalDevice(pd) {
|
||
|
return {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(pd.start_date),
|
||
|
"precision": "day"
|
||
|
}/*,
|
||
|
"high": {
|
||
|
"date": fDate(pd.end_date),
|
||
|
"precision": "day"
|
||
|
}*/
|
||
|
},
|
||
|
"device_type": "UDI",
|
||
|
"device": {
|
||
|
"name": pd.code_text,
|
||
|
"code": cleanCode(pd.code),
|
||
|
"code_system_name": "SNOMED CT",
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.3.3719",
|
||
|
"extension": pd.udi
|
||
|
}],
|
||
|
"status": "completed",
|
||
|
"body_sites": [{
|
||
|
"name": "",
|
||
|
"code": "",
|
||
|
"code_system_name": ""
|
||
|
}],
|
||
|
"udi": pd.udi
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": pd.author.physician_type || '',
|
||
|
"code": pd.author.physician_type_code || '',
|
||
|
"code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
|
||
|
"extension": pd.author.npi ? pd.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateResult(pd) {
|
||
|
let icode = pd.subtest.abnormal_flag;
|
||
|
let value = parseFloat(pd.subtest.result_value) || pd.subtest.result_value || "";
|
||
|
let type = isNaN(value) ? "ST" : "PQ";
|
||
|
type = !pd.subtest.unit ? "ST" : type;
|
||
|
value += "";
|
||
|
let range_type = pd.subtest.range.toUpperCase() == "NEGATIVE" ? "CO" : type;
|
||
|
type = value.toUpperCase() == "NEGATIVE" ? "CO" : type;
|
||
|
|
||
|
switch (pd.subtest.abnormal_flag.toUpperCase()) {
|
||
|
case "NO":
|
||
|
icode = "Normal";
|
||
|
break;
|
||
|
case "YES":
|
||
|
icode = "Abnormal";
|
||
|
break;
|
||
|
case "":
|
||
|
icode = "";
|
||
|
break;
|
||
|
}
|
||
|
let result = {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.subtest.root,
|
||
|
"extension": pd.subtest.extension
|
||
|
}],
|
||
|
"result": {
|
||
|
"name": pd.title,
|
||
|
"code": cleanCode(pd.subtest.result_code) || "",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date_ordered),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"status": pd.order_status,
|
||
|
"reference_range": {
|
||
|
"low": pd.subtest.low,
|
||
|
"high": pd.subtest.high,
|
||
|
"unit": pd.subtest.unit,
|
||
|
"type": type,
|
||
|
"range_type": range_type
|
||
|
},
|
||
|
"value": value + "",
|
||
|
"unit": pd.subtest.unit,
|
||
|
"type": type,
|
||
|
"range": pd.subtest.range,
|
||
|
"range_type": range_type
|
||
|
};
|
||
|
// interpretation cannot be an empty value so we skip it if it is
|
||
|
// empty as Observation.interpretationCode is [0..*]
|
||
|
if (icode !== "") {
|
||
|
result["interpretations"] = [icode];
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function getResultSet(results) {
|
||
|
|
||
|
if (!results) return '';
|
||
|
|
||
|
// not sure if the result set should be grouped better on the backend as the author information needs to be more nuanced here
|
||
|
let tResult = results.result[0] || results.result;
|
||
|
var resultSet = {
|
||
|
"identifiers": [{
|
||
|
"identifier": tResult.root,
|
||
|
"extension": tResult.extension
|
||
|
}],
|
||
|
"author": populateAuthorFromAuthorContainer(tResult),
|
||
|
"result_set": {
|
||
|
"name": tResult.test_name,
|
||
|
"code": cleanCode(tResult.test_code),
|
||
|
"code_system_name": "LOINC"
|
||
|
}
|
||
|
};
|
||
|
var rs = [];
|
||
|
var many = [];
|
||
|
var theone = {};
|
||
|
var count = 0;
|
||
|
many.results = [];
|
||
|
try {
|
||
|
count = isOne(results.result);
|
||
|
} catch (e) {
|
||
|
count = 0;
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in results.result) {
|
||
|
theone[i] = populateResult(results.result[i]);
|
||
|
many.results.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = populateResult(results.result);
|
||
|
many.results.push(theone);
|
||
|
}
|
||
|
rs.results = Object.assign(resultSet);
|
||
|
rs.results.results = Object.assign(many.results);
|
||
|
return rs;
|
||
|
}
|
||
|
|
||
|
function getPlanOfCare(pd) {
|
||
|
let name = '';
|
||
|
let code = '';
|
||
|
let code_system_name = "";
|
||
|
let status = "Active";
|
||
|
let one = true;
|
||
|
let encounter;
|
||
|
|
||
|
let planType = "observation";
|
||
|
switch (pd.care_plan_type) {
|
||
|
case 'plan_of_care':
|
||
|
planType = "observation"; // mood code INT. sets code in template
|
||
|
break;
|
||
|
case 'test_or_order':
|
||
|
planType = "observation"; // mood code RQO
|
||
|
break;
|
||
|
case 'procedure':
|
||
|
planType = "procedure";
|
||
|
break;
|
||
|
case 'appointments':
|
||
|
planType = "encounter";
|
||
|
break;
|
||
|
case 'instructions':
|
||
|
planType = "instructions";
|
||
|
break;
|
||
|
case 'referral':
|
||
|
planType = ""; // for now exclude. unsure how to template.
|
||
|
break;
|
||
|
default:
|
||
|
planType = "observation";
|
||
|
}
|
||
|
if (pd.code_type === 'RXCUI') {
|
||
|
pd.code_type = 'RXNORM';
|
||
|
}
|
||
|
if (pd.code_type === 'RXNORM') {
|
||
|
planType = "substanceAdministration";
|
||
|
}
|
||
|
if (planType === "") {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
for (let key in all.encounter_list.encounter) {
|
||
|
// skip loop if the property is from prototype
|
||
|
if (!all.encounter_list.encounter.hasOwnProperty(key)) {
|
||
|
continue;
|
||
|
}
|
||
|
encounter = all.encounter_list.encounter[key];
|
||
|
if (pd.encounter == encounter.encounter_id) {
|
||
|
one = false;
|
||
|
name = encounter.encounter_diagnosis.text;
|
||
|
code = cleanCode(encounter.encounter_diagnosis.code);
|
||
|
code_system_name = encounter.encounter_diagnosis.code_type;
|
||
|
status = encounter.encounter_diagnosis.status;
|
||
|
encounter = all.encounter_list.encounter[key]; // to be sure.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (one) {
|
||
|
let value = "";
|
||
|
if (all.encounter_list && all.encounter_list.encounter && all.encounter_list.encounter.encounter_diagnosis) {
|
||
|
value = all.encounter_list.encounter.encounter_diagnosis;
|
||
|
}
|
||
|
name = value.text;
|
||
|
code = cleanCode(value.code);
|
||
|
code_system_name = value.code_type;
|
||
|
status = value.status;
|
||
|
encounter = all.encounter_list.encounter;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
"plan": {
|
||
|
"name": pd.code_text || "",
|
||
|
"code": cleanCode(pd.code) || "",
|
||
|
"code_system_name": pd.code_type || "SNOMED CT"
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension
|
||
|
}],
|
||
|
"goal": {
|
||
|
"code": cleanCode(pd.code) || "",
|
||
|
"name": cleanText(pd.description) || ""
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"type": planType,
|
||
|
"status": {
|
||
|
"code": cleanCode(pd.status)
|
||
|
},
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
"performers": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": encounter.npi || ""
|
||
|
}],
|
||
|
"code": [{
|
||
|
"name": encounter.physician_type,
|
||
|
"code": cleanCode(encounter.physician_type_code),
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": encounter.lname || "",
|
||
|
"first": encounter.fname || ""
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": encounter.work_phone,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
}],
|
||
|
"locations": [{
|
||
|
"name": encounter.location,
|
||
|
"location_type": {
|
||
|
"name": encounter.location_details,
|
||
|
"code": "1160-1",
|
||
|
"code_system_name": "HealthcareServiceLocation"
|
||
|
},
|
||
|
"address": [{
|
||
|
"street_lines": [encounter.facility_address],
|
||
|
"city": encounter.facility_city,
|
||
|
"state": encounter.facility_state,
|
||
|
"zip": encounter.facility_zip,
|
||
|
"country": encounter.facility_country || "US"
|
||
|
}],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": encounter.facility_phone,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
}],
|
||
|
"findings": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": encounter.sha_extension,
|
||
|
"extension": encounter.extension
|
||
|
}],
|
||
|
"value": {
|
||
|
"name": name,
|
||
|
"code": code,
|
||
|
"code_system_name": code_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": fDate(encounter.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"status": status,
|
||
|
"reason": encounter.encounter_reason
|
||
|
}],
|
||
|
"name": cleanText(pd.description),
|
||
|
"mood_code": pd.moodCode
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getGoals(pd) {
|
||
|
return {
|
||
|
"goal_code": {
|
||
|
"name": pd.code_text !== "NULL" ? pd.code_text : "",
|
||
|
"code": cleanCode(pd.code) || "",
|
||
|
"code_system_name": pd.code_type || ""
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"type": "observation",
|
||
|
"status": {
|
||
|
"code": "active", //cleanCode(pd.status)
|
||
|
},
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
"name": pd.description
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getFunctionalStatus(pd) {
|
||
|
let functionalStatusAuthor = {
|
||
|
"code": {
|
||
|
"name": all.author.physician_type || '',
|
||
|
"code": all.author.physician_type_code || '',
|
||
|
"code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": authorDateTime,
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
|
||
|
"extension": all.author.npi ? all.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": all.author.lname,
|
||
|
"first": all.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": oidFacility || "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
all.encounter_provider.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
};
|
||
|
|
||
|
return {
|
||
|
"status": "completed",
|
||
|
"author": functionalStatusAuthor,
|
||
|
"identifiers": [{
|
||
|
"identifier": "9a6d1bac-17d3-4195-89a4-1121bc809000"
|
||
|
}],
|
||
|
|
||
|
"observation": {
|
||
|
"value": {
|
||
|
"name": pd.code_text !== "NULL" ? cleanText(pd.code_text) : "",
|
||
|
"code": cleanCode(pd.code) || "",
|
||
|
"code_system_name": pd.code_type || "SNOMED-CT"
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": "9a6d1bac-17d3-4195-89a4-1121bc8090ab"
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"author": functionalStatusAuthor
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getMentalStatus(pd) {
|
||
|
return {
|
||
|
"value": {
|
||
|
"name": pd.code_text !== "NULL" ? pd.code_text : "",
|
||
|
"code": cleanCode(pd.code) || "",
|
||
|
"code_system_name": pd.code_type || ""
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": "9a6d1bac-17d3-4195-89a4-1121bc809ccc"
|
||
|
}],
|
||
|
"note": cleanText(pd.description),
|
||
|
"date_time": {
|
||
|
"low": templateDate(pd.date, "day")
|
||
|
//"high": templateDate(pd.date, "day")
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": all.author.physician_type || '',
|
||
|
"code": all.author.physician_type_code || '',
|
||
|
"code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": authorDateTime,
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
|
||
|
"extension": all.author.npi ? all.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": all.author.lname,
|
||
|
"first": all.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": oidFacility || "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
all.encounter_provider.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getAssessments(pd) {
|
||
|
return {
|
||
|
"description": cleanText(pd.description),
|
||
|
"author": populateAuthorFromAuthorContainer(pd)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getHealthConcerns(pd) {
|
||
|
let one = true;
|
||
|
let issue_uuid;
|
||
|
let problems = [], problem = {};
|
||
|
if (isOne(pd.issues.issue_uuid) !== 0) {
|
||
|
for (let key in pd.issues.issue_uuid) {
|
||
|
issue_uuid = pd.issues.issue_uuid[key];
|
||
|
if (issue_uuid) {
|
||
|
one = false;
|
||
|
}
|
||
|
problem = {
|
||
|
"identifiers": [{
|
||
|
"identifier": issue_uuid
|
||
|
}]
|
||
|
};
|
||
|
problems.push(problem);
|
||
|
}
|
||
|
}
|
||
|
if (one) {
|
||
|
if (pd.issues.issue_uuid) {
|
||
|
problem = {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.issues.issue_uuid
|
||
|
}]
|
||
|
};
|
||
|
problems.push(problem);
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
"type": "act",
|
||
|
"text": cleanText(pd.text),
|
||
|
"value": {
|
||
|
"name": pd.code_text || "",
|
||
|
"code": cleanCode(pd.code) || "",
|
||
|
"code_system_name": pd.code_type || "SNOMED CT"
|
||
|
},
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension
|
||
|
}],
|
||
|
problems: problems
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getReferralReason(pd) {
|
||
|
return {
|
||
|
"reason": cleanText(pd.text),
|
||
|
"author": populateAuthorFromAuthorContainer(pd)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateVital(pd) {
|
||
|
return {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension
|
||
|
}],
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
// our list of vitals per organizer.
|
||
|
"vital_list": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_bps
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Blood Pressure Systolic",
|
||
|
"code": "8480-6",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.bps) || pd.bps,
|
||
|
"unit": "mm[Hg]",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_bpd
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Blood Pressure Diastolic",
|
||
|
"code": "8462-4",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.bpd) || pd.bpd,
|
||
|
"unit": "mm[Hg]",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_height
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Height",
|
||
|
"code": "8302-2",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.height) || pd.height,
|
||
|
"unit": pd.unit_height,
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_weight
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Weight Measured",
|
||
|
"code": "29463-7",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.weight) || "",
|
||
|
"unit": pd.unit_weight,
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_BMI
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "BMI (Body Mass Index)",
|
||
|
"code": "39156-5",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": [pd.BMI_status == 'Overweight' ? 'High' : pd.BMI_status == 'Overweight' ? 'Low' : 'Normal'],
|
||
|
"value": parseFloat(pd.BMI) || "",
|
||
|
"unit": "kg/m2",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_pulse
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Heart Rate",
|
||
|
"code": "8867-4",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.pulse) || "",
|
||
|
"unit": "/min",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.2",
|
||
|
"extension": pd.extension_breath
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Respiratory Rate",
|
||
|
"code": "9279-1",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.breath) || "",
|
||
|
"unit": "/min",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.3.140.1.0.6.10.14.3",
|
||
|
"extension": pd.extension_temperature
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Body Temperature",
|
||
|
"code": "8310-5",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.temperature) || "",
|
||
|
"unit": pd.unit_temperature,
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_oxygen_saturation
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "O2 % BldC Oximetry",
|
||
|
"code": "59408-5",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.oxygen_saturation) || "",
|
||
|
"unit": "%",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_ped_weight_height
|
||
|
}],
|
||
|
"vital": { // --------------------------------------------------------------------------------
|
||
|
"name": "Weight for Height Percentile",
|
||
|
"code": "77606-2",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.ped_weight_height) || "",
|
||
|
"unit": "%",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_inhaled_oxygen_concentration
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Inhaled Oxygen Concentration",
|
||
|
"code": "3150-0",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.inhaled_oxygen_concentration) || "",
|
||
|
"unit": "%",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_ped_bmi
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "BMI Percentile",
|
||
|
"code": "59576-9",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.ped_bmi) || "",
|
||
|
"unit": "%",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}, {
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension_ped_head_circ
|
||
|
}],
|
||
|
"vital": {
|
||
|
"name": "Head Occipital-frontal Circumference Percentile",
|
||
|
"code": "8289-1",
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"status": "completed",
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.effectivetime),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"interpretations": ["Normal"],
|
||
|
"value": parseFloat(pd.ped_head_circ) || "",
|
||
|
"unit": "%",
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateSocialHistory(pd) {
|
||
|
return {
|
||
|
"date_time": {
|
||
|
"low": templateDate(pd.date, "day")
|
||
|
//"high": templateDate(pd.date, "day")
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": pd.sha_extension,
|
||
|
"extension": pd.extension
|
||
|
}],
|
||
|
"code": {
|
||
|
"name": pd.code
|
||
|
},
|
||
|
"element": pd.element,
|
||
|
"value": pd.description,
|
||
|
"gender": all.patient.gender,
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": pd.author.physician_type || '',
|
||
|
"code": pd.author.physician_type_code || '',
|
||
|
"code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
|
||
|
"extension": pd.author.npi ? pd.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
, "gender_author": {
|
||
|
"code": {
|
||
|
"name": all.patient.author.physician_type || '',
|
||
|
"code": all.patient.author.physician_type_code || '',
|
||
|
"code_system": all.patient.author.physician_type_system, "code_system_name": all.patient.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(all.patient.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": all.patient.author.npi ? "2.16.840.1.113883.4.6" : all.patient.author.id,
|
||
|
"extension": all.patient.author.npi ? all.patient.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": all.patient.author.lname,
|
||
|
"first": all.patient.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": all.patient.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": all.patient.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
all.patient.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateImmunization(pd) {
|
||
|
return {
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.administered_on),
|
||
|
"precision": "month"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": "e6f1ba43-c0ed-4b9b-9f12-f435d8ad8f92",
|
||
|
"extension": pd.extension || ""
|
||
|
}],
|
||
|
"status": "complete",
|
||
|
"product": {
|
||
|
"product": {
|
||
|
"name": pd.code_text,
|
||
|
"code": cleanCode(pd.cvx_code),
|
||
|
"code_system_name": "CVX"
|
||
|
/*"translations": [{
|
||
|
"name": "",
|
||
|
"code": "",
|
||
|
"code_system_name": "CVX"
|
||
|
}]*/
|
||
|
},
|
||
|
"lot_number": "",
|
||
|
"manufacturer": ""
|
||
|
},
|
||
|
"administration": {
|
||
|
"route": {
|
||
|
"name": pd.route_of_administration,
|
||
|
"code": cleanCode(pd.route_code) || "",
|
||
|
"code_system_name": "Medication Route FDA"
|
||
|
}/*,
|
||
|
"dose": {
|
||
|
"value": 50,
|
||
|
"unit": "mcg"
|
||
|
}*/
|
||
|
},
|
||
|
"performer": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.npi || ""
|
||
|
}],
|
||
|
"name": [{
|
||
|
"last": pd.lname,
|
||
|
"first": pd.fname
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": [pd.address],
|
||
|
"city": pd.city,
|
||
|
"state": pd.state,
|
||
|
"zip": pd.zip,
|
||
|
"country": "US"
|
||
|
}],
|
||
|
"organization": [{
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}],
|
||
|
"name": [pd.facility_name]
|
||
|
}]
|
||
|
},
|
||
|
"instructions": {
|
||
|
"code": {
|
||
|
"name": "immunization education",
|
||
|
"code": "171044003",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"free_text": "Needs Attention for more data."
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": pd.author.physician_type || '',
|
||
|
"code": pd.author.physician_type_code || '',
|
||
|
"code_system": pd.author.physician_type_system, "code_system_name": pd.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.author.time),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": pd.author.npi ? "2.16.840.1.113883.4.6" : pd.author.id,
|
||
|
"extension": pd.author.npi ? pd.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": pd.author.facility_oid || "2.16.840.1.113883.4.6",
|
||
|
"extension": pd.author.facility_npi || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.author.facility_name
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populatePayer(pd) {
|
||
|
return {
|
||
|
"identifiers": [{
|
||
|
"identifier": "1fe2cdd0-7aad-11db-9fe1-0800200c9a66"
|
||
|
}],
|
||
|
"policy": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "3e676a50-7aac-11db-9fe1-0800200c9a66"
|
||
|
}],
|
||
|
"code": {
|
||
|
"code": "SELF",
|
||
|
"code_system_name": "HL7 RoleCode"
|
||
|
},
|
||
|
"insurance": {
|
||
|
"code": {
|
||
|
"code": "PAYOR",
|
||
|
"code_system_name": "HL7 RoleCode"
|
||
|
},
|
||
|
"performer": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.19"
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": ["123 Insurance Road"],
|
||
|
"city": "Blue Bell",
|
||
|
"state": "MA",
|
||
|
"zip": "02368",
|
||
|
"country": "US",
|
||
|
"use": "work place"
|
||
|
}],
|
||
|
"phone": [{
|
||
|
"number": "(781)555-1515",
|
||
|
"type": "work place"
|
||
|
}],
|
||
|
"organization": [{
|
||
|
"name": ["Good Health Insurance"],
|
||
|
"address": [{
|
||
|
"street_lines": ["123 Insurance Road"],
|
||
|
"city": "Blue Bell",
|
||
|
"state": "MA",
|
||
|
"zip": "02368",
|
||
|
"country": "US",
|
||
|
"use": "work place"
|
||
|
}],
|
||
|
"phone": [{
|
||
|
"number": "(781)555-1515",
|
||
|
"type": "work place"
|
||
|
}]
|
||
|
}],
|
||
|
"code": [{
|
||
|
"code": "PAYOR",
|
||
|
"code_system_name": "HL7 RoleCode"
|
||
|
}]
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"guarantor": {
|
||
|
"code": {
|
||
|
"code": "GUAR",
|
||
|
"code_system_name": "HL7 Role"
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": "329fcdf0-7ab3-11db-9fe1-0800200c9a66"
|
||
|
}],
|
||
|
"name": [{
|
||
|
"prefix": "Mr.",
|
||
|
"middle": ["Frankie"],
|
||
|
"last": "Everyman",
|
||
|
"first": "Adam"
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": ["17 Daws Rd."],
|
||
|
"city": "Blue Bell",
|
||
|
"state": "MA",
|
||
|
"zip": "02368",
|
||
|
"country": "US",
|
||
|
"use": "primary home"
|
||
|
}],
|
||
|
"phone": [{
|
||
|
"number": "(781)555-1212",
|
||
|
"type": "primary home"
|
||
|
}]
|
||
|
},
|
||
|
"participant": {
|
||
|
"code": {
|
||
|
"name": "Self",
|
||
|
"code": "SELF",
|
||
|
"code_system_name": "HL7 Role"
|
||
|
},
|
||
|
"performer": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "14d4a520-7aae-11db-9fe1-0800200c9a66",
|
||
|
"extension": "1138345"
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": ["17 Daws Rd."],
|
||
|
"city": "Blue Bell",
|
||
|
"state": "MA",
|
||
|
"zip": "02368",
|
||
|
"country": "US",
|
||
|
"use": "primary home"
|
||
|
}],
|
||
|
"code": [{
|
||
|
"name": "Self",
|
||
|
"code": "SELF",
|
||
|
"code_system_name": "HL7 Role"
|
||
|
}]
|
||
|
},
|
||
|
"name": [{
|
||
|
"prefix": "Mr.",
|
||
|
"middle": ["A."],
|
||
|
"last": "Everyman",
|
||
|
"first": "Frank"
|
||
|
}]
|
||
|
},
|
||
|
"policy_holder": {
|
||
|
"performer": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "2.16.840.1.113883.19",
|
||
|
"extension": "1138345"
|
||
|
}],
|
||
|
"address": [{
|
||
|
"street_lines": ["17 Daws Rd."],
|
||
|
"city": "Blue Bell",
|
||
|
"state": "MA",
|
||
|
"zip": "02368",
|
||
|
"country": "US",
|
||
|
"use": "primary home"
|
||
|
}]
|
||
|
}
|
||
|
},
|
||
|
"authorization": {
|
||
|
"identifiers": [{
|
||
|
"identifier": "f4dce790-8328-11db-9fe1-0800200c9a66"
|
||
|
}],
|
||
|
"procedure": {
|
||
|
"code": {
|
||
|
"name": "Colonoscopy",
|
||
|
"code": "73761001",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateNote(pd) {
|
||
|
return {
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.date),
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"translations": {
|
||
|
code_system: "2.16.840.1.113883.6.1",
|
||
|
code_system_name: "LOINC",
|
||
|
code: cleanCode(pd.code),
|
||
|
name: pd.code_text || ""
|
||
|
},
|
||
|
"author": populateAuthorFromAuthorContainer(pd),
|
||
|
"note": cleanText(pd.description),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function populateParticipant(participant) {
|
||
|
return {
|
||
|
"name": {
|
||
|
"prefix": participant.prefix || "",
|
||
|
"suffix": participant.suffix || "",
|
||
|
"middle": [participant.mname] || "",
|
||
|
"last": participant.lname || "",
|
||
|
"first": participant.fname || ""
|
||
|
},
|
||
|
"typeCode": participant.type || "",
|
||
|
"classCode": "ASSIGNED",
|
||
|
"code": {
|
||
|
"name": participant.organization_taxonomy_description || "",
|
||
|
"code": cleanCode(participant.organization_taxonomy) || "",
|
||
|
"code_system": "2.16.840.1.113883.6.101",
|
||
|
"code_system_name": "NUCC Health Care Provider Taxonomy"
|
||
|
},
|
||
|
"identifiers": [{
|
||
|
"identifier": participant.organization_npi ? "2.16.840.1.113883.4.6" : participant.organization_id,
|
||
|
"extension": participant.organization_npi ? participant.organization_npi : ''
|
||
|
}],
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": participant.date_time,
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": participant.phonew1 || "",
|
||
|
"type": "WP"
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
participant.street
|
||
|
],
|
||
|
"city": participant.city,
|
||
|
"state": participant.state,
|
||
|
"zip": participant.postalCode,
|
||
|
"country": participant.country || "US",
|
||
|
"use": participant.address_use || "WP"
|
||
|
}
|
||
|
],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function populateHeader(pd) {
|
||
|
// default doc type ToC CCD
|
||
|
let name = "Summarization of Episode Note";
|
||
|
let docCode = "34133-9";
|
||
|
let docOid = "2.16.840.1.113883.10.20.22.1.2";
|
||
|
if (pd.doc_type == 'referral') {
|
||
|
name = "Referral Note";
|
||
|
docCode = "57133-1";
|
||
|
docOid = "2.16.840.1.113883.10.20.22.1.14";
|
||
|
}
|
||
|
|
||
|
const head = {
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": oidFacility,
|
||
|
"extension": "123456"
|
||
|
}
|
||
|
],
|
||
|
"code": {
|
||
|
"name": name,
|
||
|
"code": docCode,
|
||
|
"code_system_name": "LOINC"
|
||
|
},
|
||
|
"template": {
|
||
|
"root": docOid,
|
||
|
"extension": "2015-08-01"
|
||
|
},
|
||
|
"title": name,
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": fDate(pd.created_time_timezone),
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"author": {
|
||
|
"code": {
|
||
|
"name": all.author.physician_type || '',
|
||
|
"code": all.author.physician_type_code || '',
|
||
|
"code_system": all.author.physician_type_system, "code_system_name": all.author.physician_type_system_name
|
||
|
},
|
||
|
"date_time": {
|
||
|
"point": {
|
||
|
"date": authorDateTime,
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": all.author.npi ? "2.16.840.1.113883.4.6" : all.author.id,
|
||
|
"extension": all.author.npi ? all.author.npi : ''
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": all.author.lname,
|
||
|
"first": all.author.fname
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
all.author.streetAddressLine
|
||
|
],
|
||
|
"city": all.author.city,
|
||
|
"state": all.author.state,
|
||
|
"zip": all.author.postalCode,
|
||
|
"country": all.author.country || "US",
|
||
|
"use": "work place"
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": all.author.telecom || "",
|
||
|
"type": "WP"
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": oidFacility || "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
all.encounter_provider.facility_name
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
all.encounter_provider.facility_street
|
||
|
],
|
||
|
"city": all.encounter_provider.facility_city,
|
||
|
"state": all.encounter_provider.facility_state,
|
||
|
"zip": all.encounter_provider.facility_postal_code,
|
||
|
"country": all.encounter_provider.facility_country_code || "US",
|
||
|
"use": "work place"
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": all.encounter_provider.facility_phone,
|
||
|
"type": "work primary"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"custodian": {
|
||
|
"identity": [
|
||
|
{
|
||
|
"root": "2.16.840.1.113883.4.6",
|
||
|
"extension": npiFacility || ""
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.custodian.organization || pd.custodian.name
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
pd.custodian.streetAddressLine
|
||
|
],
|
||
|
"city": pd.custodian.city,
|
||
|
"state": pd.custodian.state,
|
||
|
"zip": pd.custodian.postalCode,
|
||
|
"country": pd.custodian.country || "US"
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.custodian.telecom,
|
||
|
"type": "work primary"
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"information_recipient": {
|
||
|
"name": {
|
||
|
"prefix": pd.information_recipient.prefix || "",
|
||
|
"suffix": pd.information_recipient.suffix || "",
|
||
|
"middle": [pd.information_recipient.mname] || "",
|
||
|
"last": pd.information_recipient.lname || "",
|
||
|
"first": pd.information_recipient.fname || ""
|
||
|
},
|
||
|
"organization": {
|
||
|
"name": pd.information_recipient.organization || "org"
|
||
|
},
|
||
|
}
|
||
|
};
|
||
|
let participants = [];
|
||
|
let docParticipants = pd.document_participants || {participant: []};
|
||
|
let count = 0;
|
||
|
try {
|
||
|
count = isOne(docParticipants.participant);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count === 1) {
|
||
|
participants = [populateParticipant(docParticipants.participant)];
|
||
|
} else {
|
||
|
// grab the values of our object
|
||
|
participants = Object.values(docParticipants.participant).filter(pcpt => pcpt.type).map(pcpt => populateParticipant(pcpt));
|
||
|
}
|
||
|
if (participants.length) {
|
||
|
head.participants = participants;
|
||
|
}
|
||
|
|
||
|
if (isOne(all.encounter_list.encounter) === 1) {
|
||
|
let primary_care_provider = pd.primary_care_provider || {provider: {}};
|
||
|
head.component_of = {
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": oidFacility || "",
|
||
|
"extension": "PT-" + (pd.patient.id || "")
|
||
|
}
|
||
|
],
|
||
|
"code": {
|
||
|
"name": pd.primary_diagnosis.text || "",
|
||
|
"code": pd.primary_diagnosis.code || "",
|
||
|
"code_system_name": pd.primary_diagnosis.code_type || ""
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": pd.primary_diagnosis.encounter_date || "",
|
||
|
"precision": "tz"
|
||
|
},
|
||
|
"high": {
|
||
|
"date": pd.primary_diagnosis.encounter_end_date || "",
|
||
|
"precision": "tz"
|
||
|
}
|
||
|
},
|
||
|
"responsible_party": {
|
||
|
"root": oidFacility,
|
||
|
"name": {
|
||
|
"last": pd.author.lname,
|
||
|
"first": pd.author.fname
|
||
|
},
|
||
|
},
|
||
|
"encounter_participant": {
|
||
|
"root": oidFacility,
|
||
|
"name": {
|
||
|
"last": primary_care_provider.provider.lname || "",
|
||
|
"first": primary_care_provider.provider.fname || ""
|
||
|
},
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
pd.encounter_provider.facility_street
|
||
|
],
|
||
|
"city": pd.encounter_provider.facility_city,
|
||
|
"state": pd.encounter_provider.facility_state,
|
||
|
"zip": pd.encounter_provider.facility_postal_code,
|
||
|
"country": pd.encounter_provider.facility_country_code || "US",
|
||
|
"use": "work place"
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.encounter_provider.facility_phone,
|
||
|
"type": "work primary"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return head;
|
||
|
}
|
||
|
|
||
|
function getMeta(pd) {
|
||
|
var meta = {};
|
||
|
meta = {
|
||
|
"type": pd.doc_type,
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": oidFacility || "",
|
||
|
"extension": "TT988"
|
||
|
}
|
||
|
],
|
||
|
"confidentiality": "Normal",
|
||
|
"set_id": {
|
||
|
"identifier": oidFacility || "",
|
||
|
"extension": "sTT988"
|
||
|
}
|
||
|
}
|
||
|
return meta;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
/ * function genCcda
|
||
|
/* The main document builder
|
||
|
/* pd array the xml parsed array of data sent from CCM.
|
||
|
*/
|
||
|
function genCcda(pd) {
|
||
|
let doc = {};
|
||
|
let data = {};
|
||
|
let count = 0;
|
||
|
let many = [];
|
||
|
let theone = {};
|
||
|
let primary_care_provider = all.primary_care_provider || {};
|
||
|
all = pd;
|
||
|
npiProvider = primary_care_provider.provider ? primary_care_provider.provider.npi : "";
|
||
|
oidFacility = all.encounter_provider.facility_oid ? all.encounter_provider.facility_oid : "2.16.840.1.113883.19.5.99999.1";
|
||
|
npiFacility = all.encounter_provider.facility_npi;
|
||
|
webRoot = all.serverRoot;
|
||
|
documentLocation = all.document_location;
|
||
|
|
||
|
authorDateTime = pd.created_time_timezone;
|
||
|
if (pd.author.time.length > 7) {
|
||
|
authorDateTime = pd.author.time;
|
||
|
} else if (all.encounter_list && all.encounter_list.encounter) {
|
||
|
if (isOne(all.encounter_list.encounter) === 1) {
|
||
|
authorDateTime = all.encounter_list.encounter.date;
|
||
|
} else {
|
||
|
authorDateTime = all.encounter_list.encounter[0].date;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
authorDateTime = fDate(authorDateTime);
|
||
|
// Demographics
|
||
|
let demographic = populateDemographic(pd.patient, pd.guardian, pd);
|
||
|
// This populates documentationOf. We are using providerOrganization also.
|
||
|
if (pd.primary_care_provider) {
|
||
|
Object.assign(demographic, populateProviders(pd));
|
||
|
}
|
||
|
|
||
|
data.demographics = Object.assign(demographic);
|
||
|
// Encounters
|
||
|
let encs = [];
|
||
|
let enc = {};
|
||
|
encs.encounters = [];
|
||
|
try {
|
||
|
count = isOne(pd.encounter_list.encounter);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.encounter_list.encounter) {
|
||
|
enc[i] = populateEncounter(pd.encounter_list.encounter[i]);
|
||
|
encs.encounters.push(enc[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
enc = populateEncounter(pd.encounter_list.encounter);
|
||
|
encs.encounters.push(enc);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.encounters = Object.assign(encs.encounters);
|
||
|
}
|
||
|
// vitals
|
||
|
many.vitals = [];
|
||
|
try {
|
||
|
count = isOne(pd.history_physical.vitals_list.vitals);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.vitals = Object.assign(populateVital(pd.history_physical.vitals_list.vitals));
|
||
|
}
|
||
|
// Medications
|
||
|
let meds = [];
|
||
|
let m = {};
|
||
|
meds.medications = [];
|
||
|
try {
|
||
|
count = isOne(pd.medications.medication);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.medications.medication) {
|
||
|
m[i] = populateMedication(pd.medications.medication[i]);
|
||
|
meds.medications.push(m[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
m = populateMedication(pd.medications.medication);
|
||
|
meds.medications.push(m);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.medications = Object.assign(meds.medications);
|
||
|
}
|
||
|
// Allergies
|
||
|
let allergies = [];
|
||
|
let allergy = {};
|
||
|
allergies.allergies = [];
|
||
|
try {
|
||
|
count = isOne(pd.allergies.allergy);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.allergies.allergy) {
|
||
|
allergy[i] = populateAllergy(pd.allergies.allergy[i]);
|
||
|
allergies.allergies.push(allergy[i]);
|
||
|
}
|
||
|
} else if (count <= 1) {
|
||
|
allergy = populateAllergy(pd.allergies.allergy);
|
||
|
allergies.allergies.push(allergy);
|
||
|
count = 1;
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.allergies = Object.assign(allergies.allergies);
|
||
|
}
|
||
|
// Problems
|
||
|
let problems = [];
|
||
|
let problem = {};
|
||
|
problems.problems = [];
|
||
|
try {
|
||
|
count = isOne(pd.problem_lists.problem);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.problem_lists.problem) {
|
||
|
problem[i] = populateProblem(pd.problem_lists.problem[i], pd);
|
||
|
problems.problems.push(problem[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
problem = populateProblem(pd.problem_lists.problem);
|
||
|
problems.problems.push(problem);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.problems = Object.assign(problems.problems);
|
||
|
}
|
||
|
// Procedures
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.procedures = [];
|
||
|
try {
|
||
|
count = isOne(pd.procedures.procedure);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.procedures.procedure) {
|
||
|
theone[i] = populateProcedure(pd.procedures.procedure[i]);
|
||
|
many.procedures.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = populateProcedure(pd.procedures.procedure);
|
||
|
many.procedures.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.procedures = Object.assign(many.procedures);
|
||
|
}
|
||
|
// Medical Devices
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.medical_devices = [];
|
||
|
try {
|
||
|
count = isOne(pd.medical_devices.device);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.medical_devices.device) {
|
||
|
theone[i] = populateMedicalDevice(pd.medical_devices.device[i]);
|
||
|
many.medical_devices.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = populateMedicalDevice(pd.medical_devices.device);
|
||
|
many.medical_devices.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.medical_devices = Object.assign(many.medical_devices);
|
||
|
}
|
||
|
// Results
|
||
|
if (pd.results) {
|
||
|
data.results = Object.assign(getResultSet(pd.results, pd)['results']);
|
||
|
}
|
||
|
|
||
|
// Referral TODO sjp I'm not happy with this.
|
||
|
// different referral sources. 1st is dynamic with doc gen from CCM.
|
||
|
// 2nd is the latest referral from transactions.
|
||
|
if (pd.referral_reason[0].text !== "") {
|
||
|
data.referral_reason = Object.assign(getReferralReason(pd.referral_reason[0], pd));
|
||
|
} else if (pd.referral_reason[1].text !== "" && typeof pd.referral_reason[1].text !== 'undefined') {
|
||
|
data.referral_reason = Object.assign(getReferralReason(pd.referral_reason[1], pd));
|
||
|
} else {
|
||
|
data.referral_reason = {}; // leave as empty so we can get our null flavor section.
|
||
|
}
|
||
|
// Health Concerns
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.health_concerns = [];
|
||
|
try {
|
||
|
count = isOne(pd.health_concerns.concern);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.health_concerns.concern) {
|
||
|
theone[i] = getHealthConcerns(pd.health_concerns.concern[i]);
|
||
|
many.health_concerns.push(theone[i]);
|
||
|
break;
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = getHealthConcerns(pd.health_concerns.concern);
|
||
|
many.health_concerns.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.health_concerns = Object.assign(many.health_concerns);
|
||
|
} else {
|
||
|
data.health_concerns = {"type": "act"}; // leave it as an empty section that we'll null flavor
|
||
|
}
|
||
|
// Immunizations
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.immunizations = [];
|
||
|
try {
|
||
|
count = isOne(pd.immunizations.immunization);
|
||
|
} catch (e) {
|
||
|
count = 0;
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.immunizations.immunization) {
|
||
|
theone[i] = populateImmunization(pd.immunizations.immunization[i]);
|
||
|
many.immunizations.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = populateImmunization(pd.immunizations.immunization);
|
||
|
many.immunizations.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.immunizations = Object.assign(many.immunizations);
|
||
|
}
|
||
|
// Plan of Care
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.plan_of_care = [];
|
||
|
try {
|
||
|
count = isOne(pd.planofcare.item);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.planofcare.item) {
|
||
|
if (cleanCode(pd.planofcare.item[i].date) === '') {
|
||
|
i--;
|
||
|
continue;
|
||
|
}
|
||
|
theone[i] = getPlanOfCare(pd.planofcare.item[i]);
|
||
|
if (theone[i]) {
|
||
|
many.plan_of_care.push(theone[i]);
|
||
|
}
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = getPlanOfCare(pd.planofcare.item);
|
||
|
if (theone) {
|
||
|
many.plan_of_care.push(theone);
|
||
|
}
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.plan_of_care = Object.assign(many.plan_of_care);
|
||
|
}
|
||
|
// Goals
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.goals = [];
|
||
|
try {
|
||
|
count = isOne(pd.goals.item);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.goals.item) {
|
||
|
theone[i] = getGoals(pd.goals.item[i]);
|
||
|
many.goals.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = getGoals(pd.goals.item);
|
||
|
many.goals.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.goals = Object.assign(many.goals);
|
||
|
}
|
||
|
// Assessments.
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.clinicalNoteAssessments = [];
|
||
|
try {
|
||
|
count = isOne(pd.clinical_notes.evaluation_note);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.clinical_notes.evaluation_note) {
|
||
|
theone[i] = getAssessments(pd.clinical_notes.evaluation_note[i]);
|
||
|
many.clinicalNoteAssessments.push(theone[i]);
|
||
|
break; // for now only one assessment. @todo concat notes to one.
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = getAssessments(pd.clinical_notes.evaluation_note);
|
||
|
many.clinicalNoteAssessments.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.clinicalNoteAssessments = Object.assign(many.clinicalNoteAssessments);
|
||
|
}
|
||
|
|
||
|
// Functional Status.
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.functional_status = [];
|
||
|
try {
|
||
|
count = isOne(pd.functional_status.item);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.functional_status.item) {
|
||
|
theone[i] = getFunctionalStatus(pd.functional_status.item[i]);
|
||
|
many.functional_status.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = getFunctionalStatus(pd.functional_status.item);
|
||
|
many.functional_status.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.functional_status = Object.assign(many.functional_status);
|
||
|
}
|
||
|
|
||
|
// Mental Status.
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.mental_status = [];
|
||
|
try {
|
||
|
count = isOne(pd.mental_status.item);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.mental_status.item) {
|
||
|
theone[i] = getMentalStatus(pd.mental_status.item[i]);
|
||
|
many.mental_status.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = getMentalStatus(pd.mental_status.item);
|
||
|
many.mental_status.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.mental_status = Object.assign(many.mental_status);
|
||
|
}
|
||
|
|
||
|
// Social History
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
many.social_history = [];
|
||
|
try {
|
||
|
count = isOne(pd.history_physical.social_history.history_element);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.history_physical.social_history.history_element) {
|
||
|
if (i > 0) break;
|
||
|
theone[i] = populateSocialHistory(pd.history_physical.social_history.history_element[i]);
|
||
|
many.social_history.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = populateSocialHistory(pd.history_physical.social_history.history_element);
|
||
|
many.social_history.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data.social_history = Object.assign(many.social_history);
|
||
|
}
|
||
|
// Notes
|
||
|
for (let currentNote in pd.clinical_notes) {
|
||
|
many = [];
|
||
|
theone = {};
|
||
|
switch (pd.clinical_notes[currentNote].clinical_notes_type) {
|
||
|
case 'evaluation_note':
|
||
|
continue;
|
||
|
break;
|
||
|
case 'progress_note':
|
||
|
|
||
|
break;
|
||
|
case 'history_physical':
|
||
|
pd.clinical_notes[currentNote].code_text = "History and Physical";
|
||
|
break;
|
||
|
case 'nurse_note':
|
||
|
break;
|
||
|
case 'general_note':
|
||
|
break;
|
||
|
case 'discharge_summary':
|
||
|
break;
|
||
|
case 'procedure_note':
|
||
|
break;
|
||
|
case 'consultation_note':
|
||
|
break;
|
||
|
case 'imaging_narrative':
|
||
|
break;
|
||
|
case 'laboratory_report_narrative':
|
||
|
break;
|
||
|
case 'pathology_report_narrative':
|
||
|
break;
|
||
|
default:
|
||
|
continue;
|
||
|
}
|
||
|
try {
|
||
|
count = isOne(pd.clinical_notes[currentNote]);
|
||
|
} catch (e) {
|
||
|
count = 0
|
||
|
}
|
||
|
if (count > 1) {
|
||
|
for (let i in pd.clinical_notes[currentNote]) {
|
||
|
theone[i] = populateNote(pd.clinical_notes[currentNote]);
|
||
|
many.push(theone[i]);
|
||
|
}
|
||
|
} else if (count !== 0) {
|
||
|
theone = populateNote(pd.clinical_notes[currentNote]);
|
||
|
many.push(theone);
|
||
|
}
|
||
|
if (count !== 0) {
|
||
|
data[currentNote] = Object.assign(many);
|
||
|
}
|
||
|
}
|
||
|
// Care Team and members
|
||
|
if (pd.care_team.is_active == 'active') {
|
||
|
data.care_team = Object.assign(populateCareTeamMembers(pd));
|
||
|
}
|
||
|
// ------------------------------------------ End Sections ----------------------------------------//
|
||
|
|
||
|
doc.data = Object.assign(data);
|
||
|
let meta = getMeta(pd);
|
||
|
let header = populateHeader(pd);
|
||
|
|
||
|
meta.ccda_header = Object.assign(header);
|
||
|
doc.meta = Object.assign(meta);
|
||
|
|
||
|
if (pd.timezone_local_offset) {
|
||
|
populateTimezones(doc, pd.timezone_local_offset, 0);
|
||
|
}
|
||
|
// build to cda
|
||
|
let xml = bbg.generateCCD(doc);
|
||
|
|
||
|
/* Debug */
|
||
|
if (enableDebug === true) {
|
||
|
let place = documentLocation + "/documents/temp/";
|
||
|
if (fs.existsSync(place)) {
|
||
|
fs.writeFile(place + "ccda.json", JSON.stringify(all, null, 4), function (err) {
|
||
|
if (err) {
|
||
|
return console.log(err);
|
||
|
}
|
||
|
//console.log("Json saved!");
|
||
|
});
|
||
|
|
||
|
fs.writeFile(place + "ccda.xml", xml, function (err) {
|
||
|
if (err) {
|
||
|
return console.log(err);
|
||
|
}
|
||
|
//console.log("Xml saved!");
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return xml;
|
||
|
}
|
||
|
|
||
|
function processConnection(connection) {
|
||
|
conn = connection; // make it global
|
||
|
let remoteAddress = conn.remoteAddress + ':' + conn.remotePort;
|
||
|
conn.setEncoding('utf8');
|
||
|
|
||
|
let xml_complete = "";
|
||
|
|
||
|
function eventData(xml) {
|
||
|
xml_complete = xml.toString();
|
||
|
//console.log("length: " + xml.length + " " + xml_complete);
|
||
|
// ensure we have an array start and end
|
||
|
if (xml_complete.match(/^<CCDA/g) && xml_complete.match(/<\/CCDA>$/g)) {
|
||
|
let doc = "";
|
||
|
let xslUrl = "";
|
||
|
xml_complete = xml_complete.replace(/(\u000b|\u001c)/gm, "").trim();
|
||
|
// let's not allow windows CR/LF
|
||
|
xml_complete = xml_complete.replace(/[\r\n]/gm, '').trim();
|
||
|
xml_complete = xml_complete.replace(/\t\s+/g, ' ').trim();
|
||
|
// convert xml data set for document to json array
|
||
|
to_json(xml_complete, function (error, data) {
|
||
|
//console.log(JSON.stringify(data, null, 4));
|
||
|
if (error) { // need try catch
|
||
|
console.log('toJson error: ' + error + 'Len: ' + xml_complete.length);
|
||
|
return;
|
||
|
}
|
||
|
// create document
|
||
|
doc = genCcda(data.CCDA);
|
||
|
if (data.CCDA.xslUrl) {
|
||
|
xslUrl = data.CCDA.xslUrl || "";
|
||
|
}
|
||
|
});
|
||
|
|
||
|
doc = headReplace(doc, xslUrl);
|
||
|
doc = doc.toString().replace(/(\u000b|\u001c|\r)/gm, "").trim();
|
||
|
let chunk = "";
|
||
|
let numChunks = Math.ceil(doc.length / 1024);
|
||
|
for (let i = 0, o = 0; i < numChunks; ++i, o += 1024) {
|
||
|
chunk = doc.substring(o, o + 1024);
|
||
|
conn.write(chunk);
|
||
|
}
|
||
|
conn.write(String.fromCharCode(28) + "\r\r" + '');
|
||
|
conn.end();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function eventCloseConn() {
|
||
|
//console.log('connection from %s closed', remoteAddress);
|
||
|
}
|
||
|
|
||
|
function eventErrorConn(err) {
|
||
|
console.log('Connection %s error: %s', remoteAddress, err.message);
|
||
|
}
|
||
|
|
||
|
// Connection Events //
|
||
|
// CCM will send two File Separator characters to mark end of array.
|
||
|
let received = new DataStack(String.fromCharCode(28));
|
||
|
conn.on("data", data => {
|
||
|
received.pushToStack(data);
|
||
|
while (!received.endOfCcda() && data.length > 0) {
|
||
|
data = "";
|
||
|
eventData(received.returnData())
|
||
|
}
|
||
|
});
|
||
|
|
||
|
conn.once('close', eventCloseConn);
|
||
|
conn.on('error', eventErrorConn);
|
||
|
}
|
||
|
|
||
|
function setUp(server) {
|
||
|
server.on('connection', processConnection);
|
||
|
server.listen(6661, 'localhost', function () { // never change port!
|
||
|
//console.log('server listening to %j', server.address());
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// start up listener for requests from CCM or others.
|
||
|
setUp(server);
|
||
|
|
||
|
/* ---------------------------------For future use in header. Do not remove!-------------------------------------------- */
|
||
|
/*"data_enterer": {
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": "999999943252"
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.data_enterer.lname,
|
||
|
"first": pd.data_enterer.fname
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
pd.data_enterer.streetAddressLine
|
||
|
],
|
||
|
"city": pd.data_enterer.city,
|
||
|
"state": pd.data_enterer.state,
|
||
|
"zip": pd.data_enterer.postalCode,
|
||
|
"country": pd.data_enterer.country
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.data_enterer.telecom,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
"informant": {
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": "2.16.840.1.113883.19.5",
|
||
|
"extension": "KP00017"
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.informer.lname || "",
|
||
|
"first": pd.informer.fname || ""
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
pd.informer.streetAddressLine || ""
|
||
|
],
|
||
|
"city": pd.informer.city,
|
||
|
"state": pd.informer.state,
|
||
|
"zip": pd.informer.postalCode,
|
||
|
"country": pd.informer.country
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.informer.telecom || "",
|
||
|
"type": "work place"
|
||
|
}
|
||
|
]
|
||
|
},*/
|
||
|
/*"service_event": {
|
||
|
"code": {
|
||
|
"name": "",
|
||
|
"code": "",
|
||
|
"code_system_name": "SNOMED CT"
|
||
|
},
|
||
|
"date_time": {
|
||
|
"low": {
|
||
|
"date": "2021-03-11",
|
||
|
"precision": "day"
|
||
|
},
|
||
|
"high": {
|
||
|
"date": pd.created_time,
|
||
|
"precision": "day"
|
||
|
}
|
||
|
},
|
||
|
"performer": [
|
||
|
{
|
||
|
"performer": [
|
||
|
{
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": "2.16.840.1.113883.4.6",
|
||
|
"extension": npiProvider
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
{
|
||
|
"last": pd.information_recipient.lname || "DAH",
|
||
|
"first": pd.information_recipient.fname || "DAH"
|
||
|
}
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
pd.information_recipient.streetAddressLine
|
||
|
],
|
||
|
"city": pd.information_recipient.city,
|
||
|
"state": pd.information_recipient.state,
|
||
|
"zip": pd.information_recipient.postalCode,
|
||
|
"country": pd.information_recipient.country || "US"
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.information_recipient.telecom,
|
||
|
"type": "work place"
|
||
|
}
|
||
|
],
|
||
|
"organization": [
|
||
|
{
|
||
|
"identifiers": [
|
||
|
{
|
||
|
"identifier": "2.16.840.1.113883.19.5.9999.1393"
|
||
|
}
|
||
|
],
|
||
|
"name": [
|
||
|
pd.encounter_provider.facility_name
|
||
|
],
|
||
|
"address": [
|
||
|
{
|
||
|
"street_lines": [
|
||
|
pd.encounter_provider.facility_street
|
||
|
],
|
||
|
"city": pd.encounter_provider.facility_city,
|
||
|
"state": pd.encounter_provider.facility_state,
|
||
|
"zip": pd.encounter_provider.facility_postal_code,
|
||
|
"country": pd.encounter_provider.facility_country_code || "US"
|
||
|
}
|
||
|
],
|
||
|
"phone": [
|
||
|
{
|
||
|
"number": pd.encounter_provider.facility_phone,
|
||
|
"type": "primary work"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"code": [
|
||
|
{
|
||
|
"name": "",
|
||
|
"code": "",
|
||
|
"code_system_name": "Provider Codes"
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"code": {
|
||
|
"name": "Primary Performer",
|
||
|
"code": "PP",
|
||
|
"code_system_name": "Provider Role"
|
||
|
}
|
||
|
}
|
||
|
]
|
||
|
}*/
|