From fd4bc8adb4361d8410786704fb2b991fe4984ed6 Mon Sep 17 00:00:00 2001 From: Stephen Nielson Date: Tue, 2 Jul 2024 21:26:02 -0600 Subject: [PATCH] Feat openemr fix 7480 7494 email prescription (#7495) * Prep template to be moved to twig * #7480 #7494 email prescriptions This supports sending a prescription as a pdf to an email address, sending the prescription inline as a formatted html email, and sending the prescription in the native mail client using the mailto: protocol. Mailto: doesn't support email attachments so the pdf option currently doesn't work with this. When the Default Mail Client is selected (#7494) then the mailto link is generated and if the browser or operating system has a mailto: protocol handler setup it will launch the registered handler with the subject and email body populated. * Initial refactor to make edit page extensible * Fixes #7496 move erx general edit to twig Made it so the edit prescription dialog is in twig instead of in the old html format. This fixes #7496. I've done some testing but probably need to do more testing to verify we've handled all the use cases. * Form save button position, bug fixes Fixed a bug in the eye base where the window closing wasn't working properly. Moved the prescription action buttons out of the demographics.php file and put them directly into the prescription dialog forms. This helps fix some UX buttons flow issues as well as allows us to move the buttons around as needed in the form. Added a feature to have the form buttons on top of the form or on the bottom. Tried to have an option to show both top and bottom but that fails in demographics. I put the option in the demographics as well as in the prescriptions form. Hopefully other forms will follow suite and allow the customization. * Fix escaping issue. * Not sure how this got left out but it did. * Fixes #7525, #7524 prescription faxing Made it so the prescription pdf faxing button will ask you to continue printing if the signature isn't setup properly (at least to let users know about it). Fixes #7525. Fixed some php8 typecast errors preventing the pdf signature from printing in the print to fax button for prescriptions. #7525. * Switch to promise for erx dialog * Handling variable escaping. * Mark deprecated function --- controllers/C_Prescription.class.php | 430 ++++++++++----- interface/forms/eye_mag/js/eye_base.php | 12 +- interface/patient_file/encounter/coding.php | 1 + .../patient_file/summary/demographics.php | 52 +- .../summary/demographics_full.php | 24 + library/globals.inc.php | 14 + src/Common/Forms/FormActionBarSettings.php | 37 ++ ...neral_edit.html => general_edit.html.twig} | 287 ++++++---- templates/prescription/general_list.html | 316 ----------- templates/prescription/general_list.html.twig | 520 ++++++++++++++++++ 10 files changed, 1058 insertions(+), 635 deletions(-) create mode 100644 src/Common/Forms/FormActionBarSettings.php rename templates/prescription/{general_edit.html => general_edit.html.twig} (52%) delete mode 100644 templates/prescription/general_list.html create mode 100644 templates/prescription/general_list.html.twig diff --git a/controllers/C_Prescription.class.php b/controllers/C_Prescription.class.php index c264f79cb66..b2a34107ed8 100644 --- a/controllers/C_Prescription.class.php +++ b/controllers/C_Prescription.class.php @@ -18,9 +18,12 @@ require_once($GLOBALS['fileroot'] . "/library/amc.php"); use OpenEMR\Common\Csrf\CsrfUtils; +use OpenEMR\Common\Forms\FormActionBarSettings; use OpenEMR\Common\Http\oeHttp; use OpenEMR\Rx\RxList; use PHPMailer\PHPMailer\PHPMailer; +use OpenEMR\Common\Database\QueryUtils; +use OpenEMR\Common\Twig\TwigContainer; class C_Prescription extends Controller { @@ -36,7 +39,6 @@ function __construct($template_mod = "general") { parent::__construct(); $this->template_mod = $template_mod; - $this->assign("FORM_ACTION", $GLOBALS['webroot'] . "/controller.php?" . attr($_SERVER['QUERY_STRING'])); $this->assign("TOP_ACTION", $GLOBALS['webroot'] . "/controller.php?" . "prescription" . "&"); $this->assign("STYLE", $GLOBALS['style']); $this->assign("WEIGHT_LOSS_CLINIC", $GLOBALS['weight_loss_clinic']); @@ -100,8 +102,21 @@ function __construct($template_mod = "general") function default_action() { - $this->assign("prescription", $this->prescriptions[0]); - $this->display($GLOBALS['template_dir'] . "prescription/" . $this->template_mod . "_edit.html"); + $prescription = $this->prescriptions[0]; + $this->assign("prescription", $prescription); + $vars = $this->getTemplateVars(); + $vars['enable_amc_prompting'] = $GLOBALS['enable_amc_prompting'] ?? false; + $vars['weno_rx_enable'] = $GLOBALS['weno_rx_enable'] ?? false; + $vars['topActionBarDisplay'] = FormActionBarSettings::shouldDisplayTopActionBar(); + $vars['bottomActionBarDisplay'] = FormActionBarSettings::shouldDisplayBottomActionBar(); + + if ($GLOBALS['enable_amc_prompting']) { + $vars['amcCollectReturnFlag'] = amcCollect('e_prescribe_amc', $prescription->patient->id, 'prescriptions', $prescription->id); + $vars['amcCollectReturnFormulary'] = amcCollect('e_prescribe_chk_formulary_amc', $prescription->patient->id, 'prescriptions', $prescription->id); + $vars['amcCollectReturnControlledSubstances'] = amcCollect('e_prescribe_cont_subst_amc', $prescription->patient->id, 'prescriptions', $prescription->id); + } + $twig = (new TwigContainer(null, $GLOBALS['kernel']))->getTwig(); + echo $twig->render("prescription/" . $this->template_mod . "_edit.html.twig", $vars); } function edit_action($id = "", $patient_id = "", $p_obj = null) @@ -189,7 +204,25 @@ function list_action($id, $sort = "") // flag to indicate the CAMOS form is regsitered and active $this->assign("CAMOS_FORM", isRegistered("CAMOS")); - $this->display($GLOBALS['template_dir'] . "prescription/" . $this->template_mod . "_list.html"); + $vars = $this->getTemplateVars(); + $vars['pid'] = $id; + $vars['rx_send_email'] = $GLOBALS['rx_send_email'] ?? false; + $vars['rx_show_drug_drug'] = $GLOBALS['rx_show_drug_drug'] ?? false; + $vars['rx_zend_pdf_template'] = $GLOBALS['rx_zend_pdf_template'] ?? false; + $vars['baseModDir'] = $GLOBALS['baseModDir'] ?? ''; + $vars['zendModDir'] = $GLOBALS['zendModDir'] ?? ''; + $vars['printm'] = null; // TODO: figure out where printm is used or defined + $vars['rx_zend_pdf_action'] = $GLOBALS['rx_zend_pdf_action'] ?? ''; + $vars['rx_zend_html_template'] = $GLOBALS['rx_zend_html_template'] ?? ''; + $vars['rx_zend_html_action'] = $GLOBALS['rx_zend_pdf_action'] ?? ''; + $vars['rx_use_fax_template'] = $GLOBALS['rx_use_fax_template'] ?? ''; + $vars['rx_send_email'] = $GLOBALS['rx_send_email'] ?? false; + $vars['faxSignatureMissing'] = false; + if (!($this->pconfig['use_signature'] && $this->current_user_has_signature())) { + $vars['faxSignatureMissing'] = true; + } + $twig = (new TwigContainer(null, $GLOBALS['kernel']))->getTwig(); + echo $twig->render("prescription/" . $this->template_mod . "_list.html.twig", $vars); } function block_action($id, $sort = "") @@ -209,6 +242,14 @@ function block_action($id, $sort = "") $this->display($GLOBALS['template_dir'] . "prescription/" . $this->template_mod . "_block.html"); } + /** + * TODO: remove this function in a future expansion. + * @deprecated As far as we can see this function isn't used + * @param $id + * @param $sort + * @return void + * @throws SmartyException + */ function fragment_action($id, $sort = "") { if (empty($id)) { @@ -228,6 +269,7 @@ function fragment_action($id, $sort = "") function lookup_action() { + $this->assign("FORM_ACTION", $GLOBALS['webroot'] . "/controller.php?" . attr($_SERVER['QUERY_STRING'])); $this->do_lookup(); $this->display($GLOBALS['template_dir'] . "prescription/" . $this->template_mod . "_lookup.html"); } @@ -297,39 +339,10 @@ function edit_action_process() processAmcCall('e_prescribe_cont_subst_amc', true, 'remove', $this->prescriptions[0]->get_patient_id(), 'prescriptions', $this->prescriptions[0]->id); } -// TajEmo Work by CB 2012/05/29 02:58:29 PM to stop from going to send screen. Improves Work Flow -// if ($this->prescriptions[0]->get_active() > 0) { -// return $this->send_action($this->prescriptions[0]->id); -// } $this->list_action($this->prescriptions[0]->get_patient_id()); exit; } - function send_action($id) - { - $_POST['process'] = "true"; - if (empty($id)) { - $this->function_argument_error(); - } - - $rx = new Prescription($id); - // Populate pharmacy info if the patient has a default pharmacy. - // Probably the Prescription object should handle this instead, but - // doing it there will require more careful research and testing. - $prow = sqlQuery("SELECT pt.pharmacy_id FROM prescriptions AS rx, " . - "patient_data AS pt WHERE rx.id = ? AND pt.pid = rx.patient_id", [$id]); - if ($prow['pharmacy_id']) { - $rx->pharmacy->set_id($prow['pharmacy_id']); - $rx->pharmacy->populate(); - } - - $this->assign("prescription", $rx); - - $this->_state = false; - return $this->fetch($GLOBALS['template_dir'] . "prescription/" . - $this->template_mod . "_send.html"); - } - function multiprintfax_header(&$pdf, $p) { return $this->multiprint_header($pdf, $p); @@ -551,14 +564,29 @@ function multiprintfax_footer(&$pdf) return $this->multiprint_footer($pdf); } + function current_user_has_signature() + { + if (!empty($this->pconfig['signature'])) { + $sigfile = str_replace('{userid}', $_SESSION["authUser"], $this->pconfig['signature']); + if (file_exists($sigfile)) { + return true; + } + } + return false; + } + function multiprint_footer(&$pdf) { - if ($this->pconfig['use_signature'] && ( $this->is_faxing || $this->is_print_to_fax )) { + if ( + $this->pconfig['use_signature'] + && $this->current_user_has_signature() + && ( $this->is_faxing || $this->is_print_to_fax ) + ) { $sigfile = str_replace('{userid}', $_SESSION["authUser"], $this->pconfig['signature']); if (file_exists($sigfile)) { $pdf->ezText(xl('Signature') . ": ", 12); - // $pdf->ezImage($sigfile, "", "", "none", "left"); - $pdf->ezImage($sigfile, "", "", "none", "center"); + $width = 0; // set to 0 so it uses the image width + $pdf->ezImage($sigfile, null, 0, "none", "center"); $pdf->ezText(xl('Date') . ": " . date('Y-m-d'), 12); if ($this->is_print_to_fax) { $pdf->ezText(xl('Please do not accept this prescription unless it was received via facsimile.')); @@ -688,40 +716,157 @@ function multiprint_action($id = "") $this->function_argument_error(); } - $pdf = new Cezpdf($GLOBALS['rx_paper_size']); - $pdf->ezSetMargins($GLOBALS['rx_top_margin'], $GLOBALS['rx_bottom_margin'], $GLOBALS['rx_left_margin'], $GLOBALS['rx_right_margin']); - $pdf->selectFont('Helvetica'); + list($pdf, $patient) = $this->generatePdfObjectForPrescriptionIds($id); - // $print_header = true; - $on_this_page = 0; + $pFirstName = $patient->fname; //modified by epsdky for prescription filename change to include patient name and ID + $pFName = convert_safe_file_dir_name($pFirstName); + $modedFileName = "Rx_{$pFName}_{$patient->id}.pdf"; + $pdf->ezStream(array('Content-Disposition' => $modedFileName)); + return; + } - //print prescriptions body - $this->_state = false; // Added by Rod - see Controller.class.php - $ids = preg_split('/::/', substr($id, 1, strlen($id) - 2), -1, PREG_SPLIT_NO_EMPTY); + function multiprintplain_header($p) + { + $this->providerid = $p->provider->id; + $sql = "SELECT f.name, f.street, f.state, f.postal_code, f.phone, if(f.fax != '', f.fax, '') FROM users JOIN facility AS f ON f.name = users.facility where users.id = ?"; + $result = QueryUtils::fetchRecords($sql, [$p->provider->id]); + $address = ''; + if (!empty($result)) { + $res = $result[0]; + $parts = []; + $parts[] = $res['name']; + $parts[] = $res['street']; + if (!empty($res['city'])) { + $parts[] = $res['city'] ?? '' . ', ' . $res['state'] ?? '' . ' ' . $res['postal_code'] ?? ''; + } else if (!empty($res['state']) && !empty($res['postal_code'])) { + $parts[] = $res['state'] ?? '' . ' ' . $res['postal_code'] ?? ''; + } + if (!empty($res['phone'])) { + $parts[] = xl('Tel:') . $res['phone'] ?? ''; + } + if (!empty($res['fax'])) { + $parts[] = xl('Fax:') . $res['fax'] ?? ''; + } + $address = implode("\n", $parts); + if (trim($address) == "") { + $address = ""; + } + } + echo xl("Digital Prescription Information") . "\n"; + echo xl("Prescriber") . "\n"; + echo $address; + echo ("\n"); + echo ("\n"); + echo ($p->provider->get_name_display()) . "\n"; + + if ($GLOBALS['rx_enable_DEA']) { + if ($GLOBALS['rx_show_DEA']) { + echo (xl('DEA') . ':' . $p->provider->federal_drug_id . "\n"); + } else { + echo (xl('DEA') . ": ________________________\n" ); + } + } + + if ($GLOBALS['rx_enable_NPI']) { + if ($GLOBALS['rx_show_NPI']) { + echo (xl('NPI') . ':' . $p->provider->npi . '') . "\n"; + } else { + echo ('' . xl('NPI') . ": ________________________\n"); + } + } + + if ($GLOBALS['rx_enable_SLN']) { + if ($GLOBALS['rx_show_SLN']) { + echo (xl('State Lic. #') . ':' . $p->provider->state_license_number . "\n"); + } else { + echo (xl('State Lic. #') . ": ________________________\n"); + } + } + echo "\n\n"; + echo (xl('Patient Name & Address') . "\n"); + echo ($p->patient->get_name_display() . "\n"); + $sql = "SELECT street, city, `state`, postal_code, if(phone_home!='',phone_home,if(phone_cell!='',phone_cell,if(phone_biz!='',phone_biz,''))) AS phone from patient_data where pid = ?"; + $result = QueryUtils::fetchRecords($sql, [$p->patient->id]); + $address = ''; + if (!empty($result)) { + $res = $result[0]; + $parts = []; + $parts[] = $res['street']; + if (!empty($res['city'])) { + $parts[] = $res['city'] ?? '' . ', ' . $res['state'] ?? '' . ' ' . $res['postal_code'] ?? ''; + } else if (!empty($res['state']) && !empty($res['postal_code'])) { + $parts[] = $res['state'] ?? '' . ' ' . $res['postal_code'] ?? ''; + } + + if (!empty($res['phone'])) { + $parts[] = xl('Tel:') . $res['phone'] ?? ''; + } + $address = implode("\n", $parts); + $address = trim($address); + } + + echo ($address); + echo "\n"; + echo (xl('Date of Birth')) . " "; + echo ($p->patient->date_of_birth ); + echo "\n"; + echo xl('Medical Record #'); + echo (str_pad($p->patient->get_pubpid(), 10, "0", STR_PAD_LEFT)); + echo "\n\n"; + echo xl('Prescriptions') . "\n"; + } + + + function multiprintplain_footer() + { + echo xl('Signature') . ":________________________________\n"; + echo xl('Date') . ": " . date('Y-m-d') . "\n"; + } + + + /** + * Outputs a JSON response of the subject and message body for the prescription contents to go into a native + * email client. Useful if you want to use the native mailto: handler in the browser or user-agent's operating system. + * @return void + */ + function getDefaultMailClientText_action() + { + $idsGet = $_GET['ids']; + + if (empty($idsGet)) { + $this->function_argument_error(); + return; + } + ob_start(); + + $ids = preg_split('/::/', substr($idsGet, 1, strlen($idsGet) - 2), -1, PREG_SPLIT_NO_EMPTY); + + $on_this_page = 0; foreach ($ids as $id) { $p = new Prescription($id); - // if ($print_header == true) { if ($on_this_page == 0) { - $this->multiprint_header($pdf, $p); + $this->multiprintplain_header($p); } if (++$on_this_page > 3 || $p->provider->id != $this->providerid) { - $this->multiprint_footer($pdf); - $pdf->ezNewPage(); - $this->multiprint_header($pdf, $p); - // $print_header = false; + $this->multiprintplain_footer(); + $this->multiprintplain_header($p); $on_this_page = 1; } - $this->multiprint_body($pdf, $p); + // we don't want any html in the plain text rendering + echo strip_tags($this->get_prescription_body_text($p)); } - $this->multiprint_footer($pdf); - - $pFirstName = $p->patient->fname; //modified by epsdky for prescription filename change to include patient name and ID - $pFName = convert_safe_file_dir_name($pFirstName); - $modedFileName = "Rx_{$pFName}_{$p->patient->id}.pdf"; - $pdf->ezStream(array('Content-Disposition' => $modedFileName)); + $this->multiprintplain_footer(); + $data = ob_get_clean(); + $result = [ + 'subject' => $GLOBALS['openemr_name'] . " " . xl(" Prescription ") + ,'message' => $data + ]; + http_response_code(200); + header("Content-Type:" . "application/json"); + echo json_encode($result); return; } @@ -758,73 +903,21 @@ function multiprintcss_action($id = "") return; } - function send_action_process($id) + function send_action_process() { $dummy = ""; // Added by Rod to avoid run-time warnings if ($_POST['process'] != "true") { return; } + $id = $_POST['sendEmailPrescriptionIds']; if (empty($id)) { $this->function_argument_error(); } + $sendAsPDF = intval($_POST['sendAsPdf'] ?? 0) == 1; - $p = new Prescription($id); - switch ($_POST['submit']) { - case (xl("Print") . " (" . xl("PDF") . ")"): - // The following statement added by Rod. - // Looking at Controller.class.php, it appears that _state is set to false - // to indicate that no further HTML is to be generated. - $this->_state = false; // Added by Rod - see Controller.class.php - return $this->print_prescription($p, $dummy); - break; - case (xl("Print") . " (" . xl("HTML") . ")"): - $this->_state = false; - return $this->print_prescription_css($p, $dummy); - break; - case xl("Print To Fax"): - $this->_state = false; - $this->is_print_to_fax = true; - return $this->print_prescription($p, $dummy); - break; - case xl("Email"): - return $this->email_prescription($p, $_POST['email_to']); - break; - case xl("Fax"): - //this is intended to be the hook for the hylafax code we already have that hasn't worked its way into the tree yet. - //$this->assign("process_result","No fax server is currently setup."); - return $this->fax_prescription($p, $_POST['fax_to']); - break; - case xl("Auto Send"): - $pharmacy_id = $_POST['pharmacy_id']; - //echo "auto sending to : " . $_POST['pharmacy_id']; - $phar = new Pharmacy($_POST['pharmacy_id']); - //print_r($phar); - if ($phar->get_transmit_method() == TRANSMIT_PRINT) { - return $this->print_prescription($p, $dummy); - } elseif ($phar->get_transmit_method() == TRANSMIT_EMAIL) { - $email = $phar->get_email(); - if (!empty($email)) { - return $this->email_prescription($p, $phar->get_email()); - } - - //else print it - } elseif ($phar->get_transmit_method() == TRANSMIT_FAX) { - $faxNum = $phar->get_fax(); - if (!empty($faxNum)) { - return $this->fax_prescription($p, $faxNum); - } - - // return $this->assign("process_result","No fax server is currently setup."); - // else default is printing, - } else { - //the pharmacy has no default or default is print - return $this->print_prescription($p, $dummy); - } - break; - } - - return; + $patient = $this->email_prescription($id, $_POST['email_to'], $sendAsPDF); + return $this->list_action($patient->id); } function print_prescription($p, &$toFile) @@ -863,56 +956,39 @@ function print_prescription_css($p, &$toFile) $this->multiprintcss_postfooter(); } - function print_prescription_old($p, &$toFile) - { - $pdf = new Cezpdf($GLOBALS['rx_paper_size']); - $pdf->ezSetMargins($GLOBALS['rx_top_margin'], $GLOBALS['rx_bottom_margin'], $GLOBALS['rx_left_margin'], $GLOBALS['rx_right_margin']); - $pdf->selectFont('Helvetica'); - if (!empty($this->pconfig['logo'])) { - $pdf->ezImage($this->pconfig['logo'], "", "", "none", "left"); - } - - $pdf->ezText($p->get_prescription_display(), 10); - if ($this->pconfig['use_signature']) { - $pdf->ezImage($this->pconfig['signature'], "", "", "none", "left"); - } else { - $pdf->ezText("\n\n\n\nSignature:________________________________", 10); - } - - if (!empty($toFile)) { - $toFile = $pdf->ezOutput(); - } else { - $pdf->ezStream(); - // $pdf->ezStream(array('compress' => 0)); // for testing with uncompressed output - } - - return; - } - - function email_prescription($p, $email) + function email_prescription($id, $email, $sendAsPdf) { if (empty($email)) { $this->assign("process_result", "Email could not be sent, the address supplied: '$email' was empty or invalid."); return; } - $mail = new PHPMailer(); - //this is a temporary config item until the rest of the per practice billing settings make their way in + $mail = new MyMailer(); + if ($sendAsPdf) { + list($pdf, $patient) = $this->generatePdfObjectForPrescriptionIds($id); + $pdfAsString = $pdf->output(); + $mailBody = $GLOBALS['openemr_name'] . " " . xl("Prescription attached to this email.") . " " . xl("Patient") . " " . $patient->get_name_display(); + } else { + list($mailBody, $patient) = $this->generateHtmlObjectForPrescriptionIds($id); + $mail->isHTML(true); + } + $mail->From = $GLOBALS['practice_return_email_path']; - $mail->FromName = $p->provider->get_name_display(); - $mail->isMail(); - $mail->Host = "localhost"; - $mail->Mailer = "mail"; - $text_body = $p->get_prescription_display(); - $mail->Body = $text_body; - $mail->Subject = "Prescription for: " . $p->patient->get_name_display(); +// $mail->FromName = $p->provider->get_name_display(); +// $text_body = $p->get_prescription_display(); + $mail->Body = $mailBody; + $mail->Subject = $GLOBALS['openemr_name'] . " " . xl("Prescription"); $mail->AddAddress($email); + if ($sendAsPdf) { + $mail->addStringAttachment($pdfAsString, 'Prescription-' . date("Y-m-d_H_i_s") . ".pdf"); + } + if ($mail->Send()) { $this->assign("process_result", "Email was successfully sent to: " . $email); - return; + return $patient; } else { $this->assign("process_result", "There has been a mail error sending to " . $_POST['email_to'] . " " . $mail->ErrorInfo); - return; + return $patient; } } @@ -994,4 +1070,54 @@ function fax_prescription($p, $faxNum) $this->assign("process_result", $err); } } + + /** + * @param mixed $id + * @return array + */ + private function generatePdfObjectForPrescriptionIds(mixed $id): array + { + $pdf = new Cezpdf($GLOBALS['rx_paper_size']); + $pdf->ezSetMargins($GLOBALS['rx_top_margin'], $GLOBALS['rx_bottom_margin'], $GLOBALS['rx_left_margin'], $GLOBALS['rx_right_margin']); + $pdf->selectFont('Helvetica'); + + // $print_header = true; + $on_this_page = 0; + + //print prescriptions body + $this->_state = false; // Added by Rod - see Controller.class.php + $ids = preg_split('/::/', substr($id, 1, strlen($id) - 2), -1, PREG_SPLIT_NO_EMPTY); + foreach ($ids as $id) { + $p = new Prescription($id); + // if ($print_header == true) { + if ($on_this_page == 0) { + $this->multiprint_header($pdf, $p); + } + + if (++$on_this_page > 3 || $p->provider->id != $this->providerid) { + $this->multiprint_footer($pdf); + $pdf->ezNewPage(); + $this->multiprint_header($pdf, $p); + // $print_header = false; + $on_this_page = 1; + } + + $this->multiprint_body($pdf, $p); + } + + $this->multiprint_footer($pdf); + return array($pdf, $p->patient); + } + + private function generateHtmlObjectForPrescriptionIds($id) + { + ob_start(); + $this->multiprintcss_action($id); + $html = ob_get_clean(); + $ids = preg_split('/::/', substr($id, 1, strlen($id) - 2), -1, PREG_SPLIT_NO_EMPTY); + if (!empty($ids)) { + $prescription = new Prescription($ids[0]); + } + return [$html, $prescription->patient]; + } } diff --git a/interface/forms/eye_mag/js/eye_base.php b/interface/forms/eye_mag/js/eye_base.php index c3d8c1d14a9..39011a48a3a 100644 --- a/interface/forms/eye_mag/js/eye_base.php +++ b/interface/forms/eye_mag/js/eye_base.php @@ -1033,17 +1033,15 @@ function editScripts(url) { let w = 810; w = 910; - dlgopen(url, 'editScripts', w, 300, '', '', { - buttons: [ - {text: 'Add', close: false, style: 'primary btn-sm', click: AddScript}, - {text: 'List', close: false, style: 'primary btn-sm', click: ListScripts}, - {text: 'Done', close: true, style: 'default btn-sm'} - ], - onClosed: 'refreshme', + dlgopen(url, 'editScripts', w, 400, '', '', { + resolvePromiseOn: 'close', allowResize: true, allowDrag: true, dialogId: 'editscripts', type: 'iframe' + }).then(() => { + top.restoreSession(); + location.reload(); }); } diff --git a/interface/patient_file/encounter/coding.php b/interface/patient_file/encounter/coding.php index 03ce3c29f87..29dfcf0a9ff 100644 --- a/interface/patient_file/encounter/coding.php +++ b/interface/patient_file/encounter/coding.php @@ -1,6 +1,7 @@ /controller.php?prescription&edit&id=0&pid=' + ; - }; - var ListScripts = function () { - var __this = $(this); - __this.find("#clearButton").css("display", "none"); - __this.find("#backButton").css("display", "none"); - __this.find("#addButton").css("display", ""); - var iam = top.frames.editScripts - iam.location.href = '/controller.php?prescription&list&id=' + ; - }; let title = ; let w = 960; // for weno width dlgopen(url, 'editScripts', w, 400, '', '', { - buttons: [{ - text: , - close: false, - id: 'addButton', - class: 'btn-primary btn-sm', - click: AddScript - }, - { - text: , - close: false, - id: 'clearButton', - style: 'display:none;', - class: 'btn-primary btn-sm', - click: AddScript - }, - { - text: , - close: false, - id: 'backButton', - style: 'display:none;', - class: 'btn-primary btn-sm', - click: ListScripts - }, - { - text: , - close: true, - id: 'doneButton', - class: 'btn-secondary btn-sm' - } - ], - onClosed: 'refreshme', + resolvePromiseOn: 'close', allowResize: true, allowDrag: true, dialogId: 'editscripts', type: 'iframe' - }); + }) + .then(() => refreshme()); return false; } diff --git a/interface/patient_file/summary/demographics_full.php b/interface/patient_file/summary/demographics_full.php index e1d0bf2aa37..0eaeb771d91 100644 --- a/interface/patient_file/summary/demographics_full.php +++ b/interface/patient_file/summary/demographics_full.php @@ -21,6 +21,7 @@ require_once("$srcdir/patient.inc.php"); use OpenEMR\Common\Acl\AclMain; +use OpenEMR\Common\Forms\FormActionBarSettings; use OpenEMR\Common\Csrf\CsrfUtils; use OpenEMR\Core\Header; use OpenEMR\Events\PatientDemographics\UpdateEvent; @@ -418,6 +419,7 @@ function validate(f) {
+

@@ -432,6 +434,11 @@ function validate(f) {

+ +
+

+
+ + +
+
+
+
+
+ + + + +
+
+
+
+
diff --git a/library/globals.inc.php b/library/globals.inc.php index c9cf54aea73..ec939e5c0c7 100644 --- a/library/globals.inc.php +++ b/library/globals.inc.php @@ -76,6 +76,7 @@ // Uzbek // xl('Uzbek') // Vietnamese // xl('Vietnamese') +use OpenEMR\Common\Forms\FormActionBarSettings; use OpenEMR\Events\Globals\GlobalsInitializedEvent; use OpenEMR\OeUI\RenderFormFieldHelper; use OpenEMR\Services\Globals\GlobalsService; @@ -433,6 +434,13 @@ function gblTimeZones() xl('Recommended setting is warn and prevent web browser refresh. Only use other settings if needed and use at own risk.') ), + 'form_actionbar_position' => array( + xl('Form ActionBar (save, cancel, etc) position') + ,FormActionBarSettings::getGlobalSettingsList() + ,FormActionBarSettings::getDefaultSetting() // default = top of the form + ,xl('Placement of the save/cancel, and other bottons where supported (Demographics, Encounter Forms, etc).') + ), + ), 'Branding' => [ @@ -3804,6 +3812,12 @@ function gblTimeZones() 'default', xl('Name of zend template for pdf export, possible to add custom template in the PrescriptionTemplate module') ), + 'rx_send_email' => array( + xl('Allow email sending of prescriptions'), + 'bool', // data type + '1', + xl('Enable email option (available on prescriptions list screen) for emailing prescriptions') + ), ), 'PDF' => array( 'pdf_layout' => array( diff --git a/src/Common/Forms/FormActionBarSettings.php b/src/Common/Forms/FormActionBarSettings.php new file mode 100644 index 00000000000..1b737c4c8c5 --- /dev/null +++ b/src/Common/Forms/FormActionBarSettings.php @@ -0,0 +1,37 @@ + xl('Top of Form (default)') + ,self::ACTION_BAR_DISPLAY_FORM_BOTTOM => xl('Bottom of Form') +// ,self::ACTION_BAR_DISPLAY_FORM_TOP_AND_BOTTOM => xl('Top and Bottom of Form') + ); + } + + public static function getDefaultSetting() + { + return self::ACTION_BAR_DISPLAY_FORM_TOP; + } + + public static function shouldDisplayTopActionBar() + { + // probably could make this more efficient by doing integer position comparisons, but the global values are stored as strings... + return $GLOBALS['form_actionbar_position'] == self::ACTION_BAR_DISPLAY_FORM_TOP + || $GLOBALS['form_actionbar_position'] == self::ACTION_BAR_DISPLAY_FORM_TOP_AND_BOTTOM; + } + public static function shouldDisplayBottomActionBar() + { + return $GLOBALS['form_actionbar_position'] == self::ACTION_BAR_DISPLAY_FORM_BOTTOM + || $GLOBALS['form_actionbar_position'] == self::ACTION_BAR_DISPLAY_FORM_TOP_AND_BOTTOM; + } +} diff --git a/templates/prescription/general_edit.html b/templates/prescription/general_edit.html.twig similarity index 52% rename from templates/prescription/general_edit.html rename to templates/prescription/general_edit.html.twig index 91ab7456d91..5685670fbb4 100644 --- a/templates/prescription/general_edit.html +++ b/templates/prescription/general_edit.html.twig @@ -1,4 +1,4 @@ -{** +{## * Prescription edit * * @package OpenEMR @@ -6,13 +6,11 @@ * @author Brady Miller * @copyright Copyright (c) 2017-2018 Brady Miller * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 - *} +#} - - {headerTemplate assets='datetime-picker|select2'} - + {{ setupHeader(['datetime-picker','datetime-picker-translated', 'select2']) }} @@ -318,7 +379,7 @@ }); - {if $GLOBALS.weno_rx_enable} + {% if weno_rx_enable %} $("#drug").select2({ ajax: { @@ -326,7 +387,7 @@ dataType: 'json', data: function(params) { return { - csrf_token_form: {$CSRF_TOKEN_FORM|js_escape}, + csrf_token_form: {{ CSRF_TOKEN_FORM|js_escape }}, term: params.term }; @@ -347,7 +408,7 @@ minimumInputLength: 3 } }); - {else} + {% else %} $("#drug").select2({ ajax: { @@ -355,7 +416,7 @@ dataType: 'json', data: function(params) { return { - csrf_token_form: {$CSRF_TOKEN_FORM|js_escape}, + csrf_token_form: {{ CSRF_TOKEN_FORM|js_escape }}, term: params.term, use_rxnorm: document.prescribe.rxcui_select[1].checked, @@ -379,13 +440,13 @@ tags: true, minimumInputLength: 3 }); - {/if} - {if $prescription->drug} + {% endif %} + {% if prescription.drug %} // Show the current drug name in the select - var newOption = new Option({$prescription->drug|js_escape}, {$prescription->drug|js_escape}, true, true); + var newOption = new Option({{prescription.drug|js_escape}}, {{prescription.drug|js_escape}}, true, true); $('#drug').append(newOption).trigger('change'); - {/if} + {% endif %} $("#drug").focus(); @@ -412,7 +473,7 @@ // for text boxes if ($('#'+objID).is('input')) { if ($('#'+objID).val() == "") { - alert({xlj t='Missing a required field and will be highlighted'}); + alert({{'Missing a required field and will be highlighted'|xlj}}); $('#'+objID).css("backgroundColor", "pink"); return false; } @@ -421,7 +482,7 @@ // for select boxes if ($('#'+objID).is('select')) { if ($('#'+objID).val() == "0") { - alert({xlj t='Missing a required field'}); + alert({{'Missing a required field'|xlj}}); $('#'+objID).css("backgroundColor", "pink"); return false; } @@ -442,7 +503,11 @@ }); $(function () { - {datetimepickerSupport input='format'} + datetimepickerTranslated('.datepicker', { + timepicker: false + , showSeconds: false + , formatInput: true + }); }); diff --git a/templates/prescription/general_list.html b/templates/prescription/general_list.html deleted file mode 100644 index 41489ab51db..00000000000 --- a/templates/prescription/general_list.html +++ /dev/null @@ -1,316 +0,0 @@ -{** - * Prescription list - * - * @package OpenEMR - * @link http://www.open-emr.org - * @author Brady Miller - * @author Sherwin Gaddis - * @copyright Copyright (c) 2017-2018 Brady Miller - * @copyright Copyright (c) 2018 Sherwin Gaddis - * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 - *} - - - -{headerTemplate assets='no_textformat|no_dialog'} - - - - - - - -
-
- {if $prescriptions} -
-

{xlt t='List'}

-
-
-
- {if $GLOBALS.rx_zend_pdf_template} - {xlt t='Download'} ({xlt t='PDF'}) - {else} - {xlt t='Download'} ({xl t='PDF'}) - {/if} - {if $GLOBALS.rx_zend_html_template} - {xl t='View Printable Version'|text} ({xlt t='HTML'}) - {else} - - {xlt t='View Printable Version'} ({xlt t='HTML'}) - {/if} - {if $GLOBALS.rx_use_fax_template} - {xlt t='Download'} ({xlt t='Fax'}) - {/if} - {if $CAMOS_FORM == true} - {xlt t='View Four Panel'} - {/if} -
- -
-
-
-
-
- - - - - - - - - - - - - - - - - - - {foreach from=$prescriptions item=prescription} - - - - {if empty($prescription->erx_source) || $prescription->erx_source==0} - - - {else} - - - {/if} - - - - {if empty($prescription->erx_source) || $prescription->erx_source==0} - - {else} - - {/if} - - - - - - {/foreach} - -
  {xlt t='Drug'}{xlt t='RxNorm'}{xlt t='Created'}
{xlt t='Changed'}
{xlt t='Dosage'}{xlt t='Qty'}.{xlt t='Unit'}{xlt t='Refills'}{xlt t='Provider'}
- encounter) && $prescription->encounter == $prescription->get_encounter() && $prescription->active > 0}checked="checked" {/if}onclick="changeLinkHref('multiprint',this.checked, this.value);changeLinkHref('multiprintcss',this.checked, this.value);changeLinkHref('multiprintToFax',this.checked, this.value)" title="{xla t='Select for printing'}"> - - {xlt t='Edit'} - - - {if $prescription->active > 0}{/if}{$prescription->drug|text}{if $prescription->active > 0}{/if}  -
{$prescription->note|text} -
  - {if $prescription->active > 0}{/if}{$prescription->drug|text}{if $prescription->active > 0}{/if}  -
{$prescription->note|text} -
- {$prescription->rxnorm_drugcode|text}  - - {$prescription->date_added|oeFormatShortDate|text}
- {$prescription->date_modified|oeFormatShortDate|text}  -
- {$prescription->get_dosage_display()|text}   - - {$prescription->quantity|text}   - - {$prescription->quantity|text}   - - {$prescription->get_size()|text} {$prescription->get_unit_display()|text}  - - {$prescription->refills|text}   - - {$prescription->provider->get_name_display()|text}  - {xlt t='Delete'}
-
-
-
-
- {if $GLOBALS.rx_show_drug_drug} -
-
-

{xlt t='Drug-Drug Interaction'}

-

*{xlt t='Notice'}

-
- {$INTERACTION} -
-
-
- {/if} - - {else} -
{xlt t='There are currently no prescriptions'}.
- {/if} -
-
- - - - - diff --git a/templates/prescription/general_list.html.twig b/templates/prescription/general_list.html.twig new file mode 100644 index 00000000000..86be53fb126 --- /dev/null +++ b/templates/prescription/general_list.html.twig @@ -0,0 +1,520 @@ +{## + * Prescription list + * + * @package OpenEMR + * @link http://www.open-emr.org + * @author Brady Miller + * @author Sherwin Gaddis + * @author Stephen Nielson + * @copyright Copyright (c) 2017-2018 Brady Miller + * @copyright Copyright (c) 2018 Sherwin Gaddis + * @copyright Copyright (c) 2024 Discover and Change, Inc. + * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 + * +#} + + +{{ setupHeader(['no_textformat']) }} + + + + + + + +
+
+ {% if prescriptions %} +
+

{{'List'|xlt}}

+
+ {% block prescriptionTopNavbar %} +
+
+ {# Don't think the top.restoreSessions are needed here since the CheckForChecks function does that, but leaving it just in case #} + {% block prescriptionTopNavbarButtons %} + {% if rx_zend_pdf_template %} + {{'Download'|xlt}} ({{'PDF'|xlt}}) + {% else %} + {{'Download'|xlt}} ({{'PDF'|xlt}}) + {% endif %} + {% if rx_zend_html_template %} + {{'View Printable Version'|xlt}} ({{'HTML'|xlt}}) + {% else %} + + {{'View Printable Version'|xlt}} ({{'HTML'|xlt}}) + {% endif %} + {%if rx_use_fax_template%} + {{'Download'|xlt}} ({{'Fax'|xlt}}) + {% endif %} + {% if rx_send_email %} + {{'Send Email'|xlt}} + {% endif %} + {% if CAMOS_FORM == true %} + {{'View Four Panel'|xlt}} + {% endif %} + {% endblock %} +
+ +
+ {% endblock %} + + {% if process_result %} +
+
+ {{process_result|text}} +
+
+ {% endif %} +
+
+
+

{{ "Email Prescriptions"|xlt }}

+
+
+ {# Note this will call the send_action_process, there is no corresponding send_action method #} +
+
+
+
+ + + +
+
+
+
+ + +
+
+ + +
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + {% for prescription in prescriptions %} + + + + {% if prescription.erx_source is empty or prescription.erx_source==0 %} + + + {% else %} + + + {% endif %} + + + + {%if prescription.erx_source is empty or prescription.erx_source==0%} + + {% else %} + + {% endif %} + + + + + + {% endfor %} + +
  {{'Drug'|xlt}}{{'RxNorm'|xlt}}{{'Created'|xlt}}
{{'Changed'|xlt}}
{{'Dosage'|xlt}}{{'Qty'|xlt}}.{{'Unit'|xlt}}{{'Refills'|xlt}}{{'Provider'|xlt}}
+ 0 %} + checked="checked" + {% endif %} + title="{{'Select for printing'|xla}}"> + + {{'Edit'|xlt}} + + {% if prescription.active > 0%} + {{prescription.drug|text}} + {% else %} + {{prescription.drug|text}} + {% endif %}  +
{{prescription.note|text}} +
  + {% if prescription.active > 0%} + {{prescription.drug|text}} + {% else %} + {{prescription.drug|text}} + {% endif %}  +
{{prescription.note|text}} +
+ {{prescription.rxnorm_drugcode|text}}  + + {{prescription.date_added|shortDate|text}}
+ {{prescription.date_modified|shortDate|text}}  +
+ {{prescription.get_dosage_display()|text}}   + + {{ prescription.quantity|text }}   + + {{prescription.quantity|text}}   + + {{prescription.get_size()|text}} {{prescription.get_unit_display()|text}}  + + {{prescription.refills|text}}   + + {{prescription.provider.get_name_display()|text}}  + + {{'Delete'|xlt}} +
+
+
+
+
+ {% if rx_show_drug_drug %} +
+
+

{{'Drug-Drug Interaction'|xlt}}

+

*{{'Notice'|xlt}}

+
+ {{INTERACTION|text}} +
+
+
+ {% endif %} + + {% else %} +
{{ "There are currently no prescriptions"|xlt}}.
+ {% endif %} +
+ +
+ + + + +