diff --git a/src/App.jsx b/src/App.jsx index fb92f96e..add66b8c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -273,7 +273,7 @@ export default class App extends Component { }); } }); - console.log(fullBundle); + console.log(allLibrariesResults); this.setState({ bundle: fullBundle, cqlPrepopulationResults: allLibrariesResults, @@ -619,8 +619,7 @@ export default class App extends Component { render() { if ( (this.state.questionnaire && - this.state.cqlPrepopulationResults && - this.state.bundle) + this.state.cqlPrepopulationResults) || (this.state.questionnaire && this.state.response && diff --git a/src/components/QuestionnaireForm/QuestionnaireForm.jsx b/src/components/QuestionnaireForm/QuestionnaireForm.jsx index f08db2b6..42d209bf 100644 --- a/src/components/QuestionnaireForm/QuestionnaireForm.jsx +++ b/src/components/QuestionnaireForm/QuestionnaireForm.jsx @@ -668,9 +668,9 @@ export default class QuestionnaireForm extends Component { system = "RxNorm" } - if (system.length > 0) { - displayText = displayText + ' - ' + system + ' - ' + v.code - } + // if (system.length > 0) { + // displayText = displayText + ' - ' + system + ' - ' + v.code + // } } return { @@ -1098,272 +1098,274 @@ export default class QuestionnaireForm extends Component { } }; - const priorAuthBundle = JSON.parse(JSON.stringify(this.props.bundle)); - if (priorAuthBundle && this.isPriorAuthBundleValid(priorAuthBundle)) { - priorAuthBundle.entry.unshift({ resource: managingOrg }); - priorAuthBundle.entry.unshift({ resource: facility }); - priorAuthBundle.entry.unshift({ resource: this.props.deviceRequest }); - priorAuthBundle.entry.unshift({ resource: qr }); - - this.generateAndStoreDocumentReference(qr, priorAuthBundle); - this.storeQuestionnaireResponseToEhr(qr, false); - - const priorAuthClaim = { - resourceType: "Claim", - status: "active", - type: { - coding: [ - { - system: "http://terminology.hl7.org/CodeSystem/claim-type", - code: "professional", - display: "Professional" - } - ] - }, - identifier: [ - { - system: "urn:uuid:mitre-drls", - value: shortid.generate() - } - ], - use: "preauthorization", - patient: { reference: this.makeReference(priorAuthBundle, "Patient") }, - created: qr.authored, - provider: { - // TODO: make this organization - reference: this.makeReference(priorAuthBundle, "Practitioner") - }, - facility: { - reference: this.makeReference(priorAuthBundle, "Location") - }, - priority: { coding: [{ code: "normal" }] }, - careTeam: [ - { - sequence: 1, - provider: { - reference: this.makeReference(priorAuthBundle, "Practitioner") - }, - extension: [ + if(this.props.bundle){ + const priorAuthBundle = JSON.parse(JSON.stringify(this.props.bundle)); + if (priorAuthBundle && this.isPriorAuthBundleValid(priorAuthBundle)) { + priorAuthBundle.entry.unshift({ resource: managingOrg }); + priorAuthBundle.entry.unshift({ resource: facility }); + priorAuthBundle.entry.unshift({ resource: this.props.deviceRequest }); + priorAuthBundle.entry.unshift({ resource: qr }); + + this.generateAndStoreDocumentReference(qr, priorAuthBundle); + this.storeQuestionnaireResponseToEhr(qr, false); + + const priorAuthClaim = { + resourceType: "Claim", + status: "active", + type: { + coding: [ { - url: "http://terminology.hl7.org/ValueSet/v2-0912", - valueCode: "OP" + system: "http://terminology.hl7.org/CodeSystem/claim-type", + code: "professional", + display: "Professional" } ] - } - ], - supportingInfo: [ - { - sequence: 1, - category: { - coding: [ - { - system: - "http://hl7.org/us/davinci-pas/CodeSystem/PASSupportingInfoType", - code: "patientEvent" - } - ] - }, - timingPeriod: { - start: "2020-01-01", - end: "2021-01-01" + }, + identifier: [ + { + system: "urn:uuid:mitre-drls", + value: shortid.generate() } + ], + use: "preauthorization", + patient: { reference: this.makeReference(priorAuthBundle, "Patient") }, + created: qr.authored, + provider: { + // TODO: make this organization + reference: this.makeReference(priorAuthBundle, "Practitioner") }, - { - sequence: 2, - category: { - coding: [ + facility: { + reference: this.makeReference(priorAuthBundle, "Location") + }, + priority: { coding: [{ code: "normal" }] }, + careTeam: [ + { + sequence: 1, + provider: { + reference: this.makeReference(priorAuthBundle, "Practitioner") + }, + extension: [ { - system: - "http://terminology.hl7.org/CodeSystem/claiminformationcategory", - code: "info", - display: "Information" + url: "http://terminology.hl7.org/ValueSet/v2-0912", + valueCode: "OP" } ] - }, - valueReference: { - reference: this.makeReference( - priorAuthBundle, - "QuestionnaireResponse" - ) - } - } - ], - item: [ - { - sequence: 1, - careTeamSequence: [1], - productOrService: this.getCode(), - quantity: { - value: 1 - } - // TODO: add extensions - } - ], - diagnosis: [], - insurance: [ - { - sequence: 1, - focal: true, - coverage: { - // TODO: diagnosis is not a reference it must be CodeableConcept - reference: this.makeReference(priorAuthBundle, "Coverage") } - } - ] - }; - - const signature = { - resourceType: "Signature", - type: [ - { - system: "urn:iso-astm:E1762-95:2013", - code: "1.2.840.10065.1.12.1.14", - display: "Source Signature" - } - ], - when: new Date(Date.now()).toISOString(), - who: this.makeReference(priorAuthBundle, "Practitioner") - } - var sequence = 1; - priorAuthBundle.entry.forEach(function (entry, index) { - if (entry.resource.resourceType == "Condition") { - priorAuthClaim.diagnosis.push({ - sequence: sequence++, - diagnosisReference: { reference: "Condition/" + entry.resource.id } - }); - } - }); - priorAuthBundle.timestamp = new Date(Date.now()).toISOString() - priorAuthBundle.language = "en"; - priorAuthBundle.id = shortid.generate(); - priorAuthBundle.meta = { - lastUpdated: Date.now() - } - priorAuthBundle.implicitRules = "http://build.fhir.org/ig/HL7/davinci-pas/StructureDefinition-profile-pas-request-bundle" - priorAuthBundle.identifier = { - use: "official", - system: "urn:uuid:mitre-drls", - value: shortid.generate() - } - priorAuthBundle.signature = signature; - priorAuthBundle.entry.unshift({ resource: priorAuthClaim }); - - const specialtyRxBundle = JSON.parse(JSON.stringify(priorAuthBundle)); - specialtyRxBundle.type = "message"; - if (this.makeReference(priorAuthBundle, "MedicationRequest")) { - const pharmacy = { - resourceType: "Organization", - id: "pharm0111", - identifier: [ + ], + supportingInfo: [ { - system: "http://hl7.org/fhir/sid/us-npi", - value: "1837247346" + sequence: 1, + category: { + coding: [ + { + system: + "http://hl7.org/us/davinci-pas/CodeSystem/PASSupportingInfoType", + code: "patientEvent" + } + ] + }, + timingPeriod: { + start: "2020-01-01", + end: "2021-01-01" + } }, { - system: "http://terminology.hl7.org/CodeSystem/NCPDPProviderIdentificationNumber", - value: "838283882" + sequence: 2, + category: { + coding: [ + { + system: + "http://terminology.hl7.org/CodeSystem/claiminformationcategory", + code: "info", + display: "Information" + } + ] + }, + valueReference: { + reference: this.makeReference( + priorAuthBundle, + "QuestionnaireResponse" + ) + } } ], - telecom: [ + item: [ { - system : "phone", - value : "919-234-5174", - use : "work", - rank : "1", + sequence: 1, + careTeamSequence: [1], + productOrService: this.getCode(), + quantity: { + value: 1 + } + // TODO: add extensions } ], - address: [ + diagnosis: [], + insurance: [ { - use: "work", - state: "IL", - postalCode: "62864", - city: "Mount Vernon", - line: ["1500 Main St"] + sequence: 1, + focal: true, + coverage: { + // TODO: diagnosis is not a reference it must be CodeableConcept + reference: this.makeReference(priorAuthBundle, "Coverage") + } } ] - } + }; - const specialtyRxSearchResult = { - resourceType: "Bundle", - type: "searchset", - id: "bundle02", - total: 0, - link: [ + const signature = { + resourceType: "Signature", + type: [ { - relation: "self", - url: "", + system: "urn:iso-astm:E1762-95:2013", + code: "1.2.840.10065.1.12.1.14", + display: "Source Signature" } ], - entry: [] + when: new Date(Date.now()).toISOString(), + who: this.makeReference(priorAuthBundle, "Practitioner") } - - const specialtyRxParameters = { - resourceType: "Parameters", - id: "param0111", - parameter: [ - { - name: "source-patient", - reference: this.makeReference(priorAuthBundle, "Patient") - }, - { - name: "prescription", - reference: this.makeReference(priorAuthBundle, "MedicationRequest") - }, - { - name: "pharmacy", - reference: "Organization/pharm0111" - }, - { - name: "prescriber", - reference: this.makeReference(priorAuthBundle, "Practitioner") - }, - { - name: "search-result", - reference: "Bundle/bundle02" - }, - - ] + var sequence = 1; + priorAuthBundle.entry.forEach(function (entry, index) { + if (entry.resource.resourceType == "Condition") { + priorAuthClaim.diagnosis.push({ + sequence: sequence++, + diagnosisReference: { reference: "Condition/" + entry.resource.id } + }); + } + }); + priorAuthBundle.timestamp = new Date(Date.now()).toISOString() + priorAuthBundle.language = "en"; + priorAuthBundle.id = shortid.generate(); + priorAuthBundle.meta = { + lastUpdated: Date.now() } - - const specialtyRxMessageHeader = { - resourceType: "MessageHeader", - id: "msghdr0111", - event: [ - { - eventCoding: { - system: "http://hl7.org/fhir/us/specialty-rx/CodeSystem/specialty-rx-event-type", - code: "query-response-unsolicited", + priorAuthBundle.implicitRules = "http://build.fhir.org/ig/HL7/davinci-pas/StructureDefinition-profile-pas-request-bundle" + priorAuthBundle.identifier = { + use: "official", + system: "urn:uuid:mitre-drls", + value: shortid.generate() + } + priorAuthBundle.signature = signature; + priorAuthBundle.entry.unshift({ resource: priorAuthClaim }); + + const specialtyRxBundle = JSON.parse(JSON.stringify(priorAuthBundle)); + specialtyRxBundle.type = "message"; + if (this.makeReference(priorAuthBundle, "MedicationRequest")) { + const pharmacy = { + resourceType: "Organization", + id: "pharm0111", + identifier: [ + { + system: "http://hl7.org/fhir/sid/us-npi", + value: "1837247346" + }, + { + system: "http://terminology.hl7.org/CodeSystem/NCPDPProviderIdentificationNumber", + value: "838283882" } - } - ], - focus: { - parameters: { - reference: "Parameters/param0111" - } - }, - source: { - // TODO: url should be dynamically created - // also if DTR expects to recieve a response it - // will need an endpoint to recieve it at - endpoint: "http://localhost:3005" + ], + telecom: [ + { + system : "phone", + value : "919-234-5174", + use : "work", + rank : "1", + } + ], + address: [ + { + use: "work", + state: "IL", + postalCode: "62864", + city: "Mount Vernon", + line: ["1500 Main St"] + } + ] } - - } - - specialtyRxBundle.entry.unshift({ resource: specialtyRxSearchResult }); - specialtyRxBundle.entry.unshift({ resource: pharmacy }); - specialtyRxBundle.entry.unshift({ resource: specialtyRxParameters }); - specialtyRxBundle.entry.unshift({ resource: specialtyRxMessageHeader }); - } + const specialtyRxSearchResult = { + resourceType: "Bundle", + type: "searchset", + id: "bundle02", + total: 0, + link: [ + { + relation: "self", + url: "", + } + ], + entry: [] + } - console.log("specialtyRx", specialtyRxBundle); + const specialtyRxParameters = { + resourceType: "Parameters", + id: "param0111", + parameter: [ + { + name: "source-patient", + reference: this.makeReference(priorAuthBundle, "Patient") + }, + { + name: "prescription", + reference: this.makeReference(priorAuthBundle, "MedicationRequest") + }, + { + name: "pharmacy", + reference: "Organization/pharm0111" + }, + { + name: "prescriber", + reference: this.makeReference(priorAuthBundle, "Practitioner") + }, + { + name: "search-result", + reference: "Bundle/bundle02" + }, + + ] + } + + const specialtyRxMessageHeader = { + resourceType: "MessageHeader", + id: "msghdr0111", + event: [ + { + eventCoding: { + system: "http://hl7.org/fhir/us/specialty-rx/CodeSystem/specialty-rx-event-type", + code: "query-response-unsolicited", + } + } + ], + focus: { + parameters: { + reference: "Parameters/param0111" + } + }, + source: { + // TODO: url should be dynamically created + // also if DTR expects to recieve a response it + // will need an endpoint to recieve it at + endpoint: "http://localhost:3005" + } + + } + + specialtyRxBundle.entry.unshift({ resource: specialtyRxSearchResult }); + specialtyRxBundle.entry.unshift({ resource: pharmacy }); + specialtyRxBundle.entry.unshift({ resource: specialtyRxParameters }); + specialtyRxBundle.entry.unshift({ resource: specialtyRxMessageHeader }); + } - this.props.setPriorAuthClaim(priorAuthBundle); - this.props.setSpecialtyRxBundle(specialtyRxBundle); - } else { - alert("Prior Auth Bundle is not available or does not contain enough resources for Prior Auth. Can't submit to prior auth.") + console.log("specialtyRx", specialtyRxBundle); + + + this.props.setPriorAuthClaim(priorAuthBundle); + this.props.setSpecialtyRxBundle(specialtyRxBundle); + } else { + alert("Prior Auth Bundle is not available or does not contain enough resources for Prior Auth. Can't submit to prior auth.") + } } } diff --git a/src/components/RemsInterface/RemsInterface.jsx b/src/components/RemsInterface/RemsInterface.jsx index 7a58f75a..4f2129b0 100644 --- a/src/components/RemsInterface/RemsInterface.jsx +++ b/src/components/RemsInterface/RemsInterface.jsx @@ -57,38 +57,71 @@ export default class RemsInterface extends Component { return (
-
{metReq.requirement.name}
+
{metReq.requirementName}
{metReq.completed ? "✅" : "❌"}
-
{metReq.requirement.description}
+
{metReq.requirementDescription}
- { - metReq.childMetRequirements.map(subMetReq => -
-
{subMetReq.requirement.name}
-
{subMetReq.completed ? "✅" : "❌"}
-
{subMetReq.requirement.description}
-
- ) - }
) }); } + getResource(bundle, resourceReference) { + let temp = resourceReference.split("/"); + let _resourceType = temp[0]; + let _id = temp[1]; + + for (let i = 0; i < bundle.entry.length; i++) { + if ((bundle.entry[i].resource.resourceType === _resourceType) + && (bundle.entry[i].resource.id === _id)) { + return bundle.entry[i].resource; + } + } + return null; + } + async sendRemsMessage() { - const remsAdminResponse = await axios.post("http://localhost:8090/rems", this.props.specialtyRxBundle, this.getAxiosOptions()); + const remsAdminResponse = await axios.post("http://localhost:8090/etasu/met", this.props.specialtyRxBundle, this.getAxiosOptions()); + console.log(remsAdminResponse) this.setState({ remsAdminResponse }); - console.log(remsAdminResponse) - - // Will not send post request to PIS if only for prescriber enrollment + + // Will not send post request to PIS if only for patient enrollment if(this.state.remsAdminResponse?.data?.case_number){ - axios.post("http://localhost:3010/api/doctorOrder/$process-message", remsAdminResponse.data, this.getAxiosOptions()).then((response) => { + + // extract params and questionnaire response identifier + let params = this.getResource(this.props.specialtyRxBundle, this.props.specialtyRxBundle.entry[0].resource.focus.parameters.reference); + + // stakeholder and medication references + let prescriptionReference = ""; + let patientReference = ""; + for (let param of params.parameter) { + if (param.name === "prescription") { + prescriptionReference = param.reference; + } + else if (param.name === "source-patient") { + patientReference = param.reference; + } + } + + // obtain drug information from database + let presciption = this.getResource(this.props.specialtyRxBundle, prescriptionReference); + let prescriptionDisplay = presciption.medicationCodeableConcept.coding[0].display.split(" ")[0]; + let patient = this.getResource(this.props.specialtyRxBundle, patientReference); + let patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; + + // console.log(`http://localhost:5051/api/getRx/paitent/${patientName}/drug/${prescriptionDisplay}`); + + axios.get(`http://localhost:5051/doctorOrders/api/getRx/patient/${patientName}/drug/${prescriptionDisplay}`, remsAdminResponse.data, this.getAxiosOptions()).then((response) => { this.setState({ response }); console.log(response); console.log(response.data); }); } + + // const remsAdminResponse = await axios.post("http://localhost:8090/etasu/met", this.props.specialtyRxBundle, this.getAxiosOptions()); + // this.setState({ remsAdminResponse }); + // console.log(remsAdminResponse) } toggleBundle() { @@ -124,14 +157,36 @@ export default class RemsInterface extends Component { refreshPisBundle() { this.setState({ spinPis: true }); - axios.get(`http://localhost:3010/api/doctorOrder/${this.state.response.data.doctorOrder._id}`).then((response) => { + + let params = this.getResource(this.props.specialtyRxBundle, this.props.specialtyRxBundle.entry[0].resource.focus.parameters.reference); + + // stakeholder and medication references + let prescriptionReference = ""; + let patientReference = ""; + for (let param of params.parameter) { + if (param.name === "prescription") { + prescriptionReference = param.reference; + } + else if (param.name === "source-patient") { + patientReference = param.reference; + } + } + + // obtain drug information from database + let presciption = this.getResource(this.props.specialtyRxBundle, prescriptionReference); + let prescriptionDisplay = presciption.medicationCodeableConcept.coding[0].display.split(" ")[0]; + let patient = this.getResource(this.props.specialtyRxBundle, patientReference); + let patientName = patient.name[0].given[0] + ' ' + patient.name[0].family; + + axios.get(`http://localhost:5051/doctorOrders/api/getRx/patient/${patientName}/drug/${prescriptionDisplay}`) + .then((response) => { this.setState({ response: response }); }) } refreshBundle() { this.setState({ spin: true }); - axios.get(`http://localhost:8090/rems/${this.state.remsAdminResponse.data.case_number}`).then((response) => { + axios.get(`http://localhost:8090/etasu/met/${this.state.remsAdminResponse.data.case_number}`).then((response) => { this.setState({ remsAdminResponse: response }); }) } @@ -146,7 +201,7 @@ export default class RemsInterface extends Component { } let colorPis = "#f7f7f7" - const statusPis = this.state.response?.data?.doctorOrder?.dispenseStatus; + const statusPis = this.state.response?.data?.dispenseStatus; if (statusPis === "Approved") { colorPis = "#5cb85c" @@ -157,116 +212,127 @@ export default class RemsInterface extends Component { } // Checking if REMS Request (pt enrollment) || Met Requirments (prescriber Form) + let hasRemsResponse = this.state.remsAdminResponse?.data ? true : false let hasRemsCase = this.state.remsAdminResponse?.data?.case_number ? true : false; return (
- {hasRemsCase ? + { + hasRemsResponse ?
-
-

REMS Admin Status

- -
-
- Case Number : {this.state.remsAdminResponse?.data?.case_number || "N/A"} -
-
- Status: {this.state.remsAdminResponse?.data?.status} -
-
- - - - {this.state.remsAdminResponse?.data?.case_number ? - this.setState({ spin: false })} - /> - : "" - } - -
- -
- {this.state.viewResponse ? -
+ {hasRemsCase ? +
+
+

REMS Admin Status

+ +
+
+ Case Number : {this.state.remsAdminResponse?.data?.case_number || "N/A"} +
+
+ Status: {this.state.remsAdminResponse?.data?.status} +
+
+ + + + {this.state.remsAdminResponse?.data?.case_number ? + this.setState({ spin: false })} + /> + : "" + } + +
+ +
+ {this.state.viewResponse ? +
+

+

ETASU

+ {this.unfurlJson(this.state.remsAdminResponse?.data, 0)} +
+ : + ""} + {this.state.viewBundle ?


-

ETASU

- {this.unfurlJson(this.state.remsAdminResponse?.data, 0)} -
- : - ""} - {this.state.viewBundle ?
-

-

Bundle

- {this.renderBundle(this.props.specialtyRxBundle)} -
: ""} - +

Bundle

+ {this.renderBundle(this.props.specialtyRxBundle)} +
: ""} + +
+ +
+

Pharmacy Status

+ +
+
+ ID : {this.state.response?.data?._id || "N/A"} +
+
+ Status: {this.state.response?.data?.dispenseStatus} +
+
+ {/* */} + {this.state.response?.data?._id ? + this.setState({ spinPis: false })} + /> + : "" + } +
+ +
+ {this.state.viewPisBundle ?
+

+

Bundle

+ {this.renderBundle(this.props.specialtyRxBundle)} +
: ""} +
- -
-

Pharmacy Status

- -
-
- ID : {this.state.response?.data?.doctorOrder?._id || "N/A"} -
-
- Status: {this.state.response?.data?.doctorOrder?.dispenseStatus} -
-
- - {this.state.response?.data?.doctorOrder?._id ? - this.setState({ spinPis: false })} - /> - : "" - } -
- -
- {this.state.viewPisBundle ?
-

-

Bundle

- {this.renderBundle(this.props.specialtyRxBundle)} -
: ""} + : +
+
+

Prescriber Document Status

+ +
+
+ Status: Documents successfully submitted +
+
+ + + {this.state.remsAdminResponse?.data?.case_number ? + this.setState({ spin: false })} + /> + : "" + } +
+ +
+ {this.state.viewBundle ?
+

+

Bundle

+ {this.renderBundle(this.props.specialtyRxBundle)} +
: ""} + +
+ }
:
-
-

Prescriber Document Status

- -
-
- Status: Documents successfully submitted -
-
- - - {this.state.remsAdminResponse?.data?.case_number ? - this.setState({ spin: false })} - /> - : "" - } -
- -
- {this.state.viewBundle ?
-

-

Bundle

- {this.renderBundle(this.props.specialtyRxBundle)} -
: ""} - -
+ No response - form has already been submitted previously....
} +
) } diff --git a/src/elmExecutor/buildPopulatedResourceBundle.js b/src/elmExecutor/buildPopulatedResourceBundle.js index eccc28db..ef7b2442 100644 --- a/src/elmExecutor/buildPopulatedResourceBundle.js +++ b/src/elmExecutor/buildPopulatedResourceBundle.js @@ -80,6 +80,21 @@ function doSearch(smart, type, fhirVersion, request, callback) { // unknown version break; } + break; + case "MedicationStatement": + smart.patient.request(type, {resolveReferences: 'medicationReference', flat: true, graph: false}).then((result) =>{ + let finalResult = [] + // TODO: This system should be untangled, reference resolution and resource gathering shouldn't be done separately + if(result && result.data){ + if(result.references) { + Object.keys(result.references).forEach((e)=>{ + finalResult.push(result.references[e]) + }) + } + callback(finalResult); + } + }) + break; } // If this is for Epic, there are some specific modifications needed for the queries to work properly @@ -126,6 +141,7 @@ function doSearch(smart, type, fhirVersion, request, callback) { Object.keys(q).forEach((parameter)=>{ query.set(parameter, q[parameter]); }); + if( usePatient ) { smart.patient.request(`${type}?${query}`) .then(processSuccess(smart, [], callback), processError(smart, callback));