dump db version
[openemr.git] / interface / eRxSOAP.php
blobd1c0e77bb8ea02cfd18d89ea363deaa21efaf0d5
1 <?php
2 /**
3 * interface/eRxSOAP.php Functions for interacting with NewCrop SOAP calls.
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Sam Likins <sam.likins@wsi-services.com>
8 * @copyright Copyright (c) 2015 Sam Likins <sam.likins@wsi-services.com>
9 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
13 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 /**
35 * Repair HTML/XML and return array
36 * @param string $xml XML for processing
37 * @return array|boolean Array on success, false on failure
39 public static function htmlFixXmlToArray($xml)
41 $xmltoarray = new xmltoarray_parser_htmlfix(); //create instance of class
43 $xmltoarray->xmlparser_setoption(XML_OPTION_SKIP_WHITE, 1); //set options same as xml_parser_set_option
44 $xmltoarray->xmlparser_setoption(XML_OPTION_CASE_FOLDING, 0);
46 $xmltoarray->xmlparser_fix_into_struct(base64_decode($xml)); //fixes html values for XML
48 $array = $xmltoarray->createArray(); //creates an array with fixed html values
50 foreach ($array as $key => $value) {
51 $array[$key] = $xmltoarray->fix_html_entities($value); //returns proper html values
54 if (array_key_exists('NewDataSet', $array) && array_key_exists('Table', $array['NewDataSet'])) {
55 $array = $array['NewDataSet']['Table'];
56 } else {
57 $array = false;
60 return $array;
63 /**
64 * Set Globals for retrieving eRx global configurations
65 * @param object $globals The eRx Globals object to use for processing
66 * @return eRxPage This object is returned for method chaining
68 public function setGlobals($globals)
70 $this->globals = $globals;
72 return $this;
75 /**
76 * Get Globals for retrieving eRx global configurations
77 * @return object The eRx Globals object to use for processing
79 public function getGlobals()
81 return $this->globals;
84 /**
85 * Set Store to handle eRx cashed data
86 * @param object $store The eRx Store object to use for processing
87 * @return eRxSOAP This object is returned for method chaining
89 public function setStore($store)
91 $this->store = $store;
93 return $this;
96 /**
97 * Get Store for handling eRx cashed data
98 * @return object The eRx Store object to use for processing
100 public function getStore()
102 return $this->store;
106 * Get Account Id set for SOAP communications with NewCrop
107 * @return string The Account Id sent with SOAP requests to NewCrop
109 public function getAccountId()
111 return $this->getGlobals()->getAccountId();
115 * Set SiteId for SOAP communications with NewCrop
116 * @param string $id The Site Id to send with SOAP requests to NewCrop
117 * @return eRxSOAP This object is returned for method chaining
119 public function setSiteId($id)
121 $this->siteId = $id;
123 return $this;
127 * Get Site Id set for SOAP communications with NewCrop
128 * @return string The Site Id sent with SOAP requests to NewCrop
130 public function getSiteId()
132 if (null === $this->siteId) {
133 $this->siteId = $this->getStore()
134 ->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()
146 if (null === $this->authUserDetails) {
147 $this->authUserDetails = $this->getStore()
148 ->getUserById($this->getAuthUserId());
151 return $this->authUserDetails;
155 * Set the Id of the authenticated user
156 * @param integer $user The Id for the authenticated user
157 * @return eRxSOAP This object is returned for method chaining
159 public function setAuthUserId($user)
161 $this->authUserId = $user;
163 return $this;
167 * Get the Id of the authenticated user
168 * @return integer The Id of the authenticated user
170 public function getAuthUserId()
172 return $this->authUserId;
176 * Set the Id of the current patient
177 * @param integer $id The Id of the current patient
178 * @return eRxSOAP This object is returned for method chaining
180 public function setPatientId($id)
182 $this->patientId = (integer) $id;
184 return $this;
188 * Get the Id of the current patient
189 * @return integer The Id of the current patient
191 public function getPatientId()
193 return $this->patientId;
197 * Generate and set a new SOAP client with provided Path Id
198 * @param integer $pathId Id for NewCrop eRx SOAP path: index [0 = Update, 1 = Patient]
199 * @return SoapClient Soap Client
201 public function initializeSoapClient($pathId)
203 $paths = $this->getGlobals()->getSoapPaths();
205 return $this->setSoapClient(new SoapClient($paths[(integer) $pathId]));
209 * Set SOAP client for communication with NewCrop
210 * @param SoapClient $client SOAP client for communication with NewCrop
211 * @return eRxSOAP This object is returned for method chaining
213 public function setSoapClient(SoapClient $client)
215 $this->soapClient = $client;
217 return $this;
221 * Get SOAP client for communication with NewCrop
222 * @return SoapClient SOAP client for communication with NewCrop
224 public function getSoapClient()
226 return $this->soapClient;
230 * Set SOAP call settings for calls to NewCrop
231 * @param array $settings [optional] Setting to send with SOAP call to NewCrop
232 * @return eRxSOAP This object is returned for method chaining
234 public function setSoapSettings($settings = array())
236 $this->soapSettings = (array) $settings;
238 return $this;
242 * Get SOAP call settings for calls to NewCrop
243 * @return array Settings to send with SOAP call to NewCrop
245 public function &getSoapSettings()
247 return $this->soapSettings;
251 * Get TTL for provided SOAP process
252 * @param string $process SOAP process to retrieve TTL for
253 * @return number|boolean Number on success, false on failure
255 public function getTTL($process)
257 switch ($process) {
258 case self::ACTION_ALLERGIES:
259 $return = $this->getGlobals()->getTTLSoapAllergies();
260 break;
261 case self::ACTION_MEDICATIONS:
262 $return = $this->getGlobals()->getTTLSoapMedications();
263 break;
264 default:
265 $return = false;
268 return $return;
272 * Check if TTL of current patient has elapsed for provided SOAP process
273 * @param string $process SOAP process to check against for elapsed TTL of current patient
274 * @return boolean True if TTL of current patient has elapsed for provided SOAP process, otherwise false
276 public function elapsedTTL($process)
278 $ttl = $this->getTTL($process);
279 if (false === $ttl || 0 == $ttl) {
280 return true;
283 $soap = $this->getStore()->getLastSOAP($process, $this->getPatientId());
284 if (false === $soap) {
285 return true;
288 return strtotime('-'.$ttl.' seconds') >= strtotime($soap);
292 * Update provided SOAP process TTL timestamp of current patient
293 * @param string $process SOAP process to update TTL of current patient
294 * @return eRxSOAP This object is returned for method chaining
296 public function updateTTL($process)
298 $this->getStore()->setLastSOAP($process, $this->getPatientId());
300 return $this;
304 * Check if import status of current patient is set to provided SOAP process(es)
305 * @param string|array $status SOAP process to check against import status of current patient, optionally an array of SOAP processes can be substituted
306 * @return boolean True if import status of current patient is set to provided SOAP process(es), otherwise false
308 public function checkPatientImportStatus($status)
310 $currentStatus = $this->getStore()
311 ->getPatientImportStatusByPatientId(
312 $this->getPatientId()
315 if (is_array($status)) {
316 $return = in_array($currentStatus, $status);
317 } else {
318 $return = ($currentStatus == $status);
321 return $return;
325 * [updatePatientImportStatus description]
326 * @param string $status SOAP process to update import status of current patient
327 * @return eRxSOAP This object is returned for method chaining
329 public function updatePatientImportStatus($status)
331 $this->getStore()
332 ->updatePatientImportStatusByPatientId(
333 $this->getPatientId(),
334 $status
337 return $this;
341 * Initialize SOAP settings with the credentials currently set
342 * @return eRxSOAP This object is returned for method chaining
344 public function initializeCredentials()
346 $credentials = $this->getGlobals()->getCredentials();
348 $this->soapSettings['credentials'] = array(
349 'PartnerName' => $credentials['0'],
350 'Name' => $credentials['1'],
351 'Password' => $credentials['2'],
354 return $this;
358 * Initialize SOAP settings with the NewCrop account and site Ids
359 * @return eRxSOAP This object is returned for method chaining
361 public function initializeAccountRequest()
363 $this->soapSettings['accountRequest'] = array(
364 'AccountId' => $this->getGlobals()->getAccountId(),
365 'SiteId' => $this->getSiteId(),
368 return $this;
372 * Initialize SOAP settings with patient information
373 * @return eRxSOAP This object is returned for method chaining
375 public function initializePatientInformationRequester()
377 $userDetails = $this->getAuthUserDetails();
379 $this->soapSettings['patientInformationRequester'] = array(
380 'UserId' => $userDetails['id'],
381 'UserType' => 'D',
384 return $this;
388 * Get account status information for current patient
389 * @return object SOAP client response from NewCrop call
391 public function getAccountStatus()
393 $this->setSoapSettings()
394 ->initializeCredentials()
395 ->initializeAccountRequest();
397 $userDetails = $this->getAuthUserDetails();
399 $this->soapSettings['locationId'] = $this->getPatientId();
400 $this->soapSettings['userId'] = $userDetails['npi'];
401 $this->soapSettings['userType'] = 'P';
403 $this->initializeSoapClient(1);
405 return $this->getSoapClient()
406 ->GetAccountStatus($this->soapSettings);
410 * Get allergy history for current patient
411 * @return object SOAP client response from NewCrop call
413 public function getPatientAllergyHistoryV3()
415 $this->setSoapSettings()
416 ->initializeCredentials()
417 ->initializeAccountRequest()
418 ->initializePatientInformationRequester();
420 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
422 $this->initializeSoapClient(0);
424 return $this->getSoapClient()
425 ->GetPatientAllergyHistoryV3($this->soapSettings);
429 * Get full medication history for current patient
430 * @return object SOAP client response from NewCrop call
432 public function getPatientFullMedicationHistory6()
434 $this->setSoapSettings()
435 ->initializeCredentials()
436 ->initializeAccountRequest()
437 ->initializePatientInformationRequester();
439 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
441 $this->soapSettings['prescriptionHistoryRequest'] = array(
442 'StartHistory' => '2011-01-01T00:00:00.000',
443 'EndHistory' => date('Y-m-d').'T23:59:59.000',
444 'PrescriptionStatus' => 'C',
445 'PrescriptionSubStatus' => '%',
446 'PrescriptionArchiveStatus' => 'N',
449 $this->soapSettings['patientIdType'] = '';
450 $this->soapSettings['includeSchema'] = '';
452 $this->initializeSoapClient(0);
454 return $this->getSoapClient()
455 ->GetPatientFullMedicationHistory6($this->soapSettings);
459 * Get free form allergy history for current patient
460 * @return object SOAP client response from NewCrop call
462 public function getPatientFreeFormAllergyHistory()
464 $this->setSoapSettings()
465 ->initializeCredentials()
466 ->initializeAccountRequest()
467 ->initializePatientInformationRequester();
469 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
471 $client = $this->initializeSoapClient(0);
473 return $this->getSoapClient()
474 ->GetPatientFreeFormAllergyHistory($this->soapSettings);
478 * Insert list option if missing and return the associated option Id
479 * @param string $listId Id of list to reference
480 * @param string $title Title text to find
481 * @return string Option Id of selected list item
483 public function insertMissingListOptions($listId, $title)
485 $store = $this->getStore();
487 $optionId = $store->selectOptionIdByTitle($listId, $title);
489 if (false === $optionId) {
490 $optionId = 1 + $store->selectOptionIdsByListId($listId);
492 $store->insertListOptions($listId, $optionId, $title);
495 return $optionId;
499 * Trigger Allergy History SOAP call to NewCrop for current patient and update local cached data
500 * @return integer Count of newly cached records
502 public function insertUpdateAllergies()
504 $store = $this->getStore();
506 $insertedRows = 0;
508 $allergyArray = self::htmlFixXmlToArray(
509 $this->getPatientAllergyHistoryV3()
510 ->GetPatientAllergyHistoryV3Result
511 ->XmlResponse
514 if (is_array($allergyArray)) {
515 foreach ($allergyArray as $allergy) {
516 $optionId = $this->insertMissingListOptions(
517 'outcome',
518 $allergy['AllergySeverityName']
521 $allergySource = $store->selectAllergyErxSourceByPatientIdName(
522 $this->getPatientId(),
523 $allergy['AllergyName']
527 if (false === $allergySource) {
528 $store->insertAllergy(
529 $allergy['AllergyName'],
530 $allergy['AllergyId'],
531 $this->getPatientId(),
532 $this->getAuthUserId(),
533 $optionId
536 ++$insertedRows;
537 } elseif (0 == $allergySource) {
538 $store->updateAllergyOutcomeExternalIdByPatientIdName(
539 $optionId,
540 $allergy['AllergyId'],
541 $this->getPatientId(),
542 $allergy['AllergyName']
544 } else {
545 $store->updateAllergyOutcomeByPatientIdExternalIdName(
546 $optionId,
547 $this->getPatientId(),
548 $allergy['AllergyId'],
549 $allergy['AllergyName']
554 $this->updatePatientAllergyEndDate($allergyArray);
557 return $insertedRows;
561 * Iterate through provided list of allergies and update records with end dates
562 * @param array $allergyArray List of allergies
563 * @return eRxSOAP This object is returned for method chaining
565 public function updatePatientAllergyEndDate($allergyArray)
567 $store = $this->getStore();
568 $patientId = $this->getPatientId();
570 $resource = $store->selectActiveAllergiesByPatientId($patientId);
572 while ($row = sqlFetchArray($resource)) {
573 $noMatch = true;
575 foreach ($allergyArray as $allergy) {
576 if (array_key_exists('AllergyName', $allergy) && $allergy['AllergyName'] == $row['title']) {
577 $noMatch = false;
578 break;
582 if ($noMatch) {
583 $store->updateAllergyEndDateByPatientIdListId(
584 $patientId,
585 $row['id']
590 return $this;
594 * Update eRx uploaded status for current patient allergies
595 * @return boolean True on success, false on failure
597 public function updateUploadedErx()
599 $patientFreeFormAllergyHistory = $this
600 ->getPatientFreeFormAllergyHistory()
601 ->GetPatientFreeFormAllergyHistoryResult;
603 if (0 < $patientFreeFormAllergyHistory->result->RowCount) {
604 $response = $patientFreeFormAllergyHistory
605 ->patientFreeFormAllergyExtendedDetail
606 ->PatientFreeFormAllergyExtendedDetail;
608 if (!is_array($response)) {
609 $response = array($response);
612 foreach ($response as $response) {
613 $this->getStore()
614 ->updateErxUploadedByListId($response->ExternalId);
618 return isset($response);
622 * Insert or update medications for current patient
623 * @return integer Count of newly cached records
625 public function insertUpdateMedications()
627 $store = $this->getStore();
629 $insertedRows = 0;
631 $medArray = self::htmlFixXmlToArray(
632 $this->getPatientFullMedicationHistory6()
633 ->GetPatientFullMedicationHistory6Result
634 ->XmlResponse
636 $store->updatePrescriptionsActiveByPatientId($this->getPatientId());
637 if (is_array($medArray)) {
638 foreach ($medArray as $med) {
639 if ($med['DosageForm']) {
640 $optionIdDosageForm = $this->insertMissingListOptions(
641 'drug_form',
642 $med['DosageForm']
644 } else {
645 $optionIdDosageForm = null;
648 if ($med['Route']) {
649 $optionIdRoute = $this->insertMissingListOptions(
650 'drug_route',
651 $med['Route']
653 } else {
654 $optionIdRoute = null;
657 if ($med['StrengthUOM']) {
658 $optionIdStrengthUOM = $this->insertMissingListOptions(
659 'drug_units',
660 $med['StrengthUOM']
662 } else {
663 $optionIdStrengthUOM = null;
666 if ($med['DosageFrequencyDescription']) {
667 $optionIdFrequencyDescription = $this->insertMissingListOptions(
668 'drug_interval',
669 $med['DosageFrequencyDescription']
671 } else {
672 $optionIdFrequencyDescription = null;
675 $providerId = $store->selectUserIdByUserName($med['ExternalPhysicianID']);
677 $check = $store->selectPrescriptionIdByGuidPatientId(
678 $med['PrescriptionGuid'],
679 $med['ExternalPatientID']
682 $prescriptionId = '';
684 if (0 == sqlNumRows($check)) {
685 $prescriptionId = $store->insertPrescriptions(
686 $med,
687 $encounter,
688 $providerId,
689 $this->getAuthUserId(),
690 $optionIdDosageForm,
691 $optionIdRoute,
692 $optionIdStrengthUOM,
693 $optionIdFrequencyDescription
696 ++$insertedRows;
698 setListTouch($this->getPatientId(), 'prescription_erx');
699 } else {
700 $store->updatePrescriptions(
701 $med,
702 $providerId,
703 $this->getAuthUserId(),
704 $optionIdDosageForm,
705 $optionIdRoute,
706 $optionIdStrengthUOM,
707 $optionIdFrequencyDescription
711 $result = sqlFetchArray($check);
712 if ($result['id']) {
713 $prescriptionId = $result['id'];
716 // Making sure only transmitted prescriptions entry added into amc_misc_data for eRx Numerator
717 if (!empty($med['PharmacyNCPDP'])) {
718 processAmcCall(
719 'e_prescribe_amc',
720 true,
721 'add',
722 $med['ExternalPatientID'],
723 'prescriptions',
724 $prescriptionId
728 if ($med['FormularyChecked'] === 'true') {
729 processAmcCall('e_prescribe_chk_formulary_amc', true, 'add', $med['ExternalPatientID'], 'prescriptions', $prescriptionId);
734 return $insertedRows;