Skip to content

Commit

Permalink
Fax Custom Module Support (openemr#2658)
Browse files Browse the repository at this point in the history
* Fax Custom Module Support
- add dispatch events to patient documents for fax send.
- New patient documents event class

* - path fix
- use organize

* - custom report fax support
- dialog grab focus not supported any longer(crosssite etc)
- fix alertMsg dialog

* - add fax enable/disable to key areas
- menu enable is in bootstrap

* - Revert document dispatcher event for fax button

* - new smarty plugin to make event dispatcher work

* - normalized directory separators
  • Loading branch information
sjpadgett committed Sep 11, 2019
1 parent 67bb71d commit c243db5
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 51 deletions.
19 changes: 17 additions & 2 deletions interface/patient_file/report/custom_report.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
$GLOBALS['PATIENT_REPORT_ACTIVE'] = true;

$PDF_OUTPUT = empty($_POST['pdf']) ? 0 : intval($_POST['pdf']);
$PDF_FAX = empty($_POST['fax']) ? 0 : intval($_POST['fax']);
if ($PDF_FAX) {
$PDF_OUTPUT = 1;
}

if ($PDF_OUTPUT) {
$config_mpdf = array(
Expand Down Expand Up @@ -817,7 +821,10 @@ function postToGet($arin)
if ($PDF_OUTPUT) {
$content = getContent();
$ptd = getPatientData($pid, "fname,lname");
$fn = strtolower($ptd['fname'] . '_' . $ptd['lname'] . '_' . $pid . '_' . xl('report') . '.pdf');
// escape names for pesky periods hyphen etc.
$esc = $ptd['fname'] . '_' . $ptd['lname'];
$esc = str_replace(array('.', ',', ' '), '', $esc);
$fn = basename_international(strtolower($esc . '_' . $pid . '_' . xl('report') . '.pdf'));
$pdf->SetTitle(ucfirst($ptd['fname']) . ' ' . $ptd['lname'] . ' ' . xl('Id') . ':' . $pid . ' ' . xl('Report'));
$isit_utf8 = preg_match('//u', $content); // quick check for invalid encoding
if (! $isit_utf8) {
Expand All @@ -837,7 +844,15 @@ function postToGet($arin)

if ($PDF_OUTPUT == 1) {
try {
$pdf->Output($fn, $GLOBALS['pdf_output']); // D = Download, I = Inline
if ($PDF_FAX === 1) {
$fax_pdf = $pdf->Output($fn, 'S');
$tmp_file = $GLOBALS['temporary_files_dir'] . '/' . $fn; // is deleted in sendFax...
file_put_contents($tmp_file, $fax_pdf);
echo $tmp_file;
exit();
} else {
$pdf->Output($fn, $GLOBALS['pdf_output']); // D = Download, I = Inline
}
} catch (MpdfException $exception) {
die(text($exception));
}
Expand Down
13 changes: 11 additions & 2 deletions interface/patient_file/report/patient_report.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
* @link http:https://www.open-emr.org
* @author Brady Miller <[email protected]>
* @copyright Copyright (c) 2017-2018 Brady Miller <[email protected]>
* @author Stephen Nielson <[email protected]>
* @copyright Copyright (c) 2019 Stephen Nielson <[email protected]>
* @author Jerry Padgett <[email protected]>
* @copyright Copyright (c) 2019 Jerry Padgett <[email protected]>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
*/

Expand Down Expand Up @@ -34,6 +38,7 @@
$auth_med = acl_check('patients', 'med');
$auth_demo = acl_check('patients', 'demo');

$oefax = !empty($GLOBALS['oefax_enable']) ? $GLOBALS['oefax_enable'] : 0;
/**
* @var EventDispatcherInterface $eventDispatcher The event dispatcher / listener object
*/
Expand Down Expand Up @@ -268,7 +273,9 @@ function show_date_fun(){
<button type="button" class="genportal btn btn-default btn-send-msg btn-sm" value="<?php echo xla('Send to Portal'); ?>" ><?php echo xlt('Send to Portal'); ?></button>
<?php } ?>
<?php
$eventDispatcher->dispatch(OpenEMR\Events\PatientReport::ACTIONS_RENDER_POST, new GenericEvent());
if ($oefax) {
$eventDispatcher->dispatch(PatientReportEvent::ACTIONS_RENDER_POST, new GenericEvent());
}
?>
<input type='hidden' name='pdf' value='0'>
<br>
Expand Down Expand Up @@ -751,7 +758,9 @@ function(data) {
<?php } ?>

<?php
$eventDispatcher->dispatch(PatientReportEvent::JAVASCRIPT_READY_POST, new GenericEvent());
if ($oefax) {
$eventDispatcher->dispatch(PatientReportEvent::JAVASCRIPT_READY_POST, new GenericEvent());
}
?>

});
Expand Down
38 changes: 19 additions & 19 deletions library/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function dlgOpenWindow(url, winname, width, height) {
}
top.modaldialog = cascwin(url, winname, width, height,
"resizable=1,scrollbars=1,location=0,toolbar=0");
grabfocus(top);

return false;
}

Expand Down Expand Up @@ -231,26 +231,26 @@ if (typeof alertMsg !== "function") {
console.log(error.message)
});
}
const persistUserOption = function (option, value) {
return $.ajax({
url: top.webroot_url + "/library/ajax/user_settings.php",
type: 'post',
contentType: 'application/x-www-form-urlencoded',
data: {
csrf_token_form: top.csrf_token_js,
target: option,
setting: value
},
beforeSend: function () {
top.restoreSession;
},
error: function (jqxhr, status, errorThrown) {
console.log(errorThrown);
}
});
};
}

const persistUserOption = function (option, value) {
return $.ajax({
url: top.webroot_url + "/library/ajax/user_settings.php",
type: 'post',
contentType: 'application/x-www-form-urlencoded',
data: {
csrf_token_form: top.csrf_token_js,
target: option,
setting: value
},
beforeSend: function () {
top.restoreSession;
},
error: function (jqxhr, status, errorThrown) {
console.log(errorThrown);
}
});
};


// Test if supporting dialog callbacks and close dependencies are in scope.
Expand Down
17 changes: 14 additions & 3 deletions library/globals.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -2028,6 +2028,17 @@ function gblTimeZones()
//
'Notifications' => array(

'oefax_enable' => array(
xl('Enable Fax SMS Module'),
array(
0 => xl('Disabled'),
1 => xl('RingCentral'),
2 => xl('Twilio'),
),
'0',
xl('Enable Fax SMS Support. Remember to install fax module.')
),

'patient_reminder_sender_name' => array(
xl('Patient Reminder Sender Name'),
'text', // data type
Expand Down Expand Up @@ -2789,9 +2800,9 @@ function gblTimeZones()
'fhir_enable' => array(
xl('Enable FHIR Provider Client Service'),
array(
0 => xl('Off: No Service.'),
1 => xl('On: HAPI FHIR.'),
2 => xl('On: Smart on FHIR.'),
0 => xl('Disabled'),
1 => xl('HAPI FHIR'),
2 => xl('Smart on FHIR'),
),
'0',
xl('Enable FHIR Provider Client Service')
Expand Down
55 changes: 55 additions & 0 deletions library/smarty/plugins/function.dispatchPatientDocumentEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* Smarty plugin
* @package Smarty
* @subpackage plugins
* dispatchPatientDocumentEvent() version for smarty templates
*
* Copyright (C) 2019 Brady Miller <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*/

use OpenEMR\Events\PatientDocuments\PatientDocumentEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;

/**
* Smarty {dispatchPatientDocumentEvent} function plugin
*
* Type: function<br>
* Name: dispatchPatientDocumentEvent<br>
* Purpose: Event listener for PatientDocumentEvent<br>
*
* Examples:
*
* {dispatchPatientDocumentEvent event="javascript_ready_fax_dialog"}
* {dispatchPatientDocumentEvent event="actions_render_fax_anchor"}
*
* @param array
* @param Smarty
*/


function smarty_function_dispatchPatientDocumentEvent($params, &$smarty)
{
if (empty($params['event'])) {
$smarty->trigger_error("dispatchPatientDocumentEvent: missing 'event' parameter");
return;
} else {
$event = $params['event'];
}

$eventDispatcher = $GLOBALS['kernel']->getEventDispatcher();
if ($event == "javascript_ready_fax_dialog") {
$eventDispatcher->dispatch(PatientDocumentEvent::JAVASCRIPT_READY_FAX_DIALOG, new GenericEvent());
} else if ($event == "actions_render_fax_anchor") {
$eventDispatcher->dispatch(PatientDocumentEvent::ACTIONS_RENDER_FAX_ANCHOR, new GenericEvent());
} else {
$smarty->trigger_error("dispatchPatientDocumentEvent: invalid 'event' parameter");
return;
}
}
29 changes: 14 additions & 15 deletions src/Core/ModulesApplication.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

/**
* MainMenuRole class.
* ModulesApplication class.
*
* @package OpenEMR
* @link http:https://www.open-emr.org
Expand All @@ -13,28 +13,28 @@

namespace OpenEMR\Core;

use OpenEMR\Core\Kernel;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Zend\Mvc\Application;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class ModulesApplication
{

/**
* The application reference pointer for the zend mvc modules application
* @var \Zend\Mvc\Application
* @var Application
*
*/
private $application;

const CUSTOM_MODULE_BOOSTRAP_NAME = 'openemr.bootstrap.php';

public function __construct(Kernel $kernel, $webRootPath, $modulePath, $zendModulePath)
{
$zendConfigurationPath = $webRootPath . DIRECTORY_SEPARATOR . $modulePath . DIRECTORY_SEPARATOR . $zendModulePath;
$customModulePath = $webRootPath . DIRECTORY_SEPARATOR . $modulePath . DIRECTORY_SEPARATOR . "custom_modules" . DIRECTORY_SEPARATOR;
$configuration = require $zendConfigurationPath . DIRECTORY_SEPARATOR . 'config/application.config.php';
// Beware: default module path ends in a slash. Really should not but have to refactor to change..
$zendConfigurationPath = $webRootPath . '/' . $modulePath . $zendModulePath;
$customModulePath = $webRootPath . '/' . $modulePath . "custom_modules" . '/';
$configuration = require $zendConfigurationPath . '/' . 'config/application.config.php';

// Prepare the service manager
// We customize this and skip using the static Zend\Mvc\Application::init in order to inject the
Expand All @@ -51,8 +51,8 @@ public function __construct(Kernel $kernel, $webRootPath, $modulePath, $zendModu
$serviceManager->get('ModuleManager')->loadModules();

// Prepare list of listeners to bootstrap
$listenersFromAppConfig = isset($configuration['listeners']) ? $configuration['listeners'] : [];
$config = $serviceManager->get('config');
$listenersFromAppConfig = isset($configuration['listeners']) ? $configuration['listeners'] : [];
$config = $serviceManager->get('config');
$listenersFromConfigService = isset($config['listeners']) ? $config['listeners'] : [];

$listeners = array_unique(array_merge($listenersFromConfigService, $listenersFromAppConfig));
Expand All @@ -75,7 +75,7 @@ private function bootstrapCustomModules($eventDispatcher, $customModulePath)
$resultSet = sqlStatementNoLog($statement = "SELECT mod_name, mod_directory FROM modules WHERE mod_active = 1 AND type != 1 ORDER BY `mod_ui_order`, `date`");
$db_modules = [];
while ($row = sqlFetchArray($resultSet)) {
$db_modules[] = ["name" => $row["mod_name"], "directory" => $row['mod_directory'], "path" => $customModulePath . $row['mod_directory'] ];
$db_modules[] = ["name" => $row["mod_name"], "directory" => $row['mod_directory'], "path" => $customModulePath . $row['mod_directory']];
}
foreach ($db_modules as $module) {
$this->loadCustomModule($module, $eventDispatcher);
Expand All @@ -85,17 +85,16 @@ private function bootstrapCustomModules($eventDispatcher, $customModulePath)

private function loadCustomModule($module, $eventDispatcher)
{
if (!is_readable($module['path'] . DIRECTORY_SEPARATOR . self::CUSTOM_MODULE_BOOSTRAP_NAME)) {
// TODO: stephen need to escape filename here.
if (!is_readable($module['path'] . '/' . attr(self::CUSTOM_MODULE_BOOSTRAP_NAME))) {
error_log("Custom module file path " . errorLogEscape($module['path'])
. DIRECTORY_SEPARATOR . self::CUSTOM_MODULE_BOOSTRAP_NAME
. '/' . self::CUSTOM_MODULE_BOOSTRAP_NAME
. " is not readable. Check directory permissions");
}
try {
// the only thing in scope here is $module and $eventDispatcher which is ok for our bootstrap piece.
// do we really want to just include a file?? Should we go all zend and actually force a class instantiation
// here and then inject the EventDispatcher or even possibly the Symfony Kernel here?
include $module['path'] . DIRECTORY_SEPARATOR . self::CUSTOM_MODULE_BOOSTRAP_NAME;
include $module['path'] . '/' . attr(self::CUSTOM_MODULE_BOOSTRAP_NAME);
} catch (Exception $exception) {
error_log(errorLogEscape($exception->getMessage()));
}
Expand Down
20 changes: 20 additions & 0 deletions src/Events/PatientDocuments/PatientDocumentEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* PatientDocumentEvents
*
* @package OpenEMR
* @link http:https://www.open-emr.org
* @author Jerry Padgett <[email protected]>
* @copyright Copyright (c) 2019 Jerry Padgett <[email protected]>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
*/

namespace OpenEMR\Events\PatientDocuments;

use Symfony\Component\EventDispatcher\Event;

class PatientDocumentEvent extends Event
{
const ACTIONS_RENDER_FAX_ANCHOR = 'documents.actions.render.fax.anchor';
const JAVASCRIPT_READY_FAX_DIALOG = 'documents.javascript.fax.dialog';
}
12 changes: 11 additions & 1 deletion src/Events/PatientReport/PatientReportEvent.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
<?php
/**
* PatientReportEvent class.
*
* @package OpenEMR
* @link http:https://www.open-emr.org
*
* @author Stephen Nielson <[email protected]>
* @copyright Copyright (c) 2019 Stephen Nielson <[email protected]>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
*/

namespace OpenEMR\Events\PatientReport;

use Symfony\Component\EventDispatcher\Event;

class PatientReportEvent extends Event
{

/**
* This event fires after the action buttons for the report have rendered.
* It allows listeners to render additional content or buttons.
Expand Down
20 changes: 11 additions & 9 deletions templates/documents/general_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
* @link http:https://www.open-emr.org
* @author Brady Miller <brady[email protected]>
* @copyright Copyright (c) 2017-2019 Brady Miller <brady[email protected]>
* @author Jerry Padgett <sjpadgett@gmail.com>
* @copyright Copyright (c) 2018-2019 Jerry Padgett <sjpadgett@gmail.com>
* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
*}

<script language="JavaScript">

{if $GLOBALS.oefax_enable}
{dispatchPatientDocumentEvent event="javascript_ready_fax_dialog"}
{/if}
function popoutcontent(othis) {literal}{{/literal}
let popsrc = $(othis).parents('body').find('#DocContents iframe').attr("src");
let wname = '_' + Math.random().toString(36).substr(2, 6);
Expand Down Expand Up @@ -38,12 +42,7 @@
dlgopen(url, 'pno1', 'modal-xl', 500, '', '', {
buttons: [
{text: btnClose, close: true, style: 'default btn-xs'}
],
sizeHeight: 'auto',
allowResize: true,
allowDrag: true,
dialogId: '',
type: 'iframe'
]
});
return false;
}{/literal}
Expand Down Expand Up @@ -132,8 +131,11 @@ <h4>{$file->get_url_web()|text}
<button class="btn btn-xs btn-primary active">{xlt t='Contents'}</button>
</div>
<span style="float:right;">
<a class="css_button" href='' onclick='return popoutcontent(this)' title="{xla t='Pop Out Full Screen.'}">
<span class="glyphicon glyphicon-fullscreen"></span></a>
<script>var file = {$file->get_url()|js_escape};</script>
{if $GLOBALS.oefax_enable}
{dispatchPatientDocumentEvent event="actions_render_fax_anchor"}
{/if}
<a class="css_button" href='' onclick='return popoutcontent(this)' title="{xla t='Pop Out Full Screen.'}">{xlt t='Pop Out'}</a>
<a class="css_button" href="{$web_path|attr}" title="{xla t='Original file'}" onclick="top.restoreSession()"><span>{xlt t='Download'}</span></a>
<a class="css_button" href='' onclick='return showpnotes({$file->get_id()|attr_js})'><span>{xlt t='Show Notes'}</span></a>
{$delete_string}
Expand Down

0 comments on commit c243db5

Please sign in to comment.