Hide dashboard card 2 (#7423)
[openemr.git] / interface / eRxSOAP.php
blob3b01db128bf6dcc494e202055a035e1143a4e2e4
1 <?php
3 /**
4 * interface/eRxSOAP.php Functions for interacting with NewCrop SOAP calls.
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Sam Likins <sam.likins@wsi-services.com>
9 * @copyright Copyright (c) 2015 Sam Likins <sam.likins@wsi-services.com>
10 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
14 class eRxSOAP
16 const ACTION_ALLERGIES = 'allergies';
17 const ACTION_MEDICATIONS = 'medications';
19 const FLAG_PRESCRIPTION_PRESS = '1';
20 const FLAG_PRESCRIPTION_IMPORT = '2';
21 const FLAG_ALLERGY_PRESS = '3';
22 const FLAG_ALLERGY_IMPORT = '4';
24 private $globals;
25 private $store;
27 private $authUserId;
28 private $authUserDetails;
29 private $patientId;
30 private $soapClient;
31 private $soapSettings = array();
32 private $siteId;
34 protected static function fixHtmlEntities($array, $xmltoarray)
36 $encoded = json_encode($array);
37 $fixed = $xmltoarray->fix_html_entities($encoded);
38 return json_decode($fixed, true);
41 /**
42 * Repair HTML/XML and return array
43 * @param string $xml XML for processing
44 * @return array|boolean Array on success, false on failure
46 public static function htmlFixXmlToArray($xml)
48 $xmltoarray = new xmltoarray_parser_htmlfix(); //create instance of class
50 $xmltoarray->xmlparser_setoption(XML_OPTION_SKIP_WHITE, 1); //set options same as xml_parser_set_option
51 $xmltoarray->xmlparser_setoption(XML_OPTION_CASE_FOLDING, 0);
53 $xmltoarray->xmlparser_fix_into_struct(base64_decode($xml)); //fixes html values for XML
55 $array = $xmltoarray->createArray(); //creates an array with fixed html values
57 $array = self::fixHtmlEntities($array, $xmltoarray);
59 if (array_key_exists('NewDataSet', $array) && array_key_exists('Table', $array['NewDataSet'])) {
60 $array = $array['NewDataSet']['Table'];
61 } else {
62 $array = false;
65 return $array;
68 /**
69 * Set Globals for retrieving eRx global configurations
70 * @param object $globals The eRx Globals object to use for processing
71 * @return eRxPage This object is returned for method chaining
73 public function setGlobals($globals)
75 $this->globals = $globals;
77 return $this;
80 /**
81 * Get Globals for retrieving eRx global configurations
82 * @return object The eRx Globals object to use for processing
84 public function getGlobals()
86 return $this->globals;
89 /**
90 * Set Store to handle eRx cashed data
91 * @param object $store The eRx Store object to use for processing
92 * @return eRxSOAP This object is returned for method chaining
94 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()
107 return $this->store;
111 * Get Account Id set for SOAP communications with NewCrop
112 * @return string The Account Id sent with SOAP requests to NewCrop
114 public function getAccountId()
116 return $this->getGlobals()->getAccountId();
120 * Set SiteId for SOAP communications with NewCrop
121 * @param string $id The Site Id to send with SOAP requests to NewCrop
122 * @return eRxSOAP This object is returned for method chaining
124 public function setSiteId($id)
126 $this->siteId = $id;
128 return $this;
132 * Get Site Id set for SOAP communications with NewCrop
133 * @return string The Site Id sent with SOAP requests to NewCrop
135 public function getSiteId()
137 if (null === $this->siteId) {
138 $this->siteId = $this->getStore()
139 ->selectFederalEin();
142 return $this->siteId;
146 * Get the authenticated users ID and NPI
147 * @return array The users ID and NPI
149 public function getAuthUserDetails()
151 if (null === $this->authUserDetails) {
152 $this->authUserDetails = $this->getStore()
153 ->getUserById($this->getAuthUserId());
156 return $this->authUserDetails;
160 * Set the Id of the authenticated user
161 * @param integer $user The Id for the authenticated user
162 * @return eRxSOAP This object is returned for method chaining
164 public function setAuthUserId($user)
166 $this->authUserId = $user;
168 return $this;
172 * Get the Id of the authenticated user
173 * @return integer The Id of the authenticated user
175 public function getAuthUserId()
177 return $this->authUserId;
181 * Set the Id of the current patient
182 * @param integer $id The Id of the current patient
183 * @return eRxSOAP This object is returned for method chaining
185 public function setPatientId($id)
187 $this->patientId = (int) $id;
189 return $this;
193 * Get the Id of the current patient
194 * @return integer The Id of the current patient
196 public function getPatientId()
198 return $this->patientId;
202 * Generate and set a new SOAP client with provided Path Id
203 * @param integer $pathId Id for NewCrop eRx SOAP path: index [0 = Update, 1 = Patient]
204 * @return SoapClient Soap Client
206 public function initializeSoapClient($pathId)
208 $paths = $this->getGlobals()->getSoapPaths();
210 return $this->setSoapClient(new SoapClient($paths[(int) $pathId]));
214 * Set SOAP client for communication with NewCrop
215 * @param SoapClient $client SOAP client for communication with NewCrop
216 * @return eRxSOAP This object is returned for method chaining
218 public function setSoapClient(SoapClient $client)
220 $this->soapClient = $client;
222 return $this;
226 * Get SOAP client for communication with NewCrop
227 * @return SoapClient SOAP client for communication with NewCrop
229 public function getSoapClient()
231 return $this->soapClient;
235 * Set SOAP call settings for calls to NewCrop
236 * @param array $settings [optional] Setting to send with SOAP call to NewCrop
237 * @return eRxSOAP This object is returned for method chaining
239 public function setSoapSettings($settings = array())
241 $this->soapSettings = (array) $settings;
243 return $this;
247 * Get SOAP call settings for calls to NewCrop
248 * @return array Settings to send with SOAP call to NewCrop
250 public function &getSoapSettings()
252 return $this->soapSettings;
256 * Get TTL for provided SOAP process
257 * @param string $process SOAP process to retrieve TTL for
258 * @return number|boolean Number on success, false on failure
260 public function getTTL($process)
262 switch ($process) {
263 case self::ACTION_ALLERGIES:
264 $return = $this->getGlobals()->getTTLSoapAllergies();
265 break;
266 case self::ACTION_MEDICATIONS:
267 $return = $this->getGlobals()->getTTLSoapMedications();
268 break;
269 default:
270 $return = false;
273 return $return;
277 * Check if TTL of current patient has elapsed for provided SOAP process
278 * @param string $process SOAP process to check against for elapsed TTL of current patient
279 * @return boolean True if TTL of current patient has elapsed for provided SOAP process, otherwise false
281 public function elapsedTTL($process)
283 $ttl = $this->getTTL($process);
284 if (false === $ttl || 0 == $ttl) {
285 return true;
288 $soap = $this->getStore()->getLastSOAP($process, $this->getPatientId());
289 if (false === $soap) {
290 return true;
293 return strtotime('-' . $ttl . ' seconds') >= strtotime($soap);
297 * Update provided SOAP process TTL timestamp of current patient
298 * @param string $process SOAP process to update TTL of current patient
299 * @return eRxSOAP This object is returned for method chaining
301 public function updateTTL($process)
303 $this->getStore()->setLastSOAP($process, $this->getPatientId());
305 return $this;
309 * Check if import status of current patient is set to provided SOAP process(es)
310 * @param string|array $status SOAP process to check against import status of current patient, optionally an array of SOAP processes can be substituted
311 * @return boolean True if import status of current patient is set to provided SOAP process(es), otherwise false
313 public function checkPatientImportStatus($status)
315 $currentStatus = $this->getStore()
316 ->getPatientImportStatusByPatientId(
317 $this->getPatientId()
320 if (is_array($status)) {
321 $return = in_array($currentStatus, $status);
322 } else {
323 $return = ($currentStatus == $status);
326 return $return;
330 * [updatePatientImportStatus description]
331 * @param string $status SOAP process to update import status of current patient
332 * @return eRxSOAP This object is returned for method chaining
334 public function updatePatientImportStatus($status)
336 $this->getStore()
337 ->updatePatientImportStatusByPatientId(
338 $this->getPatientId(),
339 $status
342 return $this;
346 * Initialize SOAP settings with the credentials currently set
347 * @return eRxSOAP This object is returned for method chaining
349 public function initializeCredentials()
351 $credentials = $this->getGlobals()->getCredentials();
353 $this->soapSettings['credentials'] = array(
354 'PartnerName' => $credentials['0'],
355 'Name' => $credentials['1'],
356 'Password' => $credentials['2'],
359 return $this;
363 * Initialize SOAP settings with the NewCrop account and site Ids
364 * @return eRxSOAP This object is returned for method chaining
366 public function initializeAccountRequest()
368 $this->soapSettings['accountRequest'] = array(
369 'AccountId' => $this->getGlobals()->getAccountId(),
370 'SiteId' => $this->getSiteId(),
373 return $this;
377 * Initialize SOAP settings with patient information
378 * @return eRxSOAP This object is returned for method chaining
380 public function initializePatientInformationRequester()
382 $userDetails = $this->getAuthUserDetails();
384 $this->soapSettings['patientInformationRequester'] = array(
385 'UserId' => $userDetails['id'],
386 'UserType' => 'D',
389 return $this;
393 * Get account status information for current patient
394 * @return object SOAP client response from NewCrop call
396 public function getAccountStatus()
398 $this->setSoapSettings()
399 ->initializeCredentials()
400 ->initializeAccountRequest();
402 $userDetails = $this->getAuthUserDetails();
404 $this->soapSettings['locationId'] = $this->getPatientId();
405 $this->soapSettings['userId'] = $userDetails['npi'];
406 $this->soapSettings['userType'] = 'P';
408 $this->initializeSoapClient(1);
410 return $this->getSoapClient()
411 ->GetAccountStatus($this->soapSettings);
415 * Get allergy history for current patient
416 * @return object SOAP client response from NewCrop call
418 public function getPatientAllergyHistoryV3()
420 $this->setSoapSettings()
421 ->initializeCredentials()
422 ->initializeAccountRequest()
423 ->initializePatientInformationRequester();
425 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
427 $this->initializeSoapClient(0);
429 return $this->getSoapClient()
430 ->GetPatientAllergyHistoryV3($this->soapSettings);
434 * Get full medication history for current patient
435 * @return object SOAP client response from NewCrop call
437 public function getPatientFullMedicationHistory6()
439 $this->setSoapSettings()
440 ->initializeCredentials()
441 ->initializeAccountRequest()
442 ->initializePatientInformationRequester();
444 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
446 $this->soapSettings['prescriptionHistoryRequest'] = array(
447 'StartHistory' => '2011-01-01T00:00:00.000',
448 'EndHistory' => date('Y-m-d') . 'T23:59:59.000',
449 'PrescriptionStatus' => 'C',
450 'PrescriptionSubStatus' => '%',
451 'PrescriptionArchiveStatus' => 'N',
454 $this->soapSettings['patientIdType'] = '';
455 $this->soapSettings['includeSchema'] = '';
457 $this->initializeSoapClient(0);
459 return $this->getSoapClient()
460 ->GetPatientFullMedicationHistory6($this->soapSettings);
464 * Get free form allergy history for current patient
465 * @return object SOAP client response from NewCrop call
467 public function getPatientFreeFormAllergyHistory()
469 $this->setSoapSettings()
470 ->initializeCredentials()
471 ->initializeAccountRequest()
472 ->initializePatientInformationRequester();
474 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
476 $client = $this->initializeSoapClient(0);
478 return $this->getSoapClient()
479 ->GetPatientFreeFormAllergyHistory($this->soapSettings);
483 * Insert list option if missing and return the associated option Id
484 * @param string $listId Id of list to reference
485 * @param string $title Title text to find
486 * @return string Option Id of selected list item
488 public function insertMissingListOptions($listId, $title)
490 $store = $this->getStore();
492 $optionId = $store->selectOptionIdByTitle($listId, $title);
494 if (false === $optionId) {
495 $optionId = 1 + $store->selectOptionIdsByListId($listId);
497 $store->insertListOptions($listId, $optionId, $title);
500 return $optionId;
504 * Trigger Allergy History SOAP call to NewCrop for current patient and update local cached data
505 * @return integer Count of newly cached records
507 public function insertUpdateAllergies()
509 $store = $this->getStore();
511 $insertedRows = 0;
513 $allergyArray = self::htmlFixXmlToArray(
514 $this->getPatientAllergyHistoryV3()
515 ->GetPatientAllergyHistoryV3Result
516 ->XmlResponse
519 if (is_array($allergyArray)) {
520 foreach ($allergyArray as $allergy) {
521 $optionId = $this->insertMissingListOptions(
522 'outcome',
523 $allergy['AllergySeverityName']
526 $allergySource = $store->selectAllergyErxSourceByPatientIdName(
527 $this->getPatientId(),
528 $allergy['AllergyName']
532 if (false === $allergySource) {
533 $store->insertAllergy(
534 $allergy['AllergyName'],
535 $allergy['AllergyId'],
536 $this->getPatientId(),
537 $this->getAuthUserId(),
538 $optionId
541 ++$insertedRows;
542 } elseif (0 == $allergySource) {
543 $store->updateAllergyOutcomeExternalIdByPatientIdName(
544 $optionId,
545 $allergy['AllergyId'],
546 $this->getPatientId(),
547 $allergy['AllergyName']
549 } else {
550 $store->updateAllergyOutcomeByPatientIdExternalIdName(
551 $optionId,
552 $this->getPatientId(),
553 $allergy['AllergyId'],
554 $allergy['AllergyName']
559 $this->updatePatientAllergyEndDate($allergyArray);
562 return $insertedRows;
566 * Iterate through provided list of allergies and update records with end dates
567 * @param array $allergyArray List of allergies
568 * @return eRxSOAP This object is returned for method chaining
570 public function updatePatientAllergyEndDate($allergyArray)
572 $store = $this->getStore();
573 $patientId = $this->getPatientId();
575 $resource = $store->selectActiveAllergiesByPatientId($patientId);
577 while ($row = sqlFetchArray($resource)) {
578 $noMatch = true;
580 foreach ($allergyArray as $allergy) {
581 if (array_key_exists('AllergyName', $allergy) && $allergy['AllergyName'] == $row['title']) {
582 $noMatch = false;
583 break;
587 if ($noMatch) {
588 $store->updateAllergyEndDateByPatientIdListId(
589 $patientId,
590 $row['id']
595 return $this;
599 * Update eRx uploaded status for current patient allergies
600 * @return boolean True on success, false on failure
602 public function updateUploadedErx()
604 $patientFreeFormAllergyHistory = $this
605 ->getPatientFreeFormAllergyHistory()
606 ->GetPatientFreeFormAllergyHistoryResult;
608 if (0 < $patientFreeFormAllergyHistory->result->RowCount) {
609 $response = $patientFreeFormAllergyHistory
610 ->patientFreeFormAllergyExtendedDetail
611 ->PatientFreeFormAllergyExtendedDetail;
613 if (!is_array($response)) {
614 $response = array($response);
617 foreach ($response as $response) {
618 $this->getStore()
619 ->updateErxUploadedByListId($response->ExternalId);
623 return isset($response);
627 * Insert or update medications for current patient
628 * @return integer Count of newly cached records
630 public function insertUpdateMedications()
632 $store = $this->getStore();
634 $insertedRows = 0;
636 $medArray = self::htmlFixXmlToArray(
637 $this->getPatientFullMedicationHistory6()
638 ->GetPatientFullMedicationHistory6Result
639 ->XmlResponse
641 $store->updatePrescriptionsActiveByPatientId($this->getPatientId());
642 if (is_array($medArray)) {
643 foreach ($medArray as $med) {
644 if ($med['DosageForm']) {
645 $optionIdDosageForm = $this->insertMissingListOptions(
646 'drug_form',
647 $med['DosageForm']
649 } else {
650 $optionIdDosageForm = null;
653 if ($med['Route']) {
654 $optionIdRoute = $this->insertMissingListOptions(
655 'drug_route',
656 $med['Route']
658 } else {
659 $optionIdRoute = null;
662 if ($med['StrengthUOM']) {
663 $optionIdStrengthUOM = $this->insertMissingListOptions(
664 'drug_units',
665 $med['StrengthUOM']
667 } else {
668 $optionIdStrengthUOM = null;
671 if ($med['DosageFrequencyDescription']) {
672 $optionIdFrequencyDescription = $this->insertMissingListOptions(
673 'drug_interval',
674 $med['DosageFrequencyDescription']
676 } else {
677 $optionIdFrequencyDescription = null;
680 $providerId = $store->selectUserIdByUserName($med['ExternalPhysicianID']);
682 $check = $store->selectPrescriptionIdByGuidPatientId(
683 $med['PrescriptionGuid'],
684 $med['ExternalPatientID']
687 $prescriptionId = '';
689 if (0 == sqlNumRows($check)) {
690 $prescriptionId = $store->insertPrescriptions(
691 $med,
692 $encounter,
693 $providerId,
694 $this->getAuthUserId(),
695 $optionIdDosageForm,
696 $optionIdRoute,
697 $optionIdStrengthUOM,
698 $optionIdFrequencyDescription
701 ++$insertedRows;
703 setListTouch($this->getPatientId(), 'prescription_erx');
704 } else {
705 $store->updatePrescriptions(
706 $med,
707 $providerId,
708 $this->getAuthUserId(),
709 $optionIdDosageForm,
710 $optionIdRoute,
711 $optionIdStrengthUOM,
712 $optionIdFrequencyDescription
716 $result = sqlFetchArray($check);
717 if ($result['id']) {
718 $prescriptionId = $result['id'];
721 // Making sure only transmitted prescriptions entry added into amc_misc_data for eRx Numerator
722 if (!empty($med['PharmacyNCPDP'])) {
723 processAmcCall(
724 'e_prescribe_amc',
725 true,
726 'add',
727 $med['ExternalPatientID'],
728 'prescriptions',
729 $prescriptionId
733 if ($med['FormularyChecked'] === 'true') {
734 processAmcCall('e_prescribe_chk_formulary_amc', true, 'add', $med['ExternalPatientID'], 'prescriptions', $prescriptionId);
739 return $insertedRows;