AMC changes for summary of care and CPOE, see note below:
[openemr.git] / interface / eRxSOAP.php
blobd6e6c7ddd0f408c2d3e9c99708072f2867205eec
1 <?php
3 /**
4 * interface/eRxSOAP.php Functions for interacting with NewCrop SOAP calls.
6 * Copyright (C) 2013-2015 Sam Likins <sam.likins@wsi-services.com>
8 * LICENSE: This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 3 of the License, or (at your option) any
11 * later version. This program is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 * Public License for more details. You should have received a copy of the GNU
15 * General Public License along with this program.
16 * If not, see <http://opensource.org/licenses/gpl-license.php>.
18 * @package OpenEMR
19 * @subpackage NewCrop
20 * @author Sam Likins <sam.likins@wsi-services.com>
21 * @link http://www.open-emr.org
24 class eRxSOAP {
26 const ACTION_ALLERGIES = 'allergies';
27 const ACTION_MEDICATIONS = 'medications';
29 const FLAG_PRESCRIPTION_PRESS = '1';
30 const FLAG_PRESCRIPTION_IMPORT = '2';
31 const FLAG_ALLERGY_PRESS = '3';
32 const FLAG_ALLERGY_IMPORT = '4';
34 private $globals;
35 private $store;
37 private $authUserId;
38 private $authUserDetails;
39 private $patientId;
40 private $soapClient;
41 private $soapSettings = array();
42 private $siteId;
44 /**
45 * Repair HTML/XML and return array
46 * @param string $xml XML for processing
47 * @return array|boolean Array on success, false on failure
49 static public function htmlFixXmlToArray($xml) {
50 $xmltoarray = new xmltoarray_parser_htmlfix(); //create instance of class
52 $xmltoarray->xmlparser_setoption(XML_OPTION_SKIP_WHITE, 1); //set options same as xml_parser_set_option
53 $xmltoarray->xmlparser_setoption(XML_OPTION_CASE_FOLDING, 0);
55 $xmltoarray->xmlparser_fix_into_struct(base64_decode($xml)); //fixes html values for XML
57 $array = $xmltoarray->createArray(); //creates an array with fixed html values
59 foreach($array as $key => $value) {
60 $array[$key] = $xmltoarray->fix_html_entities($value); //returns proper html values
63 if(array_key_exists('NewDataSet', $array) && array_key_exists('Table', $array['NewDataSet']))
64 $array = $array['NewDataSet']['Table'];
65 else
66 $array = false;
68 return $array;
71 /**
72 * Set Globals for retrieving eRx global configurations
73 * @param object $globals The eRx Globals object to use for processing
74 * @return eRxPage This object is returned for method chaining
76 public function setGlobals($globals) {
77 $this->globals = $globals;
79 return $this;
82 /**
83 * Get Globals for retrieving eRx global configurations
84 * @return object The eRx Globals object to use for processing
86 public function getGlobals() {
87 return $this->globals;
90 /**
91 * Set Store to handle eRx cashed data
92 * @param object $store The eRx Store object to use for processing
93 * @return eRxSOAP This object is returned for method chaining
95 public function setStore($store) {
96 $this->store = $store;
98 return $this;
102 * Get Store for handling eRx cashed data
103 * @return object The eRx Store object to use for processing
105 public function getStore() {
106 return $this->store;
110 * Get Account Id set for SOAP communications with NewCrop
111 * @return string The Account Id sent with SOAP requests to NewCrop
113 public function getAccountId() {
114 return $this->getGlobals()->getAccountId();
118 * Set SiteId for SOAP communications with NewCrop
119 * @param string $id The Site Id to send with SOAP requests to NewCrop
120 * @return eRxSOAP This object is returned for method chaining
122 public function setSiteId($id) {
123 $this->siteId = $id;
125 return $this;
129 * Get Site Id set for SOAP communications with NewCrop
130 * @return string The Site Id sent with SOAP requests to NewCrop
132 public function getSiteId() {
133 if(null === $this->siteId)
134 $this->siteId = $this->getStore()
135 ->selectFederalEin();
137 return $this->siteId;
141 * Get the authenticated users ID and NPI
142 * @return array The users ID and NPI
144 public function getAuthUserDetails() {
145 if(null === $this->authUserDetails)
146 $this->authUserDetails = $this->getStore()
147 ->getUserById($this->getAuthUserId());
149 return $this->authUserDetails;
153 * Set the Id of the authenticated user
154 * @param integer $user The Id for the authenticated user
155 * @return eRxSOAP This object is returned for method chaining
157 public function setAuthUserId($user) {
158 $this->authUserId = $user;
160 return $this;
164 * Get the Id of the authenticated user
165 * @return integer The Id of the authenticated user
167 public function getAuthUserId() {
168 return $this->authUserId;
172 * Set the Id of the current patient
173 * @param integer $id The Id of the current patient
174 * @return eRxSOAP This object is returned for method chaining
176 public function setPatientId($id) {
177 $this->patientId = (integer) $id;
179 return $this;
183 * Get the Id of the current patient
184 * @return integer The Id of the current patient
186 public function getPatientId() {
187 return $this->patientId;
191 * Generate and set a new SOAP client with provided Path Id
192 * @param integer $pathId Id for NewCrop eRx SOAP path: index [0 = Update, 1 = Patient]
193 * @return SoapClient Soap Client
195 public function initializeSoapClient($pathId) {
196 $paths = $this->getGlobals()->getSoapPaths();
198 return $this->setSoapClient(new SoapClient($paths[(integer) $pathId]));
202 * Set SOAP client for communication with NewCrop
203 * @param SoapClient $client SOAP client for communication with NewCrop
204 * @return eRxSOAP This object is returned for method chaining
206 public function setSoapClient(SoapClient $client) {
207 $this->soapClient = $client;
209 return $this;
213 * Get SOAP client for communication with NewCrop
214 * @return SoapClient SOAP client for communication with NewCrop
216 public function getSoapClient() {
217 return $this->soapClient;
221 * Set SOAP call settings for calls to NewCrop
222 * @param array $settings [optional] Setting to send with SOAP call to NewCrop
223 * @return eRxSOAP This object is returned for method chaining
225 public function setSoapSettings($settings = array()) {
226 $this->soapSettings = (array) $settings;
228 return $this;
232 * Get SOAP call settings for calls to NewCrop
233 * @return array Settings to send with SOAP call to NewCrop
235 public function &getSoapSettings() {
236 return $this->soapSettings;
240 * Get TTL for provided SOAP process
241 * @param string $process SOAP process to retrieve TTL for
242 * @return number|boolean Number on success, false on failure
244 public function getTTL($process) {
245 switch ($process) {
246 case self::ACTION_ALLERGIES:
247 $return = $this->getGlobals()->getTTLSoapAllergies();
248 case self::ACTION_MEDICATIONS:
249 $return = $this->getGlobals()->getTTLSoapMedications();
250 default:
251 $return = false;
254 return $return;
258 * Check if TTL of current patient has elapsed for provided SOAP process
259 * @param string $process SOAP process to check against for elapsed TTL of current patient
260 * @return boolean True if TTL of current patient has elapsed for provided SOAP process, otherwise false
262 public function elapsedTTL($process) {
263 $ttl = $this->getTTL($process);
264 if(false === $ttl || 0 == $ttl)
265 return true;
267 $soap = $this->getStore()->getLastSOAP($process, $this->getPatientId());
268 if(false === $soap)
269 return true;
271 return strtotime('-'.$ttl.' seconds') >= strtotime($soap);
275 * Update provided SOAP process TTL timestamp of current patient
276 * @param string $process SOAP process to update TTL of current patient
277 * @return eRxSOAP This object is returned for method chaining
279 public function updateTTL($process) {
280 $this->getStore()->setLastSOAP($process, $this->getPatientId());
282 return $this;
286 * Check if import status of current patient is set to provided SOAP process(es)
287 * @param string|array $status SOAP process to check against import status of current patient, optionally an array of SOAP processes can be substituted
288 * @return boolean True if import status of current patient is set to provided SOAP process(es), otherwise false
290 public function checkPatientImportStatus($status) {
291 $currentStatus = $this->getStore()
292 ->getPatientImportStatusByPatientId(
293 $this->getPatientId()
296 if(is_array($status))
297 $return = in_array($currentStatus, $status);
298 else
299 $return = ($currentStatus == $status);
301 return $return;
305 * [updatePatientImportStatus description]
306 * @param string $status SOAP process to update import status of current patient
307 * @return eRxSOAP This object is returned for method chaining
309 public function updatePatientImportStatus($status) {
310 $this->getStore()
311 ->updatePatientImportStatusByPatientId(
312 $this->getPatientId(),
313 $status
316 return $this;
320 * Initialize SOAP settings with the credentials currently set
321 * @return eRxSOAP This object is returned for method chaining
323 public function initializeCredentials() {
324 $credentials = $this->getGlobals()->getCredentials();
326 $this->soapSettings['credentials'] = array(
327 'PartnerName' => $credentials['0'],
328 'Name' => $credentials['1'],
329 'Password' => $credentials['2'],
332 return $this;
336 * Initialize SOAP settings with the NewCrop account and site Ids
337 * @return eRxSOAP This object is returned for method chaining
339 public function initializeAccountRequest() {
340 $this->soapSettings['accountRequest'] = array(
341 'AccountId' => $this->getGlobals()->getAccountId(),
342 'SiteId' => $this->getSiteId(),
345 return $this;
349 * Initialize SOAP settings with patient information
350 * @return eRxSOAP This object is returned for method chaining
352 public function initializePatientInformationRequester() {
353 $userDetails = $this->getAuthUserDetails();
355 $this->soapSettings['patientInformationRequester'] = array(
356 'UserId' => $userDetails['id'],
357 'UserType' => 'D',
360 return $this;
364 * Get account status information for current patient
365 * @return object SOAP client response from NewCrop call
367 public function getAccountStatus() {
368 $this->setSoapSettings()
369 ->initializeCredentials()
370 ->initializeAccountRequest();
372 $userDetails = $this->getAuthUserDetails();
374 $this->soapSettings['locationId'] = $this->getPatientId();
375 $this->soapSettings['userId'] = $userDetails['npi'];
376 $this->soapSettings['userType'] = 'P';
378 $this->initializeSoapClient(1);
380 return $this->getSoapClient()
381 ->GetAccountStatus($this->soapSettings);
385 * Get allergy history for current patient
386 * @return object SOAP client response from NewCrop call
388 public function getPatientAllergyHistoryV3() {
389 $this->setSoapSettings()
390 ->initializeCredentials()
391 ->initializeAccountRequest()
392 ->initializePatientInformationRequester();
394 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
396 $this->initializeSoapClient(0);
398 return $this->getSoapClient()
399 ->GetPatientAllergyHistoryV3($this->soapSettings);
403 * Get full medication history for current patient
404 * @return object SOAP client response from NewCrop call
406 public function getPatientFullMedicationHistory6() {
407 $this->setSoapSettings()
408 ->initializeCredentials()
409 ->initializeAccountRequest()
410 ->initializePatientInformationRequester();
412 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
414 $this->soapSettings['prescriptionHistoryRequest'] = array(
415 'StartHistory' => '2011-01-01T00:00:00.000',
416 'EndHistory' => date('Y-m-d').'T23:59:59.000',
417 'PrescriptionStatus' => 'C',
418 'PrescriptionSubStatus' => '%',
419 'PrescriptionArchiveStatus' => 'N',
422 $this->soapSettings['patientIdType'] = '';
423 $this->soapSettings['includeSchema'] = '';
425 $this->initializeSoapClient(0);
427 return $this->getSoapClient()
428 ->GetPatientFullMedicationHistory6($this->soapSettings);
432 * Get free form allergy history for current patient
433 * @return object SOAP client response from NewCrop call
435 public function getPatientFreeFormAllergyHistory() {
436 $this->setSoapSettings()
437 ->initializeCredentials()
438 ->initializeAccountRequest()
439 ->initializePatientInformationRequester();
441 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
443 $client = $this->initializeSoapClient(0);
445 return $this->getSoapClient()
446 ->GetPatientFreeFormAllergyHistory($this->soapSettings);
450 * Insert list option if missing and return the associated option Id
451 * @param string $listId Id of list to reference
452 * @param string $title Title text to find
453 * @return string Option Id of selected list item
455 public function insertMissingListOptions($listId, $title) {
456 $store = $this->getStore();
458 $optionId = $store->selectOptionIdByTitle($listId, $title);
460 if(false === $optionId) {
461 $optionId = 1 + $store->selectOptionIdsByListId($listId);
463 $store->insertListOptions($listId, $optionId, $title);
466 return $optionId;
470 * Trigger Allergy History SOAP call to NewCrop for current patient and update local cached data
471 * @return integer Count of newly cached records
473 public function insertUpdateAllergies() {
474 $store = $this->getStore();
476 $insertedRows = 0;
478 $allergyArray = self::htmlFixXmlToArray(
479 $this->getPatientAllergyHistoryV3()
480 ->GetPatientAllergyHistoryV3Result
481 ->XmlResponse
484 if(is_array($allergyArray)) {
485 foreach($allergyArray as $allergy) {
486 $optionId = $this->insertMissingListOptions(
487 'outcome',
488 $allergy['AllergySeverityName']
491 $allergySource = $store->selectAllergyErxSourceByPatientIdName(
492 $this->getPatientId(),
493 $allergy['AllergyName']
497 if(false === $allergySource) {
498 $store->insertAllergy(
499 $allergy['AllergyName'],
500 $allergy['AllergyId'],
501 $this->getPatientId(),
502 $this->getAuthUserId(),
503 $optionId
506 ++$insertedRows;
507 } elseif(0 == $allergySource) {
508 $store->updateAllergyOutcomeExternalIdByPatientIdName(
509 $optionId,
510 $allergy['AllergyId'],
511 $this->getPatientId(),
512 $allergy['AllergyName']
514 } else {
515 $store->updateAllergyOutcomeByPatientIdExternalIdName(
516 $optionId,
517 $this->getPatientId(),
518 $allergy['AllergyId'],
519 $allergy['AllergyName']
524 $this->updatePatientAllergyEndDate($allergyArray);
527 return $insertedRows;
531 * Iterate through provided list of allergies and update records with end dates
532 * @param array $allergyArray List of allergies
533 * @return eRxSOAP This object is returned for method chaining
535 public function updatePatientAllergyEndDate($allergyArray) {
536 $store = $this->getStore();
537 $patientId = $this->getPatientId();
539 $resource = $store->selectActiveAllergiesByPatientId($patientId);
541 while($row = sqlFetchArray($resource)) {
542 $noMatch = true;
544 foreach($allergyArray as $allergy) {
545 if(array_key_exists('AllergyName', $allergy) && $allergy['AllergyName'] == $row['title']) {
546 $noMatch = false;
547 break;
551 if($noMatch)
552 $store->updateAllergyEndDateByPatientIdListId(
553 $patientId,
554 $row['id']
558 return $this;
562 * Update eRx uploaded status for current patient allergies
563 * @return boolean True on success, false on failure
565 public function updateUploadedErx() {
566 $patientFreeFormAllergyHistory = $this
567 ->getPatientFreeFormAllergyHistory()
568 ->GetPatientFreeFormAllergyHistoryResult;
570 if(0 < $patientFreeFormAllergyHistory->result->RowCount) {
571 $response = $patientFreeFormAllergyHistory
572 ->patientFreeFormAllergyExtendedDetail
573 ->PatientFreeFormAllergyExtendedDetail;
575 if(!is_array($response))
576 $response = array($response);
578 foreach($response as $response) {
579 $this->getStore()
580 ->updateErxUploadedByListId($response->ExternalId);
584 return isset($response);
588 * Insert or update medications for current patient
589 * @return integer Count of newly cached records
591 public function insertUpdateMedications() {
592 $store = $this->getStore();
594 $insertedRows = 0;
596 $medArray = self::htmlFixXmlToArray(
597 $this->getPatientFullMedicationHistory6()
598 ->GetPatientFullMedicationHistory6Result
599 ->XmlResponse
602 $store->updatePrescriptionsActiveByPatientId($this->getPatientId());
604 if(is_array($medArray)) {
605 foreach($medArray as $med) {
606 if($med['DosageForm']) {
607 $optionIdDosageForm = $this->insertMissingListOptions(
608 'drug_form',
609 $med['DosageForm']
611 } else {
612 $optionIdDosageForm = null;
615 if($med['Route']) {
616 $optionIdRoute = $this->insertMissingListOptions(
617 'drug_route',
618 $med['Route']
620 } else {
621 $optionIdRoute = null;
624 if($med['StrengthUOM']) {
625 $optionIdStrengthUOM = $this->insertMissingListOptions(
626 'drug_units',
627 $med['StrengthUOM']
629 } else {
630 $optionIdStrengthUOM = null;
633 if($med['DosageFrequencyDescription']) {
634 $optionIdFrequencyDescription = $this->insertMissingListOptions(
635 'drug_interval',
636 $med['DosageFrequencyDescription']
638 } else {
639 $optionIdFrequencyDescription = null;
642 $providerId = $store->selectUserIdByUserName($med['ExternalPhysicianID']);
644 $check = $store->selectPrescriptionIdByGuidPatientId(
645 $med['PrescriptionGuid'],
646 $med['ExternalPatientID']
649 $prescriptionId = '';
651 if(0 == sqlNumRows($check)) {
652 $prescriptionId = $store->insertPrescriptions(
653 $med,
654 $encounter,
655 $providerId,
656 $this->getAuthUserId(),
657 $optionIdDosageForm,
658 $optionIdRoute,
659 $optionIdStrengthUOM,
660 $optionIdFrequencyDescription
663 ++$insertedRows;
665 setListTouch($this->getPatientId(), 'prescription_erx');
666 } else {
667 $store->updatePrescriptions(
668 $med,
669 $providerId,
670 $this->getAuthUserId(),
671 $optionIdDosageForm,
672 $optionIdRoute,
673 $optionIdStrengthUOM,
674 $optionIdFrequencyDescription
678 $result = sqlFetchArray($check);
679 if($result['id'])
680 $prescriptionId = $result['id'];
682 processAmcCall(
683 'e_prescribe_amc',
684 true,
685 'add',
686 $med['ExternalPatientID'],
687 'prescriptions',
688 $prescriptionId
693 return $insertedRows;