ソースを参照

Merge branch 'dev' of rav.triplestart.com:jmudaka/stagfe2

= 4 年 前
コミット
ab345f178a

+ 33 - 0
app/Http/Controllers/HomeController.php

@@ -250,6 +250,19 @@ class HomeController extends Controller
         // num measurements that need stamping
         $keyNumbers['measurementsToBeStamped'] = ($this->performer()->pro->pro_type === 'ADMIN' ? '-' : count($this->performer()->pro->getMeasurements(true)));
 
+        // unacknowledged cancelled bills for authed pro
+        $keyNumbers['unacknowledgedCancelledBills'] = Bill::where('hcp_pro_id', $performerProID)
+            ->where('is_cancelled', true)
+            ->where('is_cancellation_acknowledged', false)
+            ->count();
+
+        // patientsHavingBirthdayToday
+        $queryClients = $this->performer()->pro->getAccessibleClientsQuery();
+        $keyNumbers['patientsHavingBirthdayToday'] = $queryClients
+            ->whereRaw('EXTRACT(DAY from dob) = ?', [date('d')])
+            ->whereRaw('EXTRACT(MONTH from dob) = ?', [date('m')])
+            ->count();
+
         $reimbursement = [];
         $reimbursement["currentBalance"] =  $performer->pro->balance;
         $reimbursement["nextPaymentDate"] = '--';
@@ -395,6 +408,10 @@ class HomeController extends Controller
             $appointment->clientUid = $appointment->client->uid;
             $appointment->proUid = $appointment->pro->uid;
             $appointment->proName = $appointment->pro->displayName();
+
+            unset($appointment->client);
+            unset($appointment->pro);
+            unset($appointment->detail_json);
         }
 
         return json_encode($appointments);
@@ -430,6 +447,12 @@ class HomeController extends Controller
                     });
                 break;
 
+            case 'having-birthday-today':
+                $query = $query
+                    ->whereRaw('EXTRACT(DAY from dob) = ?', [date('d')])
+                    ->whereRaw('EXTRACT(MONTH from dob) = ?', [date('m')]);
+                break;
+
                 // more cases can be added as needed
             default:
                 break;
@@ -639,4 +662,14 @@ class HomeController extends Controller
             return redirect(route('dashboard'));
         }
     }
+
+    public function getTicket(Request $request, Ticket $ticket) {
+        $ticket->data = json_decode($ticket->data);
+//        $ticket->created_at = friendly_date_time($ticket->created_at);
+        $ticket->assignedPro;
+        $ticket->managerPro;
+        $ticket->orderingPro;
+        $ticket->initiatingPro;
+        return json_encode($ticket);
+    }
 }

+ 11 - 4
app/Http/Controllers/NoteController.php

@@ -34,14 +34,21 @@ class NoteController extends Controller
 
         $allyPros = Pro::all(); //TODO: paginate, use select2
 
-        // load today's tickets for patient
-        $ticketsToday = Ticket::where('client_id', $patient->id)
+        // load tickets created on note->effective_date for patient
+        $ticketsOnNoteEffectiveDate = Ticket::where('client_id', $patient->id)
             ->where('is_entry_error', false)
-            ->whereRaw('DATE(created_at) = ?', [date('Y-m-d')])
+            ->whereRaw('DATE(created_at) = DATE(?)', [$note->effective_dateest])
+            ->get();
+
+        // other open tickets as of today
+        $otherOpenTickets = Ticket::where('client_id', $patient->id)
+            ->where('is_entry_error', false)
+            ->where('is_open', true)
+            ->whereRaw('DATE(created_at) <> DATE(?)', [$note->effective_dateest])
             ->get();
 
         return view('app.patient.note.dashboard', compact('patient', 'note',
-            'allyPros', 'allSections', 'ticketsToday'));
+            'allyPros', 'allSections', 'ticketsOnNoteEffectiveDate', 'otherOpenTickets'));
     }
 
     public function renderNote($noteUid, Request $request)

+ 8 - 11
app/Http/Controllers/PatientController.php

@@ -342,9 +342,16 @@ class PatientController extends Controller
         return view('app.patient.vitals-graph', compact('patient', 'pros', 'filter'));
     }
 
-    public function tickets(Request $request, Client $patient, $type = '', Ticket $currentTicket = null) {
+    public function tickets(Request $request, Client $patient, $type = '', String $currentTicket = '') {
         $pros = $this->pros;
         $allPros = Pro::all();
+        $qlTicket = $currentTicket;
+        if(!!$currentTicket) {
+            $qlTicket = Ticket::where('uid', $currentTicket)->first();
+            if($qlTicket) {
+                $currentTicket = $qlTicket;
+            }
+        }
         return view('app.patient.tickets', compact('patient', 'pros', 'allPros', 'type', 'currentTicket'));
     }
 
@@ -371,16 +378,6 @@ class PatientController extends Controller
             compact('patient', 'pros', 'appointments', 'appointmentPros', 'forPro', 'status'));
     }
 
-    public function getTicket(Request $request, Ticket $ticket) {
-        $ticket->data = json_decode($ticket->data);
-//        $ticket->created_at = friendly_date_time($ticket->created_at);
-        $ticket->assignedPro;
-        $ticket->managerPro;
-        $ticket->orderingPro;
-        $ticket->initiatingPro;
-        return json_encode($ticket);
-    }
-
     public function mcpRequests(Request $request, Client $patient) {
         return view('app.patient.mcp-requests', compact('patient'));
     }

+ 10 - 0
app/Http/Controllers/PracticeManagementController.php

@@ -151,6 +151,16 @@ class PracticeManagementController extends Controller
         return view('app.practice-management.bills', compact('bills', 'filter'));
     }
 
+    public function unacknowledgedCancelledBills(Request $request)
+    {
+        $bills = Bill::where('hcp_pro_id', $this->performer()->pro->id)
+            ->where('is_cancelled', true)
+            ->where('is_cancellation_acknowledged', false)
+            ->orderBy('created_at', 'desc')
+            ->get();
+        return view('app.practice-management.unacknowledged-cancelled-bills', compact('bills'));
+    }
+
     public function myTickets(Request $request, $filter = 'open')
     {
         $performer = $this->performer();

+ 1 - 0
app/Http/Kernel.php

@@ -66,5 +66,6 @@ class Kernel extends HttpKernel
         'pro.auth' => \App\Http\Middleware\ProAuthenticated::class,
         'pro.auth.redirect' => \App\Http\Middleware\RedirectAuthenticatedPro::class,
         'pro.auth.admin' => \App\Http\Middleware\EnsureAdminPro::class,
+        'pro.auth.can-access-patient' => \App\Http\Middleware\EnsureProCanAccessPatient::class,
     ];
 }

+ 37 - 0
app/Http/Middleware/EnsureProCanAccessPatient.php

@@ -0,0 +1,37 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use App\Models\AppSession;
+use Closure;
+
+class EnsureProCanAccessPatient
+{
+    /**
+     * Handle an incoming request.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \Closure  $next
+     * @return mixed
+     */
+    public function handle($request, Closure $next)
+    {
+        $sessionKey = $request->cookie('sessionKey');
+        $appSession = AppSession::where('session_key', $sessionKey)->where('is_active', true)->first();
+        $authenticated = $sessionKey && $appSession && $appSession->pro;
+       
+        if (!$authenticated) {
+            abort(403);
+        }
+
+        $patient = \request()->route('patient');
+
+        if(!!$patient) {
+            if(!$appSession->pro->canAccess($patient->uid)) {
+                abort(403);
+            }
+        }
+
+        return $next($request);
+    }
+}

+ 8 - 0
app/Models/Client.php

@@ -462,4 +462,12 @@ class Client extends Model
             ->orderBy('created_at', 'desc');
     }
 
+    public function numSignedNotes() {
+        return Note::where('client_id', $this->id)
+            ->where('is_cancelled', false)
+            ->where('is_signed_by_hcp', true)
+            ->count();
+
+    }
+
 }

+ 21 - 0
app/Models/Pro.php

@@ -298,6 +298,27 @@ class Pro extends Model
         return $query;
     }
 
+    public function canAccess($_patientUid) {
+        $proID = $this->id;
+        if ($this->pro_type === 'ADMIN') {
+            return true;
+        }
+        $canAccess = Client::select('uid')
+            ->where('uid', $_patientUid)
+            ->where(function ($q) use ($proID) {
+                $q->where('mcp_pro_id', $proID)
+                    ->orWhere('cm_pro_id', $proID)
+                    ->orWhere('rmm_pro_id', $proID)
+                    ->orWhere('rme_pro_id', $proID)
+                    ->orWhere('physician_pro_id', $proID)
+                    ->orWhereRaw('id IN (SELECT client_id FROM client_pro_access WHERE is_active AND pro_id = ?)', [$proID])
+                    ->orWhereRaw('id IN (SELECT client_id FROM appointment WHERE status NOT IN (\'CANCELLED\', \'ABANDONED\') AND pro_id = ?)', [$proID])
+                    ->orWhereRaw('id IN (SELECT mcp_pro_id FROM client_program WHERE client_id = client.id AND is_active = TRUE)')
+                    ->orWhereRaw('id IN (SELECT manager_pro_id FROM client_program WHERE client_id = client.id AND is_active = TRUE)');
+            })->count();
+        return !!$canAccess;
+    }
+
     public function canAddCPMEntryForMeasurement(Measurement $measurement, Pro $pro)
     {
         // check if client has any programs where this measurement type is allowed

+ 44 - 29
public/js/mc.js

@@ -150,36 +150,48 @@ function initFastLoad(_parent = false) {
 
 function onFastLoaded(_data, _href, _history) {
     var targetParent = $('.stag-content');
-    _data = '<div>' + _data + '</div>';
-    var content = $(_data).find('.stag-content');
-    if (content && content.length) {
-
-        targetParent.html(content.html());
-        hideMask();
-        hideMoeFormMask();
-        targetParent.append('<script src="/js/yemi.js?_=7"></script>');
-        window.setTimeout(function() {
-            initCreateNote();
-            initQuillEdit();
-            initFastLoad(targetParent);
-            initPrimaryForm();
-            initPatientPresenceIndicator();
-            runMCInitializers();
-            if(window.top.currentMcUrl !== window.top.location.href) {
-                $(window).scrollTop(0);
-            }
-            window.top.currentMcUrl = window.top.location.href;
-        }, 50);
-        // if(typeof initializeCalendar !== 'undefined') {
-        //     initializeCalendar();
-        // }
-        // if(typeof initIntakeEvents !== 'undefined') {
-        //     initIntakeEvents();
-        // }
+    if (!Number.isInteger(_data)) {
+        _data = '<div>' + _data + '</div>';
+        var content = $(_data).find('.stag-content');
+        if (content && content.length) {
+            targetParent.html(content.html());
+            hideMask();
+            hideMoeFormMask();
+            targetParent.append('<script src="/js/yemi.js?_=7"></script>');
+            window.setTimeout(function () {
+                initCreateNote();
+                initQuillEdit();
+                initFastLoad(targetParent);
+                initPrimaryForm();
+                initPatientPresenceIndicator();
+                runMCInitializers();
+                if (window.top.currentMcUrl !== window.top.location.href) {
+                    $(window).scrollTop(0);
+                }
+                window.top.currentMcUrl = window.top.location.href;
+            }, 50);
+        }
+        else {
+            targetParent.html('<p class="text-danger p-3 small">Error on page: <b>' + _href + '</b></p>');
+            hideMask();
+            hideMoeFormMask();
+        }
     } else {
         // fallback
+        let msg = 'Unable to open page: ';
+        switch (_data) {
+            case 403:
+                msg = 'You do not have access to this page: ';
+                break;
+            case 404:
+                msg = 'Page not found: ';
+                break;
+            case 500:
+                msg = 'Error on page: ';
+                break;
+        }
         console.warn('MC: Target page failed: ' + _href);
-        targetParent.html('<p class="text-danger p-3 small">Target page not found or returned error: <b>' + _href + '</b></p>');
+        targetParent.html('<p class="text-danger p-3 small"><b>' + _data + '</b> - ' + msg + '<b>' + _href + '</b></p>');
         hideMask();
         hideMoeFormMask();
     }
@@ -224,8 +236,11 @@ function fastLoad(_href, _history = true, _useCache = true, _replaceState = fals
     } else {
         $.get(_href, function (_data) {
             onFastLoaded(_data, _href, _history);
-        }).fail(function () {
-            onFastLoaded('error', _href, _history);
+        }).fail(function (_jqXhr) {
+            // if(_jqXhr.status === 403) {
+            //     alert('You do not have access to this patient.');
+            // }
+            onFastLoaded(_jqXhr.status, _href, _history);
         });
     }
 }

+ 35 - 9
resources/views/app/dashboard.blade.php

@@ -45,6 +45,18 @@
                                            v-on:click.prevent="tab='measurements'">Unstamped Measurements</a>
                                     </th>
                                 </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$keyNumbers['unacknowledgedCancelledBills']}}</th>
+                                    <th class="pl-2">
+                                        <a href="/practice-management/unacknowledged-cancelled-bills">Unacknowledged Cancelled Bills</a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$keyNumbers['patientsHavingBirthdayToday']}}</th>
+                                    <th class="pl-2">
+                                        <a href="/patients/having-birthday-today">Patients having birthday today</a>
+                                    </th>
+                                </tr>
                             </tbody>
                         </table>
                     </div>
@@ -118,7 +130,7 @@
                     <li class="nav-item">
                         <a native data-tab="appointments" class="nav-link"
                            :class="tab == 'appointments' ? 'active' : ''" href="#"
-                           v-on:click.prevent="tab='appointments'">
+                           v-on:click.prevent="tab='appointments'; initLoadAppointments();">
                             Appointments
                         </a>
                     </li>
@@ -173,8 +185,7 @@
                             <div class="ml-auto d-inline-flex align-items-center">
                                 <label class="text-secondary mr-2 my-0 text-nowrap">Filter by status:</label>
                                 <select v-model="filterStatus"
-                                        class="form-control form-control-sm"
-                                        v-on:change="updateNumEventsForDate()">
+                                        class="form-control form-control-sm">
                                     <option value="">All</option>
                                     <option value="CREATED">Created</option>
                                     <option value="CONFIRMED">Confirmed</option>
@@ -272,7 +283,8 @@
                     currentMonth: null,
                     currentYear: null,
                     measurementFilterStatus: 'ALL',
-                    measurements: {!! $pro->pro_type === 'ADMIN' ? '[]' : json_encode($pro->getMeasurements()) !!}
+                    measurements: {!! $pro->pro_type === 'ADMIN' ? '[]' : json_encode($pro->getMeasurements()) !!},
+                    appointmentsLoaded: false,
                 },
                 methods: {
                     formatDate: function (date) {
@@ -293,9 +305,12 @@
 
                         let self = this;
                         self.selectedDate = _newDate;
+                        showMask();
                         this.loadEvents(function() {
                             self.highlightDatesWithEvents();
-                            self.updateNumEventsForDate();
+                            // self.updateNumEventsForDate();
+                            self.appointmentsLoaded = true;
+                            hideMask();
                         });
                     },
                     selectToday: function () {
@@ -317,6 +332,7 @@
                             if(this.events[i].dateYMD === this.selectedDate &&
                                 (this.filterStatus === '' || this.filterStatus === this.events[i].status)) {
                                 this.numEventsForDate++;
+                                break;
                             }
                         }
                         Vue.nextTick(() => {
@@ -452,6 +468,12 @@
                                 .attr('with-shortcuts', 1);
 
                         })
+                    },
+                    initLoadAppointments: function() {
+                        if(this.appointmentsLoaded) return false;
+                        this.selectToday();
+                        this.updateNumEventsForDate();
+                        $('.datepicker-days .day.active').trigger('click');
                     }
                 },
                 mounted: function () {
@@ -463,11 +485,15 @@
                     this.calendarElem.on('changeDate', function () {
                         self.onDateChange(self.calendarElem.datepicker('getFormattedDate'));
                     });
-                    this.selectToday();
-                    this.updateNumEventsForDate();
 
-                    // this.loadEvents();
-                    $('.datepicker-days .day.active').trigger('click');
+                    // DEFER this till appts tab is clicked
+
+                    // this.selectToday();
+                    // this.updateNumEventsForDate();
+
+                    // $('.datepicker-days .day.active').trigger('click');
+
+
 
                     // this.initCMRTE();
                     $('#pro-dashboard-container').find('[moe][initialized]').removeAttr('initialized');

+ 1 - 1
resources/views/app/dashboard/measurements.blade.php

@@ -30,7 +30,7 @@
                         @elseif($measurement->label === 'BP')
                             {{ $measurement->sbp_mm_hg }}/{{ $measurement->dbp_mm_hg }} mmHg
                         @elseif($measurement->label === 'Wt. (lbs.)')
-                            {{ $measurement->numeric_value }} lbs
+                            {{ round(floatval($measurement->numeric_value), 2) }} lbs
                         @else
                             {{ $measurement->value }}
                         @endif

+ 156 - 9
resources/views/app/patient/note/dashboard.blade.php

@@ -358,10 +358,32 @@
                 <div class="p-3 border-bottom">
                     <div class="">
                         <div class="d-flex align-items-center mb-2">
-                            <p class="font-weight-bold text-secondary m-0 mr-2">ERx/Orders Summary - {{date('m/d/Y')}}</p>
+                            <p class="font-weight-bold text-secondary m-0 font-size-14">ERx/Orders Summary</p>
+                            <span class="mx-2 text-secondary">|</span>
+                            <a href="/patients/view/{{$patient->uid}}/tickets/erx/create?popupmode=1"
+                               native target="_blank"
+                               class="ticket-popup-trigger note-dashboard-action d-block text-nowrap font-weight-bold">
+                                + ERx
+                            </a>
+                            <span class="mx-2 text-secondary">|</span>
+                            <a href="/patients/view/{{$patient->uid}}/tickets/lab/create?popupmode=1"
+                               native target="_blank"
+                               class="ticket-popup-trigger note-dashboard-action d-block text-nowrap font-weight-bold">
+                                + Lab
+                            </a>
+                            <span class="mx-2 text-secondary">|</span>
+                            <a href="/patients/view/{{$patient->uid}}/tickets/imaging/create?popupmode=1"
+                               native target="_blank"
+                               class="ticket-popup-trigger note-dashboard-action d-block text-nowrap font-weight-bold">
+                                + Imaging
+                            </a>
                         </div>
+
+                        <hr class="my-2">
+
+                        <p class="font-weight-bold text-secondary mb-2 mr-2">Ordered on {{friendlier_date($note->effective_dateest)}} <span class="font-weight-normal">(note's effective date)</span></p>
                         <div>
-                            @if($ticketsToday && count($ticketsToday))
+                            @if($ticketsOnNoteEffectiveDate && count($ticketsOnNoteEffectiveDate))
                                 <table class="table table-sm table-bordered mb-0">
                                 <thead>
                                 <tr class="bg-light">
@@ -374,7 +396,7 @@
                                 </tr>
                                 </thead>
                                 <tbody>
-                                @foreach($ticketsToday as $ticket)
+                                @foreach($ticketsOnNoteEffectiveDate as $ticket)
                                     <?php $data = json_decode($ticket->data); ?>
                                     @if($ticket->category === 'erx' || $ticket->category === 'lab' || $ticket->category === 'imaging')
                                     <tr class="{{$ticket->is_open ? '' : 'bg-light on-hover-opaque'}}">
@@ -468,11 +490,126 @@
                                     @endif
                                 @endforeach
                                 </tbody>
-                            </table>
+                                </table>
                             @else
                                 <div class="text-secondary">None</div>
                             @endif
                         </div>
+
+                        <hr class="my-2">
+
+                        <p class="font-weight-bold text-secondary mb-2 mr-2 mt-3">Others open as of {{friendlier_date(date('Y-m-d'))}}</p>
+                        @if($otherOpenTickets && count($otherOpenTickets))
+                            <table class="table table-sm table-bordered mb-0">
+                                <thead>
+                                <tr class="bg-light">
+                                    <th class="px-2 text-secondary border-bottom-0 width-30px">Created</th>
+                                    <th class="px-2 text-secondary border-bottom-0 width-30px">Type</th>
+                                    <th class="px-2 text-secondary border-bottom-0 width-30px">Pro</th>
+                                    <th class="px-2 text-secondary border-bottom-0 width-30px">View</th>
+                                    <th class="px-2 text-secondary border-bottom-0 width-30px">Status</th>
+                                    <th class="px-2 text-secondary border-bottom-0">Detail</th>
+                                </tr>
+                                </thead>
+                                <tbody>
+                                @foreach($otherOpenTickets as $ticket)
+                                    <?php $data = json_decode($ticket->data); ?>
+                                    @if($ticket->category === 'erx' || $ticket->category === 'lab' || $ticket->category === 'imaging')
+                                        <tr class="{{$ticket->is_open ? '' : 'bg-light on-hover-opaque'}}">
+                                            <td class="px-2 text-nowrap">
+                                                {{friendly_time($ticket->created_at)}}
+                                            </td>
+                                            <td class="px-2 text-nowrap">
+                                                {{$ticket->category}}
+                                            </td>
+                                            <td class="px-2 text-nowrap">
+                                                @if($ticket->orderingPro)
+                                                    @if($ticket->orderingPro->id !== $pro->id)
+                                                        <b>{{$ticket->orderingPro->displayName()}}</b>
+                                                    @else
+                                                        You
+                                                    @endif
+                                                @else
+                                                    -
+                                                @endif
+                                            </td>
+                                            <td class="px-2 text-nowrap">
+                                                <div class="d-flex align-items-center flex-nowrap">
+                                                    <a href="/patients/view/{{$ticket->patient->uid}}/tickets/{{$ticket->category}}/{{$ticket->uid}}?popupmode=1"
+                                                       native target="_blank"
+                                                       class="ticket-popup-trigger note-dashboard-action d-block text-nowrap mr-3">
+                                                        View
+                                                    </a>
+                                                </div>
+                                            </td>
+                                            <td class="px-2 text-nowrap">
+                                                {{$ticket->is_open ? 'Open' : 'Closed'}}
+                                            </td>
+                                            <td class="px-2">
+                                                @if($ticket->category === 'erx')
+                                                    <div class="font-size-13 mb-1">{{$data->medication}}</div>
+                                                    <div class="d-flex align-items-center flex-wrap text-secondary">
+                                                        @if($data->strength)
+                                                            <span class="d-inline-flex align-items-center">
+                                                    <span class="mx-2 text-secondary">•</span>
+                                                    <span>{{$data->strength}}</span>
+                                                </span>
+                                                        @endif
+                                                        @if($data->route)
+                                                            <span class="d-inline-flex align-items-center">
+                                                    <span class="mx-2 text-secondary">•</span>
+                                                    <span>{{$data->route}}</span>
+                                                </span>
+                                                        @endif
+                                                        @if($data->frequency)
+                                                            <span class="d-inline-flex align-items-center">
+                                                    <span class="mx-2 text-secondary">•</span>
+                                                    <span>{{$data->frequency}}</span>
+                                                </span>
+                                                        @endif
+                                                        @if($data->dispense)
+                                                            <span class="d-inline-flex align-items-center">
+                                                    <span class="mx-2 text-secondary">•</span>
+                                                    <span>Dispense:</span> {{$data->dispense}}
+                                                </span>
+                                                        @endif
+                                                        @if($data->frequency)
+                                                            <span class="d-inline-flex align-items-center">
+                                                    <span class="mx-2 text-secondary">•</span>
+                                                    <span><span>Refills:</span> {{$data->refills}}</span>
+                                                </span>
+                                                        @endif
+                                                        @if($data->dispense)
+                                                            <span class="d-inline-flex align-items-center">
+                                                    <span class="mx-2 text-secondary">•</span>
+                                                    <span><span>Purpose:</span> {{$data->purpose}}</span>
+                                                </span>
+                                                        @endif
+                                                    </div>
+                                                @endif
+                                                @if($ticket->category === 'lab' || $ticket->category === 'imaging')
+                                                    @if(@$data->tests && is_array($data->tests))
+                                                        <div>
+                                                            <span class="text-secondary">Tests:</span>
+                                                            {{implode(", ", $data->tests)}}
+                                                        </div>
+                                                    @endif
+                                                    @if(@$data->icds && is_array($data->icds))
+                                                        <div>
+                                                            <span class="text-secondary">ICDs:</span>
+                                                            {{implode(", ", $data->icds)}}
+                                                        </div>
+                                                    @endif
+                                                @endif
+                                            </td>
+                                        </tr>
+                                    @endif
+                                @endforeach
+                                </tbody>
+                            </table>
+                        @else
+                            <div class="text-secondary">None</div>
+                        @endif
                     </div>
                 </div>
 
@@ -893,6 +1030,9 @@
                                     <td>  <!-- cancellation -->
                                         @if($bill->is_cancelled)
                                             <div class="text-warning-mellow font-weight-bold">Cancelled</div>
+                                            @if($bill->cancellation_memo)
+                                                <div class="text-dark text-sm font-italic my-1">{{$bill->cancellation_memo}}</div>
+                                            @endif
                                             @if($bill->is_cancelled_by_administrator)
                                                 <div class="text-secondary text-sm">(by Administrator)</div>
                                             @endif
@@ -901,8 +1041,10 @@
                                                 <form url="/api/bill/updateCancellationMemo">
                                                     <input type="hidden" name="uid" value="{{$bill->uid}}">
                                                     <p>Update Cancellation Memo</p>
-                                                    <div class="mb-0">
-                                                        <input type="text" class="text form-control form-control-sm" name="updateCancellationMemo" value="{{$bill->cancellation_memo}}" placeholder=""><br>
+                                                    <div class="mb-2">
+                                                        <textarea class="text form-control form-control-sm" name="cancellationMemo" placeholder="">{{$bill->cancellation_memo ? $bill->cancellation_memo : 'Insufficient documentation for billable service.'}}</textarea>
+                                                    </div>
+                                                    <div>
                                                         <button class="btn btn-success btn-sm" submit>Submit</button>
                                                         <button class="btn btn-default border btn-sm" cancel>Cancel</button>
                                                     </div>
@@ -916,7 +1058,7 @@
                                                     <p class="mb-2">Cancel this bill?</p>
                                                     <div class="mb-2">
                                                         <label class="mb-1 text-secondary">Cancellation Memo</label>
-                                                        <input type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">
+                                                        <textarea type="text" name="memo" placeholder="Memo" class="form-control form-control-sm">Insufficient documentation for billable service.</textarea>
                                                     </div>
                                                     <div class="mb-0">
                                                         <button class="btn btn-danger btn-sm" submit>Yes</button>
@@ -1191,8 +1333,13 @@
                             </thead>
                             <tbody>
                             @foreach ($note->claims as $claim)
-                                <tr>
-                                    <td class="pl-2">{{ $claim->iid }}</td>
+                                <tr class="{{ $claim->is_cancelled ? 'text-secondary bg-light on-hover-opaque' : '' }}"">
+                                    <td class="pl-2">
+                                        {{ $claim->iid }}
+                                        @if($claim->is_cancelled)
+                                            <div class="text-secondary font-weight-bold text-sm mt-1">[CANCELLED]</div>
+                                        @endif
+                                    </td>
                                     <td class="p-0">
                                         @if($claim->lines->count())
                                             <table class="table table-sm table-condensed border-left border-right mb-0">

+ 5 - 0
resources/views/app/patient/note/dashboard_script.blade.php

@@ -308,6 +308,11 @@
                         showMask();
                         window.noMc = true;
                         $.get(this.href, (_data) => {
+
+                            if(!$('.ticket-popup').length) {
+                                $('main.stag-content').append('<div class="stag-popup stag-popup-lg ticket-popup mcp-theme-1" stag-popup-key="ticket-popup"></div>');
+                            }
+
                             $('.ticket-popup').html(_data);
                             showStagPopup('ticket-popup', true);
                             $('.ticket-popup .stag-popup.stag-slide').attr('close-all-with-self', 1);

+ 58 - 0
resources/views/app/patient/settings.blade.php

@@ -338,6 +338,64 @@
             </div>
             <div class="col-6 border-left">
 
+                <span>
+                    <span class="mr-1">MCP Onboarding Active?</span>
+                    @if($patient->has_mcp_done_onboarding_visit === 'YES')
+                        <b class="text-secondary"><i class="fa fa-check"></i>&nbsp;Already Onboarded</b>
+                    @else
+                        @if($patient->is_mcp_onboarding_active === 'YES')
+                            <b>Yes</b>
+                        @elseif($patient->is_mcp_onboarding_active === 'NO')
+                            <b>No</b>
+                        @else
+                            <b>-</b>
+                        @endif
+                        <div moe class="ml-2">
+                            <a start show><i class="fa fa-edit"></i></a>
+                            <form url="/api/client/updateMcpOnboardingActiveInfo" class="mcp-theme-1">
+                                <input type="hidden" name="uid" value="{{$patient->uid}}">
+                                <div class="mb-2">
+                                    <label class="text-secondary text-sm">MCP Onboarding Active?</label>
+                                    <select name="isMcpOnboardingActive"
+                                            class="form-control form-control-sm"
+                                            onchange="$('.if-mcb-ob-not-active')[this.value==='NO' ? 'removeClass' : 'addClass']('d-none')"
+                                            required>
+                                        <option value=""> --select--</option>
+                                        <option value="YES">Yes</option>
+                                        <option value="NO">No</option>
+                                        <option value="UNKNOWN">Unknown</option>
+                                    </select>
+                                </div>
+                                <div class="if-mcb-ob-not-active d-none">
+                                    <div class="mb-2">
+                                        <label class="text-secondary text-sm">Category</label>
+                                        <input type="text" class="form-control form-control-sm"
+                                               name="whyIsMcpOnboardingNotActiveCategory"
+                                               value="{{ $patient->why_is_mcp_onboarding_not_active_category }}">
+                                    </div>
+                                    <div class="mb-2">
+                                        <label class="text-secondary text-sm">Memo</label>
+                                        <input type="text" class="form-control form-control-sm"
+                                               name="whyIsMcpOnboardingNotActiveMemo"
+                                               value="{{ $patient->why_is_mcp_onboarding_not_active_memo }}">
+                                    </div>
+                                </div>
+                                <div>
+                                    <button submit class="btn btn-sm btn-primary mr-1">Submit</button>
+                                    <button cancel class="btn btn-sm btn-default border">Cancel</button>
+                                </div>
+                            </form>
+                        </div>
+                    @endif
+                    @if($patient->has_mcp_done_onboarding_visit !== 'YES' && $patient->is_mcp_onboarding_active === 'NO')
+                        <div class="text-secondary p-2 border my-2 bg-light">
+                            <div class="font-weight-bold">{{$patient->why_is_mcp_onboarding_not_active_category}}</div>
+                            <div>{{$patient->why_is_mcp_onboarding_not_active_memo}}</div>
+                        </div>
+                    @endif
+                </span>
+
+                <hr class="m-negator-3 my-3">
                 <span>MCP: <b>{{ $patient->mcp ? $patient->mcp->displayName() : '-' }}</b></span>
                 @if($pro->pro_type == 'ADMIN')
                     <div moe class="ml-2">

+ 12 - 6
resources/views/app/patient/tickets.blade.php

@@ -974,12 +974,18 @@
                             }, 1000);
                         @endfor
 
-                        @if(@$currentTicket && $currentTicket->category && $currentTicket->uid)
-                            setTimeout(() => {
-                                let currentTicket = this.tickets.filter(_x => _x.uid === '{{$currentTicket->uid}}');
-                                if (currentTicket && currentTicket.length)
-                                    this['{{$currentTicket->category}}ShowPopup'](currentTicket[0]);
-                            }, 10);
+                        @if(@$currentTicket)
+                            @if($currentTicket === 'create')
+                                setTimeout(() => {
+                                    this['{{$type}}ShowPopup']();
+                                });
+                            @elseif($currentTicket->category && $currentTicket->uid)
+                                setTimeout(() => {
+                                    let currentTicket = this.tickets.filter(_x => _x.uid === '{{$currentTicket->uid}}');
+                                    if (currentTicket && currentTicket.length)
+                                        this['{{$currentTicket->category}}ShowPopup'](currentTicket[0]);
+                                }, 10);
+                            @endif
                         @endif
 
                     }

+ 30 - 17
resources/views/app/patients.blade.php

@@ -34,6 +34,7 @@
             <select class="ml-auto max-width-300px form-control form-control-sm" onchange="fastLoad('/patients/' + this.value, true, false, false)">
                 <option value="" {{ $filter === '' ? 'selected' : '' }}>All patients</option>
                 <option value="not-yet-seen" {{ $filter === 'not-yet-seen' ? 'selected' : '' }}>Patients I have not seen yet</option>
+                <option value="having-birthday-today" {{ $filter === 'having-birthday-today' ? 'selected' : '' }}>Patients having birthday today</option>
             </select>
         </div>
         <div class="card-body p-0">
@@ -45,13 +46,15 @@
                     @endif
                     <th class="px-3 border-0">Chart #</th>
                     <th class="border-0">Patient</th>
+                    <th class="border-0 px-1">OB</th>
+                    <th class="border-0">Signed<br>Notes</th>
                     <th class="border-0">Created At</th>
-		    <th class="border-0">Address</th>
+		            <th class="border-0">Address</th>
                     @if($showProgramsColumn)<th class="border-0">Program(s)</th>@endif
                     <th class="border-0">MCN</th>
                     <th class="border-0">PCP</th>
                     {{--<th class="border-0">RMM</th>--}}
-                    <th class="border-0">Upcoming Appointments</th>
+                    <th class="border-0">Appointments</th>
                 </tr>
                 </thead>
                 <tbody>
@@ -67,25 +70,35 @@
                         </td>
                         <td>
                             {{$patient->displayName()}}
+                            <div>{{ friendly_date_time($patient->dob, false) }}{{ $patient->sex === 'M' ? ', Male' : ($patient->sex === ', F' ? 'Female' : '') }}</div>
+                        </td>
+                        <td class="px-1">
                             @if($patient->has_mcp_done_onboarding_visit !== 'YES')
-                            <span title="MCP Onboarding Visit Pending"><i class="fa fa-exclamation-triangle"></i></span>
+                                <span title="MCP Onboarding Visit Pending"><i class="fa fa-exclamation-triangle"></i></span>
+                            @else
+                                <i class="fa fa-check text-secondary on-hover-opaque"></i>
                             @endif
-                            <div>{{ friendly_date_time($patient->dob, false) }}{{ $patient->sex === 'M' ? ', Male' : ($patient->sex === ', F' ? 'Female' : '') }}</div>
+                        </td>
+                        <td>
+                            <?php $numSignedNotes = $patient->numSignedNotes(); ?>
+                            <span class="{{$numSignedNotes && $patient->has_mcp_done_onboarding_visit !== 'YES' ? 'font-weight-bold text-warning-mellow' : 'text-secondary'}}">
+                                {{$numSignedNotes ? $numSignedNotes :'-'}}
+                            </span>
                         </td>
                         <td>{{friendly_date_time_short_with_tz($patient->created_at, true, 'EASTERN')}}</td>
-			<td>
-				<?php
-                                                $addressParts = [];
-                                                if (!!$patient->mailing_address_line1) $addressParts[] = $patient->mailing_address_line1;
-                                                if (!!$patient->mailing_address_line2) $addressParts[] = $patient->mailing_address_line2;
-                                                $addressParts = implode(", ", $addressParts) . "<br/>";
-                                                $addressPart2 = [];
-                                                if (!!$patient->mailing_address_city) $addressPart2[] = $patient->mailing_address_city;
-                                                if (!!$patient->mailing_address_state) $addressPart2[] = $patient->mailing_address_state;
-                                                $addressParts .= implode(", ", $addressPart2);
-                                                echo $addressParts;
-                                                ?>	
-			</td>
+                        <td>
+                            <?php
+                            $addressParts = [];
+                            if (!!$patient->mailing_address_line1) $addressParts[] = $patient->mailing_address_line1;
+                            if (!!$patient->mailing_address_line2) $addressParts[] = $patient->mailing_address_line2;
+                            $addressParts = implode(", ", $addressParts) . "<br/>";
+                            $addressPart2 = [];
+                            if (!!$patient->mailing_address_city) $addressPart2[] = $patient->mailing_address_city;
+                            if (!!$patient->mailing_address_state) $addressPart2[] = $patient->mailing_address_state;
+                            $addressParts .= implode(", ", $addressPart2);
+                            echo $addressParts;
+                            ?>
+                        </td>
                         @if($showProgramsColumn)
                         <td>
                             <?php $programNumber = 0; ?>

+ 126 - 0
resources/views/app/practice-management/unacknowledged-cancelled-bills.blade.php

@@ -0,0 +1,126 @@
+@extends ('layouts/template')
+
+@section('content')
+
+    <div class="p-3 mcp-theme-1">
+    <div class="card">
+
+        <div class="card-header px-3 py-2 d-flex align-items-center">
+            <strong class="mr-4 font-size-16">
+                <i class="fas fa-user-injured"></i>
+                Unacknowledged Cancelled Bills
+            </strong>
+        </div>
+        <div class="card-body p-0">
+
+            <table class="table table-sm table-condensed p-0 m-0">
+                <thead class="bg-light">
+                <tr>
+                    <th class="px-3 border-0">Created</th>
+                    <th class="border-0">Patient</th>
+                    <th class="border-0 w-50">Context</th>
+                    <th class="border-0">Role</th>
+                    <th class="border-0">Amount</th>
+                </tr>
+                </thead>
+                <tbody>
+                @foreach ($bills as $bill)
+                    <tr class="">
+                        <td class="px-3">
+                            {{ friendly_date_time($bill->created_at, true) }}
+                        </td>
+                        <td class="">
+                            <a href="/patients/view/{{ $bill->client->uid }}">{{ $bill->client->displayName() }}</a>
+                        </td>
+                        <td class="stag-no-wrap-td">
+                            @if($bill->careMonth)
+                                <b>{{ $bill->code }}</b>
+                                -
+                                <a href="/patients/view/{{ $bill->client->uid }}/care-months/view/{{ $bill->careMonth->uid }}">
+                                    <b>{{ friendly_month($bill->careMonth->start_date) }}</b>
+                                </a>
+                            @elseif($bill->note)
+                                <b>{{ $bill->code }}</b>
+                                -
+                                <a href="/patients/view/{{ $bill->client->uid }}/notes/view/{{ $bill->note->uid }}">
+                                    <b>Note</b>
+                                </a>
+                            @endif
+                            @if(!empty($bill->reason1))
+                                <div class="text-secondary text-sm stag-no-wrap" title="{{ $bill->reason1 }}">{{ $bill->reason1 }}</div>
+                            @endif
+                        </td>
+                        <td>
+                            <?php
+                            $roles = [];
+                            if($bill->hcp_pro_id === $pro->id) $roles[] = 'HCP';
+                            if($bill->cm_pro_id === $pro->id) $roles[] = 'CM';
+                            if($bill->rme_pro_id === $pro->id) $roles[] = 'RME';
+                            if($bill->rmm_pro_id === $pro->id) $roles[] = 'RMM';
+                            $roles = implode("<br>", $roles);
+                            ?>
+                            {!! $roles !!}
+                        </td>
+                        <td>
+                            @if($bill->hcp_pro_id === $pro->id)
+                                @if($bill->has_hcp_been_paid)
+                                    <div>
+                                        <span class="text-dark">HCP Received:</span>
+                                        <span class="font-weight-bold text-success ml-2">${{ $bill->hcp_payment_amount }}</span>
+                                    </div>
+                                @else
+                                    <div>
+                                        <span class="text-dark">HCP Expected:</span>
+                                        <span class="font-weight-bold text-dark ml-2">{{ $bill->hcp_expected_payment_amount ? '$' . $bill->hcp_expected_payment_amount : '-' }}</span>
+                                    </div>
+                                @endif
+                            @endif
+                            @if($bill->cm_pro_id === $pro->id)
+                                @if($bill->has_cm_been_paid)
+                                    <div>
+                                        <span class="text-dark">CM Received:</span>
+                                        <span class="font-weight-bold text-success ml-2">${{ $bill->cm_payment_amount }}</span>
+                                    </div>
+                                @else
+                                    <div>
+                                        <span class="text-dark">CM Expected:</span>
+                                        <span class="font-weight-bold text-dark ml-2">{{ $bill->cm_expected_payment_amount ? '$' . $bill->cm_expected_payment_amount : '-' }}</span>
+                                    </div>
+                                @endif
+                            @endif
+                            @if($bill->rmm_pro_id === $pro->id)
+                                @if($bill->has_rmm_been_paid)
+                                    <div>
+                                        <span class="text-dark">RMM Received:</span>
+                                        <span class="font-weight-bold text-success ml-2">${{ $bill->rmm_payment_amount }}</span>
+                                    </div>
+                                @else
+                                    <div>
+                                        <span class="text-dark">RMM Expected:</span>
+                                        <span class="font-weight-bold text-dark ml-2">{{ $bill->rmm_expected_payment_amount ? '$' . $bill->rmm_expected_payment_amount : '-' }}</span>
+                                    </div>
+                                @endif
+                            @endif
+                            @if($bill->rme_pro_id === $pro->id)
+                                @if($bill->has_rme_been_paid)
+                                    <div>
+                                        <span class="text-dark">RME Received:</span>
+                                        <span class="font-weight-bold text-success ml-2">${{ $bill->rme_payment_amount }}</span>
+                                    </div>
+                                @else
+                                    <div>
+                                        <span class="text-dark">RME Expected:</span>
+                                        <span class="font-weight-bold text-dark ml-2">{{ $bill->rme_expected_payment_amount ? '$' . $bill->rme_expected_payment_amount : '-' }}</span>
+                                    </div>
+                                @endif
+                            @endif
+                        </td>
+                    </tr>
+                @endforeach
+                </tbody>
+            </table>
+        </div>
+    </div>
+    </div>
+
+@endsection

+ 12 - 3
resources/views/layouts/patient.blade.php

@@ -187,7 +187,7 @@
             @endif
             <main role="main" class="w-100">
                 @if($pro->is_enrolled_as_mcp && !$patient->mcp)
-                    <div class="alert alert-info bg-white mt-3 mcp-theme-1 p-3">
+                    <div class="alert alert-info bg-white mt-3 mcp-theme-1 p-3 hide-inside-ticket-poppup">
                         <div class="font-size-16">
                             <i class="fa fa-exclamation-triangle text-warning-mellow"></i>
                             This patient currently does not have an MCP assigned.
@@ -218,6 +218,15 @@
                         </div>
                     </div>
                 @endif
+                @if($patient->has_mcp_done_onboarding_visit !== 'YES' && $patient->is_mcp_onboarding_active === 'NO')
+                    <div class="alert alert-warning mt-3 mcp-theme-1 p-3 hide-inside-ticket-poppup">
+                        <div class="font-weight-bold text-dark font-size-16">MCP onboarding is not active for this patient.</div>
+                        <div class="text-secondary p-2 border mt-2 bg-light">
+                            <div class="font-weight-bold">{{$patient->why_is_mcp_onboarding_not_active_category}}</div>
+                            <div>{{$patient->why_is_mcp_onboarding_not_active_memo}}</div>
+                        </div>
+                    </div>
+                @endif
                 <div class="card mt-3">
                     <div class="card-header py-1 hide-inside-ticket-poppup">
                         <?php
@@ -354,7 +363,7 @@
                                                         </form>
                                                     </div>
                                                     @endif
-                                                    @if($patient->is_coverage_manually_verified)
+                                                    {{--@if($patient->is_coverage_manually_verified)
                                                         <div moe relative class="ml-2">
                                                             <a start show class="font-weight-bold">Undo manual verification</a>
                                                             <form url="/api/client/undoMarkCoverageAsManuallyVerified" class="mcp-theme-1" right>
@@ -366,7 +375,7 @@
                                                                 </div>
                                                             </form>
                                                         </div>
-                                                    @endif
+                                                    @endif--}}
                                                 @endif
                                             </div>
                                         </div>

+ 1 - 1
resources/views/layouts/template.blade.php

@@ -168,7 +168,7 @@
                             </a>
                         @endif
                         <a native target="_top" class="d-block ml-2 pt-1" href="{{config('stag.authUrl')}}" title="">
-                            Exit
+                            Return to Home
                         </a>
                         <a native target="_top" href="{{route('logout')}}" class="d-block ml-2 pt-1">
                             Sign Out

+ 71 - 66
routes/web.php

@@ -81,6 +81,7 @@ Route::middleware('pro.auth')->group(function () {
         Route::get('contract', 'PracticeManagementController@contract')->name('contract');
         Route::get('notes/{filter?}', 'PracticeManagementController@notes')->name('notes');
         Route::get('bills/{filter?}', 'PracticeManagementController@bills')->name('bills');
+        Route::get('unacknowledged-cancelled-bills', 'PracticeManagementController@unacknowledgedCancelledBills')->name('unacknowledged-cancelled-bills');
         Route::get('my-tickets/{filter?}', 'PracticeManagementController@myTickets')->name('myTickets');
         Route::get('my-text-shortcuts', 'PracticeManagementController@myTextShortcuts')->name('myTextShortcuts');
         Route::get('my-favorites/{filter?}', 'PracticeManagementController@myFavorites')->name('myFavorites');
@@ -133,73 +134,77 @@ Route::middleware('pro.auth')->group(function () {
     });
 
     Route::name('patients.view.')->prefix('patients/view/{patient}')->group(function () {
-        Route::get('intake', 'PatientController@intake')->name('intake');
-        Route::get('', 'PatientController@dashboard')->name('dashboard');
-        Route::get('care-plan', 'PatientController@carePlan')->name('care-plan');
-        Route::get('medications', 'PatientController@medications')->name('medications');
-        Route::get('dx-and-focus-areas', 'PatientController@dxAndFocusAreas')->name('dx-and-focus-areas');
-        Route::get('care-team', 'PatientController@careTeam')->name('care-team');
-        Route::get('devices', 'PatientController@devices')->name('devices');
-        Route::get('measurements', 'PatientController@measurements')->name('measurements');
-        Route::get('labs-and-studies', 'PatientController@labsAndStudies')->name('labs-and-studies');
-        Route::get('history', 'PatientController@history')->name('history');
-        Route::get('memos', 'PatientController@memos')->name('memos');
-        Route::get('sms', 'PatientController@sms')->name('sms');
-        Route::get('sms-numbers', 'PatientController@smsNumbers')->name('sms-numbers');
-        Route::get('immunizations', 'PatientController@immunizations')->name('immunizations');
-        Route::get('allergies', 'PatientController@allergies')->name('allergies');
-        Route::get('action-items', 'PatientController@actionItems')->name('action-items');
-        Route::get('action-items-erx/view/{ticket}', 'PatientController@actionItemsErxSingle')->name('action-items-erx-single');
-        Route::get('action-items-lab/view/{ticket}', 'PatientController@actionItemsLabSingle')->name('action-items-lab-single');
-        Route::get('action-items-imaging/view/{ticket}', 'PatientController@actionItemsImagingSingle')->name('action-items-imaging-single');
-        Route::get('action-items-equipment/view/{ticket}', 'PatientController@actionItemsEquipmentSingle')->name('action-items-equipment-single');
-        Route::get('action-items-other/view/{ticket}', 'PatientController@actionItemsOtherSingle')->name('action-items-other-single');
-        Route::get('action-items-erx/{filter?}', 'PatientController@actionItemsErx')->name('action-items-erx');
-        Route::get('action-items-lab/{filter?}', 'PatientController@actionItemsLab')->name('action-items-lab');
-        Route::get('action-items-imaging/{filter?}', 'PatientController@actionItemsImaging')->name('action-items-imaging');
-        Route::get('action-items-equipment/{filter?}', 'PatientController@actionItemsEquipment')->name('action-items-equipment');
-        Route::get('action-items-other/{filter?}', 'PatientController@actionItemsOther')->name('action-items-other');
-        Route::get('notes/{filter?}', 'PatientController@notes')->name('notes');
-        Route::name('notes.view.')->prefix('notes/view/{note}')->group(function () {
-            Route::get('', 'NoteController@dashboard')->name('dashboard');
-        });
-        Route::get('sections', 'PatientController@sections')->name('sections');
-        Route::get('handouts', 'PatientController@handouts')->name('handouts');
-        Route::get('settings', 'PatientController@settings')->name('settings');
-        Route::get('pros', 'PatientController@pros')->name('pros');
-        Route::get('account', 'PatientController@account')->name('account');
-        Route::get('care-checklist', 'PatientController@careChecklist')->name('care-checklist');
-        Route::get('documents', 'PatientController@documents')->name('documents');
-        Route::get('incoming-reports/{currentReport?}', 'PatientController@incomingReports')->name('incoming-reports');
-        Route::get('education', 'PatientController@education')->name('education');
-        Route::get('messaging', 'PatientController@messaging')->name('messaging');
-        Route::get('duplicate', 'PatientController@duplicate')->name('duplicate');
-        Route::get('care-months', 'PatientController@careMonths')->name('care-months');
-        Route::name('care-months.view.')->prefix('care-months/view/{careMonth}')->group(function () {
-            Route::get('', 'CareMonthController@dashboard')->name('dashboard');
-        });
-
-        // appointment calendar
-        Route::get('calendar/{currentAppointment?}', 'PatientController@calendar')->name('calendar');
-
-        // programs
-        Route::get('programs/{filter?}', 'PatientController@programs')->name('programs');
-
-        // flowsheets
-        Route::get('flowsheets/{filter?}', 'PatientController@flowsheets')->name('flowsheets');
 
-        // vitals-graph
-        Route::get('vitals-graph/{filter?}', 'PatientController@vitalsGraph')->name('vitals-graph');
-
-        // tickets
-        Route::get('tickets/{type?}/{currentTicket?}', 'PatientController@tickets')->name('patient-tickets');
-
-        // appointments
-        Route::get('appointments/{forPro}/{status}', 'PatientController@appointments')->name('appointments');
-
-        Route::get('supply-orders/{supplyOrder?}', 'PatientController@supplyOrders')->name('supply-orders');
-        Route::get('shipments/{shipment?}', 'PatientController@shipments')->name('shipments');
+        Route::middleware('pro.auth.can-access-patient')->group(function() {
+
+            Route::get('intake', 'PatientController@intake')->name('intake');
+            Route::get('', 'PatientController@dashboard')->name('dashboard');
+            Route::get('care-plan', 'PatientController@carePlan')->name('care-plan');
+            Route::get('medications', 'PatientController@medications')->name('medications');
+            Route::get('dx-and-focus-areas', 'PatientController@dxAndFocusAreas')->name('dx-and-focus-areas');
+            Route::get('care-team', 'PatientController@careTeam')->name('care-team');
+            Route::get('devices', 'PatientController@devices')->name('devices');
+            Route::get('measurements', 'PatientController@measurements')->name('measurements');
+            Route::get('labs-and-studies', 'PatientController@labsAndStudies')->name('labs-and-studies');
+            Route::get('history', 'PatientController@history')->name('history');
+            Route::get('memos', 'PatientController@memos')->name('memos');
+            Route::get('sms', 'PatientController@sms')->name('sms');
+            Route::get('sms-numbers', 'PatientController@smsNumbers')->name('sms-numbers');
+            Route::get('immunizations', 'PatientController@immunizations')->name('immunizations');
+            Route::get('allergies', 'PatientController@allergies')->name('allergies');
+            Route::get('action-items', 'PatientController@actionItems')->name('action-items');
+            Route::get('action-items-erx/view/{ticket}', 'PatientController@actionItemsErxSingle')->name('action-items-erx-single');
+            Route::get('action-items-lab/view/{ticket}', 'PatientController@actionItemsLabSingle')->name('action-items-lab-single');
+            Route::get('action-items-imaging/view/{ticket}', 'PatientController@actionItemsImagingSingle')->name('action-items-imaging-single');
+            Route::get('action-items-equipment/view/{ticket}', 'PatientController@actionItemsEquipmentSingle')->name('action-items-equipment-single');
+            Route::get('action-items-other/view/{ticket}', 'PatientController@actionItemsOtherSingle')->name('action-items-other-single');
+            Route::get('action-items-erx/{filter?}', 'PatientController@actionItemsErx')->name('action-items-erx');
+            Route::get('action-items-lab/{filter?}', 'PatientController@actionItemsLab')->name('action-items-lab');
+            Route::get('action-items-imaging/{filter?}', 'PatientController@actionItemsImaging')->name('action-items-imaging');
+            Route::get('action-items-equipment/{filter?}', 'PatientController@actionItemsEquipment')->name('action-items-equipment');
+            Route::get('action-items-other/{filter?}', 'PatientController@actionItemsOther')->name('action-items-other');
+            Route::get('notes/{filter?}', 'PatientController@notes')->name('notes');
+            Route::name('notes.view.')->prefix('notes/view/{note}')->group(function () {
+                Route::get('', 'NoteController@dashboard')->name('dashboard');
+            });
+            Route::get('sections', 'PatientController@sections')->name('sections');
+            Route::get('handouts', 'PatientController@handouts')->name('handouts');
+            Route::get('settings', 'PatientController@settings')->name('settings');
+            Route::get('pros', 'PatientController@pros')->name('pros');
+            Route::get('account', 'PatientController@account')->name('account');
+            Route::get('care-checklist', 'PatientController@careChecklist')->name('care-checklist');
+            Route::get('documents', 'PatientController@documents')->name('documents');
+            Route::get('incoming-reports/{currentReport?}', 'PatientController@incomingReports')->name('incoming-reports');
+            Route::get('education', 'PatientController@education')->name('education');
+            Route::get('messaging', 'PatientController@messaging')->name('messaging');
+            Route::get('duplicate', 'PatientController@duplicate')->name('duplicate');
+            Route::get('care-months', 'PatientController@careMonths')->name('care-months');
+            Route::name('care-months.view.')->prefix('care-months/view/{careMonth}')->group(function () {
+                Route::get('', 'CareMonthController@dashboard')->name('dashboard');
+            });
+
+            // appointment calendar
+            Route::get('calendar/{currentAppointment?}', 'PatientController@calendar')->name('calendar');
+
+            // programs
+            Route::get('programs/{filter?}', 'PatientController@programs')->name('programs');
+
+            // flowsheets
+            Route::get('flowsheets/{filter?}', 'PatientController@flowsheets')->name('flowsheets');
+
+            // vitals-graph
+            Route::get('vitals-graph/{filter?}', 'PatientController@vitalsGraph')->name('vitals-graph');
+
+            // tickets
+            Route::get('tickets/{type?}/{currentTicket?}', 'PatientController@tickets')->name('patient-tickets');
+
+            // appointments
+            Route::get('appointments/{forPro}/{status}', 'PatientController@appointments')->name('appointments');
+
+            Route::get('supply-orders/{supplyOrder?}', 'PatientController@supplyOrders')->name('supply-orders');
+            Route::get('shipments/{shipment?}', 'PatientController@shipments')->name('shipments');
 
+        });
 
     });
 
@@ -237,7 +242,7 @@ Route::middleware('pro.auth')->group(function () {
     Route::get('/patients/{patient}/presence', 'PatientController@presence');
 
     // refresh single ticket
-    Route::get('/get-ticket/{ticket}', 'PatientController@getTicket');
+    Route::get('/get-ticket/{ticket}', 'HomeController@getTicket');
 
 
     Route::get('/appointment-confirmation-history/{appointment}', 'AppointmentController@appointmentConfirmationHistory')->name('appointment-confirmation-history');

+ 137 - 0
spec/front-end-documentation.md

@@ -0,0 +1,137 @@
+## Table of Contents
+
+1. [Top level window](#top-level-window)
+2. [The MC engine](#the-mc-engine)
+
+
+___
+## Top level window
+
+When the top level window receives a request, it does the following:
+
+1. Check if URL has /mc/ prefix
+2. If no:
+    1. Redirect to /mc/{request-path}
+3. If yes:
+    1. Load (via AJAX) {request-path} into LHS
+    2. Load blank video page into RHS (the one that shows MCP queue at the bottom)
+
+The top level window object exposes the following app-specific methods:
+
+1. `openInLHS(_url)`
+2. `openInRHS(_url)`
+3. `toggleRHS()`
+4. `showRHS()`
+5. `hideRHS()`
+
+The above are defined in **mc.blade.php** - which is included *only* from the top level window - and *never* from the LHS or RHS child windows.
+
+---
+## The MC engine
+
+Responsible for loading, initialization, history state management, fastLoading, reloads, etc. of the LHS
+
+Assuming the URL as **/mc/path/to-page**, a page load in the LHS involves the following:
+
+1. Fetch **/path/to-page** via AJAX GET
+2. Fill LHS with the retrieved content (including any scripts that it includes) - **more on this below**
+3. Enable *fast loading* for all `<a>` tags with a href that are not `[native]` - **more on this below**
+4. Run all registered **mc initializers** - **more on this below**
+
+---
+### Fill LHS with the retrieved content & fast loading
+
+After loading /path/to/page via AJAX, mc extracts the html inside the first `.stag-content` it encounters in the content - and replaces the existing `.stag-content` element in the DOM.
+
+The `.stag-content` element is at `resources/views/layouts/template.blade.php` - line 186
+
+mc.blade.php (the blade responsible for rendering the LHS anf RHS frame elements) initially loads the LHS with **/blank** - an empty page that has 1 `.stag-content` element in it to make subsequent loads work correctly.  
+
+The method `fastLoad(_url)` is available to be called from anywhere in code from with the LHS frame. It will load and display _url in LHS. There is also a `fastReload()` (which btw, will not auto-reset the scrollbar to the top).
+
+> **Important:** `fastLoad()` & `fastReload()` **will not disrupt** any calls that maybe taking place in the RHS
+
+> **Note:** The top header nav is outside `.stag-content` and is **not** refreshed during `fastLoad()` & `fastReload()`
+
+---
+### Enable fast loading for all `<a>` tags in the content
+
+Once the content is retrieved and inserted into `.stag-content`, we automatically bind fast load events into all `<a>` that are not `[native]` and that have a valid `[href]`
+
+All link clicks (other than those bound to context specific JS events - like Vue code etc.) work via the above loader - fetching and inserting only the content area. 
+
+To prevent any link from being auto-enabled for fast loading, add the **native** attribute to it. 
+
+```html
+<a native target="_top" href="/foo/bar">Some Link</a>
+```
+
+---
+### Run all registered mc initializers
+
+Because page content is loaded via AJAX and inserted into the DOM, we cannot rely on `document.onready` for running init code.
+
+Any page specific code that needs to be run on start up, must go into an **mc initializer*. The mc engine, keeps track of all registered initializers are runs all required initers after each fastLoad (or reload).
+
+Writing start up code for a page. Example:
+
+```html
+<div id="my-page">
+   Some content
+</div>
+<script>
+   (function () {
+      function init() {
+         // init code goes here
+      }
+
+      // add your initializer to mc stack
+      addMCInitializer('my-page', init, '#my-page');
+      
+   }).call(window);
+</script>
+```
+
+1. The first arg to `addMCInitializer()` is a name for the initializer (more on why these are named later)
+2. Second arg is the function to be called
+3. The Third argument is a container element - whose presence in the DOM will be checked before executing the initer. If this element is not present, the initer will be deleted from the list of registered initializers
+4. On all pages, page specific JS is **always** wrapped inside a scope-limiting [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE)
+
+> **Why named initializers**
+>  
+> Sometimes, we'll need to selectively run some initializers - for example, if we're loading a note single inside a popup, we'll need to grab just the note page markup (without mc, the layout, etc.) - but will still need to run its initializer after the popup is filled for the functionality inside to work. In such cases, we can call `runMCInitializer('note-single)` for example.
+
+> Special case **window.noMC**
+>
+> If window.noMC is true, the above flow is overridden, and the page is allowed to load as-is regardless of the presence/absence of /mc/ in the URL.
+
+> Defined in mc-init.js & mc.js
+
+---
+## Stag Popups
+
+Medium to big popups (different from moes). Identified via the `[stag-popup-key]` attribute and displayed using the `showStagPopup(_key)` method call.
+
+```html
+<div class="stag-popup stag-popup-md" stag-popup-key="my-popup">
+   popup content
+</div>
+```
+```javascript
+showStagPopup('my-popup')
+```
+
+Stag popup maintains an app-level popup stack. You can have a popup over a popup over a popup. Clicking anywhere outside or hitting ESC will close the topmost stag-popup and so on. Stag popups can also have regular moes within their content.
+
+If a stag-popup has the attribute `[close-all-with-self]` - then all stag-popups are closed along with it (regardless of the number of stacked popups currently open)
+
+Stag popups with `.stag-slide` class will slide in from the right (instead of appearing at the center).
+
+To close the topmost stag popup:
+```javascript
+closeStagPopup()
+```
+
+> Defined in stag-popup.js
+
+Yemi mods Shortcuts Stag-popup Note > templates Pro-suggest, Pharmacy suggest Popupmode queryline param