4 * interface/eRxSOAP.php Functions for interacting with NewCrop SOAP calls.
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
17 const ACTION_ALLERGIES
= 'allergies';
18 const ACTION_MEDICATIONS
= 'medications';
20 const FLAG_PRESCRIPTION_PRESS
= '1';
21 const FLAG_PRESCRIPTION_IMPORT
= '2';
22 const FLAG_ALLERGY_PRESS
= '3';
23 const FLAG_ALLERGY_IMPORT
= '4';
29 private $authUserDetails;
32 private $soapSettings = array();
36 * Repair HTML/XML and return array
37 * @param string $xml XML for processing
38 * @return array|boolean Array on success, false on failure
40 public static function htmlFixXmlToArray($xml)
42 $xmltoarray = new xmltoarray_parser_htmlfix(); //create instance of class
44 $xmltoarray->xmlparser_setoption(XML_OPTION_SKIP_WHITE
, 1); //set options same as xml_parser_set_option
45 $xmltoarray->xmlparser_setoption(XML_OPTION_CASE_FOLDING
, 0);
47 $xmltoarray->xmlparser_fix_into_struct(base64_decode($xml)); //fixes html values for XML
49 $array = $xmltoarray->createArray(); //creates an array with fixed html values
51 foreach ($array as $key => $value) {
52 $array[$key] = $xmltoarray->fix_html_entities($value); //returns proper html values
55 if (array_key_exists('NewDataSet', $array) && array_key_exists('Table', $array['NewDataSet'])) {
56 $array = $array['NewDataSet']['Table'];
65 * Set Globals for retrieving eRx global configurations
66 * @param object $globals The eRx Globals object to use for processing
67 * @return eRxPage This object is returned for method chaining
69 public function setGlobals($globals)
71 $this->globals
= $globals;
77 * Get Globals for retrieving eRx global configurations
78 * @return object The eRx Globals object to use for processing
80 public function getGlobals()
82 return $this->globals
;
86 * Set Store to handle eRx cashed data
87 * @param object $store The eRx Store object to use for processing
88 * @return eRxSOAP This object is returned for method chaining
90 public function setStore($store)
92 $this->store
= $store;
98 * Get Store for handling eRx cashed data
99 * @return object The eRx Store object to use for processing
101 public function getStore()
107 * Get Account Id set for SOAP communications with NewCrop
108 * @return string The Account Id sent with SOAP requests to NewCrop
110 public function getAccountId()
112 return $this->getGlobals()->getAccountId();
116 * Set SiteId for SOAP communications with NewCrop
117 * @param string $id The Site Id to send with SOAP requests to NewCrop
118 * @return eRxSOAP This object is returned for method chaining
120 public function setSiteId($id)
128 * Get Site Id set for SOAP communications with NewCrop
129 * @return string The Site Id sent with SOAP requests to NewCrop
131 public function getSiteId()
133 if (null === $this->siteId
) {
134 $this->siteId
= $this->getStore()
135 ->selectFederalEin();
138 return $this->siteId
;
142 * Get the authenticated users ID and NPI
143 * @return array The users ID and NPI
145 public function getAuthUserDetails()
147 if (null === $this->authUserDetails
) {
148 $this->authUserDetails
= $this->getStore()
149 ->getUserById($this->getAuthUserId());
152 return $this->authUserDetails
;
156 * Set the Id of the authenticated user
157 * @param integer $user The Id for the authenticated user
158 * @return eRxSOAP This object is returned for method chaining
160 public function setAuthUserId($user)
162 $this->authUserId
= $user;
168 * Get the Id of the authenticated user
169 * @return integer The Id of the authenticated user
171 public function getAuthUserId()
173 return $this->authUserId
;
177 * Set the Id of the current patient
178 * @param integer $id The Id of the current patient
179 * @return eRxSOAP This object is returned for method chaining
181 public function setPatientId($id)
183 $this->patientId
= (int) $id;
189 * Get the Id of the current patient
190 * @return integer The Id of the current patient
192 public function getPatientId()
194 return $this->patientId
;
198 * Generate and set a new SOAP client with provided Path Id
199 * @param integer $pathId Id for NewCrop eRx SOAP path: index [0 = Update, 1 = Patient]
200 * @return SoapClient Soap Client
202 public function initializeSoapClient($pathId)
204 $paths = $this->getGlobals()->getSoapPaths();
206 return $this->setSoapClient(new SoapClient($paths[(int) $pathId]));
210 * Set SOAP client for communication with NewCrop
211 * @param SoapClient $client SOAP client for communication with NewCrop
212 * @return eRxSOAP This object is returned for method chaining
214 public function setSoapClient(SoapClient
$client)
216 $this->soapClient
= $client;
222 * Get SOAP client for communication with NewCrop
223 * @return SoapClient SOAP client for communication with NewCrop
225 public function getSoapClient()
227 return $this->soapClient
;
231 * Set SOAP call settings for calls to NewCrop
232 * @param array $settings [optional] Setting to send with SOAP call to NewCrop
233 * @return eRxSOAP This object is returned for method chaining
235 public function setSoapSettings($settings = array())
237 $this->soapSettings
= (array) $settings;
243 * Get SOAP call settings for calls to NewCrop
244 * @return array Settings to send with SOAP call to NewCrop
246 public function &getSoapSettings()
248 return $this->soapSettings
;
252 * Get TTL for provided SOAP process
253 * @param string $process SOAP process to retrieve TTL for
254 * @return number|boolean Number on success, false on failure
256 public function getTTL($process)
259 case self
::ACTION_ALLERGIES
:
260 $return = $this->getGlobals()->getTTLSoapAllergies();
262 case self
::ACTION_MEDICATIONS
:
263 $return = $this->getGlobals()->getTTLSoapMedications();
273 * Check if TTL of current patient has elapsed for provided SOAP process
274 * @param string $process SOAP process to check against for elapsed TTL of current patient
275 * @return boolean True if TTL of current patient has elapsed for provided SOAP process, otherwise false
277 public function elapsedTTL($process)
279 $ttl = $this->getTTL($process);
280 if (false === $ttl ||
0 == $ttl) {
284 $soap = $this->getStore()->getLastSOAP($process, $this->getPatientId());
285 if (false === $soap) {
289 return strtotime('-' . $ttl . ' seconds') >= strtotime($soap);
293 * Update provided SOAP process TTL timestamp of current patient
294 * @param string $process SOAP process to update TTL of current patient
295 * @return eRxSOAP This object is returned for method chaining
297 public function updateTTL($process)
299 $this->getStore()->setLastSOAP($process, $this->getPatientId());
305 * Check if import status of current patient is set to provided SOAP process(es)
306 * @param string|array $status SOAP process to check against import status of current patient, optionally an array of SOAP processes can be substituted
307 * @return boolean True if import status of current patient is set to provided SOAP process(es), otherwise false
309 public function checkPatientImportStatus($status)
311 $currentStatus = $this->getStore()
312 ->getPatientImportStatusByPatientId(
313 $this->getPatientId()
316 if (is_array($status)) {
317 $return = in_array($currentStatus, $status);
319 $return = ($currentStatus == $status);
326 * [updatePatientImportStatus description]
327 * @param string $status SOAP process to update import status of current patient
328 * @return eRxSOAP This object is returned for method chaining
330 public function updatePatientImportStatus($status)
333 ->updatePatientImportStatusByPatientId(
334 $this->getPatientId(),
342 * Initialize SOAP settings with the credentials currently set
343 * @return eRxSOAP This object is returned for method chaining
345 public function initializeCredentials()
347 $credentials = $this->getGlobals()->getCredentials();
349 $this->soapSettings
['credentials'] = array(
350 'PartnerName' => $credentials['0'],
351 'Name' => $credentials['1'],
352 'Password' => $credentials['2'],
359 * Initialize SOAP settings with the NewCrop account and site Ids
360 * @return eRxSOAP This object is returned for method chaining
362 public function initializeAccountRequest()
364 $this->soapSettings
['accountRequest'] = array(
365 'AccountId' => $this->getGlobals()->getAccountId(),
366 'SiteId' => $this->getSiteId(),
373 * Initialize SOAP settings with patient information
374 * @return eRxSOAP This object is returned for method chaining
376 public function initializePatientInformationRequester()
378 $userDetails = $this->getAuthUserDetails();
380 $this->soapSettings
['patientInformationRequester'] = array(
381 'UserId' => $userDetails['id'],
389 * Get account status information for current patient
390 * @return object SOAP client response from NewCrop call
392 public function getAccountStatus()
394 $this->setSoapSettings()
395 ->initializeCredentials()
396 ->initializeAccountRequest();
398 $userDetails = $this->getAuthUserDetails();
400 $this->soapSettings
['locationId'] = $this->getPatientId();
401 $this->soapSettings
['userId'] = $userDetails['npi'];
402 $this->soapSettings
['userType'] = 'P';
404 $this->initializeSoapClient(1);
406 return $this->getSoapClient()
407 ->GetAccountStatus($this->soapSettings
);
411 * Get allergy history for current patient
412 * @return object SOAP client response from NewCrop call
414 public function getPatientAllergyHistoryV3()
416 $this->setSoapSettings()
417 ->initializeCredentials()
418 ->initializeAccountRequest()
419 ->initializePatientInformationRequester();
421 $this->soapSettings
['patientRequest']['PatientId'] = $this->getPatientId();
423 $this->initializeSoapClient(0);
425 return $this->getSoapClient()
426 ->GetPatientAllergyHistoryV3($this->soapSettings
);
430 * Get full medication history for current patient
431 * @return object SOAP client response from NewCrop call
433 public function getPatientFullMedicationHistory6()
435 $this->setSoapSettings()
436 ->initializeCredentials()
437 ->initializeAccountRequest()
438 ->initializePatientInformationRequester();
440 $this->soapSettings
['patientRequest']['PatientId'] = $this->getPatientId();
442 $this->soapSettings
['prescriptionHistoryRequest'] = array(
443 'StartHistory' => '2011-01-01T00:00:00.000',
444 'EndHistory' => date('Y-m-d') . 'T23:59:59.000',
445 'PrescriptionStatus' => 'C',
446 'PrescriptionSubStatus' => '%',
447 'PrescriptionArchiveStatus' => 'N',
450 $this->soapSettings
['patientIdType'] = '';
451 $this->soapSettings
['includeSchema'] = '';
453 $this->initializeSoapClient(0);
455 return $this->getSoapClient()
456 ->GetPatientFullMedicationHistory6($this->soapSettings
);
460 * Get free form allergy history for current patient
461 * @return object SOAP client response from NewCrop call
463 public function getPatientFreeFormAllergyHistory()
465 $this->setSoapSettings()
466 ->initializeCredentials()
467 ->initializeAccountRequest()
468 ->initializePatientInformationRequester();
470 $this->soapSettings
['patientRequest']['PatientId'] = $this->getPatientId();
472 $client = $this->initializeSoapClient(0);
474 return $this->getSoapClient()
475 ->GetPatientFreeFormAllergyHistory($this->soapSettings
);
479 * Insert list option if missing and return the associated option Id
480 * @param string $listId Id of list to reference
481 * @param string $title Title text to find
482 * @return string Option Id of selected list item
484 public function insertMissingListOptions($listId, $title)
486 $store = $this->getStore();
488 $optionId = $store->selectOptionIdByTitle($listId, $title);
490 if (false === $optionId) {
491 $optionId = 1 +
$store->selectOptionIdsByListId($listId);
493 $store->insertListOptions($listId, $optionId, $title);
500 * Trigger Allergy History SOAP call to NewCrop for current patient and update local cached data
501 * @return integer Count of newly cached records
503 public function insertUpdateAllergies()
505 $store = $this->getStore();
509 $allergyArray = self
::htmlFixXmlToArray(
510 $this->getPatientAllergyHistoryV3()
511 ->GetPatientAllergyHistoryV3Result
515 if (is_array($allergyArray)) {
516 foreach ($allergyArray as $allergy) {
517 $optionId = $this->insertMissingListOptions(
519 $allergy['AllergySeverityName']
522 $allergySource = $store->selectAllergyErxSourceByPatientIdName(
523 $this->getPatientId(),
524 $allergy['AllergyName']
528 if (false === $allergySource) {
529 $store->insertAllergy(
530 $allergy['AllergyName'],
531 $allergy['AllergyId'],
532 $this->getPatientId(),
533 $this->getAuthUserId(),
538 } elseif (0 == $allergySource) {
539 $store->updateAllergyOutcomeExternalIdByPatientIdName(
541 $allergy['AllergyId'],
542 $this->getPatientId(),
543 $allergy['AllergyName']
546 $store->updateAllergyOutcomeByPatientIdExternalIdName(
548 $this->getPatientId(),
549 $allergy['AllergyId'],
550 $allergy['AllergyName']
555 $this->updatePatientAllergyEndDate($allergyArray);
558 return $insertedRows;
562 * Iterate through provided list of allergies and update records with end dates
563 * @param array $allergyArray List of allergies
564 * @return eRxSOAP This object is returned for method chaining
566 public function updatePatientAllergyEndDate($allergyArray)
568 $store = $this->getStore();
569 $patientId = $this->getPatientId();
571 $resource = $store->selectActiveAllergiesByPatientId($patientId);
573 while ($row = sqlFetchArray($resource)) {
576 foreach ($allergyArray as $allergy) {
577 if (array_key_exists('AllergyName', $allergy) && $allergy['AllergyName'] == $row['title']) {
584 $store->updateAllergyEndDateByPatientIdListId(
595 * Update eRx uploaded status for current patient allergies
596 * @return boolean True on success, false on failure
598 public function updateUploadedErx()
600 $patientFreeFormAllergyHistory = $this
601 ->getPatientFreeFormAllergyHistory()
602 ->GetPatientFreeFormAllergyHistoryResult
;
604 if (0 < $patientFreeFormAllergyHistory->result
->RowCount
) {
605 $response = $patientFreeFormAllergyHistory
606 ->patientFreeFormAllergyExtendedDetail
607 ->PatientFreeFormAllergyExtendedDetail
;
609 if (!is_array($response)) {
610 $response = array($response);
613 foreach ($response as $response) {
615 ->updateErxUploadedByListId($response->ExternalId
);
619 return isset($response);
623 * Insert or update medications for current patient
624 * @return integer Count of newly cached records
626 public function insertUpdateMedications()
628 $store = $this->getStore();
632 $medArray = self
::htmlFixXmlToArray(
633 $this->getPatientFullMedicationHistory6()
634 ->GetPatientFullMedicationHistory6Result
637 $store->updatePrescriptionsActiveByPatientId($this->getPatientId());
638 if (is_array($medArray)) {
639 foreach ($medArray as $med) {
640 if ($med['DosageForm']) {
641 $optionIdDosageForm = $this->insertMissingListOptions(
646 $optionIdDosageForm = null;
650 $optionIdRoute = $this->insertMissingListOptions(
655 $optionIdRoute = null;
658 if ($med['StrengthUOM']) {
659 $optionIdStrengthUOM = $this->insertMissingListOptions(
664 $optionIdStrengthUOM = null;
667 if ($med['DosageFrequencyDescription']) {
668 $optionIdFrequencyDescription = $this->insertMissingListOptions(
670 $med['DosageFrequencyDescription']
673 $optionIdFrequencyDescription = null;
676 $providerId = $store->selectUserIdByUserName($med['ExternalPhysicianID']);
678 $check = $store->selectPrescriptionIdByGuidPatientId(
679 $med['PrescriptionGuid'],
680 $med['ExternalPatientID']
683 $prescriptionId = '';
685 if (0 == sqlNumRows($check)) {
686 $prescriptionId = $store->insertPrescriptions(
690 $this->getAuthUserId(),
693 $optionIdStrengthUOM,
694 $optionIdFrequencyDescription
699 setListTouch($this->getPatientId(), 'prescription_erx');
701 $store->updatePrescriptions(
704 $this->getAuthUserId(),
707 $optionIdStrengthUOM,
708 $optionIdFrequencyDescription
712 $result = sqlFetchArray($check);
714 $prescriptionId = $result['id'];
717 // Making sure only transmitted prescriptions entry added into amc_misc_data for eRx Numerator
718 if (!empty($med['PharmacyNCPDP'])) {
723 $med['ExternalPatientID'],
729 if ($med['FormularyChecked'] === 'true') {
730 processAmcCall('e_prescribe_chk_formulary_amc', true, 'add', $med['ExternalPatientID'], 'prescriptions', $prescriptionId);
735 return $insertedRows;