fix: prior commit had CRLF line endings in sql/database.sql (#6461)
[openemr.git] / portal / import_template_ui.php
blob01f9498a28f428666c02e02b7bb31799810485b4
1 <?php
3 /**
4 * import_template_ui.php
6 * @package OpenEMR
7 * @link https://www.open-emr.org
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @copyright Copyright (c) 2016-2022 Jerry Padgett <sjpadgett@gmail.com>
11 * @copyright Copyright (c) 2019 Brady Miller <brady.g.miller@gmail.com>
12 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
15 require_once("../interface/globals.php");
17 use OpenEMR\Common\Acl\AclMain;
18 use OpenEMR\Common\Csrf\CsrfUtils;
19 use OpenEMR\Core\Header;
20 use OpenEMR\Services\DocumentTemplates\DocumentTemplateService;
21 use OpenEMR\Services\QuestionnaireService;
22 use OpenEMR\Events\Messaging\SendSmsEvent;
23 use Symfony\Component\EventDispatcher\GenericEvent;
26 if (!(isset($GLOBALS['portal_onsite_two_enable'])) || !($GLOBALS['portal_onsite_two_enable'])) {
27 echo xlt('Patient Portal is turned off');
28 exit;
31 $eventDispatcher = $GLOBALS['kernel']->getEventDispatcher();
32 $authUploadTemplates = AclMain::aclCheckCore('admin', 'forms');
34 $templateService = new DocumentTemplateService();
35 $from_demo_pid = $_GET['from_demo_pid'] ?? '0';
36 $patient = $_REQUEST['selected_patients'] ?? null;
37 $patient = $patient ?: ($_REQUEST['upload_pid'] ?? 0);
39 $category = $_REQUEST['template_category'] ?? '';
40 $category_list = $templateService->fetchDefaultCategories();
41 $profile_list = $templateService->fetchDefaultProfiles();
42 $group_list = $templateService->fetchDefaultGroups();
44 $none_message = xlt("Nothing to show for current actions.");
47 <!DOCTYPE html>
48 <head>
49 <meta charset="UTF-8">
50 <title><?php echo xlt('Portal'); ?> | <?php echo xlt('Templates'); ?></title>
51 <meta name="description" content="Developed By sjpadgett@gmail.com">
52 <?php Header::setupHeader(['datetime-picker', 'select2', 'ckeditor']); ?>
53 <script>
54 const profiles = <?php echo js_escape($profile_list); ?>;
55 let currentEdit = "";
56 let editor;
57 let callBackCmd = null;
59 <?php
60 $eventDispatcher->dispatch(new SendSmsEvent(), SendSmsEvent::JAVASCRIPT_READY_SMS_POST);
62 // a callback from dlgclose(fn) in render form
63 function doImportSubmit() {
64 // todo add message to user
65 top.restoreSession();
66 document.getElementById('form_upload').submit();
67 return false;
70 function resolveImport(mode = 'render_import') {
71 if (mode === 'render_import') {
72 const file = document.getElementById("fetch_files").files.item(0);
73 if (file.name.toLowerCase().indexOf('.json') === -1 && file.type !== 'application/json') {
74 return false;
77 top.restoreSession();
78 callBack = '';
79 let url = './questionnaire_render.php?mode=' + encodeURIComponent(mode);
80 dlgopen(url, 'pop-questionnaire', 'modal-lg', 850, '', '', {
81 allowDrag: true,
82 allowResize: true,
83 sizeHeight: 'full',
84 resolvePromiseOn: 'close',
85 }).then(() => {
86 // set callBackCmd from iframe then eval here
87 // currently using callback from dlgclose();
88 return false;
89 });
92 let questionnaireViewCurrent = function (encounter, flag = '') {
93 currentEdit = encounter;
94 alertMsg(xl("New coming feature. View patient progress with the completion of the form with the ability to send a secure notification to patient."), 6000, 'success')
95 return false;
98 let templateEdit = function (id, flag = '') {
99 currentEdit = id;
100 handleTemplate(id, 'get', '', flag);
101 return false;
104 let templateSave = function () {
105 let markup = CKEDITOR.instances.templateContent.getData();
106 handleTemplate(currentEdit, 'save', markup);
109 let templateDelete = function (id, template = '') {
110 let delok = confirm(<?php echo xlj('You are about to delete a template'); ?> +
111 ": " + "\n" + <?php echo xlj('Is this Okay?'); ?>);
112 if (delok === true) {
113 handleTemplate(id, 'delete', '', false, template, <?php echo js_escape(CsrfUtils::collectCsrfToken('import-template-delete')); ?>)
115 return false;
118 function getSendChecks() {
119 let checked = [];
120 $('input:checked[name=send]:checked').each(function () {
121 let isProfile = this.dataset.send_profile;
122 if (isProfile == 'yes') {
123 checked.push([$(this).val(), true]);
124 } else {
125 checked.push($(this).val());
128 console.log(checked)
129 return checked;
132 function getSendCheckProfiles() {
133 let checked = [];
134 $('input:checked[name=send_profile]:checked').each(
135 function () {
136 let isProfile = this.dataset.send_profile;
137 if (isProfile == 'yes') {
138 checked.push($(this).val());
141 console.log(checked)
142 return checked;
145 function updateCategory(id) {
146 top.restoreSession();
147 let url = 'import_template.php';
148 let category = event.currentTarget.value;
149 const data = new FormData();
150 data.append('docid', id);
151 data.append('category', category);
152 data.append('mode', 'update_category');
153 fetch(url, {
154 method: 'POST',
155 body: data,
156 }).then(rtn => rtn.text()).then((rtn) => {
157 (async (time) => {
158 await asyncAlertMsg(rtn, time, 'success', 'lg');
159 })(2000).then(rtn => {
160 //document.edit_form.submit();
162 }).catch((error) => {
163 console.error('Error:', error);
167 function sendTemplate(mode = 'send', content = '') {
168 top.restoreSession();
169 let url = 'import_template.php';
170 let ids = $('#selected_patients').select2('val');
171 let category = $('#template_category').val();
172 let checked = getSendChecks();
173 const data = new FormData();
174 data.append('docid', JSON.stringify(ids));
175 data.append('category', category);
176 data.append('checked', JSON.stringify(checked));
177 data.append('mode', mode);
178 data.append('content', content);
179 fetch(url, {
180 method: 'POST',
181 body: data,
182 }).then(rtn => rtn.text()).then((rtn) => {
183 (async (time) => {
184 await asyncAlertMsg(rtn, time, 'success', 'lg');
185 })(1500).then(rtn => {
186 document.edit_form.submit();
188 }).catch((error) => {
189 console.error('Error:', error);
193 function sendProfiles() {
194 top.restoreSession();
195 let mode = 'send_profiles'
196 let url = 'import_template.php';
197 let checked = getSendCheckProfiles();
198 const data = new FormData();
199 data.append('checked', JSON.stringify(checked));
200 data.append('mode', mode);
201 fetch(url, {
202 method: 'POST',
203 body: data,
204 }).then(rtn => rtn.text()).then((rtn) => {
205 (async (time) => {
206 await asyncAlertMsg(rtn, time, 'success', 'lg');
207 })(1500).then(rtn => {
208 document.edit_form.submit();
210 }).catch((error) => {
211 console.error('Error:', error);
215 function handleTemplate(id, mode, content = '', isDocument = '', template = '', csrf = '') {
216 top.restoreSession();
217 let libUrl = 'import_template.php';
218 let renderUrl = 'import_template.php?mode=editor_render_html&docid=' + id;
220 if (document.getElementById('is_modal').checked && mode === 'get') {
221 dialog.popUp(renderUrl, null, 'edit' + id);
222 return false;
224 if (isDocument == true) {
225 dialog.popUp(renderUrl, null, ('edit' + id));
226 return false;
228 if (mode == 'get') {
229 renderUrl += '&dialog=true';
230 dlgopen(renderUrl, 'pop-editor', 'modal-lg', 850, '', '', {
231 resolvePromiseOn: 'show',
232 allowDrag: true,
233 allowResize: true,
234 sizeHeight: 'full'
237 $.ajax({
238 type: "POST",
239 url: libUrl,
240 data: {docid: id, mode: mode, content: content, template: template, csrf_token_form: csrf},
241 error: function (qXHR, textStatus, errorThrow) {
242 console.log("There was an error");
243 alert(<?php echo xlj("File Error") ?> +"\n" + id)
245 success: function (templateHtml, textStatus, jqXHR) {
246 document.edit_form.submit();
251 function popProfileDialog() {
252 top.restoreSession();
253 let url = './import_template.php?mode=render_profile';
254 dlgopen(url, 'pop-profile', 'modal-lg', 850, '', '', {
255 allowDrag: true,
256 allowResize: true,
257 sizeHeight: 'full',
261 function popPatientDialog() {
262 top.restoreSession();
263 let url = './lib/patient_groups.php';
264 dlgopen(url, 'pop-profile', 'modal-lg', 850, '', '', {
265 allowDrag: true,
266 allowResize: true,
267 sizeHeight: 'full'
271 function popGroupsDialog() {
272 let url = './lib/patient_groups.php?render_group_assignments=true';
273 dlgopen(url, 'pop-groups', 'modal-lg', 850, '', '', {
274 allowDrag: true,
275 allowResize: true,
276 sizeHeight: 'full',
280 function createBlankTemplate() {
281 top.restoreSession();
282 let name = prompt(xl('Enter a valid name for this new template.') + "\n" + xl("For example: Pain Assessment"));
283 if (name === null) {
284 return false;
286 if (name === "") {
287 alert(xl('A name must be entered. Try again.'));
288 createBlankTemplate();
290 $("#upload_name").val(name);
291 return true;
294 $(function () {
295 let ourSelect = $('.select-questionnaire');
296 ourSelect.select2({
297 multiple: false,
298 placeholder: xl('Type to search Questionnaire Repository.'),
299 theme: 'bootstrap4',
300 dropdownAutoWidth: true,
301 width: 'resolve',
302 closeOnSelect: true,
303 <?php require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?>
305 $(document).on('select2:open', () => {
306 document.querySelector('.select2-search__field').focus();
308 ourSelect.on("change", function (e) {
309 let data = $('#select_item').select2('data');
310 if (data) {
311 document.getElementById('upload_name').value = data[0].text;
313 $('#repository-submit').removeClass('d-none');
316 $("#repository-submit").on("click", function (e) {
317 top.restoreSession();
318 let data = $('#select_item').select2('data');
319 if (data) {
320 document.getElementById('upload_name').value = data[0].text;
321 } else {
322 alert(xl("Missing Template name."))
323 return false;
325 return true;
328 $('.select-dropdown').removeClass('d-none');
329 $('.select-dropdown').select2({
330 multiple: true,
331 placeholder: xl('Type to search.'),
332 theme: 'bootstrap4',
333 dropdownAutoWidth: true,
334 width: 'resolve',
335 closeOnSelect: false,
336 <?php require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?>
339 $('#fetch_files').on('click touchstart', function () {
340 $(this).val('');
343 $('#fetch_files').change(function (e) {
344 const file = document.getElementById("fetch_files").files.item(0);
345 const fileName = file.name;
346 let howManyFiles = document.getElementById("fetch_files").files.length;
347 $('#upload_submit').removeClass('d-none');
348 if (howManyFiles === 1 && document.getElementById("upload_scope").checked) {
349 if (fileName.toLowerCase().indexOf('.json') > 0 || file.type === 'application/json') {
350 $('#upload_submit_questionnaire').removeClass('d-none');
351 resolveImport();
353 } else {
354 if (fileName.toLowerCase().indexOf('.json') > 0 || file.type === 'application/json') {
355 document.getElementById("upload_submit_questionnaire").type = 'submit';
356 document.getElementById("upload_submit_questionnaire").removeAttribute("onclick");
357 document.getElementById("upload_submit_questionnaire").innerText = xl("Questionnaires Repository All")
358 $('#upload_submit_questionnaire').removeClass('d-none');
361 return false;
364 $('input:checkbox[name=send]').change(function () {
365 let checked = getSendChecks();
366 if (checked.length > 0) {
367 $('#send-button').removeClass('d-none');
368 $('#category_group').addClass('d-none');
369 $('#send-profile-hide').addClass('d-none');
370 } else {
371 $('#send-button').addClass('d-none');
372 $('#category_group').removeClass('d-none');
376 $('input:checkbox[name=send_profile]').change(function () {
377 $('#send-profile-hide').removeClass('d-none');
378 $('#category_group').addClass('d-none');
379 $('input:checkbox[name=send]').addClass('d-none');
382 $('#selected_patients').on('select2:close', function () {
383 let checked = getSendChecks();
384 if (checked.length > 0) {
385 return false;
387 $('#edit_form').submit();
390 $('#upload-nav').on('hidden.bs.collapse', function () {
391 $('#upload-nav-value').val('collapse');
393 $('#upload-nav').on('show.bs.collapse', function () {
394 $('#upload-nav-value').val('show');
395 //$('#edit_form').submit();
398 $("#template_category").change(function () {
399 $('#edit_form').submit();
402 $('#template-collapse').on('show.bs.collapse', function () {
403 $('#edit_form #all_state').val('show');
405 $('#template-collapse').on('hidden.bs.collapse', function () {
406 $('#edit_form #all_state').val('collapse');
409 $('#assigned_collapse').on('show.bs.collapse', function () {
410 $('#repository-collapse').collapse('hide');
411 $('#template-collapse').collapse('hide');
412 $('#edit_form #assigned_state').val('show');
414 $('#assigned_collapse').on('hidden.bs.collapse', function () {
415 $('#edit_form #assigned_state').val('collapse');
418 $('#repository-collapse').on('show.bs.collapse', function () {
419 $('#edit_form #repository_send_state').val('show');
421 $('#repository-collapse').on('hidden.bs.collapse', function () {
422 $('#edit_form #repository_send_state').val('collapse');
425 let selText = '';
426 let selCat = $('#template_category').find(':selected').text();
427 let ids = $('#selected_patients').find(':selected').each(function () {
428 selText += $(this).text() + '; ';
430 $('#upload_scope_category').empty().append(' ' + xl('For Category') + ': ' + selCat);
432 $(document).on('select2:open', () => {
433 document.querySelector('.select2-search__field').focus();
437 </script>
438 <style>
439 caption {
440 caption-side: top !important;
442 </style>
443 </head>
444 <body class="body-top">
445 <div class='container-xl'>
446 <nav class='nav navbar bg-light text-dark sticky-top'>
447 <span class='title'><?php echo xlt('Template Maintenance'); ?></span>
448 <div class="ml-auto">
449 <label class="form-check"><?php echo xlt('Full Editor'); ?>
450 <input type='checkbox' class='form-check-inline mx-1' id='is_modal' name='is_modal' checked='checked' />
451 </label>
452 </div>
453 <div class='btn-group ml-1'>
454 <button type='button' class='btn btn-secondary' data-toggle='collapse' data-target='#help-panel'>
455 <?php echo xlt('Help') ?>
456 </button>
457 <button class='btn btn-success' type='button' onclick="location.href='./patient/provider'">
458 <?php echo xlt('Dashboard'); ?>
459 </button>
460 </div>
461 </nav>
462 <div class='col col-12'>
463 <hr />
464 <?php include_once('./../Documentation/help_files/template_maintenance_help.php'); ?>
465 <!-- Actions Scope to act on -->
466 <nav class='navbar navbar-dark bg-dark text-light sticky-top'>
467 <form id="edit_form" name="edit_form" class="row form-inline w-100" action="" method="get">
468 <a class='navbar-brand ml-1'><?php echo xlt('Scope'); ?></a>
469 <div class="form-group">
470 <label class='font-weight-bold mx-1' for='selected_patients'><?php echo xlt('Location'); ?></label>
471 <?PHP
472 $ppt = $templateService->fetchPortalAuthUsers();
473 $auth = '';
474 foreach ($ppt as $pt) {
475 if (!empty($from_demo_pid)) {
476 $patient = [$from_demo_pid];
478 if ((is_array($patient) && !in_array($pt['pid'], $patient)) || empty($patient)) {
479 $auth .= '<option value=' . attr($pt['pid']) . '>' . text($pt['ptname']) . '</option>';
480 } else {
481 $auth .= "<option value='" . attr($pt['pid']) . "' selected='selected'>" . text($pt['ptname'] . ' ') . '</option>';
485 <select class="form-control select-dropdown d-none" id="selected_patients" name="selected_patients[]" multiple="multiple">
486 <?php echo $auth ?>
487 </select>
488 <a class='btn-refresh ml-1' onclick="$('#selected_patients').val(null).trigger('change');" role="button"></a>
489 </div>
490 <?php
491 $select_cat_options = '<option value="">' . xlt('General') . "</option>\n";
492 foreach ($category_list as $option_category) {
493 if (stripos($option_category['option_id'], 'repository') !== false) {
494 continue;
496 if ($category === $option_category['option_id']) {
497 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "' selected>" . text($option_category['title']) . "</option>\n";
498 } else {
499 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "'>" . text($option_category['title']) . "</option>\n";
503 <div class="input-group" id="category_group">
504 <label class="font-weight-bold mx-1" for="template_category"><?php echo xlt('Category'); ?></label>
505 <select class="form-control" id="template_category" name="template_category">
506 <?php echo $select_cat_options ?>
507 </select>
508 </div>
509 <div class="form-group">
510 <div class='btn-group ml-1'>
511 <button type='submit' class='btn btn-search btn-light'><i class="btn-refresh"></i></button>
512 <button type='button' id="send-button" class='btn btn-transmit btn-success d-none' onclick="return sendTemplate()">
513 <?php echo xlt('Send'); ?>
514 </button>
515 <button type='button' class='btn btn-primary' onclick='return popProfileDialog()'><?php echo xlt('Profiles') ?></button>
516 <button type='button' class='btn btn-primary' onclick='return popPatientDialog()'><?php echo xlt('Groups') ?></button>
517 <button type='button' class='btn btn-primary' onclick='return popGroupsDialog()'><?php echo xlt('Assign') ?></button>
518 </div>
519 </div>
520 <input type='hidden' id='upload-nav-value' name='upload-nav-value' value='<?php echo attr($_REQUEST['upload-nav-value'] ?? 'collapse') ?>' />
521 <input type='hidden' id='persist_checks' name='persist_checks' value='' />
522 <input type='hidden' id='all_state' name='all_state' value='<?php echo attr($_REQUEST['all_state'] ?? 'collapse') ?>' />
523 <input type='hidden' id='assigned_state' name='assigned_state' value='<?php echo attr($_REQUEST['assigned_state'] ?? 'collapse') ?>' />
524 <input type='hidden' id='repository_send_state' name='repository_send_state' value='<?php echo attr($_REQUEST['repository_send_state'] ?? 'collapse') ?>' />
525 </form>
526 </nav>
527 <!-- Upload -->
528 <nav class="collapse my-2 <?php echo attr($_REQUEST['upload-nav-value'] ?? '') ?>" id="upload-nav">
529 <div class='col col-12'>
530 <?php if ($authUploadTemplates) { ?>
531 <form id='form_upload' class='form-inline row' action='import_template.php' method='post' enctype='multipart/form-data'>
532 <input type="hidden" name="csrf_token_form" id="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken('import-template-upload')); ?>" />
533 <hr />
534 <div class='col'>
535 <div id='upload_scope_category'></div>
536 <div class="input-group">
537 <label class="form-check"><?php echo xlt('If questionnaire import, use Questionnaire tool'); ?>
538 <input type="checkbox" class='form-check-inline ml-1' id='upload_scope' checked>
539 </div>
540 </div>
541 <div class='form-group col'>
542 <input type='file' class='btn btn-outline-info mr-1 mt-1' id="fetch_files" name='template_files[]' multiple />
543 <div class="mt-1">
544 <button class='btn btn-outline-success d-none' type='submit' name='upload_submit' id='upload_submit' title="<?php echo xla("Import a template file or if a Questionnaire then auto create a questionnaire template."); ?>">
545 <i class='fa fa-upload mr-1' aria-hidden='true'></i><?php echo xlt("Templates"); ?></button>
546 <button class='btn btn-outline-success d-none' type='button' name='upload_submit_questionnaire' id='upload_submit_questionnaire' title="<?php echo xla("Import to the questionnaire repository for later use in encounters or FHIR API"); ?>" onclick="return resolveImport();">
547 <i class='fa fa-upload mr-1' aria-hidden='true'></i><?php echo xlt("Questionnaires Repository"); ?></button>
548 <button type='button' id='render-nav-button' name='render-nav-button' class='btn btn-save btn-outline-primary' onclick="return resolveImport('render_import_manual');" title="<?php echo xla('Used to cut and paste Questionnaire or LHC Form json. Will then convert and import to questionnaire repository.') ?>"><?php echo xlt('Manual Questionnaire') ?></button>
549 <button type='submit' id='blank-nav-button' name='blank-nav-button' class='btn btn-save btn-outline-primary' onclick="return createBlankTemplate();" title="<?php echo xla('Use this to create a new empty template for use with built in editor.') ?>"><?php echo xlt('New Empty Template') ?></button>
550 </div>
551 </div>
552 <div class="mt-2">
553 <div class="text-center m-0 p-0"><small class="my-1 font-weight-bolder font-italic"><?php echo xlt("Shows all existing Questionnaires available from repository. Select to automatically create template."); ?></small></div>
554 <div class="input-group input-group-append">
555 <select class="select-questionnaire" type="text" id="select_item" name="select_item" autocomplete="off" role="combobox" aria-expanded="false" title="<?php echo xla('Items that are already an existing template will be overwritten if selected.') ?>">
556 <option value=""></option>
557 <?php
558 $qService = new QuestionnaireService();
559 $q_list = $qService->getQuestionnaireList(false);
560 $repository_item = $_POST['select_item'] ?? null;
561 foreach ($q_list as $item) {
562 $id = attr($item['id']);
563 if ($id == $repository_item) {
564 echo "<option selected value='$id'>" . text($item['name']) . "</option>";
565 continue;
567 echo "<option value='$id'>" . text($item['name']) . "</option>";
570 </select>
571 <button type='submit' id='repository-submit' name='repository-submit' class='btn btn-save btn-success d-none' value="true"><?php echo xlt('Create') ?></button>
572 </div>
573 </div>
574 <input type='hidden' name='upload_pid' value='<?php echo attr(json_encode([-1])); ?>' />
575 <input type='hidden' name="template_category" value='<?php echo attr($category); ?>' />
576 <input type='hidden' name='upload_name' id='upload_name' value='<?php echo attr(json_encode([-1])); ?>' />
577 <input type="hidden" id="q_mode" name="q_mode" value="" />
578 <input type="hidden" id="lform" name="lform" value="" />
579 <input type="hidden" id="questionnaire" name="questionnaire" value="" />
580 </form>
581 <?php } else { ?>
582 <div class="alert alert-danger"><?php echo xlt("Not Authorized to Upload Templates") ?></div>
583 <?php } ?>
584 </div>
585 </nav>
586 <hr />
587 <!-- Repository -->
588 <div class='row'>
589 <div class='col col-12'>
590 <div class="h5"><i class='fa fa-eye mr-1' data-toggle='collapse' data-target='#repository-collapse' role='button' title="<?php echo xla('Click to expand or collapse Repository templates panel.'); ?>"></i><?php echo xlt('Template Repository') ?>
591 <span>
592 <button type='button' id='upload-nav-button' name='upload-nav-button' class='btn btn-sm btn-primary' data-toggle='collapse' data-target='#upload-nav'>
593 <i class='fa fa-upload mr-1' aria-hidden='true'></i><?php echo xlt('Upload') ?></button>
594 </span>
595 </div>
596 </div>
597 <!-- Repository table -->
598 <div class='col col-12 table-responsive <?php echo attr($_REQUEST['repository_send_state'] ?? 'collapse') ?>' id="repository-collapse">
599 <?php
600 $templates = [];
601 $show_cat_flag = false;
602 if (!empty($category)) {
603 $templates = $templateService->getTemplateListByCategory($category, -1);
604 } else {
605 $templates = $templateService->getTemplateListAllCategories(-1);
607 echo "<table class='table table-sm table-striped table-bordered'>\n";
608 echo "<thead>\n";
609 echo "<tr>\n" .
610 "<th style='width:5%'>" . xlt('Send') . "</th>" .
611 '<th>' . xlt('Category') . '</th>' .
612 "<th>" . xlt("Template Actions") . "</th>" .
613 "<th>" . xlt("Size") . "</th>" .
614 "<th>" . xlt("Last Modified") . "</th>" .
615 "</tr>\n";
616 echo "</thead>\n";
617 echo "<tbody>\n";
618 foreach ($templates as $cat => $files) {
619 if (empty($cat)) {
620 $cat = xlt('General');
622 foreach ($files as $file) {
623 $template_id = $file['id'];
624 $this_cat = $file['category'];
625 $notify_flag = false;
626 $select_cat_options = '<option value="">' . xlt('General') . "</option>\n";
627 foreach ($category_list as $option_category) {
628 if (stripos($option_category['option_id'], 'repository') !== false) {
629 continue;
631 if ($this_cat === $option_category['option_id']) {
632 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "' selected>" . text($option_category['title']) . "</option>\n";
633 } else {
634 $select_cat_options .= "<option value='" . attr($option_category['option_id']) . "'>" . text($option_category['title']) . "</option>\n";
637 echo "<tr>";
638 if ($file['mime'] == 'application/pdf') {
639 $this_cat = xlt('PDF Document');
640 $notify_flag = true;
641 echo '<td>' . '*' . '</td>';
642 echo "<td>" . $this_cat . " Id: " . attr($template_id) . "</td>";
643 } else {
644 echo "<td><input type='checkbox' class='form-check-inline' name='send' value='" . attr($template_id) . "' /></td>";
645 echo '<td><select class="form-control form-control-sm" id="category_table' . attr($template_id) .
646 '" onchange="updateCategory(' . attr_js($template_id) . ')" value="' . attr($this_cat) . '">' .
647 $select_cat_options . '</select></td>';
649 echo '<td>' .
650 '<button id="templateEdit' . attr($template_id) .
651 '" class="btn btn-sm btn-outline-primary" onclick="templateEdit(' . attr_js($template_id) . ',' . attr_js($notify_flag) . ')" type="button">' . text($file['template_name']) .
652 '</button>';
653 if ($authUploadTemplates) {
654 echo '<button id="templateDelete' . attr($template_id) .
655 '" class="btn btn-sm btn-outline-danger float-right" onclick="templateDelete(' . attr_js($template_id) . ',' . attr_js($file['template_name']) . ')" type="button">' . xlt("Delete") .
656 '</button>';
658 echo "</td>";
659 echo "<td>" . text($file['size']) . "</td>";
660 echo "<td>" . text(date('m/d/Y H:i:s', strtotime($file['modified_date']))) . "</td>";
661 echo "</tr>";
663 <?php
666 if (empty($template_id)) {
667 echo '<tr><td></td><td>' . $none_message . "</td></tr>\n";
669 echo "</tbody>\n";
670 echo "</table>\n";
672 <div>
673 <?php
674 echo "<table class='table table-sm table-striped table-bordered'>\n";
675 echo '<caption>' . xlt('Profiles in Portal') . "</caption>";
676 echo "<thead>\n";
677 echo "<tr>\n" .
678 "<th>" . xlt('Active') . "<button type='button' id='send-profile-hide' class='btn btn-sm ml-1 py-0 btn-transmit btn-success d-none' onclick='return sendProfiles()'>" . xlt('Update') . "</button></th>" .
679 '<th style="min-width: 25%">' . xlt('Profile') . '</th>' .
680 '<th>' . xlt('Assigned Templates') . '</th>' .
681 '<th>' . xlt('Assigned Groups') . '</th>' .
682 "</tr>\n";
683 echo "</thead>\n";
684 foreach ($profile_list as $profile => $profiles) {
685 $template_list = '';
686 $group_list_text = '';
687 $group_items_list = $templateService->getPatientGroupsByProfile($profile);
688 $profile_items_list = $templateService->getTemplateListByProfile($profile);
689 if (empty($profile_items_list)) {
690 continue;
692 $total = 0;
693 foreach ($profile_items_list as $key => $files) {
694 $total += count($files ?? []);
695 foreach ($files as $file) {
696 if (is_array($file)) {
697 $template_list .= $file['template_name'] . ', ';
701 $template_list = substr($template_list, 0, -2);
702 $profile_esc = attr($profile);
703 foreach ($group_items_list as $key => $groups) {
704 foreach ($groups as $group) {
705 if (is_array($group)) {
706 $group_list_text .= $group_list[$group['member_of']]['title'] . ', ';
710 $group_list_text = substr($group_list_text, 0, -2);
711 $send = 'send';
712 if (!empty($group_list_text)) {
713 $send = 'send_profile';
715 echo '<tr>';
716 $is_checked = '';
717 if ((int)$templateService->fetchProfileStatus($profiles['option_id']) === 1) {
718 $is_checked = 'checked';
720 echo "<td><input type='checkbox' class='form-check-inline' $is_checked name='" . attr($send) . "' data-send_profile='yes' value='" . $profile_esc . "' /></td>";
721 echo '<td>' . text($profiles['title']) . '</td>';
722 echo '<td><em>' . text($template_list) . '</em></td>';
723 echo '<td><em>' . text($group_list_text) . '</em></td>';
724 echo '</tr>';
726 if (empty($profile_list)) {
727 echo '<tr><td></td><td>' . $none_message . "</td></tr>\n";
729 echo "</tbody>\n";
730 echo "</table>\n";
732 </div>
733 </div>
734 </div>
735 <!-- All Patients -->
736 <hr />
737 <div class='row'>
738 <div class='col col-12' data-toggle='collapse' data-target='#template-collapse'>
739 <h5><i class='fa fa-eye mr-1' role='button' title="<?php echo xla('Click to expand or collapse All active patient templates panel.'); ?>"></i><?php echo '' . xlt('Default Patient Templates') . '' ?></h5>
740 </div>
741 <div class='col col-12 table-responsive <?php echo attr(($_REQUEST['all_state'] ?? '') ?: 'collapse') ?>' id='template-collapse'>
742 <?php
743 $templates = [];
744 $show_cat_flag = false;
745 if (!empty($category)) {
746 $templates = $templateService->getTemplateListByCategory($category);
747 } else {
748 $templates = $templateService->getTemplateListAllCategories();
750 echo "<table class='table table-sm table-striped table-bordered'>\n";
751 echo "<thead>\n";
752 echo "<tr>\n" .
753 '<th>' . xlt('Category') . '</th>' .
754 '<th>' . xlt('Template Actions') . '</th>' .
755 '<th>' . xlt('Size') . '</th>' .
756 '<th>' . xlt('Last Modified') . '</th>' .
757 "</tr>\n";
758 echo "</thead>\n";
759 echo "<tbody>\n";
760 foreach ($templates as $cat => $files) {
761 if (empty($cat)) {
762 $cat = xlt('General');
764 foreach ($files as $file) {
765 $template_id = $file['id'];
766 echo '<tr>';
767 /*echo "<td><input type='checkbox' class='form-check-inline' id='send' name='send' value='" . attr($template_id) . "' /></td>";*/
768 echo '<td>' . text(ucwords($cat)) . '</td><td>';
769 echo '<button id="templateEdit' . attr($template_id) .
770 '" class="btn btn-sm btn-outline-primary" onclick="templateEdit(' . attr_js($template_id) . ')" type="button">' . text($file['template_name']) . '</button>';
771 if ($authUploadTemplates) {
772 echo '<button id="templateDelete' . attr($template_id) .
773 '" class="btn btn-sm btn-outline-danger" onclick="templateDelete(' . attr_js($template_id) . ')" type="button">' . xlt('Delete') . '</button>';
775 echo '<td>' . text($file['size']) . '</td>';
776 echo '<td>' . text(date('m/d/Y H:i:s', strtotime($file['modified_date']))) . '</td>';
777 echo '</tr>';
779 <?php
782 if (empty($files)) {
783 echo '<tr><td>' . $none_message . "</td></tr>\n";
785 echo "</tbody>\n";
786 echo "</table>\n";
788 </div>
789 </div>
790 <hr />
791 <div class='row'>
792 <div class='col col-12'>
793 <div class='h5'>
794 <i class='fa fa-eye mr-1' data-toggle='collapse' data-target='#assigned_collapse' role='button' title="<?php echo xla('Click to expand or collapse Assigned Patients panel.'); ?>"></i><?php echo xlt('Patient Assigned Templates') ?>
795 </div>
796 </div>
797 <!-- Assigned table -->
798 <div class='col col-12 table-responsive <?php echo attr(($_REQUEST['assigned_state'] ?? '') ?: 'collapse') ?>' id="assigned_collapse">
799 <?php
800 // by categories and patient pid.
801 $templates = [];
802 $show_cat_flag = false;
803 if (is_array($patient) && $patient[0] === '0') {// All templates for all patients
804 $patient_templates = $templateService->getPortalAssignedTemplates(0, $category, false);
805 } else {// Category selected so get all of them for pid's
806 $patient_templates = $templateService->getTemplateCategoriesByPids($patient, $category);
808 echo "<table class='table table-sm table-bordered'>\n";
809 echo "<tbody>";
810 $idcnt = 0;
811 foreach ($patient_templates as $name => $templates) {
812 $count = 0;
813 $fetched_groups = $fetch_pid = null;
814 foreach ($templates as $c => $t) {
815 if (is_array($t)) {
816 $fetch_pid = $t[0]['pid'];
817 if (empty($fetched_groups)) {
818 $fetched_groups = str_replace('|', ', ', $t[0]['patient_groups'] ?? '');
820 $count += count($t);
824 echo "<tr><td class='h6 font-weight-bolder bg-light text-dark' data-toggle='collapse' data-target='" .
825 attr('#id' . ++$idcnt) . "' role='button'>" . text($name) .
826 " (" . text($count . ' ' . xl('Templates')) . ") in " . text($fetched_groups) . "</td></tr>";
827 echo "<td class='collapse' id='" . attr('id' . $idcnt) . "'><table class='table table-sm table-striped table-bordered'>\n";
828 //echo '<caption><h5>' . text($name) . '</h5></caption>';
829 echo "<thead>\n";
830 echo "<tr>\n" .
831 '<th>' . xlt('Category') . '</th>' .
832 '<th>' . xlt('Profile') . '</th>' .
833 '<th>' . xlt('Template Actions') . '</th>' .
834 '<th>' . xlt('Status') .
835 '</th><th>' . xlt('Last Action') . '</th>' .
836 '<th>' . xlt('Next Due') .
837 "</th></tr>\n";
838 echo "</thead>\n";
839 echo "<tbody>\n";
840 foreach ($templates as $cat => $files) {
841 if (empty($cat)) {
842 $cat = xlt('General');
844 foreach ($files as $file) {
845 $template_id = $file['id'];
846 $audit_status = array(
847 'pid' => '',
848 'create_date' => (($file['profile_date'] ?? null) ?: $file['modified_date']) ?? '',
849 'doc_type' => '',
850 'patient_signed_time' => '',
851 'authorize_signed_time' => '',
852 'patient_signed_status' => '',
853 'review_date' => '',
854 'denial_reason' => $file['status'] ?? '',
855 'file_name' => '',
856 'file_path' => '',
858 $audit_status_fetch = $templateService->fetchTemplateStatus($file['pid'], $file['id']);
859 if (is_array($audit_status_fetch)) {
860 $audit_status = $audit_status_fetch;
862 $next_due = $templateService->showTemplateFromEvent($file, true);
863 if ($next_due > 1) {
864 if ($audit_status['denial_reason'] === 'In Review') {
865 $audit_status['denial_reason'] = xl('Scheduled') . ' ' . xl('but Needs Review');
866 } else {
867 $audit_status['denial_reason'] = xl('Scheduled');
869 $next_due = date('m/d/Y', $next_due);
870 } elseif ($next_due === 1 || ($next_due === true && ($file['recurring'] ?? 0))) {
871 $audit_status['denial_reason'] = xl('Recurring');
872 $next_due = xl('Active');
873 } elseif ($next_due === 0) {
874 $audit_status['denial_reason'] = xl('Completed');
875 $next_due = xl('Inactive');
876 } elseif ($next_due === true && empty($file['recurring'] ?? 0)) {
877 $next_due = xl('Active');
880 echo '<tr><td>' . text(ucwords($cat)) . '</td>';
881 echo '<td>' . text($profile_list[$file['profile']]['title'] ?? '') . '</td>';
882 echo '<td>' .
883 '<button type="button" id="patientEdit' . attr($template_id) .
884 '" class="btn btn-sm btn-outline-primary" onclick="templateEdit(' . attr_js($template_id) . ')" title="' . xla("Click to edit in editor.") . '">' .
885 text($file['template_name']) . "</button>\n";
886 if ($authUploadTemplates && $cat == 'questionnaire' && !empty($audit_status['encounter'])) {
887 echo '<button type="button" id="patientView' . attr($template_id) .
888 '" class="btn btn-sm btn-outline-success" onclick="questionnaireViewCurrent(' . attr_js($audit_status['encounter']) . ')">' .
889 xlt("View") . "</button>\n";
891 if ($authUploadTemplates && empty($file['member_of']) && !empty($file['status'])) {
892 echo '<button type="button" id="patientDelete' . attr($template_id) .
893 '" class="btn btn-sm btn-outline-danger" onclick="templateDelete(' . attr_js($template_id) . ')">' . xlt('Delete') . "</button>\n";
895 $eventDispatcher->dispatch(new SendSmsEvent($fetch_pid, $file['template_name']), SendSmsEvent::ACTIONS_RENDER_SMS_POST);
897 echo '</td><td>' . text($audit_status['denial_reason']) . '</td>';
898 echo '<td>' . text(date('m/d/Y H:i:s', strtotime($audit_status['create_date']))) . '</td>';
899 echo '<td>' . text($next_due) . '</td>';
900 echo "</tr>\n";
903 echo "</tbody>\n";
904 echo "</table></td>\n";
906 if (empty($templates)) {
907 echo '<tr><td>' . xlt('Multi Select Patients or All Patients using toolbar Location') . "</td></tr>\n";
909 echo "</tbody>\n";
910 echo "</table>\n";
912 </div>
913 </div>
914 <hr />
915 </div>
916 </div>
917 </body>
918 </html>