2 // +-----------------------------------------------------------------------------+
3 // Copyright (C) 2011 Z&H Consultancy Services Private Limited <sam@zhservices.com>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
18 // A copy of the GNU General Public License is included along with this program:
19 // openemr/interface/login/GnuGPL.html
20 // For more information write to the Free Software
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 // Author: Eldho Chacko <eldho@zhservices.com>
24 // Jacob T Paul <jacob@zhservices.com>
26 // +------------------------------------------------------------------------------+
27 require_once("server_audit.php");
29 use OpenEMR\Common\Logging\EventAuditLogger
;
31 class Userforms
extends UserAudit
36 public function issue_type($data)
38 if (UserService
::valid($data[0])=='existingpatient') {
40 require_once("../../library/lists.inc");
43 throw new SoapFault("Server", "credentials failed");
49 public function print_report($data)
52 if (UserService
::valid($data[0])=='existingpatient') {
56 require_once("../../library/forms.inc");
57 require_once("../../library/pnotes.inc");
58 require_once("../../library/patient.inc");
59 require_once("../../library/options.inc.php");
60 require_once("../../library/acl.inc");
61 require_once("../../library/lists.inc");
62 require_once("../../library/report.inc");
63 require_once("../../custom/code_types.inc.php");
64 foreach ($repArr as $value) {
66 if ($type=="profile") {
67 $this->getIncudes($value);
68 $out .= ob_get_clean();
71 $this->getIid($value);
75 $this->getforms($value);
78 $out .= ob_get_clean();
84 throw new SoapFault("Server", "credentials failed");
91 public function print_ccr_report($data)
93 if (UserService
::valid($data[0])=='existingpatient') {
94 $ccraction = $data[1];
96 require_once("../../ccr/createCCR.php");
98 createCCR($ccraction, $raw);
99 $html = ob_get_clean();
100 if ($ccraction=='viewccd') {
101 $html = preg_replace('/<!DOCTYPE html PUBLIC "-\/\/W3C\/\/DTD HTML 4.01\/\/EN" "http:\/\/www.w3.org\/TR\/html4\/strict.dtd">/', '', $html);
102 $pos1 = strpos($html, 'body {');
103 $pos2 = strpos($html, '.h1center');
104 $tes = substr("$html", $pos1, ($pos2-$pos1));
105 $html = str_replace($tes, '', $html);
106 $html = str_replace('h3>', 'h2>', $html);
107 $html = base64_encode($html);
109 $pos1 = strpos($html, '*{');
110 $pos2 = strpos($html, 'h1');
111 $tes = substr("$html", $pos1, ($pos2-$pos1));
112 $html = str_replace($tes, '', $html);
117 throw new SoapFault("Server", "credentials failed");
121 //Return the forms requested from Portal.
123 private function getforms($fId)
126 $GLOBALS['pid'] = $pid;
127 $inclookupres = sqlStatement("SELECT DISTINCT formdir FROM forms WHERE pid = ? AND deleted=0", array($pid));
128 while ($result = sqlFetchArray($inclookupres)) {
129 $formdir = $result['formdir'];
130 if (substr($formdir, 0, 3) == 'LBF') {
131 include_once($GLOBALS['incdir'] . "/forms/LBF/report.php");
133 include_once($GLOBALS['incdir'] . "/forms/$formdir/report.php");
138 $inclookupres = sqlStatement("SELECT encounter,form_id,formdir,id FROM forms WHERE pid = ? AND deleted=0
139 AND id =? ", array($pid,$fId));
140 while ($result = sqlFetchArray($inclookupres)) {
141 $form_encounter=$result['encounter'];
142 $form_id=$result['form_id'];
143 $formdir = $result['formdir'];
146 if (substr($formdir, 0, 3) == 'LBF') {
147 call_user_func("lbf_report", $pid, $form_encounter, $N, $form_id, $formdir);
149 call_user_func($formdir . "_report", $pid, $form_encounter, $N, $form_id);
155 <th
><?php
echo htmlspecialchars($formdir, ENT_QUOTES
);?
></th
>
165 private function getIid($val)
169 $inclookupres = sqlStatement("SELECT DISTINCT formdir FROM forms WHERE pid = ? AND deleted=?", array($pid,0));
170 while ($result = sqlFetchArray($inclookupres)) {
171 $formdir = $result['formdir'];
172 if (substr($formdir, 0, 3) == 'LBF') {
173 include_once($GLOBALS['incdir'] . "/forms/LBF/report.php");
175 include_once($GLOBALS['incdir'] . "/forms/$formdir/report.php");
183 $irow = sqlQuery("SELECT type, title, comments, diagnosis FROM lists WHERE id =? ", array($val));
184 $diagnosis = $irow['diagnosis'];
186 if ($prevIssueType != $irow['type']) {
187 $disptype = $ISSUE_TYPES[$irow['type']][0];
189 <div
class='issue_type' style
='font-weight: bold;'><?php
echo htmlspecialchars($disptype, ENT_QUOTES
);?
>:</div
>
191 $prevIssueType = $irow['type'];
194 <div
class='text issue'>
195 <span
class='issue_title'><?php
echo htmlspecialchars($irow['title'], ENT_QUOTES
);?
>:</span
>
196 <span
class='issue_comments'><?php
echo htmlspecialchars($irow['comments'], ENT_QUOTES
);?
></span
>
200 <div
class='text issue_diag'>
201 <span
class='bold'>[<?php
echo htmlspecialchars(xl('Diagnosis'), ENT_QUOTES
);?
>]</span
><br
>
203 $dcodes = explode(";", $diagnosis);
204 foreach ($dcodes as $dcode) {
206 <span
class='italic'><?php
echo htmlspecialchars($dcode, ENT_QUOTES
);?
></span
>:
208 echo htmlspecialchars(lookup_code_descriptions($dcode), ENT_QUOTES
);
218 if ($irow['type'] == 'ippf_gcac') {
222 display_layout_rows('GCA', sqlQuery("SELECT * FROM lists_ippf_gcac WHERE id = ?", array($rowid)));
227 } else if ($irow['type'] == 'contraceptive') {
231 display_layout_rows('CON', sqlQuery("SELECT * FROM lists_ippf_con WHERE id = ?", array($rowid)));
246 private function getIncudes($val)
249 if ($val == "demographics") {
252 <div
class='text demographics' id
='DEM'>
254 // printRecDataOne($patient_data_array, getRecPatientData ($pid), $N);
255 $result1 = getPatientData($pid);
256 $result2 = getEmployerData($pid);
259 <tr
><td
><h6
><?php
echo htmlspecialchars(xl('Patient Data').":", ENT_QUOTES
);?
></h6
></td
></tr
>
261 display_layout_rows('DEM', $result1, $result2);
266 } elseif ($val == "history") {
269 <div
class='text history' id
='HIS'>
271 $result1 = getHistoryData($pid);
274 <tr
><td
><h6
><?php
echo htmlspecialchars(xl('History Data').":", ENT_QUOTES
);?
></h6
></td
></tr
>
276 display_layout_rows('HIS', $result1);
281 } elseif ($val == "insurance") {
284 <div
class='text insurance'>";
285 <h6><?php echo htmlspecialchars(xl('Insurance Data').":", ENT_QUOTES);?></h6>
286 <br><span class=bold><?php echo htmlspecialchars(xl('Primary Insurance Data').":", ENT_QUOTES);?></span><br>
288 printRecDataOne($insurance_data_array, getRecInsuranceData($pid, "primary
"), $N);
290 <span class=bold><?php echo htmlspecialchars(xl('Secondary Insurance Data').":", ENT_QUOTES);?></span><br>
292 printRecDataOne($insurance_data_array, getRecInsuranceData($pid, "secondary
"), $N);
294 <span class=bold><?php echo htmlspecialchars(xl('Tertiary Insurance Data').":", ENT_QUOTES);?></span><br>
296 printRecDataOne($insurance_data_array, getRecInsuranceData($pid, "tertiary
"), $N);
300 } elseif ($val == "billing
") {
303 <div class='text billing'>
304 <h6><?php echo htmlspecialchars(xl('Billing Information').":", ENT_QUOTES);?></h6>
306 if (count($ar['newpatient']) > 0) {
310 <tr><td width='400' class='bold'><?php echo htmlspecialchars(xl('Code'), ENT_QUOTES);?></td><td class='bold'><?php echo htmlspecialchars(xl('Fee'), ENT_QUOTES);?></td></tr>
314 foreach ($ar['newpatient'] as $be) {
315 $ta = split(":", $be);
316 $billing = getPatientBillingEncounter($pid, $ta[1]);
317 $billings[] = $billing;
318 foreach ($billing as $b) {
323 echo htmlspecialchars($b['code_type'], ENT_QUOTES) . ":\t" .htmlspecialchars($b['code'], ENT_QUOTES) . " 
;". htmlspecialchars($b['modifier'], ENT_QUOTES) . " 
; 
; 
;" . htmlspecialchars($b['code_text'], ENT_QUOTES) . " 
; 
; 
; 
; 
;";
328 echo htmlspecialchars(oeFormatMoney($b['fee']), ENT_QUOTES);
334 if ($b['code_type'] == "COPAY
") {
335 $copays += $b['fee'];
340 echo "<tr
><td
> 
;</td
></tr
>";
341 echo "<tr
><td
class=bold
>".htmlspecialchars(xl('Sub-Total'), ENT_QUOTES)."</td
><td
class=text
>" . htmlspecialchars(oeFormatMoney($total + abs($copays)), ENT_QUOTES) . "</td
></tr
>";
342 echo "<tr
><td
class=bold
>".htmlspecialchars(xl('Paid'), ENT_QUOTES)."</td
><td
class=text
>" . htmlspecialchars(oeFormatMoney(abs($copays)), ENT_QUOTES) . "</td
></tr
>";
343 echo "<tr
><td
class=bold
>".htmlspecialchars(xl('Total'), ENT_QUOTES)."</td
><td
class=text
>" .htmlspecialchars(oeFormatMoney($total), ENT_QUOTES) . "</td
></tr
>";
346 //print_r($billings);
349 printPatientBilling($pid);
352 echo "</div
>\n"; // end of billing DIV
353 } elseif ($val == "immunizations
") {
356 <div class='text immunizations'>
357 <h6><?php echo htmlspecialchars(xl('Patient Immunization').":", ENT_QUOTES);?></h6>
359 $sql = "select i1
.immunization_id
as immunization_id
, if(i1
.administered_date
,concat(i1
.administered_date
,' - ') ,substring(i1
.note
,1,20) ) as immunization_data from immunizations i1 where i1
.patient_id
= ? order by administered_date desc
";
360 $result = sqlStatement($sql, array($pid));
361 while ($row=sqlFetchArray($result)) {
362 echo htmlspecialchars($row{'immunization_data'}, ENT_QUOTES);
363 echo generate_display_field(array('data_type'=>'1','list_id'=>'immunizations'), $row['immunization_id']);
371 } elseif ($val == "batchcom
") {
374 <div class='text transactions'>
375 <h6><?php htmlspecialchars(xl('Patient Communication sent').":", ENT_QUOTES);?></h6>
377 $sql="SELECT
concat( 'Messsage Type: ', batchcom
.msg_type
, ', Message Subject: ', batchcom
.msg_subject
, ', Sent on:', batchcom
.msg_date_sent
) AS batchcom_data
, batchcom
.msg_text
, concat( users
.fname
, users
.lname
) AS user_name FROM `batchcom` JOIN `users` ON users
.id
= batchcom
.sent_by WHERE batchcom
.patient_id
=?
";
378 $result = sqlStatement($sql, array($pid));
379 while ($row=sqlFetchArray($result)) {
380 echo htmlspecialchars($row{'batchcom_data'}.", ".xl('By').": ".$row{'user_name'}, ENT_QUOTES);
382 <br><?php echo htmlspecialchars(xl('Text'), ENT_QUOTES);?>:<br><?php echo htmlspecialchars($row{'msg_txt'}, ENT_QUOTES);?><br>
388 } elseif ($val == "notes
") {
391 <div class='text notes'>
392 <h6><?php echo htmlspecialchars(xl('Patient Notes').":", ENT_QUOTES);?></h6>
394 printPatientNotes($pid);
398 } elseif ($val == "transactions
") {
401 <div class='text transactions'>
402 <h6><?php echo htmlspecialchars(xl('Patient Transactions').":", ENT_QUOTES);?></h6>
404 printPatientTransactions($pid);
412 * Method to fetch CCDA
416 public function ccdaFetching($data)
421 if (UserService::valid($data[0])=='existingpatient') {
422 if ($this->checkModuleInstalled($moduleName = 'Carecoordination')) {
423 $site_id = $data[0][0];
426 $url = $server_url . "/interface/modules
/zend_modules
/public/encounterccdadispatch
/index?cron
=1&pid
=$pid&site
=$site_id";
428 curl_setopt($ch, CURLOPT_URL, $url);
429 curl_setopt($ch, CURLOPT_COOKIEFILE, "cookiefile
");
430 curl_setopt($ch, CURLOPT_COOKIEJAR, "cookiefile
");
431 curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla
/4.0 (compatible
; MSIE
6.0; Windows NT
5.1)");
432 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
433 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
434 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
435 $result = curl_exec($ch) or die(curl_error($ch));
437 } catch (Exception $e) {
441 $event = isset($data['event']) ? $data['event'] : 'patient-record';
442 $menu_item = isset($data['menu_item']) ? $data['menu_item'] : 'Dashboard';
443 EventAuditLogger::instance()->newEvent($event, 1, '', 1, '', $pid, $log_from = 'patient-portal', $menu_item);
444 } catch (Exception $e) {
449 return '<?xml version="1.0" encoding="UTF
-8"?>
451 <heading>WARNING!</heading>
452 <body>Unable to fetch CCDA Carecoordination module not installed!</body>
456 return '<?xml version="1.0" encoding="UTF
-8"?>
458 <heading>WARNING!</heading>
459 <body>Existing patient checking failed!</body>
463 return '<?xml version="1.0" encoding="UTF
-8"?>
465 <heading>WARNING!</heading>
466 <body>Un known error occured</body>
470 public function checkModuleInstalled($moduleName = 'Carecoordination')
472 $sql = "SELECT mod_id FROM modules WHERE mod_name
= ?
AND mod_active
= '1'";
473 $res = sqlStatement($sql, array($moduleName));
474 $row = sqlFetchArray($res);
479 * @param mysql_resource - $inputArray - mysql query result
480 * @param string - $rootElementName - root element name
481 * @param string - $childElementName - child element name
483 public function arrayToXml($inputArray, $rootElementName = 'root', $childElementName = 'RowItem')
485 $xmlData = "<?xml version
=\"1.0\" encoding
=\"ISO
-8859-1\" ?
>\n";
486 $xmlData .= "<" . $rootElementName . ">";
487 foreach ($inputArray as $rowItem) {
488 $xmlData .= "<" . $childElementName . ">";
489 foreach ($rowItem as $fieldName => $fieldValue) {
490 $xmlData .= "<" . $fieldName . ">";
491 $xmlData .= !empty($fieldValue) ? $fieldValue : "null";
492 $xmlData .= "</" . $fieldName . ">";
495 $xmlData .= "</" . $childElementName . ">";
498 $xmlData .= "</" . $rootElementName . ">";
508 public function getEventLog($data)
511 if (UserService::valid($data[0])=='existingpatient') {
512 $date1 = $data['start_date'];
513 $date2 = $data['end_date'];
514 $keyword = $data['keyword'];
516 $cols = "DISTINCT log
.date
, event
, user
, groupname
, patient_id
, success
, comments
,checksum
,crt_user
";
517 $sql = "SELECT
$cols, CONCAT(fname
, ' ', lname
) as patient_ful_name
, patient_portal_menu
.`menu_name`
,
518 patient_portal_menu_group
.`menu_group_name`
, ccda_doc_id FROM log
519 JOIN patient_data ON log
.patient_id
= patient_data
.pid
520 JOIN patient_access_offsite ON log
.patient_id
= patient_access_offsite
.pid
521 JOIN patient_portal_menu ON patient_portal_menu
.`patient_portal_menu_id`
= log
.menu_item_id
522 JOIN patient_portal_menu_group ON patient_portal_menu_group
.`patient_portal_menu_group_id`
= patient_portal_menu
.`patient_portal_menu_group_id`
523 WHERE log
.date
>= ?
AND log
.date
<= ?
";
525 $sql .= " AND log_from
= 'patient-portal'";
526 $sql .= " AND patient_id
= ?
";
527 $arrBinds = array($date1 . ' 00:00:00', $date2 . ' 23:59:59', $pid);
528 if (!empty($keyword)) {
529 $sql .= " AND (log
.date LIKE ?
530 OR LOWER(event
) LIKE ?
531 OR LOWER(user
) LIKE ?
532 OR LOWER(CONCAT(fname
, ' ', lname
)) LIKE ?
533 OR LOWER(groupname
) LIKE ?
534 OR LOWER(comments
) LIKE ?
535 OR LOWER(user
) LIKE ?
537 $arrBinds[] = '%' . $keyword . '%' ;
538 $arrBinds[] = '%' . strtolower($keyword) . '%';
539 $arrBinds[] = '%' . strtolower($keyword) . '%';
540 $arrBinds[] = '%' . strtolower($keyword) . '%';
541 $arrBinds[] = '%' . strtolower($keyword) . '%';
542 $arrBinds[] = '%' . strtolower($keyword) . '%';
543 $arrBinds[] = '%' . strtolower($keyword) . '%';
546 $sql .= " ORDER BY date DESC LIMIT
5000";
548 $res = sqlStatement($sql, $arrBinds);
550 for ($iter=0; $row=sqlFetchArray($res); $iter++) {
554 $responseString = $this->arrayToXml($all);
556 return $responseString;
561 * Connect to a phiMail Direct Messaging server and transmit
562 * a CCD document to the specified recipient. If the message is accepted by the
563 * server, the script will return "SUCCESS
", otherwise it will return an error msg.
564 * @param DOMDocument ccd the xml data to transmit, a CCDA document is assumed
565 * @param string recipient the Direct Address of the recipient
566 * @param string requested_by user | patient
567 * @return string result of operation
569 function transmitCCD($data = array())
572 $recipient = $data['recipient'];
573 $requested_by = $data['requested_by'];
574 $xml_type = $data['xml_type'];
576 if (UserService::valid($data[0])=='existingpatient') {
578 $_SESSION['authProvider'] = 1;
580 //get patient name in Last_First format (used for CCDA filename) and
581 //First Last for the message text.
582 $patientData = getPatientPID(array("pid
"=>$pid));
583 if (empty($patientData[0]['lname'])) {
587 //spaces are the argument delimiter for the phiMail API calls and must be removed
588 $extension = $xml_type == 'CCDA' ? 'xml' : strtolower($xml_type);
589 $att_filename = " " .
590 str_replace(" ", "_
", $xml_type . "_
" . $patientData[0]['lname']
591 . "_
" . $patientData[0]['fname']) . "." . $extension;
592 $patientName2 = $patientData[0]['fname'] . " " . $patientData[0]['lname'];
595 $config_err = xl("Direct messaging is currently unavailable
.")." EC
:";
596 if ($GLOBALS['phimail_enable']==false) {
597 return("$config_err 1");
600 $fp = phimail_connect($err);
602 return("$config_err $err");
605 $phimail_username = $GLOBALS['phimail_username'];
606 $phimail_password = decryptStandard($GLOBALS['phimail_password']);
607 $ret = phimail_write_expect_OK($fp, "AUTH
$phimail_username $phimail_password\n");
609 return("$config_err 4");
612 $ret = phimail_write_expect_OK($fp, "TO
$recipient\n");
614 return( xl("Delivery is not allowed to the specified Direct Address
.") );
617 $ret=fgets($fp, 1024); //ignore extra server data
619 if ($requested_by=="patient
") {
620 $text_out = xl("Delivery of the attached clinical document was requested by the patient
") .
621 ($patientName2=="" ? "." : ", " . $patientName2 . ".");
623 $text_out = xl("A clinical document is attached
") .
624 ($patientName2=="" ? "." : " " . xl("for patient
") . " " . $patientName2 . ".");
627 $text_len=strlen($text_out);
628 phimail_write($fp, "TEXT
$text_len\n");
629 $ret=@fgets($fp, 256);
631 if ($ret!="BEGIN\n
") {
633 return("$config_err 5");
636 $ret=phimail_write_expect_OK($fp, $text_out);
638 return("$config_err 6");
641 if (in_array($xml_type, array('CCR', 'CCDA', 'CDA'))) {
642 $ccd = simplexml_load_string($ccd);
643 $ccd_out = $ccd->saveXml();
644 $ccd_len = strlen($ccd_out);
645 phimail_write($fp, "ADD
" . ($xml_type=="CCR
" ? $xml_type . ' ' : "CDA
") . $ccd_len . $att_filename . "\n
");
646 //phimail_write($fp,"ADD
" . (isset($xml_type) ? $xml_type . ' ' : "CDA
") . $ccd_len . $att_filename . "\n
");
647 } else if (strtolower($xml_type) == 'html' || strtolower($xml_type) == 'pdf') {
648 $ccd_out = base64_decode($ccd);
649 $message_length = strlen($ccd_out);
650 $add_type = (strtolower($xml_type) == 'html') ? 'TEXT' : 'RAW';
651 phimail_write($fp, "ADD
" . $add_type . " " . $message_length . "" . $att_filename . "\n
");
655 $ret=fgets($fp, 256);
657 if ($ret!="BEGIN\n
") {
659 return("$config_err 7");
662 $ret=phimail_write_expect_OK($fp, $ccd_out);
665 return("$config_err 8");
669 phimail_write($fp, "SEND\n
");
670 $ret=fgets($fp, 256);
673 if ($requested_by=="patient
") {
674 $reqBy="portal
-user
";
675 $sql = "SELECT id FROM users WHERE username
='portal-user'";
677 if (($r = sqlStatement($sql)) === false ||
678 ($u = sqlFetchArray($r)) === false) {
679 $reqID = 1; //default if we don't have a service user
684 $reqBy=$_SESSION['authUser'];
685 $reqID=$_SESSION['authUserID'];
688 if (substr($ret, 5)=="ERROR
") {
690 EventAuditLogger::instance()->newEvent("transmit
-ccd
", $reqBy, $_SESSION['authProvider'], 0, $ret, $pid);
691 return( xl("The message could not be sent at this time
."));
695 * If we get here, the message was successfully sent and the return
696 * value $ret is of the form "QUEUED recipient message
-id
" which
697 * is suitable for logging.
699 $msg_id=explode(" ", trim($ret), 4);
700 if ($msg_id[0]!="QUEUED
" || !isset($msg_id[2])) { //unexpected response
701 $ret = "UNEXPECTED RESPONSE
: " . $ret;
702 EventAuditLogger::instance()->newEvent("transmit
-ccd
", $reqBy, $_SESSION['authProvider'], 0, $ret, $pid);
703 return( xl("There was a problem sending the message
."));
706 EventAuditLogger::instance()->newEvent("transmit
-".$xml_type, $reqBy, $_SESSION['authProvider'], 1, $ret, $pid);
707 $adodb=$GLOBALS['adodb']['db'];
709 // $sql="INSERT INTO
direct_message_log (msg_type
,msg_id
,sender
,recipient
,status
,status_ts
,patient_id
,user_id
) " .
710 // "VALUES ('S', ?
, ?
, ?
, 'S', NOW(), ?
, ?
)";
711 // $res=@sqlStatement($sql,array($msg_id[2],$phimail_username,$recipient,$pid,$reqID));
714 } catch (Exception $e) {
715 return 'Error: ' . $e->getMessage();