put adj group codes on same line for 2ndary claims (#1959)
[openemr.git] / interface / eRxSOAP.php
blob10491df8473636030f258ad3103f4bc6517df23c
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
27 const ACTION_ALLERGIES = 'allergies';
28 const ACTION_MEDICATIONS = 'medications';
30 const FLAG_PRESCRIPTION_PRESS = '1';
31 const FLAG_PRESCRIPTION_IMPORT = '2';
32 const FLAG_ALLERGY_PRESS = '3';
33 const FLAG_ALLERGY_IMPORT = '4';
35 private $globals;
36 private $store;
38 private $authUserId;
39 private $authUserDetails;
40 private $patientId;
41 private $soapClient;
42 private $soapSettings = array();
43 private $siteId;
45 /**
46 * Repair HTML/XML and return array
47 * @param string $xml XML for processing
48 * @return array|boolean Array on success, false on failure
50 public static function htmlFixXmlToArray($xml)
52 $xmltoarray = new xmltoarray_parser_htmlfix(); //create instance of class
54 $xmltoarray->xmlparser_setoption(XML_OPTION_SKIP_WHITE, 1); //set options same as xml_parser_set_option
55 $xmltoarray->xmlparser_setoption(XML_OPTION_CASE_FOLDING, 0);
57 $xmltoarray->xmlparser_fix_into_struct(base64_decode($xml)); //fixes html values for XML
59 $array = $xmltoarray->createArray(); //creates an array with fixed html values
61 foreach ($array as $key => $value) {
62 $array[$key] = $xmltoarray->fix_html_entities($value); //returns proper html values
65 if (array_key_exists('NewDataSet', $array) && array_key_exists('Table', $array['NewDataSet'])) {
66 $array = $array['NewDataSet']['Table'];
67 } else {
68 $array = false;
71 return $array;
74 /**
75 * Set Globals for retrieving eRx global configurations
76 * @param object $globals The eRx Globals object to use for processing
77 * @return eRxPage This object is returned for method chaining
79 public function setGlobals($globals)
81 $this->globals = $globals;
83 return $this;
86 /**
87 * Get Globals for retrieving eRx global configurations
88 * @return object The eRx Globals object to use for processing
90 public function getGlobals()
92 return $this->globals;
95 /**
96 * Set Store to handle eRx cashed data
97 * @param object $store The eRx Store object to use for processing
98 * @return eRxSOAP This object is returned for method chaining
100 public function setStore($store)
102 $this->store = $store;
104 return $this;
108 * Get Store for handling eRx cashed data
109 * @return object The eRx Store object to use for processing
111 public function getStore()
113 return $this->store;
117 * Get Account Id set for SOAP communications with NewCrop
118 * @return string The Account Id sent with SOAP requests to NewCrop
120 public function getAccountId()
122 return $this->getGlobals()->getAccountId();
126 * Set SiteId for SOAP communications with NewCrop
127 * @param string $id The Site Id to send with SOAP requests to NewCrop
128 * @return eRxSOAP This object is returned for method chaining
130 public function setSiteId($id)
132 $this->siteId = $id;
134 return $this;
138 * Get Site Id set for SOAP communications with NewCrop
139 * @return string The Site Id sent with SOAP requests to NewCrop
141 public function getSiteId()
143 if (null === $this->siteId) {
144 $this->siteId = $this->getStore()
145 ->selectFederalEin();
148 return $this->siteId;
152 * Get the authenticated users ID and NPI
153 * @return array The users ID and NPI
155 public function getAuthUserDetails()
157 if (null === $this->authUserDetails) {
158 $this->authUserDetails = $this->getStore()
159 ->getUserById($this->getAuthUserId());
162 return $this->authUserDetails;
166 * Set the Id of the authenticated user
167 * @param integer $user The Id for the authenticated user
168 * @return eRxSOAP This object is returned for method chaining
170 public function setAuthUserId($user)
172 $this->authUserId = $user;
174 return $this;
178 * Get the Id of the authenticated user
179 * @return integer The Id of the authenticated user
181 public function getAuthUserId()
183 return $this->authUserId;
187 * Set the Id of the current patient
188 * @param integer $id The Id of the current patient
189 * @return eRxSOAP This object is returned for method chaining
191 public function setPatientId($id)
193 $this->patientId = (integer) $id;
195 return $this;
199 * Get the Id of the current patient
200 * @return integer The Id of the current patient
202 public function getPatientId()
204 return $this->patientId;
208 * Generate and set a new SOAP client with provided Path Id
209 * @param integer $pathId Id for NewCrop eRx SOAP path: index [0 = Update, 1 = Patient]
210 * @return SoapClient Soap Client
212 public function initializeSoapClient($pathId)
214 $paths = $this->getGlobals()->getSoapPaths();
216 return $this->setSoapClient(new SoapClient($paths[(integer) $pathId]));
220 * Set SOAP client for communication with NewCrop
221 * @param SoapClient $client SOAP client for communication with NewCrop
222 * @return eRxSOAP This object is returned for method chaining
224 public function setSoapClient(SoapClient $client)
226 $this->soapClient = $client;
228 return $this;
232 * Get SOAP client for communication with NewCrop
233 * @return SoapClient SOAP client for communication with NewCrop
235 public function getSoapClient()
237 return $this->soapClient;
241 * Set SOAP call settings for calls to NewCrop
242 * @param array $settings [optional] Setting to send with SOAP call to NewCrop
243 * @return eRxSOAP This object is returned for method chaining
245 public function setSoapSettings($settings = array())
247 $this->soapSettings = (array) $settings;
249 return $this;
253 * Get SOAP call settings for calls to NewCrop
254 * @return array Settings to send with SOAP call to NewCrop
256 public function &getSoapSettings()
258 return $this->soapSettings;
262 * Get TTL for provided SOAP process
263 * @param string $process SOAP process to retrieve TTL for
264 * @return number|boolean Number on success, false on failure
266 public function getTTL($process)
268 switch ($process) {
269 case self::ACTION_ALLERGIES:
270 $return = $this->getGlobals()->getTTLSoapAllergies();
271 break;
272 case self::ACTION_MEDICATIONS:
273 $return = $this->getGlobals()->getTTLSoapMedications();
274 break;
275 default:
276 $return = false;
279 return $return;
283 * Check if TTL of current patient has elapsed for provided SOAP process
284 * @param string $process SOAP process to check against for elapsed TTL of current patient
285 * @return boolean True if TTL of current patient has elapsed for provided SOAP process, otherwise false
287 public function elapsedTTL($process)
289 $ttl = $this->getTTL($process);
290 if (false === $ttl || 0 == $ttl) {
291 return true;
294 $soap = $this->getStore()->getLastSOAP($process, $this->getPatientId());
295 if (false === $soap) {
296 return true;
299 return strtotime('-'.$ttl.' seconds') >= strtotime($soap);
303 * Update provided SOAP process TTL timestamp of current patient
304 * @param string $process SOAP process to update TTL of current patient
305 * @return eRxSOAP This object is returned for method chaining
307 public function updateTTL($process)
309 $this->getStore()->setLastSOAP($process, $this->getPatientId());
311 return $this;
315 * Check if import status of current patient is set to provided SOAP process(es)
316 * @param string|array $status SOAP process to check against import status of current patient, optionally an array of SOAP processes can be substituted
317 * @return boolean True if import status of current patient is set to provided SOAP process(es), otherwise false
319 public function checkPatientImportStatus($status)
321 $currentStatus = $this->getStore()
322 ->getPatientImportStatusByPatientId(
323 $this->getPatientId()
326 if (is_array($status)) {
327 $return = in_array($currentStatus, $status);
328 } else {
329 $return = ($currentStatus == $status);
332 return $return;
336 * [updatePatientImportStatus description]
337 * @param string $status SOAP process to update import status of current patient
338 * @return eRxSOAP This object is returned for method chaining
340 public function updatePatientImportStatus($status)
342 $this->getStore()
343 ->updatePatientImportStatusByPatientId(
344 $this->getPatientId(),
345 $status
348 return $this;
352 * Initialize SOAP settings with the credentials currently set
353 * @return eRxSOAP This object is returned for method chaining
355 public function initializeCredentials()
357 $credentials = $this->getGlobals()->getCredentials();
359 $this->soapSettings['credentials'] = array(
360 'PartnerName' => $credentials['0'],
361 'Name' => $credentials['1'],
362 'Password' => $credentials['2'],
365 return $this;
369 * Initialize SOAP settings with the NewCrop account and site Ids
370 * @return eRxSOAP This object is returned for method chaining
372 public function initializeAccountRequest()
374 $this->soapSettings['accountRequest'] = array(
375 'AccountId' => $this->getGlobals()->getAccountId(),
376 'SiteId' => $this->getSiteId(),
379 return $this;
383 * Initialize SOAP settings with patient information
384 * @return eRxSOAP This object is returned for method chaining
386 public function initializePatientInformationRequester()
388 $userDetails = $this->getAuthUserDetails();
390 $this->soapSettings['patientInformationRequester'] = array(
391 'UserId' => $userDetails['id'],
392 'UserType' => 'D',
395 return $this;
399 * Get account status information for current patient
400 * @return object SOAP client response from NewCrop call
402 public function getAccountStatus()
404 $this->setSoapSettings()
405 ->initializeCredentials()
406 ->initializeAccountRequest();
408 $userDetails = $this->getAuthUserDetails();
410 $this->soapSettings['locationId'] = $this->getPatientId();
411 $this->soapSettings['userId'] = $userDetails['npi'];
412 $this->soapSettings['userType'] = 'P';
414 $this->initializeSoapClient(1);
416 return $this->getSoapClient()
417 ->GetAccountStatus($this->soapSettings);
421 * Get allergy history for current patient
422 * @return object SOAP client response from NewCrop call
424 public function getPatientAllergyHistoryV3()
426 $this->setSoapSettings()
427 ->initializeCredentials()
428 ->initializeAccountRequest()
429 ->initializePatientInformationRequester();
431 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
433 $this->initializeSoapClient(0);
435 return $this->getSoapClient()
436 ->GetPatientAllergyHistoryV3($this->soapSettings);
440 * Get full medication history for current patient
441 * @return object SOAP client response from NewCrop call
443 public function getPatientFullMedicationHistory6()
445 $this->setSoapSettings()
446 ->initializeCredentials()
447 ->initializeAccountRequest()
448 ->initializePatientInformationRequester();
450 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
452 $this->soapSettings['prescriptionHistoryRequest'] = array(
453 'StartHistory' => '2011-01-01T00:00:00.000',
454 'EndHistory' => date('Y-m-d').'T23:59:59.000',
455 'PrescriptionStatus' => 'C',
456 'PrescriptionSubStatus' => '%',
457 'PrescriptionArchiveStatus' => 'N',
460 $this->soapSettings['patientIdType'] = '';
461 $this->soapSettings['includeSchema'] = '';
463 $this->initializeSoapClient(0);
465 return $this->getSoapClient()
466 ->GetPatientFullMedicationHistory6($this->soapSettings);
470 * Get free form allergy history for current patient
471 * @return object SOAP client response from NewCrop call
473 public function getPatientFreeFormAllergyHistory()
475 $this->setSoapSettings()
476 ->initializeCredentials()
477 ->initializeAccountRequest()
478 ->initializePatientInformationRequester();
480 $this->soapSettings['patientRequest']['PatientId'] = $this->getPatientId();
482 $client = $this->initializeSoapClient(0);
484 return $this->getSoapClient()
485 ->GetPatientFreeFormAllergyHistory($this->soapSettings);
489 * Insert list option if missing and return the associated option Id
490 * @param string $listId Id of list to reference
491 * @param string $title Title text to find
492 * @return string Option Id of selected list item
494 public function insertMissingListOptions($listId, $title)
496 $store = $this->getStore();
498 $optionId = $store->selectOptionIdByTitle($listId, $title);
500 if (false === $optionId) {
501 $optionId = 1 + $store->selectOptionIdsByListId($listId);
503 $store->insertListOptions($listId, $optionId, $title);
506 return $optionId;
510 * Trigger Allergy History SOAP call to NewCrop for current patient and update local cached data
511 * @return integer Count of newly cached records
513 public function insertUpdateAllergies()
515 $store = $this->getStore();
517 $insertedRows = 0;
519 $allergyArray = self::htmlFixXmlToArray(
520 $this->getPatientAllergyHistoryV3()
521 ->GetPatientAllergyHistoryV3Result
522 ->XmlResponse
525 if (is_array($allergyArray)) {
526 foreach ($allergyArray as $allergy) {
527 $optionId = $this->insertMissingListOptions(
528 'outcome',
529 $allergy['AllergySeverityName']
532 $allergySource = $store->selectAllergyErxSourceByPatientIdName(
533 $this->getPatientId(),
534 $allergy['AllergyName']
538 if (false === $allergySource) {
539 $store->insertAllergy(
540 $allergy['AllergyName'],
541 $allergy['AllergyId'],
542 $this->getPatientId(),
543 $this->getAuthUserId(),
544 $optionId
547 ++$insertedRows;
548 } elseif (0 == $allergySource) {
549 $store->updateAllergyOutcomeExternalIdByPatientIdName(
550 $optionId,
551 $allergy['AllergyId'],
552 $this->getPatientId(),
553 $allergy['AllergyName']
555 } else {
556 $store->updateAllergyOutcomeByPatientIdExternalIdName(
557 $optionId,
558 $this->getPatientId(),
559 $allergy['AllergyId'],
560 $allergy['AllergyName']
565 $this->updatePatientAllergyEndDate($allergyArray);
568 return $insertedRows;
572 * Iterate through provided list of allergies and update records with end dates
573 * @param array $allergyArray List of allergies
574 * @return eRxSOAP This object is returned for method chaining
576 public function updatePatientAllergyEndDate($allergyArray)
578 $store = $this->getStore();
579 $patientId = $this->getPatientId();
581 $resource = $store->selectActiveAllergiesByPatientId($patientId);
583 while ($row = sqlFetchArray($resource)) {
584 $noMatch = true;
586 foreach ($allergyArray as $allergy) {
587 if (array_key_exists('AllergyName', $allergy) && $allergy['AllergyName'] == $row['title']) {
588 $noMatch = false;
589 break;
593 if ($noMatch) {
594 $store->updateAllergyEndDateByPatientIdListId(
595 $patientId,
596 $row['id']
601 return $this;
605 * Update eRx uploaded status for current patient allergies
606 * @return boolean True on success, false on failure
608 public function updateUploadedErx()
610 $patientFreeFormAllergyHistory = $this
611 ->getPatientFreeFormAllergyHistory()
612 ->GetPatientFreeFormAllergyHistoryResult;
614 if (0 < $patientFreeFormAllergyHistory->result->RowCount) {
615 $response = $patientFreeFormAllergyHistory
616 ->patientFreeFormAllergyExtendedDetail
617 ->PatientFreeFormAllergyExtendedDetail;
619 if (!is_array($response)) {
620 $response = array($response);
623 foreach ($response as $response) {
624 $this->getStore()
625 ->updateErxUploadedByListId($response->ExternalId);
629 return isset($response);
633 * Insert or update medications for current patient
634 * @return integer Count of newly cached records
636 public function insertUpdateMedications()
638 $store = $this->getStore();
640 $insertedRows = 0;
642 $medArray = self::htmlFixXmlToArray(
643 $this->getPatientFullMedicationHistory6()
644 ->GetPatientFullMedicationHistory6Result
645 ->XmlResponse
647 $store->updatePrescriptionsActiveByPatientId($this->getPatientId());
648 if (is_array($medArray)) {
649 foreach ($medArray as $med) {
650 if ($med['DosageForm']) {
651 $optionIdDosageForm = $this->insertMissingListOptions(
652 'drug_form',
653 $med['DosageForm']
655 } else {
656 $optionIdDosageForm = null;
659 if ($med['Route']) {
660 $optionIdRoute = $this->insertMissingListOptions(
661 'drug_route',
662 $med['Route']
664 } else {
665 $optionIdRoute = null;
668 if ($med['StrengthUOM']) {
669 $optionIdStrengthUOM = $this->insertMissingListOptions(
670 'drug_units',
671 $med['StrengthUOM']
673 } else {
674 $optionIdStrengthUOM = null;
677 if ($med['DosageFrequencyDescription']) {
678 $optionIdFrequencyDescription = $this->insertMissingListOptions(
679 'drug_interval',
680 $med['DosageFrequencyDescription']
682 } else {
683 $optionIdFrequencyDescription = null;
686 $providerId = $store->selectUserIdByUserName($med['ExternalPhysicianID']);
688 $check = $store->selectPrescriptionIdByGuidPatientId(
689 $med['PrescriptionGuid'],
690 $med['ExternalPatientID']
693 $prescriptionId = '';
695 if (0 == sqlNumRows($check)) {
696 $prescriptionId = $store->insertPrescriptions(
697 $med,
698 $encounter,
699 $providerId,
700 $this->getAuthUserId(),
701 $optionIdDosageForm,
702 $optionIdRoute,
703 $optionIdStrengthUOM,
704 $optionIdFrequencyDescription
707 ++$insertedRows;
709 setListTouch($this->getPatientId(), 'prescription_erx');
710 } else {
711 $store->updatePrescriptions(
712 $med,
713 $providerId,
714 $this->getAuthUserId(),
715 $optionIdDosageForm,
716 $optionIdRoute,
717 $optionIdStrengthUOM,
718 $optionIdFrequencyDescription
722 $result = sqlFetchArray($check);
723 if ($result['id']) {
724 $prescriptionId = $result['id'];
727 // Making sure only transmitted prescriptions entry added into amc_misc_data for eRx Numerator
728 if (!empty($med['PharmacyNCPDP'])) {
729 processAmcCall(
730 'e_prescribe_amc',
731 true,
732 'add',
733 $med['ExternalPatientID'],
734 'prescriptions',
735 $prescriptionId
739 if ($med['FormularyChecked'] === 'true') {
740 processAmcCall('e_prescribe_chk_formulary_amc', true, 'add', $med['ExternalPatientID'], 'prescriptions', $prescriptionId);
745 return $insertedRows;