Przeglądaj źródła

Updates dashboards

Samson Mutunga 3 lat temu
rodzic
commit
5a1baa57f8

+ 378 - 1
app/Http/Controllers/HomeController.php

@@ -572,7 +572,384 @@ WHERE cl.shadow_pro_id IS NULL
     }
 
     public function dashboard_HCP(Request $request){
-        return view('app/dashboard-hcp'); //TODO provide data
+        //TODO provide hcp specific data. Currently is based on MCP context
+        $keyNumbers = [];
+
+        // Patients // SELECT * FROM client WHERE mcp_pro_id = :me.id;
+        // New Patients Awaiting Visit // SELECT * FROM client WHERE mcp_pro_id = :me.id AND hasMcpDoneOnboardingVisit != 'YES';
+        // Notes Pending Signature // SELECT * FROM note WHERE hcp_pro_id = :me.id AND is_cancelled IS NOT TRUE AND has_hcp_signed IS NOT TRUE;
+        // Notes Pending Billing // SELECT * FROM note WHERE hcp_pro_id = :me.id AND is_cancelled IS NOT TRUE AND has_hcp_signed IS TRUE AND is_billing_marked_done IS FALSE;
+        // Reports Pending Signature // SELECT * FROM incoming_report WHERE hcp_pro_id = :me.id AND isEntryError IS NOT TRUE AND hasHcpProSigned IS NOT TRUE;
+        // Patients w/o Appointments // SELECT * FROM client WHERE mcp_pro_id = :me.id AND client.next_mcp_appointment_date < today();
+        // Patients Overdue for Visit // SELECT * FROM client WHERE mcp_pro_id = :me.id AND client.next_expected_mcp_visit_date < today();
+        // Cancelled Appts. Pending Review // SELECT * FROM appointment WHERE hcp_pro_id = :me.id AND status = 'REJECTED' AND wasAcknowledgedByAppointmentPro IS NOT TRUE;
+        // Cancelled Bills Pending Review // SELECT * FROM bill WHERE bill_service_type = 'NOTE' AND is_cancelled IS TRUE AND isCancellationAcknowledged IS FALSE;
+        // Cancelled Supply Orders Pending Review // SELECT * FROM supply_order WHERE signed_by_pro_id = :me.id AND is_cancelled IS TRUE AND isCancellationAcknowledged IS NOT TRUE;
+        // ERx & Orders Pending Signature // SELECT * FROM erx WHERE hcp_pro_id = :me.id AND pro_declared_status <> 'CANCELLED' AND hasHcpProSigned IS NOT TRUE;
+        // Supply Orders Pending Signature // SELECT supply_order.id FROM supply_order WHERE signed_by_pro_id IS NOT TRUE AND is_cancelled IS NOT TRUE AND created_by_pro_id = :me.id;
+
+        $performer = $this->performer();
+        $pro = $performer->pro;
+        $performerProID = $performer->pro->id;
+
+        $keyNumbers  = [];
+
+        $queryClients = $this->performer()->pro->getAccessibleClientsQuery();
+
+        $pendingNotesToSign = Note
+            ::where(function ($query) use ($performerProID) {
+                $query->where('hcp_pro_id', $performerProID)->where('is_signed_by_hcp', false)->where('is_cancelled', false)->where('is_core_note', false);
+            })
+            ->orWhere(function ($query) use ($performerProID) {
+                $query->where('ally_pro_id', $performerProID)->where('is_signed_by_ally', false)->where('is_cancelled', false)->where('is_core_note', false);
+            })
+            ->count();
+        $keyNumbers['pendingNotesToSign'] = $pendingNotesToSign;
+
+        // notes pending mcp sign (applicable to dnas only)
+        $pendingNotesToSignMCP = Note
+            ::where(function ($query) use ($performerProID) {
+                $query->where('ally_pro_id', $performerProID)->where('is_signed_by_hcp', false)->where('is_cancelled', false)->where('is_core_note', false);
+            })
+            ->count();
+        $keyNumbers['$pendingNotesToSignMCP'] = $pendingNotesToSignMCP;
+
+        $pendingNotesToSignAllySigned = Note::where(function ($query) use ($performerProID) {
+            $query->where('hcp_pro_id', $performerProID)->where('is_signed_by_hcp', false)->where('is_signed_by_ally', true)->where('is_cancelled', false)->where('is_core_note', false);;
+        })->count();
+        $keyNumbers['pendingNotesToSignAllySigned'] = $pendingNotesToSignAllySigned;
+
+
+        $signedNotesWithoutBills = Note::where(function ($query) use ($performerProID) {
+            $query->where('hcp_pro_id', $performerProID)->where('is_signed_by_hcp', true)->where('is_cancelled', false);
+        })->whereDoesntHave('bills')->count();
+
+        $keyNumbers['signedNotesWithoutBills'] = $signedNotesWithoutBills;
+
+        // open tickets
+        $keyNumbers['numOpenTickets'] = Ticket::where('is_open', true)
+            ->where(function ($q) use ($performerProID) {
+                $q->where('assigned_pro_id', $performerProID)
+                    ->orWhere('manager_pro_id', $performerProID)
+                    ->orWhere('ordering_pro_id', $performerProID)
+                    ->orWhere('initiating_pro_id', $performerProID);
+            })
+            ->count();
+
+        // unacknowledged cancelled bills for authed pro
+        $keyNumbers['unacknowledgedCancelledBills'] = Bill::where('hcp_pro_id', $performerProID)
+            ->where('is_cancelled', true)
+            ->where('is_cancellation_acknowledged', false)
+            ->count();
+
+        // unacknowledged cancelled supply orders for authed pro
+        $keyNumbers['unacknowledgedCancelledSupplyOrders'] = SupplyOrder::where('signed_by_pro_id', $performerProID)
+            ->where('is_cancelled', true)
+            ->where('is_cancellation_acknowledged', false)
+            ->count();
+
+        // unsigned supply orders created by authed pro
+        $keyNumbers['unsignedSupplyOrders'] = SupplyOrder
+            ::where('is_cancelled', false)
+            ->where('is_signed_by_pro', false)
+            ->whereRaw('created_by_session_id IN (SELECT id FROM app_session WHERE pro_id = ?)', [$performerProID])
+            ->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"] = '--';
+        $lastPayment = ProTransaction::where('pro_id', $performerProID)->where('plus_or_minus', 'PLUS')->orderBy('created_at', 'DESC')->first();
+        if ($lastPayment) {
+            $reimbursement["lastPayment"] =  $lastPayment->amount;
+            $reimbursement["lastPaymentDate"] = $lastPayment->created_at;
+        } else {
+            $reimbursement["lastPayment"] = '--';
+            $reimbursement["lastPaymentDate"] = '--';
+        }
+
+        //if today is < 15th, next payment is 15th, else nextPayment is
+        $today = strtotime(date('Y-m-d'));
+        $todayDate = date('j', $today);
+
+        $todayMonth =  date('m', $today);
+        $todayYear = date('Y', $today);
+        if ($todayDate < 15) {
+            $nextPaymentDate = new DateTime();
+            $nextPaymentDate->setDate($todayYear, $todayMonth, 15);
+            $reimbursement['nextPaymentDate'] = $nextPaymentDate->format('m/d/Y');
+        } else {
+            $nextPaymentDate = new \DateTime();
+            $lastDayOfMonth = date('t', $today);
+            $nextPaymentDate->setDate($todayYear, $todayMonth, $lastDayOfMonth);
+            $reimbursement['nextPaymentDate'] = $nextPaymentDate->format('m/d/Y');
+        }
+
+        //expectedPay
+        $expectedForHcp = DB::select(DB::raw("SELECT coalesce(SUM(hcp_expected_payment_amount),0) as expected_pay FROM bill WHERE hcp_pro_id = :performerProID  AND has_hcp_been_paid = false AND is_signed_by_hcp IS TRUE AND is_cancelled = false"), ['performerProID' => $performerProID])[0]->expected_pay;
+        $expectedForCm = DB::select(DB::raw("SELECT coalesce(SUM(cm_expected_payment_amount),0) as expected_pay  FROM bill WHERE cm_pro_id = :performerProID  AND has_cm_been_paid = false AND is_signed_by_cm IS TRUE AND is_cancelled = false"), ['performerProID' => $performerProID])[0]->expected_pay;
+        $expectedForRme = DB::select(DB::raw("SELECT coalesce(SUM(rme_expected_payment_amount),0) as expected_pay  FROM bill WHERE rme_pro_id = :performerProID  AND has_rme_been_paid = false AND is_signed_by_rme IS TRUE AND is_cancelled = false"), ['performerProID' => $performerProID])[0]->expected_pay;
+        $expectedForRmm = DB::select(DB::raw("SELECT coalesce(SUM(rmm_expected_payment_amount),0) as expected_pay  FROM bill WHERE rmm_pro_id = :performerProID  AND has_rmm_been_paid = false AND is_signed_by_rmm IS TRUE AND is_cancelled = false"), ['performerProID' => $performerProID])[0]->expected_pay;
+        $expectedForNa = DB::select(DB::raw("SELECT coalesce(SUM(generic_pro_expected_payment_amount),0) as expected_pay  FROM bill WHERE generic_pro_id = :performerProID  AND has_generic_pro_been_paid = false AND is_signed_by_generic_pro IS TRUE AND is_cancelled = false"), ['performerProID' => $performerProID])[0]->expected_pay;
+
+        $totalExpectedAmount =  $expectedForHcp + $expectedForCm + $expectedForRme + $expectedForRmm + $expectedForNa;
+        $reimbursement['nextPaymentAmount'] =  $totalExpectedAmount;
+
+        $milliseconds = strtotime(date('Y-m-d')) . '000';
+
+        // bills & claims
+        $businessNumbers = [];
+
+        // Notes with bills to resolve
+        $businessNumbers['notesWithBillsToResolve'] = Note::where('is_cancelled', '!=', true)
+            ->where('is_bill_closed', '!=', true)
+            ->whereRaw('(SELECT count(id) FROM bill WHERE note_id = note.id AND is_cancelled = false AND is_verified = false) > 0')
+            ->count();
+
+        // Notes pending bill closure
+        $businessNumbers['notesPendingBillingClosure'] = Note::where('is_cancelled', '!=', true)
+            ->where('is_bill_closed', '!=', true)
+            ->whereRaw('(SELECT count(id) FROM bill WHERE note_id = note.id AND (is_cancelled = true OR is_verified = true)) = 0')
+            ->count();
+
+        // incoming reports not signed
+        $incomingReports = IncomingReport::where('hcp_pro_id', $performerProID)
+            ->where('has_hcp_pro_signed', false)
+            ->where('is_entry_error', false)
+            ->orderBy('created_at', 'ASC')
+            ->get();
+        // erx, labs & imaging that are not closed
+        $tickets = Ticket::where('ordering_pro_id', $performerProID)
+            ->where('is_entry_error', false)
+            ->where('is_open', true)
+            ->orderBy('created_at', 'ASC')
+            ->get();
+        $supplyOrders = SupplyOrder::where('is_cleared_for_shipment', false)
+            ->where('is_cancelled', false)
+            ->whereRaw('created_by_session_id IN (SELECT id FROM app_session where pro_id = ?)', [$performer->pro->id])
+            ->orderBy('created_at', 'ASC')
+            ->get();
+
+        $numERx = Ticket::where('ordering_pro_id', $performerProID)
+            ->where('category', 'erx')
+            ->where('is_entry_error', false)
+            ->where('is_open', true)
+            ->count();
+        $numLabs = Ticket::where('ordering_pro_id', $performerProID)
+            ->where('category', 'lab')
+            ->where('is_entry_error', false)
+            ->where('is_open', true)
+            ->count();
+        $numImaging = Ticket::where('ordering_pro_id', $performerProID)
+            ->where('category', 'imaging')
+            ->where('is_entry_error', false)
+            ->where('is_open', true)
+            ->count();
+        $numSupplyOrders = SupplyOrder::where('is_cleared_for_shipment', false)
+            ->where('is_cancelled', false)
+            ->whereRaw('created_by_session_id IN (SELECT id FROM app_session where pro_id = ?)', [$performer->pro->id])
+            ->count();
+
+        $newMCPAssociations = ClientProChange
+            ::where('new_pro_id', $performerProID)
+            ->where('responsibility_type', 'MCP')
+            ->whereNull('current_client_pro_change_decision_id')
+            ->get();
+
+        $newNAAssociations = ClientProChange
+            ::where('new_pro_id', $performerProID)
+            ->where('responsibility_type', 'DEFAULT_NA')
+            ->whereNull('current_client_pro_change_decision_id')
+            ->get();
+
+        // unstamped client memos
+        // for mcp
+        $mcpClientMemos = DB::select(
+            DB::raw("
+SELECT c.uid as client_uid, c.name_first, c.name_last,
+       cm.uid, cm.content, cm.created_at
+FROM client c join client_memo cm on c.id = cm.client_id
+WHERE
+      c.mcp_pro_id = {$performerProID} AND
+      cm.mcp_stamp_id IS NULL
+      AND (is_admin_only IS FALSE OR is_admin_only IS NULL)
+ORDER BY cm.created_at DESC
+OFFSET 0 LIMIT 10
+            ")
+        );
+        $mcpClientMemosCount = DB::select(
+            DB::raw("
+SELECT count(c.uid)
+FROM client c join client_memo cm on c.id = cm.client_id
+WHERE
+      c.mcp_pro_id = {$performerProID} AND
+      cm.mcp_stamp_id IS NULL
+      AND (is_admin_only IS FALSE OR is_admin_only IS NULL)
+            ")
+        );
+        if($mcpClientMemosCount && count($mcpClientMemosCount)) {
+            $mcpClientMemosCount = $mcpClientMemosCount[0]->count;
+        }
+
+        // for na
+        $naClientMemos = DB::select(
+            DB::raw("
+SELECT c.uid as client_uid, c.name_first, c.name_last,
+       cm.uid, cm.content, cm.created_at
+FROM client c join client_memo cm on c.id = cm.client_id
+WHERE
+      c.default_na_pro_id = {$performerProID} AND
+      cm.default_na_stamp_id IS NULL
+ORDER BY cm.created_at DESC
+            ")
+        );
+
+        $keyNumbers['rmBillsToSign'] = Bill
+            ::where('is_cancelled', false)
+            ->where('cm_or_rm', 'RM')
+            ->where(function ($q) use ($performerProID) {
+                $q
+                    ->where(function ($q2) use ($performerProID) {
+                        $q2->where('hcp_pro_id', $performerProID)->where('is_signed_by_hcp', false);
+                    })
+                    ->orWhere(function ($q2) use ($performerProID) {
+                        $q2->where('rme_pro_id', $performerProID)->where('is_signed_by_rme', false);
+                    })
+                    ->orWhere(function ($q2) use ($performerProID) {
+                        $q2->where('rmm_pro_id', $performerProID)->where('is_signed_by_rmm', false);
+                    })
+                    ->orWhere(function ($q2) use ($performerProID) {
+                        $q2->where('generic_pro_id', $performerProID)->where('is_signed_by_generic_pro', false);
+                    });
+            })
+            ->count();
+
+        $count = DB::select(
+            DB::raw(
+                "
+SELECT count(client.id) as cnt FROM client join care_month on care_month.client_id = client.id
+WHERE ((client.mcp_pro_id = {$performer->pro->id}) OR (client.rmm_pro_id = {$performer->pro->id})
+          OR (client.rme_pro_id = {$performer->pro->id}) OR (client.default_na_pro_id = {$performer->pro->id}))
+  AND EXTRACT(MONTH from care_month.start_date) = EXTRACT(MONTH from now())
+  AND EXTRACT(YEAR from care_month.start_date) = EXTRACT(YEAR from now())
+  AND (care_month.number_of_days_with_remote_measurements < 16 OR care_month.number_of_days_with_remote_measurements IS NULL)
+"
+            )
+        );
+        $keyNumbers['rmPatientsWithLT16MD'] = $count[0]->cnt;
+
+        $count = DB::select(
+            DB::raw(
+                "
+SELECT count(client.id) as cnt FROM client join care_month on care_month.client_id = client.id
+WHERE ((client.mcp_pro_id = {$performer->pro->id}) OR (client.rmm_pro_id = {$performer->pro->id})
+          OR (client.rme_pro_id = {$performer->pro->id}) OR (client.default_na_pro_id = {$performer->pro->id}))
+  AND EXTRACT(MONTH from care_month.start_date) = EXTRACT(MONTH from now())
+  AND EXTRACT(YEAR from care_month.start_date) = EXTRACT(YEAR from now())
+  AND (care_month.number_of_days_with_remote_measurements >= 16 AND care_month.number_of_days_with_remote_measurements IS NOT NULL)
+"
+            )
+        );
+        $keyNumbers['rmPatientsWithGTE16MD'] = $count[0]->cnt;
+
+        $count = DB::select(
+            DB::raw(
+                "
+SELECT count(client.id) as cnt FROM client join care_month on care_month.client_id = client.id
+WHERE ((client.mcp_pro_id = {$performer->pro->id}) OR (client.rmm_pro_id = {$performer->pro->id})
+          OR (client.rme_pro_id = {$performer->pro->id}) OR (client.default_na_pro_id = {$performer->pro->id}))
+  AND EXTRACT(MONTH from care_month.start_date) = EXTRACT(MONTH from now())
+  AND EXTRACT(YEAR from care_month.start_date) = EXTRACT(YEAR from now())
+  AND (care_month.has_anyone_interacted_with_client_about_rm_outside_note = TRUE AND care_month.has_anyone_interacted_with_client_about_rm_outside_note IS NOT NULL)
+"
+            )
+        );
+        $keyNumbers['rmPatientsWithWhomCommDone'] = $count[0]->cnt;
+
+        $count = DB::select(
+            DB::raw(
+                "
+SELECT count(client.id) as cnt FROM client join care_month on care_month.client_id = client.id
+WHERE ((client.mcp_pro_id = {$performer->pro->id}) OR (client.rmm_pro_id = {$performer->pro->id})
+          OR (client.rme_pro_id = {$performer->pro->id}) OR (client.default_na_pro_id = {$performer->pro->id}))
+  AND EXTRACT(MONTH from care_month.start_date) = EXTRACT(MONTH from now())
+  AND EXTRACT(YEAR from care_month.start_date) = EXTRACT(YEAR from now())
+  AND (care_month.has_anyone_interacted_with_client_about_rm_outside_note = FALSE OR care_month.has_anyone_interacted_with_client_about_rm_outside_note IS NULL)
+"
+            )
+        );
+        $keyNumbers['rmPatientsWithWhomCommNotDone'] = $count[0]->cnt;
+
+        // num measurements that need stamping
+        $keyNumbers['measurementsToBeStamped'] = $this->performer()->pro->getUnstampedMeasurementsFromCurrentMonth(true, null, null);
+
+        if($performer->pro->pro_type === 'ADMIN') {
+
+            // patients without coverage information
+            $keyNumbers['patientsWithoutCoverageInformation'] = DB::select(DB::raw("
+SELECT count(DISTINCT (cl.id)) as cnt
+FROM client cl
+WHERE cl.shadow_pro_id IS NULL AND cl.latest_client_primary_coverage_id IS NULL -- no coverage record"
+            ))[0]->cnt;
+
+            // patients pending coverage verification
+            $keyNumbers['patientsPendingCoverageVerification'] = DB::select(DB::raw("
+SELECT count(DISTINCT (cl.id)) as cnt
+FROM client cl
+         LEFT JOIN client_primary_coverage cpc ON cl.latest_client_primary_coverage_id = cpc.id
+WHERE cl.shadow_pro_id IS NULL
+    AND (cl.latest_client_primary_coverage_id IS NOT NULL -- coverage exists, but status is null or unknown
+    AND (
+               (cpc.plan_type = 'MEDICARE' AND (cpc.is_partbprimary = 'UNKNOWN' OR cpc.is_partbprimary IS NULL))
+               OR
+               (cpc.plan_type != 'MEDICARE' AND
+                (cpc.manual_determination_category = 'UNKNOWN' OR cpc.manual_determination_category IS NULL))
+           ))"
+            ))[0]->cnt;
+
+        }
+
+        $incomingSmsMessagesPendingReply = DB::select("
+            SELECT cs.* ,c.uid as client_uid, c.name_first as client_name_first, c.name_last as client_name_last FROM client_sms cs LEFT JOIN client c ON c.id = cs.client_id
+            WHERE cs.is_reply_needed = 'YES' AND c.mcp_pro_id = :mcp_pro_id AND incoming_or_outgoing = 'INCOMING'
+            AND (cs.created_at > c.last_sms_sent_to_client_at OR c.last_sms_sent_to_client_at IS NULL)
+            ORDER BY created_at DESC
+        ", ['mcp_pro_id' => $performer->pro->id]);
+
+        $careMonthsWithMeasurementsPendingStamping = CareMonth::select('id')
+            ->where('mcp_pro_id', $this->performer->pro->id)
+            ->where('rm_num_measurements_not_stamped_by_mcp', '>', 0)
+            ->whereNotNull('rm_num_measurements_not_stamped_by_mcp')
+            ->orderBy('created_at', 'DESC')
+            ->get()
+            ->map(function($_x) {
+                return $_x->id;
+            })
+            ->toArray();
+
+        $measurementsPendingStamping = Measurement::whereIn('care_month_id', $careMonthsWithMeasurementsPendingStamping)
+            ->orderBy('created_at', 'DESC')
+            ->whereNotNull('ts')
+            ->whereNotIn('label', ['SBP', 'DBP'])
+            ->where('is_cellular_zero', '<>', true)
+            ->where('is_active', true)
+            ->where('has_been_stamped_by_mcp', false)
+            ->whereNotNull('client_bdt_measurement_id')
+            ->paginate(15);
+
+        return view('app/dashboard-hcp', compact('keyNumbers', 'reimbursement', 'milliseconds',
+            'businessNumbers',
+            'incomingReports', 'tickets', 'supplyOrders',
+            'numERx', 'numLabs', 'numImaging', 'numSupplyOrders',
+            'newMCPAssociations', 'newNAAssociations',
+            'measurementsPendingStamping', 'careMonthsWithMeasurementsPendingStamping',
+            'mcpClientMemos', 'mcpClientMemosCount', 'naClientMemos', 'incomingSmsMessagesPendingReply'));
     }
 
     public function dashboard_DNA(Request $request){

+ 528 - 2
resources/views/app/dashboard-hcp.blade.php

@@ -1,7 +1,533 @@
 @extends ('layouts.template')
 
 @section('content')
-    <div>
-        <h1>HCP Dashboard</h1>
+
+    <style>
+        #dashboard-mcp tr.thin th,
+        #dashboard-mcp tr.thin td,
+        #dashboard-mcp .dashboard-stats-table tr td,
+        #dashboard-mcp .dashboard-stats-table tr th {
+            padding: 0.25em;
+            font-weight: normal;
+        }
+
+        #dashboard-mcp table.appointments tr td {
+            vertical-align: middle;
+        }
+    </style>
+
+    <div id="dashboard-mcp">
+    <div class="p-3">
+        <div class="">
+            <div class="row mcp-theme-1" id="pro-dashboard-container">
+                <div class="col-md-3 mcp-theme-1">
+                    <div class="mb-4">
+                        <div class="pro-dashboard-inline-calendar"></div>
+                    </div>
+                    <div class="card mb-4" stag-collapsible-card="mcp-key-numbers">
+                        <div class="card-header pl-2">
+                            <strong>
+                                Key Numbers
+                            </strong>
+                        </div>
+                        <div class="card-body p-0">
+                            <table class="table table-sm mb-0 dashboard-stats-table">
+                                <tbody>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_patients_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.patients') }}">Patients</a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_new_patients_awaiting_visit_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.new_patients_awaiting_visit') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="New Patients Awaiting Visit">
+                                            New Patients Awaiting Visit
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_notes_pending_signature_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.notes_pending_signature') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Notes Pending Signature">
+                                            Notes Pending Signature
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_notes_pending_billing_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.notes_pending_billing') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Notes Pending Billing">
+                                            Notes Pending Billing
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_bills_pending_signature_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.bills_pending_signature') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Bills Pending Signature">
+                                            Bills Pending Signature
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_incoming_reports_pending_signature_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.reports_pending_signature') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Reports Pending Signature">
+                                            Reports Pending Signature
+                                        </a>
+                                    </th>
+                                </tr>
+
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_patients_without_appointment_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.patients_without_appointments') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Patients w/o Appointments">
+                                            Patients w/o Appointments
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_patients_overdue_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.patients_overdue_for_visit') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Patients Overdue for Visit">
+                                            Patients Overdue for Visit
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_cancelled_appointments_pending_acknowledgement_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.cancelled_appointments_pending_review') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Cancelled Appts. Pending Review">
+                                            Cancelled Appts. Pending Review
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_cancelled_bills_awaiting_review_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.cancelled_bills_pending_review') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Cancelled Bills Pending Review">
+                                            Cancelled Bills Pending Review
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_cancelled_supply_orders_awaiting_review_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.cancelled_supply_orders_pending_review') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Cancelled Supply Orders">
+                                            Cancelled Supply Orders
+                                        </a>
+                                    </th>
+                                </tr>
+
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_erx_and_orders_awaiting_signature_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.erx_and_orders_pending_signature') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="ERx & Orders Pending Signature">
+                                            ERx & Orders Pending Signature
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_supply_orders_awaiting_signature_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.supply_orders_pending_signature') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Supply Orders Pending Signature">
+                                            Supply Orders Pending Signature
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2 text-center">{{$pro->get_supply_orders_awaiting_shipment_count_as_mcp()}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.supply_orders_awaiting_shipment') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           popup-style="tall"
+                                           title="Supply Orders Awaiting Shipment">
+                                            Supply Orders Awaiting Shipment
+                                        </a>
+                                    </th>
+                                </tr>
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                    <div class="card mb-4" stag-collapsible-card="mcp-rm">
+                        <div class="card-header pl-2">
+                            <strong>
+                                Remote Monitoring: {{friendly_month(date('Y-m-d'))}}
+                            </strong>
+                        </div>
+                        <div class="card-body p-0">
+                            <table class="table mb-0 dashboard-stats-table">
+                                <tbody>
+                                <tr class="thin">
+                                    <th class="px-2 text-center">{{$pro->get_measurements_awaiting_review_count_as_mcp() ?? '-'}}</th>
+                                    <th class="pl-2">
+                                        <a href="{{ route('mcp.measurements_pending_stamping') }}"
+                                           native target="_blank"
+                                           open-in-stag-popup
+                                           update-parent
+                                           popup-style="tall"
+                                           title="Measurements Pending Stamping">
+                                            Measurements Pending Stamping
+                                        </a>
+                                    </th>
+                                </tr>
+                                <tr class="thin">
+                                    <th class="px-2 text-center">{{$pro->get_patients_without_remote_measurement_in_48_hours_count_as_mcp() ?? '-'}}</th>
+                                    <th class="pl-2">Patients w/o Measurement in 48 hrs.</th>
+                                </tr>
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                    <div class="card mb-4" stag-collapsible-card="mcp-practice-management" collapsed>
+                        <div class="card-header pl-2">
+                            <strong>
+                                Practice Management
+                            </strong>
+                        </div>
+                        <div class="card-body p-0">
+                            <table class="table mb-0 dashboard-stats-table">
+                                <tbody>
+                                <tr class="thin">
+                                    <th colspan="2" class="font-weight-normal px-2 pl-2">Billing & Reimbursement</th>
+                                </tr>
+                                <tr class="thin">
+                                    <th class="font-weight-normal px-2 pl-4">{{friendly_date_time($reimbursement['nextPaymentDate'], false)}}</th>
+                                    <th class="font-weight-normal pl-2">Next Payment Date</th>
+                                </tr>
+                                <tr class="thin">
+                                    <th class="font-weight-normal px-2 pl-4">
+                                        ${{friendly_money($reimbursement['currentBalance'])}}</th>
+                                    <th class="font-weight-normal pl-2 w-100"><a
+                                            href="/practice-management/financial-transactions">Current balance</a></th>
+                                </tr>
+                                <tr class="thin">
+                                    <th class="font-weight-normal px-2 pl-4">
+                                        ${{friendly_money($reimbursement['nextPaymentAmount'])}}</th>
+                                    <th class="font-weight-normal pl-2"><a
+                                            href="/practice-management/bills-under-processing">Processing</a></th>
+                                </tr>
+{{--
+                                <tr class="thin">
+                                    <th class="font-weight-normal px-2 pl-5">
+                                        ${{friendly_money($reimbursement['nextPaymentAmount'])}}</th>
+                                    <th class="font-weight-normal pl-2"><a
+                                            href="/practice-management/bills-under-processing">Treatment Services</a>
+                                    </th>
+                                </tr>
+                                <tr class="thin">
+                                    <th class="font-weight-normal px-2 pl-5">
+                                        ${{friendly_money($reimbursement['nextPaymentAmount'])}}</th>
+                                    <th class="font-weight-normal pl-2"><a
+                                            href="/practice-management/bills-under-processing">Remote Monitoring</a>
+                                    </th>
+                                </tr>
+                                <tr class="thin">
+                                    <th class="font-weight-normal px-2 pl-5">
+                                        ${{friendly_money($reimbursement['nextPaymentAmount'])}}</th>
+                                    <th class="font-weight-normal pl-2"><a
+                                            href="/practice-management/bills-under-processing">Other Services</a></th>
+                                </tr>
+                                {{--
+                                <tr>
+                                    <th class="px-2">{{$reimbursement['lastPayment']}}</th>
+                                    <th class="pl-2"><a href="/practice-management/financial-transactions">Last payment</a></th>
+                                </tr>
+                                <tr>
+                                    <th class="px-2">{{friendly_date_time($reimbursement['lastPaymentDate'], false)}}</th>
+                                    <th class="pl-2"><a href="/practice-management/financial-transactions">Last payment date</a></th>
+                                </tr>
+                                --}}
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-9 pl-1">
+                    <div class="row mcp-theme-1">
+                        <div class="col-md-6 mcp-theme-1">
+                            <div id="mcp-dashboard-appointments" class="mb-4">
+
+                            </div>
+                            <div class="card mb-4">
+                                <div class="card-header pl-2">
+                                    <strong>
+                                        Measurements Pending Stamping
+                                    </strong>
+                                </div>
+                                <div class="card-body p-0">
+                                    @include('app.mcp.dashboard.measurements-pending-stamping')
+                                </div>
+                            </div>
+                        </div>
+                        <div class="col-md-6 mcp-theme-1 pl-1">
+                            <div class="card mb-4">
+                                <div class="card-header pl-2">
+                                    <strong>
+                                        Notifications
+                                    </strong>
+                                </div>
+                                <div class="card-body px-3 py-2">
+                                    @include('app.mcp.dashboard.notifications')
+                                </div>
+                            </div>
+                            <div class="card mb-4">
+                                <div class="card-header pl-2">
+                                    <strong>
+                                        Messages
+                                    </strong>
+                                </div>
+                                <div class="card-body p-0">
+                                    @include('app.mcp.dashboard.messages')
+                                </div>
+                            </div>
+                            <div class="card mb-4">
+                                <div class="card-header pl-2">
+                                    <strong>
+                                        Phone Calls & Memos
+                                    </strong>
+                                </div>
+                                <div class="card-body p-0">
+                                    @include('app.mcp.dashboard.calls_memos')
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
     </div>
+
+    <div class="stag-popup stag-popup-md ticket-popup mcp-theme-1" stag-popup-key="ticket-popup"></div>
+
+    <script>
+        (function () {
+
+            let datesWithEvents = [],
+                selectedDate = '{{ date('Y-m-d') }}',
+                calendarElem = null,
+                currentMonth = null,
+                currentYear = null,
+                appointmentsLoaded = false;
+
+            function formatDate(date) {
+                let d = new Date(date),
+                    month = '' + (d.getMonth() + 1),
+                    day = '' + d.getDate(),
+                    year = d.getFullYear();
+
+                if (month.length < 2)
+                    month = '0' + month;
+                if (day.length < 2)
+                    day = '0' + day;
+
+                return [year, month, day].join('-');
+            }
+
+            function onDateChange(_newDate) {
+                // ajax load appts list as markup directly from server
+                selectedDate = _newDate;
+                $.get('/pro-dashboard-events-display/' + selectedDate + '/' + selectedDate, function (_data) {
+                    let apptscontainer = $('#mcp-dashboard-appointments');
+                    apptscontainer.html(_data);
+                    initFastLoad(apptscontainer);
+                    initMoes();
+                });
+            }
+
+            function loadEventDates(_refDate = false) {
+                let today = new Date(_refDate ? _refDate : '{{date('Y-m-d')}}'),
+                    firstOfMonth = new Date(today.getFullYear(), today.getMonth(), 1),
+                    lastOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0);
+                selectedDate = null;
+                $('td.day.active').removeClass('active');
+                $.get('/pro-dashboard-event-dates/' +
+                    formatDate(firstOfMonth) + '/' +
+                    formatDate(lastOfMonth), (_data) => {
+                    datesWithEvents = _data;
+                    calendarElem.datepicker('refresh');
+                    currentMonth = firstOfMonth.getMonth();
+                    currentYear = firstOfMonth.getFullYear();
+                    if (!_refDate && $('td.day[data-date="{{$milliseconds}}"]:visible').length) {
+                        $('td.day[data-date="{{$milliseconds}}"]:visible').first().click();
+                    }
+                    appointmentsLoaded = true;
+                }, 'json');
+            }
+
+            function getFormattedCurrentDate() {
+                let date = new Date();
+                let day = date.getDate();
+                day = day < 10 ? '0' + day : day;
+                return date.getFullYear() + '-' + parseInt(date.getMonth() + 1) + '-' + day;
+            }
+
+            function init(_target = null) {
+
+                if(_target && _target !== '.stag-content') return;
+
+                calendarElem = $('.pro-dashboard-inline-calendar');
+                calendarElem.datepicker({
+                    dateFormat: 'yy-mm-dd',
+                    onSelect: function (_date) {
+                        onDateChange(_date);
+                    },
+                    onChangeMonthYear: function (_year, _month) {
+                        let date = _year + '-' + (_month < 10 ? '0' : '') + _month + '-05';
+                        loadEventDates(date);
+                    },
+                    beforeShowDay: function (d) {
+                        if (datesWithEvents && datesWithEvents.indexOf(formatDate(d)) !== -1) {
+                            return [true, 'has-events'];
+                        }
+                        return [true, 'no-events'];
+                    },
+                    defaultDate: 0
+                });
+
+                let date = new Date();
+                let day = date.getDate();
+                day = day < 10 ? '0' + day : day;
+                let mon = parseInt(date.getMonth() + 1);
+                mon = mon < 10 ? '0' + mon : mon;
+                let dateStr = date.getFullYear() + '-' + mon + '-' + day;
+                loadEventDates(dateStr);
+
+                onDateChange(getFormattedCurrentDate());
+                selectedDate = getFormattedCurrentDate();
+
+                $(document)
+                    .off('click', '.ack-client-pro-change')
+                    .on('click', '.ack-client-pro-change', function () {
+                        let trigger = $(this).text('…');
+                        $.post('/api/clientProChange/accept', {
+                            uid: $(this).attr('data-uid')
+                        }, _data => {
+                            if (!hasResponseError(_data)) {
+                                trigger.hide();
+                                let doneElem = $('<i class="text-success fa fa-check"></i>');
+                                doneElem.insertAfter(trigger);
+                                setTimeout(() => {
+                                    let ackContainer = trigger.closest('.ack-container');
+                                    trigger.closest('div').slideUp('fast', function () {
+                                        $(this).remove();
+                                        if (!ackContainer.find('>div').length) {
+                                            ackContainer.remove();
+                                        }
+                                    });
+                                }, 500);
+                            }
+                        }, 'json');
+                        return false;
+                    });
+
+                $(document)
+                    .off('click', '.ack-client-memo')
+                    .on('click', '.ack-client-memo', function () {
+                        let trigger = $(this).text('…');
+                        $.post('/api/clientMemo/stamp', {
+                            uid: $(this).attr('data-uid')
+                        }, _data => {
+                            if (!hasResponseError(_data)) {
+                                trigger.hide();
+                                let doneElem = $('<i class="text-success fa fa-check"></i>');
+                                doneElem.insertAfter(trigger);
+                                setTimeout(() => {
+                                    let tbody = trigger.closest('tbody');
+                                    trigger.closest('tr').remove();
+                                    if (!tbody.find('>tr').length) {
+                                        tbody.closest('.ack-container').remove();
+                                    }
+                                }, 500);
+                            }
+                        }, 'json');
+                        return false;
+                    });
+
+                $(document)
+                    .off('click', '.ack-pro-appt-update')
+                    .on('click', '.ack-pro-appt-update', function () {
+                        let trigger = $(this).text('…');
+                        $.post('/api/appointmentConfirmationDecision/acknowledgeAsAppointmentPro', {
+                            uid: $(this).attr('data-uid')
+                        }, _data => {
+                            if (!hasResponseError(_data)) {
+                                trigger.hide();
+                                let doneElem = $('<i class="text-success fa fa-check"></i>');
+                                doneElem.insertAfter(trigger);
+                                setTimeout(() => {
+                                    let ackContainer = trigger.closest('tbody');
+                                    trigger.closest('tr').slideUp('fast', function () {
+                                        $(this).remove();
+                                        if (!ackContainer.find('>tr').length) {
+                                            ackContainer.remove();
+                                        }
+                                    });
+                                }, 500);
+                            }
+                        }, 'json');
+                        return false;
+                    });
+
+                addMCHook('refreshDashboardAppointments', function() {
+                    onDateChange(selectedDate);
+                });
+            }
+
+            addMCInitializer('pro-dashboard', init, '#pro-dashboard-container');
+        })();
+    </script>
 @endsection

+ 1 - 1
resources/views/app/mcp/dashboard/calls_memos.blade.php

@@ -2,7 +2,7 @@
 @if(!$mcpClientMemos || !count($mcpClientMemos))
 <div class="px-2 py-3">No memos</div>
 @else
-<table class="table table-sm m-0">
+<table class="table table-sm table-striped m-0">
 	<tbody>
 		@foreach($mcpClientMemos as $memo)
 		<tr>