diff --git a/.gitignore b/.gitignore index cdde22a..bcdad06 100644 --- a/.gitignore +++ b/.gitignore @@ -126,11 +126,4 @@ _modules/* /phpunit*.xml .claude/ -.serena/ - -#------------------------- -# PDF Spooler Data -#------------------------- -node_spooler/data/ -node_spooler/node_modules/ -node_spooler/logs/ \ No newline at end of file +.serena/ \ No newline at end of file diff --git a/P0_log.txt b/P0_log.txt deleted file mode 100644 index 744bdd4..0000000 --- a/P0_log.txt +++ /dev/null @@ -1,50 +0,0 @@ -1. Buat Tabel POSITIONS untuk (Role User) (ROLE, ROLEID, DESCRIPTION) - CREATE TABLE [GDC_CMOD].[dbo].[ROLES] ( - [ROLE] NVARCHAR(50) NOT NULL, -- Primary Key - [ROLEID] INT NOT NULL, -- Harus Unik - [DESCRIPTION] NVARCHAR(MAX) NULL, - - -- Menetapkan Primary Key - CONSTRAINT PK_Roles PRIMARY KEY ([ROLE]), - - -- Menetapkan Unique Constraint - CONSTRAINT UQ_RoleID UNIQUE ([ROLEID]) - ); - - INSERT INTO [GDC_CMOD].[dbo].[ROLES] ([ROLE], [ROLEID], [DESCRIPTION]) - VALUES - ('Superuser', 0, 'All Access'), - ('Admin', 1, 'Super user sistem, konfigurasi, manajemen user & data'), - ('Analis LAB', 2, 'Validasi & pengolahan hasil laboratorium'), - ('Phlebotomist', 3, 'Pengambilan dan pencatatan spesimen'), - ('Customer Service', 4, 'Monitoring & pelayanan informasi pasien'); - -2. Hapus semua isi USERS lalu : - INSERT INTO USERS(USERID, [PASSWORD], USERROLEID, NAME) - VALUES - ('LISFSE', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'SYSTEM'), - ('ABB', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Ardea Bagus Bimantara, S.Tr.Kes'), - ('AHT', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 1, 'dr. Arifoe Hajat, Sp.PK(K)'), - ('ASW', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Asti Sri Wiyanti, A.Md.AK'), - ('BYS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Betha Yogyanti Setyarini, A.Md.AK'), - ('FKS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Fairushafa Khairunnisa Sasmita, S.Tr.Kes'), - ('HAY', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Hewi Aryanti, A.Md.Kep'), - ('KNS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Kartya Nur Sholihatul Umah, S.Kep.Ns'), - ('LPS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Lintang Pramuli Suradi, S.S.T'), - ('LDK', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Lidya Dwindana Kartikasari, A.Md.Kes'), - ('RID', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 4, 'Rhemanda Ivena Dinta, A.Md.Bns'), - ('MDW', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Margareta Dwi Widiani, A.Md.Kep'), - ('MJS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Mentari Jaya Sari, A.Md.AK'), - ('MRS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Maria Scholastica, A.Md.Kep'), - ('AQP', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Anjani Okta Prastiwi, A.Md.Kep'), - ('RSW', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'Ratna Setyowati, A.Md.T'), - ('SAI', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 1, 'Sri Andayani, A.Md.Kes'), - ('SFB', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Stevani Florentina Bihi, S.Pd., S.Tr.Kes'), - ('VSO', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Veronica Sulistyo, A.Md.Kes'), - ('YAA', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Yulia Anita, A.Md.Kes'), - ('SYA', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Sutyi Yuliyana, A.Md.Kep'), - ('MTP', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'Muhammad Tegar Prasetya, S.Kom'), - ('NRR', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'Nur Rizky Romadhon, M.Tr.Kom'), - ('LAS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Luthfi Anindyani Sulistiono, S.Kep.Ns'), - ('HSI', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 1, 'Dr. dr. Hermi Suprati, M.Kes'); - diff --git a/TODO.md b/TODO.md index 2983151..67e0321 100644 --- a/TODO.md +++ b/TODO.md @@ -1,34 +1,34 @@ # Project Checklist: Glen RME & Lab Management System -**Last Updated:** 20260203 +**Last Updated:** 20260204 Pending: +- Auto generate PDF +- Print Eng Result - Reprint Label (Add functionality to reprint labels) - Print Result Audit (Track when result reports are printed/exported, log user and timestamp) Completed: -- 01 : Update User Role levels (Standardize roles: Superuser, Admin, Lab, Phlebo, CS) -- 02 : Role-Based Dashboard Filtering (Filter by patient_status or service_type) -- 03 : Fix Table Sorting (Enable sorting by "No Register" and "Patient Name") -- 04 : Fix Language Toggle (Toggle lab result preview between Indonesian and English) -- 05 : Apply Row Color-Coding (Color-code "No Register" column) -- 06 : Initialize RME Sidebar Menu (Create menu items) -- 07 : Dashboard Performance (When getting data more than 100 rows, it load too slow) -- 08 : Dashboard for Lab -> no test with only number, remove request with empty test -- 09 : Dashboard for Others -> complete -- 10 : Refactor same views/*role* to views/shared -- 11 : Move all CDN to local -- 12 : Remove 'status' field on dashboard -- 13 : Restrict 'Validate' to Lab, Admin, Superuser -- 14 : Hide/Disable 'Validation' button after 2nd validation (Prevent redundant validation actions) -- 15 : Restrict 'UnValidate' to Admin, Superuser -- 16 : Remove 'UnCollect' -- 17 : Audit Trail (Track all actions: validation, unvalidation, collection, uncollection) -- 18 : Create Validate Page -- 19 : Sync color with old gdc_cmod -- 20 : Add Val1 Val2 on the result -- 21 : Show Print / PDF button when val1 val2 done -- 22 : Restrict Print/Save-to-PDF to CS Role only (Admin, Lab, CS can print/save) - -Addition on dev : -- adding init-isDev on index.php to set default date on dev dashboard \ No newline at end of file +- Update User Role levels (Standardize roles: Superuser, Admin, Lab, Phlebo, CS) +- Role-Based Dashboard Filtering (Filter by patient_status or service_type) +- Fix Table Sorting (Enable sorting by "No Register" and "Patient Name") +- Fix Language Toggle (Toggle lab result preview between Indonesian and English) +- Apply Row Color-Coding (Color-code "No Register" column) +- Initialize RME Sidebar Menu (Create menu items) +- Dashboard Performance (When getting data more than 100 rows, it load too slow) +- Dashboard for Lab -> no test with only number, remove request with empty test +- Dashboard for Others -> complete +- Refactor same views/*role* to views/shared +- Move all CDN to local +- Remove 'status' field on dashboard +- Restrict 'Validate' to Lab, Admin, Superuser +- Hide/Disable 'Validation' button after 2nd validation (Prevent redundant validation actions) +- Restrict 'UnValidate' to Admin, Superuser +- Remove 'UnCollect' +- Audit Trail (Track all actions: validation, unvalidation, collection, uncollection) +- Create Validate Page +- Sync color with old gdc_cmod +- Add Val1 Val2 on the result +- Show Print / PDF button when val1 val2 done +- Restrict Print/Save-to-PDF to CS Role only (Admin, Lab, CS can print/save) +- Add Receive to Audit \ No newline at end of file diff --git a/app/Controllers/ApiRequestsAuditController.php b/app/Controllers/ApiRequestsAuditController.php index c620999..a2cb81b 100644 --- a/app/Controllers/ApiRequestsAuditController.php +++ b/app/Controllers/ApiRequestsAuditController.php @@ -12,7 +12,8 @@ class ApiRequestsAuditController extends BaseController { $result = [ 'accessnumber' => $accessnumber, 'validation' => [], - 'sample_collection' => [] + 'sample_collection' => [], + 'tube_received' => [] ]; $sqlAudit = "SELECT EVENT_TYPE, USERID, EVENT_AT, REASON @@ -47,6 +48,21 @@ class ApiRequestsAuditController extends BaseController { ]; } + $sqlSpTubes = "SELECT SAMPLETYPE, TUBESTATUS, COLLECTIONDATE, LOGUSERID + FROM glendb.dbo.SP_TUBES + WHERE SP_ACCESSNUMBER = ? AND TUBESTATUS = 4 + ORDER BY COLLECTIONDATE ASC"; + $spTubeRows = $db->query($sqlSpTubes, [$accessnumber])->getResultArray(); + + foreach ($spTubeRows as $row) { + $result['tube_received'][] = [ + 'sampletype' => trim($row['SAMPLETYPE']), + 'tubestatus' => (int)$row['TUBESTATUS'], + 'datetime' => $row['COLLECTIONDATE'] ? date('Y-m-d H:i:s', strtotime($row['COLLECTIONDATE'])) : null, + 'user' => trim($row['LOGUSERID']) + ]; + } + return $this->respond(['status' => 'success', 'data' => $result]); } } diff --git a/app/Controllers/ReportController.php b/app/Controllers/ReportController.php index f858b8f..735414e 100644 --- a/app/Controllers/ReportController.php +++ b/app/Controllers/ReportController.php @@ -101,7 +101,7 @@ class ReportController extends BaseController public function checkPdfStatus($jobId) { $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "http://glenlis:3030/api/pdf/status/$jobId"); + curl_setopt($ch, CURLOPT_URL, "http://glenlis:3000/api/pdf/status/$jobId"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5); @@ -123,7 +123,7 @@ class ReportController extends BaseController private function postToSpooler($html, $filename) { $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, 'http://glenlis:3030/api/pdf/generate'); + curl_setopt($ch, CURLOPT_URL, 'http://glenlis:3000/api/pdf/generate'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ 'html' => $html, diff --git a/app/Libraries/PdfHelper.php b/app/Libraries/PdfHelper.php new file mode 100644 index 0000000..ec868d3 --- /dev/null +++ b/app/Libraries/PdfHelper.php @@ -0,0 +1,54 @@ +db = $db; + } + + public function generatePdf(string $accessnumber, int $eng = 0): string + { + $reportHelper = new \App\Libraries\ReportHelper($this->db); + $data = $reportHelper->getReportData($accessnumber, $eng); + $data['eng'] = $eng; + $data['accessnumber'] = $accessnumber; + $data['ispdf'] = 1; + + $html = view('report/template', $data); + $filename = $accessnumber . '.pdf'; + + return $this->postHtmlToSpooler($html, $filename); + } + + public function postHtmlToSpooler(string $html, string $filename): string + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://glenlis:3000/api/pdf/generate'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ + 'html' => $html, + 'filename' => $filename + ])); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json' + ]); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + if ($httpCode !== 200) { + log_message('error', "Spooler API returned HTTP $httpCode"); + throw new \Exception('Failed to queue PDF generation'); + } + + $data = json_decode($response, true); + return $data['jobId']; + } +} diff --git a/app/Views/report/template.php b/app/Views/report/template.php index 36db370..35f9322 100644 --- a/app/Views/report/template.php +++ b/app/Views/report/template.php @@ -84,7 +84,7 @@ $i = 1;
Collected on  
 Received on  
-Val1 By :  | Val2 By  
+Val1 By :  | Val2 By :  
 Page / Printed By :  
diff --git a/app/Views/shared/content_requests.php b/app/Views/shared/content_requests.php index 3241621..ea9546c 100644 --- a/app/Views/shared/content_requests.php +++ b/app/Views/shared/content_requests.php @@ -227,9 +227,17 @@ diff --git a/app/Views/shared/dialog_audit.php b/app/Views/shared/dialog_audit.php index 7f7c8a6..e899c0e 100644 --- a/app/Views/shared/dialog_audit.php +++ b/app/Views/shared/dialog_audit.php @@ -20,6 +20,9 @@ + @@ -44,16 +47,18 @@