From aa2e092758043aa9c95fb47e3571d223336be8f4 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Thu, 9 Apr 2026 18:44:35 +0530 Subject: [PATCH] Add OPD Total Report with doctor/type/fee filters --- app/Config/Routes.php | 3 + app/Controllers/Report.php | 176 ++++++++++++++++++++ app/Views/partials/sidebar.php | 6 + app/Views/report/index.php | 2 + app/Views/report/opd_total_report.php | 116 +++++++++++++ app/Views/report/opd_total_report_table.php | 78 +++++++++ 6 files changed, 381 insertions(+) create mode 100644 app/Views/report/opd_total_report.php create mode 100644 app/Views/report/opd_total_report_table.php diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 78c0457..30a1475 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -717,6 +717,9 @@ $routes->get('report/index', 'Report::index'); $reportsCollectionFilter = 'permission:reports.collection.view,reports.access'; $routes->get('Report/collection_report', 'Report::collection_report', ['filter' => $reportsCollectionFilter]); +$routes->get('Report/report_opd_total', 'Report::report_opd_total', ['filter' => $reportsCollectionFilter]); +$routes->get('Report/opd_total_data/(:segment)/(:segment)/(:segment)/(:segment)', 'Report::opd_total_data/$1/$2/$3/$4', ['filter' => $reportsCollectionFilter]); +$routes->get('Report/opd_total_data/(:segment)/(:segment)/(:segment)/(:segment)/(:num)', 'Report::opd_total_data/$1/$2/$3/$4/$5', ['filter' => $reportsCollectionFilter]); $routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)', 'Report::report_total_payment_app_show/$1/$2/$3', ['filter' => $reportsCollectionFilter]); $routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)/(:num)', 'Report::report_total_payment_app_show/$1/$2/$3/$4', ['filter' => $reportsCollectionFilter]); $routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)/(:segment)', 'Report::report_total_payment_app_show/$1/$2/$3/$4', ['filter' => $reportsCollectionFilter]); diff --git a/app/Controllers/Report.php b/app/Controllers/Report.php index b0c1d2f..3fc55b7 100644 --- a/app/Controllers/Report.php +++ b/app/Controllers/Report.php @@ -31,6 +31,162 @@ class Report extends BaseController ]); } + public function report_opd_total() + { + $doctors = $this->db->table('doctor_master') + ->select('id, p_fname') + ->where('active', 1) + ->orderBy('p_fname', 'ASC') + ->get() + ->getResult(); + + $feeTypes = $this->db->table('opd_master') + ->select('opd_fee_id, opd_fee_desc, opd_fee_amount') + ->where('opd_fee_id IS NOT NULL', null, false) + ->where('opd_fee_id >', 0) + ->where('opd_fee_desc IS NOT NULL', null, false) + ->where("TRIM(opd_fee_desc) != ''", null, false) + ->groupBy('opd_fee_id, opd_fee_desc, opd_fee_amount') + ->orderBy('opd_fee_desc', 'ASC') + ->orderBy('opd_fee_amount', 'ASC') + ->get() + ->getResult(); + + return view('report/opd_total_report', [ + 'doctors' => $doctors, + 'fee_types' => $feeTypes, + ]); + } + + public function opd_total_data( + string $dateRange, + string $doctorId = '0', + string $opdType = '0', + string $feeId = '0', + int $output = 0 + ) { + [$minRange, $maxRange] = $this->parseDateRangeDateOnly($dateRange); + + $runningExpr = "(COALESCE(o.running_opd,0)=1 OR o.opd_fee_type=3 OR UPPER(COALESCE(o.opd_fee_desc,'')) LIKE '%RUNNING%')"; + $newExpr = "(o.opd_fee_type=1 OR UPPER(COALESCE(o.opd_fee_desc,'')) LIKE '%NEW%')"; + $emergencyExpr = "(UPPER(COALESCE(o.opd_fee_desc,'')) LIKE '%EMERG%')"; + $regularExpr = "(NOT {$runningExpr} AND NOT {$newExpr} AND NOT {$emergencyExpr})"; + + $builder = $this->db->table('opd_master o') + ->select("COALESCE(NULLIF(TRIM(o.doc_name),''), CONCAT('Doctor #', o.doc_id)) as doctor_name", false) + ->select('o.doc_id, o.opd_fee_id, o.opd_fee_desc, o.opd_fee_amount') + ->select('SUM(CASE WHEN o.opd_status IN (1,2) THEN 1 ELSE 0 END) as no_of_opd', false) + ->select("SUM(CASE WHEN o.opd_status IN (1,2) AND {$runningExpr} THEN 1 ELSE 0 END) as running_count", false) + ->select("SUM(CASE WHEN o.opd_status IN (1,2) AND {$regularExpr} THEN 1 ELSE 0 END) as regular_count", false) + ->select("SUM(CASE WHEN o.opd_status IN (1,2) AND {$newExpr} THEN 1 ELSE 0 END) as new_count", false) + ->select("SUM(CASE WHEN o.opd_status IN (1,2) AND {$emergencyExpr} THEN 1 ELSE 0 END) as emergency_count", false) + ->select('SUM(CASE WHEN o.opd_status IN (1,2) THEN o.opd_fee_amount ELSE 0 END) as total_amount', false) + ->where('o.apointment_date >=', $minRange) + ->where('o.apointment_date <=', $maxRange) + ->whereIn('o.opd_status', [1, 2]) + ->where('o.payment_status', 1) + ->where('(o.payment_mode > 0 OR COALESCE(o.running_opd,0)=1)', null, false); + + $doctorIdValue = (int) $doctorId; + if ($doctorIdValue > 0) { + $builder->where('o.doc_id', $doctorIdValue); + } + + $feeIdValue = (int) $feeId; + if ($feeIdValue > 0) { + $builder->where('o.opd_fee_id', $feeIdValue); + } + + $opdTypeKey = strtolower(trim((string) urldecode($opdType))); + if ($opdTypeKey !== '' && $opdTypeKey !== '0' && $opdTypeKey !== 'all') { + if ($opdTypeKey === 'running') { + $builder->where($runningExpr, null, false); + } elseif ($opdTypeKey === 'regular') { + $builder->where($regularExpr, null, false); + } elseif ($opdTypeKey === 'new') { + $builder->where($newExpr, null, false); + } elseif ($opdTypeKey === 'emergency') { + $builder->where($emergencyExpr, null, false); + } + } + + $rows = $builder + ->groupBy('o.doc_id, o.doc_name, o.opd_fee_id, o.opd_fee_desc, o.opd_fee_amount') + ->orderBy('o.doc_name', 'ASC') + ->orderBy('o.opd_fee_desc', 'ASC') + ->orderBy('o.opd_fee_amount', 'ASC') + ->get() + ->getResult(); + + $summary = [ + 'no_of_opd' => 0, + 'running_count' => 0, + 'regular_count' => 0, + 'new_count' => 0, + 'emergency_count' => 0, + 'total_amount' => 0.0, + ]; + + foreach ($rows as $row) { + $summary['no_of_opd'] += (int) ($row->no_of_opd ?? 0); + $summary['running_count'] += (int) ($row->running_count ?? 0); + $summary['regular_count'] += (int) ($row->regular_count ?? 0); + $summary['new_count'] += (int) ($row->new_count ?? 0); + $summary['emergency_count'] += (int) ($row->emergency_count ?? 0); + $summary['total_amount'] += (float) ($row->total_amount ?? 0); + } + + $content = view('report/opd_total_report_table', [ + 'rows' => $rows, + 'summary' => $summary, + 'min_range' => $minRange, + 'max_range' => $maxRange, + ]); + + if ($output === 1) { + ExportExcel($content, 'OPD_Total_Report_' . date('YmdHis')); + return $this->response->setBody(''); + } + + if ($output === 2) { + $mpdfTempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf'; + if (! is_dir($mpdfTempDir)) { + mkdir($mpdfTempDir, 0755, true); + } + + $mpdf = new Mpdf([ + 'tempDir' => $mpdfTempDir, + 'format' => 'A4-L', + 'margin_top' => 8, + 'margin_bottom' => 8, + 'margin_left' => 8, + 'margin_right' => 8, + ]); + + $pdfHtml = '' + . '

OPD Total Report

' + . $content; + + $mpdf->WriteHTML($pdfHtml); + + $fileName = 'OPD_Total_Report_' . date('Ymd_His') . '.pdf'; + + return $this->response + ->setHeader('Content-Type', 'application/pdf') + ->setHeader('Content-Disposition', 'inline; filename="' . $fileName . '"') + ->setBody($mpdf->Output($fileName, 'S')); + } + + return $this->response->setBody($content); + } + public function report_total_payment_app_show( string $dateRange, string $employeeIds, @@ -274,6 +430,26 @@ class Report extends BaseController return [$start, $end]; } + private function parseDateRangeDateOnly(string $dateRange): array + { + $rangeParts = explode('S', $dateRange); + $startRaw = (string) ($rangeParts[0] ?? ''); + $endRaw = (string) ($rangeParts[1] ?? ''); + + $startRaw = str_replace('T', ' ', $startRaw); + $endRaw = str_replace('T', ' ', $endRaw); + + $start = substr(trim($startRaw), 0, 10); + $end = substr(trim($endRaw), 0, 10); + + if ($start === '' || $end === '') { + $today = date('Y-m-d'); + return [$today, $today]; + } + + return [$start, $end]; + } + private function normalizeIdList(string $idList): array { $idList = trim($idList); diff --git a/app/Views/partials/sidebar.php b/app/Views/partials/sidebar.php index 6916fcf..1a4d6a0 100644 --- a/app/Views/partials/sidebar.php +++ b/app/Views/partials/sidebar.php @@ -386,6 +386,12 @@ if (! $canChargesSettings && $user && method_exists($user, 'inGroup')) { Collection Report +