diff --git a/interface/patient_file/report/patient_report.php b/interface/patient_file/report/patient_report.php index e7e47f1cff1..a017d255bd1 100644 --- a/interface/patient_file/report/patient_report.php +++ b/interface/patient_file/report/patient_report.php @@ -2,6 +2,8 @@ /** * Patient report + * TODO: Note that this file can be refactored to re-use shared code with the portal_patient_report.php file + * that file has been refactored to use twig templates and this file could be reworked to re-use much of that code * * @package OpenEMR * @link http://www.open-emr.org diff --git a/interface/super/edit_globals.php b/interface/super/edit_globals.php index 074b1508d2a..d01b57412a5 100644 --- a/interface/super/edit_globals.php +++ b/interface/super/edit_globals.php @@ -498,7 +498,7 @@ function checkBackgroundServices() } if ($fldtype == GlobalSetting::DATA_TYPE_HTML_DISPLAY_SECTION) { // if the field is an html display box we want to take over the entire real estate so we will continue from here. - include_once 'templates/field_html_display_section.php'; + include 'templates/field_html_display_section.php'; ++$i; // make sure we advance the iterator here... continue; } diff --git a/portal/home.php b/portal/home.php index c269aeb08a6..11a1c92ca75 100644 --- a/portal/home.php +++ b/portal/home.php @@ -24,7 +24,9 @@ use OpenEMR\Common\Csrf\CsrfUtils; use OpenEMR\Common\Twig\TwigContainer; +use OpenEMR\Common\Logging\SystemLogger; use OpenEMR\Events\PatientPortal\AppointmentFilterEvent; +use OpenEMR\Events\PatientReport\PatientReportFilterEvent; use OpenEMR\Events\PatientPortal\RenderEvent; use OpenEMR\Services\LogoService; use OpenEMR\Services\Utils\TranslationService; @@ -312,7 +314,14 @@ function buildNav($newcnt, $pid, $result): array // Render Home Page $twig = (new TwigContainer('', $GLOBALS['kernel']))->getTwig(); try { - echo $twig->render('portal/home.html.twig', [ + $healthSnapshot = [ + 'immunizationRecords' => $immunRecords, + 'patientID' => $pid + ]; + $patientReportEvent = new PatientReportFilterEvent(); + $patientReportEvent->setDataElement('healthSnapshot', $healthSnapshot); + $filteredEvent = $GLOBALS['kernel']->getEventDispatcher()->dispatch($patientReportEvent, PatientReportFilterEvent::FILTER_PORTAL_HEALTHSNAPSHOT_TWIG_DATA); + $data = [ 'user' => $user, 'whereto' => $_SESSION['whereto'] ?? null ?: ($whereto ?? '#quickstart-card'), 'result' => $result, @@ -352,7 +361,7 @@ function buildNav($newcnt, $pid, $result): array 'styleArray' => $styleArray, 'ccdaOk' => $ccdaOk, 'allow_custom_report' => $GLOBALS['allow_custom_report'] ?? '0', - 'immunRecords' => $immunRecords, + 'healthSnapshot' => $filteredEvent->getDataElement('healthSnapshot'), 'languageDirection' => $_SESSION['language_direction'] ?? 'ltr', 'dateDisplayFormat' => $GLOBALS['date_display_format'], 'timezone' => $GLOBALS['gbl_time_zone'] ?? '', @@ -363,8 +372,13 @@ function buildNav($newcnt, $pid, $result): array 'dashboardInjectCard' => RenderEvent::EVENT_DASHBOARD_INJECT_CARD, 'dashboardRenderScripts' => RenderEvent::EVENT_DASHBOARD_RENDER_SCRIPTS ] - ]); + ]; + + echo $twig->render('portal/home.html.twig', $data); } catch (LoaderError | RuntimeError | SyntaxError $e) { OpenEMR\Common\Session\SessionUtil::portalSessionCookieDestroy(); + if ($e instanceof SyntaxError) { + (new SystemLogger())->error($e->getMessage(), ['file' => $e->getFile(), 'trace' => $e->getTraceAsString()]); + } die(text($e->getMessage())); } diff --git a/portal/report/portal_patient_report.php b/portal/report/portal_patient_report.php index 39df9684a49..cdce53bec57 100644 --- a/portal/report/portal_patient_report.php +++ b/portal/report/portal_patient_report.php @@ -7,8 +7,10 @@ * @link https://www.open-emr.org * @author Jerry Padgett * @author Brady Miller + * @author Stephen Nielson * @copyright Copyright (c) 2016-2020 Jerry Padgett * @copyright Copyright (c) 2019 Brady Miller + * @copyright Copyright (C) 2024 Open Plan IT Ltd. * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 */ @@ -39,6 +41,11 @@ require_once("$srcdir/patient.inc.php"); use OpenEMR\Core\Header; +use OpenEMR\Common\Logging\SystemLogger; +use OpenEMR\Common\Twig\TwigContainer; +use OpenEMR\Controllers\Portal\PortalPatientReportController; +use OpenEMR\Events\PatientReport\PatientReportFilterEvent; +use Twig\Error\SyntaxError; // get various authorization levels $auth_notes_a = true; //AclMain::aclCheckCore('encounters', 'notes_a'); @@ -50,733 +57,85 @@ $auth_demo = true; //AclMain::aclCheckCore('patients' , 'demo'); $ignoreAuth_onsite_portal = true; -?> - - - - - - - -
-
-    - - | - -

- - - - - -
-
-
-
- >
-
- - Allergies
- Medications
- -
- - Medical Problems
- -
-
-
-
- - -
- - - - - - - -
-
- : -
-
- - - - \n"; - echo " \n"; - echo " \n"; - } - - $rowid = $prow['id']; - $disptitle = trim($prow['title']) ? $prow['title'] : "[Missing Title]"; - - $ieres = sqlStatement("SELECT encounter FROM issue_encounter WHERE " . - "pid = ? AND list_id = ?", [$pid, $rowid]); - - echo " \n"; - echo " \n"; - echo " \n"; - echo " \n"; - echo "\n"; - } - ?> -
" . text($disptype) . "
 "; - echo "" . text($disptitle) . "" . text($prow['begdate']); - - if ($prow['enddate']) { - echo " - " . text($prow['enddate']); - } else { - echo " Active"; - } - echo "
- -
-
-
- : -

- - - (Encounters not authorized) - - \n"; // end DIV encounter_forms - echo "
\n\n"; //end DIV encounter_data - echo "
"; - } - - $isfirst = 0; - echo "
\n"; - echo ""; - - // show encounter reason, not just 'New Encounter' - // trim to a reasonable length for display purposes --cfapress - $maxReasonLength = 20; - if (strlen($result["reason"]) > $maxReasonLength) { - $result['reason'] = substr($result['reason'], 0, $maxReasonLength) . " ... "; - } - - echo attr($result["reason"]) . - " (" . date("Y-m-d", strtotime($result["date"])) . - ")\n"; - echo "
\n"; - } else { - $form_name = trim($result["form_name"]); - //if form name is not in registry, look for the closest match by - // finding a registry name which is at the start of the form name. - //this is to allow for forms to put additional helpful information - //in the database in the same string as their form name after the name - $form_name_found_flag = 0; - foreach ($registry_form_name as $var) { - if ($var == $form_name) { - $form_name_found_flag = 1; - } - } - - // if the form does not match precisely with any names in the registry, now see if any front partial matches - // and change $form_name appropriately so it will print above in $toprint = $html_strings[$var] - if (!$form_name_found_flag) { - foreach ($registry_form_name as $var) { - if (strpos($form_name, $var) == 0) { - $form_name = $var; - } - } - } - - if (!is_array($html_strings[$form_name] ?? null)) { - $html_strings[$form_name] = array(); - } - - array_push($html_strings[$form_name], "" . text(xl_form_title($result["form_name"])) . "
\n"); - } - } - - foreach ($registry_form_name as $var) { - if ($toprint = $html_strings[$var] ?? null) { - foreach ($toprint as $var) { - print $var; - } - } - } - ?> - - - -
-
- - -


- - - - - - - - \n"; - echo " \n"; - echo " \n"; - echo " \n"; - echo " \n"; - echo " \n"; - } - ?> -
      
" . - "  " . text(oeFormatShortDate($row['date_ordered'])) . "  " . text(oeFormatShortDate($row['date'])) . "  "; - $opres = sqlStatement( - "SELECT procedure_code, procedure_name FROM procedure_order_code " . - "WHERE procedure_order_id = ? ORDER BY procedure_order_seq", - array($poid) - ); - while ($oprow = sqlFetchArray($opres)) { - $tmp = $oprow['procedure_name']; - if (empty($tmp)) { - $tmp = $oprow['procedure_code']; - } - - echo text($tmp) . "
"; - } - - echo "
- -
- :
-
    - Execute($sql, [$pid]); - if ($db->ErrorMsg()) { - echo $db->ErrorMsg(); - } - - while ($result && !$result->EOF) { - $fname = basename($result->fields['url']); - $extension = strtolower(substr($fname, strrpos($fname, "."))); - if ($extension !== '.zip' && $extension !== '.dcm') { - echo "
  • "; - echo ''; - echo '  ' . text(xl_document_category($result->fields['name'])) . ""; - echo '  ' . xlt('Name') . ': ' . text(basename($result->fields['url'])) . ""; - echo '
  • '; - } - - $result->MoveNext(); - } - ?> -
-
- -   -   - -
- +$portalPatientReportController = new PortalPatientReportController(); +$twig = (new TwigContainer(null, $GLOBALS['kernel']))->getTwig(); + +$issues = []; +$data = []; +try { + $data['phone_country_code'] = $GLOBALS['phone_country_code'] ?? ''; + $data['returnurl'] = (!empty($returnurl)) ? "$rootdir/patient_file/encounter/$returnurl" : ''; + $data['issues'] = $portalPatientReportController->getIssues($ISSUE_TYPES, $pid); + $data['encounters'] = $portalPatientReportController->getEncounters($pid); + $data['procedureOrders'] = $portalPatientReportController->getProcedureOrders($pid); + $data['documents'] = $portalPatientReportController->getDocuments($pid); + $data['phimail_enable'] = $GLOBALS['phimail_enable'] ?? false; + $data['phimail_ccr_enable'] = $GLOBALS['phimail_ccr_enable'] ?? false; + $data['phimail_ccd_enable'] = $GLOBALS['phimail_ccd_enable'] ?? false; + $data['sections'] = [ + 'demographics' => [ + 'selected' => true + ,'label' => xl('Demographics') + ] + ,'history' => [ + 'selected' => false + ,'label' => xl('History') + ] + ,'insurance' => [ + 'selected' => false + ,'label' => xl('Insurance') + ] + ,'billing' => [ + 'selected' => $GLOBALS['simplified_demographics'] ? false : true + ,'label' => xl('Billing') + ] + ,'allergies' => [ + 'selected' => false + ,'label' => xl('Allergies') + ] + ,'medications' => [ + 'selected' => false + ,'label' => xl('Medications') + ] + ,'immunizations' => [ + 'selected' => false + ,'label' => xl('Immunizations') + ] + ,'medical_problems' => [ + 'selected' => false + ,'label' => xl('Medical Problems') + ] + ,'notes' => [ + 'selected' => false + ,'label' => xl('Patient Notes') + ] + ,'transactions' => [ + 'selected' => false + ,'label' => xl('Transactions') + ] + ,'batchcom' => [ + 'selected' => false + ,'label' => xl('Communications') + ] + ]; + // what sections display can be controlled by the following two arrays + $data['section_one'] = [ + 'demographics', 'history', 'insurance', 'billing' + ]; + $data['section_two'] = [ + 'allergies', 'medications', 'immunizations', 'medical_problems', 'notes', 'transactions', 'batchcom' + ]; + $event = new PatientReportFilterEvent(); + $event->populateData($data); + $updatedEvent = $GLOBALS['kernel']->getEventDispatcher()->dispatch($event, PatientReportFilterEvent::FILTER_PORTAL_TWIG_DATA); + $updatedData = $event->getDataAsArray(); + echo $twig->render("portal/portal_patient_report.html.twig", $updatedData); +} catch (SyntaxError $exception) { + (new SystemLogger())->error($exception->getMessage(), ['trace' => $exception->getTraceAsString(), 'file' => $exception->getFile()]); + echo $twig->render("error/general_http_error.html.twig", []); +} catch (\Exception $exception) { + (new SystemLogger())->error($exception->getMessage(), ['trace' => $exception->getTraceAsString()]); + echo $twig->render("error/general_http_error.html.twig", []); +} +die(); diff --git a/src/Controllers/Portal/PortalPatientReportController.php b/src/Controllers/Portal/PortalPatientReportController.php new file mode 100644 index 00000000000..1a35aac21dc --- /dev/null +++ b/src/Controllers/Portal/PortalPatientReportController.php @@ -0,0 +1,220 @@ + + * @copyright Copyright (C) 2024 Open Plan IT Ltd. + * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 + */ + +namespace OpenEMR\Controllers\Portal; + +use OpenEMR\Common\Database\QueryUtils; + +class PortalPatientReportController +{ + public function getDocuments($pid) + { + + // show available documents + $sql = "SELECT d.id, d.url, d.name as document_name, c.name FROM documents AS d " . + "LEFT JOIN categories_to_documents AS ctd ON d.id=ctd.document_id " . + "LEFT JOIN categories AS c ON c.id = ctd.category_id WHERE " . + "d.foreign_id = ? AND d.deleted = 0"; + $records = QueryUtils::sqlStatementThrowException($sql, [$pid]); + $documents = []; + foreach ($records as $record) { + $fname = basename($record['url']); + $extension = strtolower(substr($fname, strrpos($fname, "."))); + if ($extension !== '.zip' && $extension !== '.dcm') { + $documents[] = [ + 'id' => $record['id'], + 'url' => basename($record['url']), + 'name' => $record['document_name'], + 'category' => xl_document_category($record['name']) + ]; + } + } + return $documents; + } + public function getProcedureOrders($pid) + { + $res = sqlStatement( + "SELECT po.procedure_order_id, po.date_ordered, fe.date " . + "FROM procedure_order AS po " . + "LEFT JOIN forms AS f ON f.pid = po.patient_id AND f.formdir = 'procedure_order' AND " . + "f.form_id = po.procedure_order_id AND f.deleted = 0 " . + "LEFT JOIN form_encounter AS fe ON fe.pid = f.pid AND fe.encounter = f.encounter " . + "WHERE po.patient_id = ? " . + "ORDER BY po.date_ordered DESC, po.procedure_order_id DESC", + array($pid) + ); + $procedures = []; + $proceduresById = []; + $index = 0; + while ($row = sqlFetchArray($res)) { + $poid = $row['procedure_order_id']; + $proceduresById[$poid] = $index++; + $procedures[] = [ + 'id' => $poid, + 'date_ordered' => $row['date_ordered'], + 'date' => $row['date'], + 'procedures' => [] + ]; + } + $sql = "SELECT procedure_order_id, procedure_code, procedure_name FROM procedure_order_code " . + "WHERE procedure_order_id IN (" . implode(",", array_keys($proceduresById)) . ") ORDER BY procedure_order_id, procedure_order_seq"; + $res = sqlStatement($sql); + while ($row = sqlFetchArray($res)) { + $poid = $row['procedure_order_id']; + $index = $proceduresById[$poid]; + $procedures[$index]['procedures'][] = [ + 'code' => $row['procedure_code'], + 'name' => $row['procedure_name'] + ]; + } + return $procedures; + } + + public function getIssues(array $ISSUE_TYPES, int $pid) + { + $issuesByType = []; + // get issues + $pres = sqlStatement("SELECT lists.* FROM lists " + . " WHERE lists.pid = ? " . + "ORDER BY lists.type, lists.begdate", [$pid]); + $lasttype = ""; + $lastEncounter = null; + $issuesIndex = 0; + $issuesByTypeMap = []; + while ($prow = sqlFetchArray($pres)) { + if ($lasttype != $prow['type']) { + $lasttype = $prow['type']; + + if (empty($issuesByType[$lasttype])) { + $issuesByType[$lasttype] = [ + 'type' => $lasttype, + 'display' => $ISSUE_TYPES[$lasttype][0], + 'issues' => [] + ]; + } + $issuesIndex = 0; + } + $rowid = $prow['id']; + $disptitle = trim($prow['title']) ? $prow['title'] : "[Missing Title]"; + + + $issuesByTypeMap[$lasttype][$rowid] = $issuesIndex; + $issuesByType[$lasttype]['issues'][$issuesIndex++] = [ + 'id' => $rowid, + 'title' => $disptitle, + 'begdate' => $prow['begdate'], + 'enddate' => $prow['enddate'], + 'status' => !empty($prow['enddate']) ? 'inactive' : 'active', + 'encounters' => [] + ]; + } + // now populate encounters + $ieres = sqlStatement("SELECT encounter,list_id,lists.type FROM issue_encounter JOIN lists ON lists.id = list_id " + . " AND issue_encounter.pid = lists.pid WHERE " . + "lists.pid = ?", [$pid]); + while ($ierow = sqlFetchArray($ieres)) { + $listId = $ierow['list_id']; + $encounter = $ierow['encounter']; + $issuesIndex = $issuesByTypeMap[$ierow['type']][$listId]; + $issuesByType[$ierow['type']]['issues'][$issuesIndex]['encounters'][] = $encounter; + } + return $issuesByType; + } + public function getEncounters($pid) + { + + $isfirst = 1; + $res = sqlStatement("SELECT forms.encounter, forms.form_id, forms.form_name, " . + "forms.formdir, forms.date AS fdate, form_encounter.date " . + ",form_encounter.reason " . + "FROM forms, form_encounter WHERE " . + "forms.pid = ? AND form_encounter.pid = ? AND " . + "form_encounter.encounter = forms.encounter " . + " AND forms.deleted=0 " . // --JRM-- + "ORDER BY form_encounter.date DESC, fdate ASC", [$pid, $pid]); + $res2 = sqlStatement("SELECT name FROM registry ORDER BY priority"); + $encountersByDate = []; + $encountersByEncounter = []; + $html_strings = array(); + $registry_form_name = array(); + while ($result2 = sqlFetchArray($res2)) { + array_push($registry_form_name, trim($result2['name'])); + } + + $encounter = null; + while ($result = sqlFetchArray($res)) { + $encounterId = $result['encounter']; + if ($result["form_name"] == "New Patient Encounter") { + $encounter = [ + 'formdir' => $result["formdir"] + ,'form_id' => $result["form_id"] + ,'encounter' => $result["encounter"] + ,'display' => '' + ,'forms' => [] + ]; + // show encounter reason, not just 'New Encounter' + // trim to a reasonable length for display purposes --cfapress + $maxReasonLength = 20; + if (strlen($result["reason"]) > $maxReasonLength) { + $encounter['display'] = substr($result['reason'], 0, $maxReasonLength) . " ... "; + } else { + $encounter['display'] = $result['reason'] ?? ''; + } + $encounter['date'] = date("Y-m-d", strtotime($result["date"])); + $encountersByDate[] = $encounterId; + $encountersByEncounter[$encounterId] = $encounter; + } else { + $form_name = trim($result["form_name"]); + // TODO: @adunsulag we need to investigate why procedure order form saves + // its name as this way.. so odd. + if ($form_name === '-procedure') { + $form_name = 'Procedure Order'; + } + //if form name is not in registry, look for the closest match by + // finding a registry name which is at the start of the form name. + //this is to allow for forms to put additional helpful information + //in the database in the same string as their form name after the name + $form_name_found_flag = 0; + foreach ($registry_form_name as $var) { + if ($var == $form_name) { + $form_name_found_flag = 1; + } + } + + // if the form does not match precisely with any names in the registry, now see if any front partial matches + // and change $form_name appropriately so it will print above in $toprint = $html_strings[$var] + if (!$form_name_found_flag) { + foreach ($registry_form_name as $var) { + if (strpos($form_name, $var) === 0) { + $form_name = $var; + } + } + } + if (empty($encountersByEncounter[$encounterId]['forms'][$form_name])) { + $encountersByEncounter[$encounterId]['forms'][$form_name] = []; + } + $encountersByEncounter[$encounterId]['forms'][$form_name][] = [ + 'formdir' => $result['formdir'] + , 'form_id' => $result['form_id'] + , 'encounter' => $result['encounter'] + , 'display' => xl_form_title($form_name) + ]; + } + } + $encounters = array_map(function ($encounterId) use ($encountersByEncounter) { + return $encountersByEncounter[$encounterId]; + }, $encountersByDate); + return $encounters; + } +} diff --git a/src/Events/PatientReport/PatientReportFilterEvent.php b/src/Events/PatientReport/PatientReportFilterEvent.php new file mode 100644 index 00000000000..2ea37ad9568 --- /dev/null +++ b/src/Events/PatientReport/PatientReportFilterEvent.php @@ -0,0 +1,89 @@ + + * @copyright Copyright (C) 2024 Open Plan IT Ltd. + * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 + */ + +namespace OpenEMR\Events\PatientReport; + +use Symfony\Contracts\EventDispatcher\Event; + +class PatientReportFilterEvent extends Event +{ + /** + * This event fires just before the data elements are sent into the patient portal's patient report twig template. + * It allows the listener to modify the data elements that are sent in (hiding/showing sections, etc). + */ + const FILTER_PORTAL_TWIG_DATA = 'patientReport.filter.portal.twig.data'; + const FILTER_PORTAL_HEALTHSNAPSHOT_TWIG_DATA = 'home.filter.portal.healthsnapshot.twig.data'; + + /** + * @var array $data The data elements that are being filtered by this array. + */ + private array $data; + + public function __construct() + { + $this->data = []; + } + + /** + * Populates the data elements for this filtered event. + * @param array $data + */ + public function populateData(array $data): void + { + $this->clearData(); + foreach ($data as $key => $value) { + $this->setDataElement($key, $value); + } + } + + /** + * Sets the data elements that are being filtered by this array. + * @param int|string $key + * @param mixed $data + */ + public function setDataElement(int|string $key, mixed $data): void + { + $this->data[$key] = $data; + } + + public function getDataElement(int|string $key): mixed + { + return $this->data[$key]; + } + + /** + * Removes a data element from the filtered data. + * @param int|string $key + * @return void + */ + public function removeDataElement(int|string $key) + { + unset($this->data[$key]); + } + + /** + * Removes the data elements from the filtered data. + * @return void + */ + public function clearData() + { + $this->data = []; + } + + public function getDataAsArray(): array + { + return $this->data; + } +} diff --git a/templates/portal/home.html.twig b/templates/portal/home.html.twig index 9e9986db042..f08fa5a5b5f 100644 --- a/templates/portal/home.html.twig +++ b/templates/portal/home.html.twig @@ -1,3 +1,20 @@ +{# +* home.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org + * @author Jerry Padgett + * @author Brady Miller + * @author Shiqiang Tao + * @author Ben Marte + * @author Stephen Nielson + * @copyright Copyright (c) 2016-2024 Jerry Padgett + * @copyright Copyright (c) 2019-2021 Brady Miller + * @copyright Copyright (c) 2020 Shiqiang Tao + * @copyright Copyright (c) 2021 Ben Marte +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} {% extends "portal/base.html.twig" %} {% block head %} @@ -197,24 +214,6 @@ }); }); - $("#medicationlist").load("./get_medications.php", {}, function () { - }); - - $("#prescriptionlist").load("./get_prescriptions.php", {}, function () { - }); - - $("#labresults").load("./get_lab_results.php", {}, function () { - }); - - /* $("#amendmentslist").load("./get_amendments.php", {}, function () { - });*/ - - $("#problemslist").load("./get_problems.php", {}, function () { - }); - - $("#allergylist").load("./get_allergies.php", {}, function () { - }); - $("#reports").load("./report/portal_patient_report.php?pid=" + {{ patientID | js_url }}, {}, function () { }); @@ -635,60 +634,7 @@ {# End of quickstart-cards #} -
-
-
{{ 'Health Snapshot (Medical Lists)' | xlt }}
-
-
-
{{ 'Patient Immunization' | xlt }}
-
- {% for record in immunRecords %} -
- {{ record.administered_formatted | xlt }} : - {{ record.code_text | xlt }} : - {{ record.note | xlt }} : - {{ record.completion_status | xlt }} -
- {% else %} -

{{ 'No records found.' | xlt }}

- {% endfor %} -
-
-
-
{{ 'Current Medications' | xlt }}
-
- {% include "portal/partial/_alert_loading.html.twig" %} -
-
-
-
{{ 'Active Prescriptions' | xlt }}
-
- {% include "portal/partial/_alert_loading.html.twig" %} -
-
-
-
{{ 'Medication Allergy List' | xlt }}
-
-
-
-
{{ 'Current Problems List' | xlt }}
-
- {% include "portal/partial/_alert_loading.html.twig" %} -
-
- {#
-
{{ 'Amendment List' | xlt }}
-
-
#} -
-
{{ 'Lab Results' | xlt }}
-
- {% include "portal/partial/_alert_loading.html.twig" %} -
-
-
-
-
+ {% include "portal/partial/cards/_health_snapshot_card.html.twig" with {healthSnapshot: healthSnapshot}%} {% include "portal/partial/_help_card.html.twig" with { diff --git a/templates/portal/partial/cards/_health_snapshot_allergylist_card.html.twig b/templates/portal/partial/cards/_health_snapshot_allergylist_card.html.twig new file mode 100644 index 00000000000..fd9781f64e1 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_allergylist_card.html.twig @@ -0,0 +1,15 @@ +{# +* _health_snapshot_allergylist_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+
{{ 'Medication Allergy List' | xlt }}
+
+
diff --git a/templates/portal/partial/cards/_health_snapshot_card.html.twig b/templates/portal/partial/cards/_health_snapshot_card.html.twig new file mode 100644 index 00000000000..b6d7daa24f0 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_card.html.twig @@ -0,0 +1,27 @@ +{# +* _health_snapshot_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} + +
+
+
{{ 'Health Snapshot (Medical Lists)' | xlt }}
+
+ {% include "portal/partial/cards/_health_snapshot_immunization_card.html.twig" with {immunizationRecords: healthSnapshot.immunizationRecords} %} + {% include "portal/partial/cards/_health_snapshot_medicationlist_card.html.twig" %} + {% include "portal/partial/cards/_health_snapshot_prescriptionlist_card.html.twig" %} + {% include "portal/partial/cards/_health_snapshot_allergylist_card.html.twig" %} + {% include "portal/partial/cards/_health_snapshot_problemslist_card.html.twig" %} + {# {% include "portal/partial/cards/_health_snapshot_amendmentslist_card.html.twig" %} #} + {% include "portal/partial/cards/_health_snapshot_labresults_card.html.twig" %} +
+
+
+{% include "portal/partial/cards/_health_snapshot_scripts.html.twig" %} diff --git a/templates/portal/partial/cards/_health_snapshot_immunization_card.html.twig b/templates/portal/partial/cards/_health_snapshot_immunization_card.html.twig new file mode 100644 index 00000000000..5cf887d781b --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_immunization_card.html.twig @@ -0,0 +1,26 @@ +{# +* _health_snapshot_immunization_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+
{{ 'Patient Immunization' | xlt }}
+
+ {% for record in immunizationRecords %} +
+ {{ record.administered_formatted | xlt }} : + {{ record.code_text | xlt }} : + {{ record.note | xlt }} : + {{ record.completion_status | xlt }} +
+ {% else %} +

{{ 'No records found.' | xlt }}

+ {% endfor %} +
+
diff --git a/templates/portal/partial/cards/_health_snapshot_labresults_card.html.twig b/templates/portal/partial/cards/_health_snapshot_labresults_card.html.twig new file mode 100644 index 00000000000..ad06c87a038 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_labresults_card.html.twig @@ -0,0 +1,17 @@ +{# +* _health_snapshot_labresults_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+
{{ 'Lab Results' | xlt }}
+
+ {% include "portal/partial/_alert_loading.html.twig" %} +
+
diff --git a/templates/portal/partial/cards/_health_snapshot_medicationlist_card.html.twig b/templates/portal/partial/cards/_health_snapshot_medicationlist_card.html.twig new file mode 100644 index 00000000000..bc20b294781 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_medicationlist_card.html.twig @@ -0,0 +1,17 @@ +{# +* _health_snapshot_medicationlist_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+
{{ 'Current Medications' | xlt }}
+
+ {% include "portal/partial/_alert_loading.html.twig" %} +
+
diff --git a/templates/portal/partial/cards/_health_snapshot_prescriptionlist_card.html.twig b/templates/portal/partial/cards/_health_snapshot_prescriptionlist_card.html.twig new file mode 100644 index 00000000000..fce592074a6 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_prescriptionlist_card.html.twig @@ -0,0 +1,17 @@ +{# +* _health_snapshot_prescriptionlist_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+
{{ 'Active Prescriptions' | xlt }}
+
+ {% include "portal/partial/_alert_loading.html.twig" %} +
+
diff --git a/templates/portal/partial/cards/_health_snapshot_problemslist_card.html.twig b/templates/portal/partial/cards/_health_snapshot_problemslist_card.html.twig new file mode 100644 index 00000000000..1cb64263e35 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_problemslist_card.html.twig @@ -0,0 +1,17 @@ +{# +* _health_snapshot_problemslist_card.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+
{{ 'Current Problems List' | xlt }}
+
+ {% include "portal/partial/_alert_loading.html.twig" %} +
+
diff --git a/templates/portal/partial/cards/_health_snapshot_scripts.html.twig b/templates/portal/partial/cards/_health_snapshot_scripts.html.twig new file mode 100644 index 00000000000..a2a36e14d99 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_scripts.html.twig @@ -0,0 +1,36 @@ +{# + * _health_snapshot_scripts.html.twig + * + * @package OpenEMR + * @link https://www.open-emr.org + * @author Jerry Padgett + * @author Stephen Nielson + * @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} + +{% include "portal/partial/cards/_health_snapshot_scripts_post.html.twig" %} diff --git a/templates/portal/partial/cards/_health_snapshot_scripts_post.html.twig b/templates/portal/partial/cards/_health_snapshot_scripts_post.html.twig new file mode 100644 index 00000000000..b2471fb4a32 --- /dev/null +++ b/templates/portal/partial/cards/_health_snapshot_scripts_post.html.twig @@ -0,0 +1 @@ +{# Module writers can override this template to do any custom scripts they need to do in the health snapshot screen #} diff --git a/templates/portal/partial/reports/patient_report/_body_scripts.html.twig b/templates/portal/partial/reports/patient_report/_body_scripts.html.twig new file mode 100644 index 00000000000..244bd4a0e09 --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_body_scripts.html.twig @@ -0,0 +1,274 @@ +{# +* _body_scripts.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} + diff --git a/templates/portal/partial/reports/patient_report/_documents.html.twig b/templates/portal/partial/reports/patient_report/_documents.html.twig new file mode 100644 index 00000000000..dd0d0589c34 --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_documents.html.twig @@ -0,0 +1,24 @@ +{# +* _documents.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+{{ 'Documents'|xlt }}:
+
    + {% for document in documents %} +
  • + +
  • + {% endfor %} +
diff --git a/templates/portal/partial/reports/patient_report/_head.html.twig b/templates/portal/partial/reports/patient_report/_head.html.twig new file mode 100644 index 00000000000..d9d3c1c1eeb --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_head.html.twig @@ -0,0 +1,159 @@ +{# +* _head.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +{{ setupHeader(['textformat', 'datetime-picker','datetime-picker-translated']) }} + diff --git a/templates/portal/partial/reports/patient_report/_issues_encounters.html.twig b/templates/portal/partial/reports/patient_report/_issues_encounters.html.twig new file mode 100644 index 00000000000..cc0a48ce91c --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_issues_encounters.html.twig @@ -0,0 +1,37 @@ +{# +* _issues_encounters.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+ {{ "Issues"|xlt }}: +

+ + {% for disptype,issuesCategory in issues %} + + + + {% for issue in issuesCategory.issues %} + + + + + + {% endfor %} + {% endfor %} +
{{ issuesCategory.display|text }}
  + + +
+
diff --git a/templates/portal/partial/reports/patient_report/_issues_encounters_form.html.twig b/templates/portal/partial/reports/patient_report/_issues_encounters_form.html.twig new file mode 100644 index 00000000000..3db3e99e8af --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_issues_encounters_form.html.twig @@ -0,0 +1,47 @@ +{# +* _issues_encounters_form.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} + + + + + + + +
+ {% include "portal/partial/reports/patient_report/_issues_encounters.html.twig" %} + +
+ {{ "Encounters & Forms"|xlt }}: +

+ {% for encounter in encounters %} +
+ +
+ {% for formName,formList in encounter.forms %} + {% for form in formList %} + +
+ {% endfor %} + {% endfor %} +
+
+ {% endfor %} +
+
diff --git a/templates/portal/partial/reports/patient_report/_procedure_orders.html.twig b/templates/portal/partial/reports/patient_report/_procedure_orders.html.twig new file mode 100644 index 00000000000..c2483d57266 --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_procedure_orders.html.twig @@ -0,0 +1,42 @@ +{# +* _procedure_orders.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +
+ + + + + + + + {% for row in procedureOrders %} + + + + + + + {% endfor %} +
{{ 'Procedures'|xlt }}  {{ 'Order Date'|xlt }}  {{ 'Encounter Date'|xlt }}  {{ 'Order Descriptions'|xlt }}
+ + + +
diff --git a/templates/portal/partial/reports/patient_report/_section_list.html.twig b/templates/portal/partial/reports/patient_report/_section_list.html.twig new file mode 100644 index 00000000000..a06ce899876 --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_section_list.html.twig @@ -0,0 +1,31 @@ +{# +* _section_list.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2024 Jerry Padgett +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} + + + {% if section_one|length > 0 %} + + {% endif %} + {% if section_two|length > 0 %} + + {% endif %} + +
+ {% for sectionId in section_one %} + {% include 'portal/partial/reports/patient_report/_section_list_item.html.twig' + with {sectionId: sectionId, section: sections[sectionId] } %} + {% endfor %} + + {% for sectionId in section_two %} + {% include 'portal/partial/reports/patient_report/_section_list_item.html.twig' + with {sectionId: sectionId, section: sections[sectionId] } %} + {% endfor %} +
diff --git a/templates/portal/partial/reports/patient_report/_section_list_item.html.twig b/templates/portal/partial/reports/patient_report/_section_list_item.html.twig new file mode 100644 index 00000000000..cdd4b8f6257 --- /dev/null +++ b/templates/portal/partial/reports/patient_report/_section_list_item.html.twig @@ -0,0 +1,11 @@ +{# +* _section_list_item.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Stephen Nielson +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} +{{ section.label|text }}
diff --git a/templates/portal/portal_patient_report.html.twig b/templates/portal/portal_patient_report.html.twig new file mode 100644 index 00000000000..52467e83e74 --- /dev/null +++ b/templates/portal/portal_patient_report.html.twig @@ -0,0 +1,48 @@ +{# +* portal_patient_report.html.twig +* +* @package OpenEMR +* @link https://www.open-emr.org +* @author Jerry Padgett +* @author Brady Miller +* @author Stephen Nielson +* @copyright Copyright (c) 2016-2020 Jerry Padgett +* @copyright Copyright (c) 2019 Brady Miller +* @copyright Copyright (C) 2024 Open Plan IT Ltd. +* @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 +#} + + + {% include "portal/partial/reports/patient_report/_head.html.twig" %} + + +
+
+ {{ "Patient Report"|xlt }}   + {{ "Check All"|xlt }} | + {{ "Clear All"|xlt }} + + {% include "portal/partial/reports/patient_report/_section_list.html.twig" %} + + +
+ {% include "portal/partial/reports/patient_report/_issues_encounters_form.html.twig" with {encounters: encounters, issues: issues} %} + + + {% include "portal/partial/reports/patient_report/_procedure_orders.html.twig" with {procedureOrders: procedureOrders} %} + + {% include "portal/partial/reports/patient_report/_documents.html.twig" with {documents: documents} %} + +
+   +   +
+{% include "portal/partial/reports/patient_report/_body_scripts.html.twig" + with { + phimail_enable: phimail_enable + ,phimail_ccd_enable: phimail_ccd_enable + ,phone_country_code: phone_country_code + } +%} + +