From 799edf958840d7efc9b9c9523ba5820ef3868157 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Wed, 18 Mar 2026 11:10:05 +0700 Subject: [PATCH] Update Fitur Certificate Training --- app/Config/Routes.php | 9 +- app/Controllers/Activities.php | 392 +++++++++++- app/Controllers/Certificates.php | 358 ++++++++--- app/Controllers/Contacts.php | 18 +- app/Models/CertificateTrainingModel.php | 63 ++ app/Views/activities_editor.php | 261 +++----- app/Views/activities_getsitecontacts.php | 319 ++++++++++ app/Views/certificate_training_index.php | 577 ++++++++---------- .../certificates/certificate_training.php | 128 ++-- app/Views/layouts/_sidebar.php | 6 +- 10 files changed, 1494 insertions(+), 637 deletions(-) create mode 100644 app/Models/CertificateTrainingModel.php create mode 100644 app/Views/activities_getsitecontacts.php diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 0de9b3b..b06b371 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -161,6 +161,8 @@ $routes->get('/activities/getproduct/(:num)', 'Activities::getproduct/$1/$2/$3') $routes->get('/activities/getvendor/(:num)', 'Activities::getvendor/$1'); $routes->get('/activities/getconsumable/(:num)', 'Activities::getconsumable/$1'); $routes->get('/activities/getcontact/(:num)', 'Activities::getcontact/$1'); +$routes->get('/activities/getsitecontact/(:num)', 'Activities::getsitecontact/$1'); +$routes->get('/activities/getsitecontact/(:num)/(:num)', 'Activities::getsitecontact/$1/$2'); $routes->get('/activities/newtextarea', 'Activities::newtextarea'); $routes->get('/activities/activitiesproduct/(:num)', 'Activities::activitiesproduct/$1'); $routes->get('/activities/dummy', 'Activities::dummy'); @@ -212,23 +214,24 @@ $routes->group('certificates', function($routes) { // Untuk Index Tiap Menu $routes->get('maintenance', 'Certificates::maintenanceIndex'); // OK $routes->get('installation', 'Certificates::installationIndex'); // OK - // $routes->get('training', 'Certificates::trainingIndex'); // OK + $routes->get('training', 'Certificates::trainingIndex'); // OK // $routes->get('calibration', 'Certificates::calibrateIndex'); // OK // Untuk Get API $routes->get('api/getindexmaintenance', 'Certificates::getDataIndexMaintenance'); // OK $routes->get('api/getindexinstallation', 'Certificates::getDataIndexInstallation'); // OK - // $routes->get('api/getindextraining', 'Certificates::getDataIndexTraining'); // OK + $routes->get('api/getindextraining', 'Certificates::getDataIndexTraining'); // OK // $routes->get('api/getindexcalibrate', 'Certificates::getDataIndexCalibrate'); // Untuk Get Modal Data $routes->post('api/showmaintenance', 'Certificates::showDataMaintenance'); // OK $routes->post('api/showinstallation', 'Certificates::showDataInstallation'); // OK + $routes->post('api/showtraining', 'Certificates::showDataTraining'); // OK // Untuk Preview Cerificate $routes->get('maintenance/show/(:any)', 'Certificates::createMaintenancePreview/$1'); // OK $routes->get('installation/show/(:any)', 'Certificates::createInstallationPreview/$1'); // OK - // $routes->get('training/show/(:any)', 'Certificates::createTrainingPreview/$1'); // OK + $routes->get('training/show/(:any)', 'Certificates::createTrainingPreview/$1'); // OK // $routes->get('calibration/show/(:any)/(:any)', 'Certificates::createCalibratePreview/$1/$2'); $routes->post('api/validatecertificate', 'Certificates::validateCertificate'); // OK diff --git a/app/Controllers/Activities.php b/app/Controllers/Activities.php index 5c7ee31..d716442 100644 --- a/app/Controllers/Activities.php +++ b/app/Controllers/Activities.php @@ -3,6 +3,7 @@ namespace App\Controllers; use App\Models\CertificateModel; +use App\Models\CertificateTrainingModel; use App\Models\ActivitiesModel; use App\Models\ActdetailModel; use App\Models\InvTransModel; @@ -376,6 +377,14 @@ class Activities extends Controller { $query = $db->query($sql); $results = $query->getResultArray(); $data['vendors'] = $results; + + // $sql = "select c.* from contacts c + // Left join sitecontact sc on sc.contactid=c.contactid + // where sc.siteid = 2"; + $sql = "SELECT contactid, firstname, lastname, initial, title, email_1 FROM contacts"; + $query = $db->query($sql); + $results = $query->getResultArray(); + $data['contacts'] = $results; if( $this->request->getVar('siteid') != '' ) { $siteid = $this->request->getVar('siteid'); } @@ -408,7 +417,13 @@ class Activities extends Controller { 'attachment' => $this->request->getVar('attachment'), 'actdetailid' => $this->request->getVar('actdetailid'), 'acttextid' => $this->request->getVar('acttextid'), - 'textvalue' => $this->request->getVar('textvalue') + 'textvalue' => $this->request->getVar('textvalue'), + ]; + $data['training_certificates'] = [ + 'trainingids' => $this->request->getVar('trainingids'), + 'trainingnames' => $this->request->getVar('trainingnames'), + 'trainingdates' => $this->request->getVar('trainingdates'), + 'validatealltraining' => $this->request->getVar('validatealltraining'), ]; $actby = $this->request->getVar('actby'); @@ -470,11 +485,17 @@ class Activities extends Controller { $userid_owner = $data['new_value']['userid_owner']; $this->createCertificate($actid, $issuedDate, $userid_owner, 'MC'); } - if ($this->request->getVar('installation')) { // Jika Maintenance Dicentang + if ($this->request->getVar('installation')) { // Jika Installation Dicentang $issuedDate = $data['new_value']['closedate'] ?? null; $userid_owner = $data['new_value']['userid_owner']; $this->createCertificate($actid, $issuedDate, $userid_owner, 'IC'); } + if ($this->request->getVar('training')) { // Jika User Training Dicentang + if ($data['training_certificates']['trainingids'] != null) { + $userid_owner = $data['new_value']['userid_owner']; + $this->createCertificateTraining($actid, $userid_owner, $data['training_certificates']); + } + } } else { // update edit @@ -550,33 +571,43 @@ class Activities extends Controller { } } - - // UNTUK CERTIFICATES - $certificateTypes = [ - 'maintenance' => 'MC', - 'installation' => 'IC', - ]; - $hasAnyAction = false; + // // UNTUK CERTIFICATES + // $certificateTypes = [ + // 'maintenance' => 'MC', + // 'installation' => 'IC' + // ]; + // $hasAnyAction = false; + // $issuedDate = $data['new_value']['closedate'] ?? null; + // $userid_owner = $data['new_value']['userid_owner']; + // foreach ($certificateTypes as $requestName => $certCode) { //perulangan untuk mengecek semua checkbox + // if ($this->request->getVar($requestName)) { + // $hasAnyAction = true; // Jika checkbox dicentang, tandai bahwa ada aksi + // $this->updateCertificate($actid, $issuedDate, $userid_owner, $certCode); + // } + // } + // if (!$hasAnyAction) { // Jika setelah dicek semua ternyata tidak ada satupun yang dicentang, baru jalankan delete + // $this->deleteCertificate($actid); + // } + $reqMaintenance = $this->request->getPost('maintenance') !== null; + $reqInstallation = $this->request->getPost('installation') !== null; + $reqTraining = $this->request->getPost('training') !== null; $issuedDate = $data['new_value']['closedate'] ?? null; $userid_owner = $data['new_value']['userid_owner']; - foreach ($certificateTypes as $requestName => $certCode) { //perulangan untuk mengecek semua checkbox - if ($this->request->getVar($requestName)) { - $hasAnyAction = true; // Jika checkbox dicentang, tandai bahwa ada aksi - $this->updateCertificate($actid, $issuedDate, $userid_owner, $certCode); - } + if ($reqMaintenance) {// MC + $this->updateCertificate($actid, $issuedDate, $userid_owner, 'MC'); + } else { + $this->deleteCertificate($actid, 'MC'); } - if (!$hasAnyAction) { // Jika setelah dicek semua ternyata tidak ada satupun yang dicentang, baru jalankan delete - $this->deleteCertificate($actid); + if ($reqInstallation) {// IC + $this->updateCertificate($actid, $issuedDate, $userid_owner, 'IC'); + } else { + $this->deleteCertificate($actid, 'IC'); + } + if ($reqTraining) {// UTC + $this->updateCertificateTraining($actid, $userid_owner, $data['training_certificates']); + } else { + $this->deleteCertificateTraining(null, $actid); } - // if ($this->request->getVar('maintenance')) { // Maintenance - // // Maintenance sertifikat create or update - // $issuedDate = $data['new_value']['closedate'] ?? null; - // $userid_owner = $data['new_value']['userid_owner']; - // $this->updateCertificate($actid, $issuedDate, $userid_owner, 'MC'); - // } else { - // // Hapus softdelete sertifikat - // $this->deleteCertificate($actid); - // } } // act by consumables @@ -1692,7 +1723,7 @@ class Activities extends Controller { return view('invtrans_index', $data); } - // Untuk CRUD Sertifikat + // Untuk CRUD Sertifikat Installation dan Maintenance public function createCertificate ($actid, $issuedDate, $userid_owner, $certificate_type) { $db = \Config\Database::connect(); @@ -1744,6 +1775,7 @@ class Activities extends Controller { $existingCerts = $certificateModel->withDeleted() ->select('status') ->where('actid', $actid) + ->where('cert_type', $certificate_type) ->findAll(); // Variabel penanda apakah data sudah pernah ada di database @@ -1807,22 +1839,25 @@ class Activities extends Controller { $newCertificate = $certificateModel->find($certid); $certificateModel->update($certid, ['file_url' => base_url('certificates/number/'.$newCertificate['cert_number'])]); } else { + // dd($isDataExist); // Jika data sudah ada, eksekusi UPDATE // Catatan: Karena bisa ada lebih dari 1 data dengan actid yang sama (karena findAll), // Update ini akan menimpa semua baris yang punya actid tersebut. $certificateModel->withDeleted() ->where('actid', $actid) + ->where('cert_type', $certificate_type) ->set($certPayload) ->update(); } } - public function deleteCertificate($actid) { + public function deleteCertificate($actid, $certificate_type) { $certificateModel = new CertificateModel(); // 1. Cek apakah data sudah ada menggunakan findAll() $existingCerts = $certificateModel->withDeleted() ->select('status') ->where('actid', $actid) + ->where('cert_type', $certificate_type) ->findAll(); // Variabel penanda apakah data sudah pernah ada di database @@ -1837,8 +1872,307 @@ class Activities extends Controller { return; } } - $certificateModel->where('actid', $actid)->delete(); + $certificateModel->where('actid', $actid)->where('cert_type', $certificate_type)->delete(); } - + public function createCertificateTraining ($actid, $userid_owner, $training_data) { + + $db = \Config\Database::connect(); + $sql = "SELECT prl.productaliastext as productname + FROM `activities` act + LEFT JOIN products pr ON pr.productid = act.productid + LEFT JOIN productcatalog prc ON prc.catalogid = pr.catalogid + LEFT JOIN productalias prl ON prl.productaliasid = prc.productaliasid + WHERE act.actid = $actid"; + $query = $db->query($sql); + $result = $query->getRowArray(); + + $insertCert = [ + 'cert_type' => "UTC", + 'actid' => $actid, + 'user_id' => $userid_owner + ]; + + $certificateModel = new CertificateModel(); + $CertificateTrainingModel = new CertificateTrainingModel(); + + // Apakah Validasi Semuanya Dicentang + if($training_data['validatealltraining'] != null) { + $currentTime = date('Y-m-d H:i:s'); + } else { + $currentTime = null; + } + + foreach ($training_data['trainingids'] as $index => $id) { + + // Ambil data berdasarkan index yang sama + $contact_id = $id; + $name = $training_data['trainingnames'][$index]; + $issued_date = $training_data['trainingdates'][$index]; + + $insertCert['cert_name'] = "UTC_" . ($result['productname'] ?? 'UNKNOWN') . "_" . $name . "_" . $actid; + $insertCert['issued_date'] = $issued_date; + $insertCert['user_validation_at'] = $currentTime; + + $certificateModel->insert($insertCert); + $certid = $certificateModel->getInsertID(); + + $newCertificate = $certificateModel->find($certid); + $certificateModel->update($certid, ['file_url' => base_url('certificates/number/'.$newCertificate['cert_number'])]); + + $CertificateTrainingModel->insert(['cert_id' => (int)$certid, 'contact_id' => (int)$contact_id]); + } + + } + public function updateCertificateTraining($actid, $userid_owner, $new_training_data) { + $certificateModel = new CertificateModel(); + + $existingTrainingCerts = $certificateModel->withDeleted() // 1. Ambil data existing dari database + ->select(' + Certificates.cert_id, + Certificates.cert_name, + Certificates.status, + Certificates_Training.contact_id + ') + ->join('Certificates_Training', 'Certificates_Training.cert_id = Certificates.cert_id', 'join') + ->where('Certificates.actid', $actid) + ->where('Certificates.cert_type', 'UTC') + ->findAll(); + + + $existingMap = []; // 2. Buat Map untuk data existing + foreach ($existingTrainingCerts as $cert) { + $contactId = is_object($cert) ? $cert->contact_id : $cert['contact_id']; + $existingMap[$contactId] = $cert; + } + + // Temp + $dataToInsert = []; + $dataToUpdate = []; + $dataToDelete = []; + + $currentTime = date('Y-m-d H:i:s'); + + // 3. Looping data baru dari form + if (!empty($new_training_data['trainingids']) && is_array($new_training_data['trainingids'])) { + foreach ($new_training_data['trainingids'] as $index => $contactId) { + + $trainingName = $new_training_data['trainingnames'][$index] ?? null; + $trainingDate = $new_training_data['trainingdates'][$index] ?? null; + + // Cek apakah data sudah ada di database + if (array_key_exists($contactId, $existingMap)) { + $existingData = $existingMap[$contactId]; + $certId = is_object($existingData) ? $existingData->cert_id : $existingData['cert_id']; + + // if ($new_training_data['validatealltraining'] != null) { + // $certificatesUpdate['user_validation_at'] = $currentTime; + // } else { + // $certificatesUpdate['user_validation_at'] = null; + // } + $certificatesUpdate['cert_id'] = $certId; + // $certificatesUpdate['actid'] = $actid; + $certificatesUpdate['issued_date'] = $trainingDate; + $certificatesUpdate['deleted_at'] = null; + + $certificatesTrainingUpdate['cert_id'] = $certId; + $certificatesTrainingUpdate['contact_id'] = $contactId; + $certificatesTrainingUpdate['deleted_at'] = null; + + $certificatesUpdates[] = $certificatesUpdate; + $certificatesTrainingUpdates[] = $certificatesTrainingUpdate; + + unset($existingMap[$contactId]); // ELIMINASI: Hapus dari map karena data ini dipertahankan + } else { + // Insert Temp + $dataToInsert['trainingids'][] = $contactId; + $dataToInsert['trainingnames'][] = $trainingName; + $dataToInsert['trainingdates'][] = $trainingDate; + } + } + } + + // 4. Proses Sisa Data di Map menjadi DELETE + // Apapun yang tersisa di $existingMap berarti tidak ada di $new_training_data + foreach ($existingMap as $contactId => $existingData) { + $certId = is_object($existingData) ? $existingData->cert_id : $existingData['cert_id']; + + // Memasukkan cert_id, contact_id, (dan actid jika itu parameter ke-3 yang dimaksud) + $dataToDelete[] = [ + 'cert_id' => $certId, + 'contact_id' => $contactId, + 'actid' => $actid + ]; + } + + // Cek hasil klasifikasinya: + // dd(['Insert' => $dataToInsert, 'Update' => $dataToUpdate, 'Delete' => $dataToDelete]); + + // OK + if (!empty($dataToInsert)) { + $dataToInsert['validatealltraining'] = $new_training_data['validatealltraining']; + $this->createCertificateTraining($actid, $userid_owner, $dataToInsert); + } + + if (!empty($certificatesUpdates)) { + + $certificateModel = new CertificateModel(); + $CertificateTrainingModel = new CertificateTrainingModel(); + + $db = \Config\Database::connect(); + $db->transStart(); + + $certificateModel->builder() + ->where('cert_type', 'UTC') + ->where('status', 'unvalidated') + ->updateBatch($certificatesUpdates, 'cert_id'); + + foreach ($certificatesTrainingUpdates as $trainingUpdate) { + $CertificateTrainingModel->builder() + ->where('cert_id', $trainingUpdate['cert_id']) + ->where('contact_id', $trainingUpdate['contact_id']) + ->set([ + 'deleted_at' => null // Paksa restore data + ])->update(); + } + + $db->transComplete(); + + if ($db->transStatus() === false) { + // Handle jika transaksi gagal + log_message('error', 'Gagal melakukan update sertifikat training.'); + } + } + + // OK + if (!empty($dataToDelete)) { + $this->deleteCertificateTraining($dataToDelete, null); + } + } + public function deleteCertificateTraining($updateToDelete, $deleteActid) { + + $certificateModel = new CertificateModel(); + $CertificateTrainingModel = new CertificateTrainingModel(); + + // if (!empty($updateToDelete)) { + // foreach ($updateToDelete as $key => $value) { + + // // 1. Cari data sertifikat terlebih dahulu untuk mendapatkan cert_id + // $certificate = $certificateModel + // ->where('actid', $value['actid']) + // ->where('status', 'unvalidated') + // ->where('cert_type', 'UTC') + // ->first(); // Gunakan first() jika Laravel, atau get()->getRowArray() jika CI4 + + // // 2. Pastikan data ditemukan sebelum melakukan penghapusan + // if ($certificate) { + + // // Ambil cert_id dari hasil query (sesuaikan dengan format return object/array framework Anda) + // $certId = $certificate['cert_id']; // atau $certificate->cert_id jika berupa object + + // // 3. Hapus data di CertificateTrainingModel menggunakan $certId yang baru didapat + // $CertificateTrainingModel + // ->where('cert_id', $certId) + // ->where('contact_id', $value['contact_id']) + // ->delete(); + + // // 4. Hapus data di certificateModel + // // Kita cukup gunakan cert_id karena itu sudah spesifik (Primary Key) + // $certificateModel + // ->where('cert_id', $certId) + // ->delete(); + // } + // } + // } + if (!empty($updateToDelete)) { + + foreach ($updateToDelete as $key => $value) { + + $isSuccess = $certificateModel + ->where('actid', $value['actid']) + ->where('cert_id', $value['cert_id']) + ->where('status', 'unvalidated') + ->where('cert_type', 'UTC')->delete(); + + // Cek apakah ada baris yang benar-benar dihapus di database + if ($isSuccess && $certificateModel->affectedRows() > 0) { + $CertificateTrainingModel + ->where('cert_id', $value['cert_id']) + ->where('contact_id', $value['contact_id'])->delete(); + } + + } + } + + if ($deleteActid != null) { + // 1. Ambil (SELECT) dulu daftar cert_id yang memenuhi syarat sebelum dihapus + $certsToDelete = $certificateModel + ->select('cert_id') // Kita hanya butuh kolom cert_id + ->where('actid', $deleteActid) + ->where('status', 'unvalidated') + ->where('cert_type', 'UTC') + ->findAll(); + + // Pastikan ada data yang ditemukan sebelum mengeksekusi delete + if (!empty($certsToDelete)) { + + // Ekstrak hasil query menjadi array 1 dimensi berisi kumpulan cert_id + // Contoh hasil: [10, 15, 22] + $certIds = array_column($certsToDelete, 'cert_id'); + + // Gunakan Transaction agar jika salah satu gagal, semuanya batal (aman) + $db = \Config\Database::connect(); + $db->transStart(); + + // 2. Hapus data relasi di tabel Certificates_Training (Pivot) + // Gunakan whereIn karena kita menghapus banyak cert_id sekaligus + $CertificateTrainingModel + ->whereIn('cert_id', $certIds) + ->delete(); + + // 3. Hapus data utama di tabel Certificates + // Kita bisa langsung pakai $certIds yang sudah didapat + $certificateModel + ->whereIn('cert_id', $certIds) + ->delete(); + + $db->transComplete(); + + if ($db->transStatus() === false) { + // Logika jika proses delete gagal + } + } + } + } + // Untuk Training Contact + public function getsitecontact($siteid=null, $actid=null){ + $db = \Config\Database::connect(); + + if($siteid == null) { + $filterquery = ''; + } else { + $filterquery = "where sc.siteid=$siteid"; + } + $sql = "SELECT sc.siteid, c.contactid, c.firstname, c.lastname, c.title, c.initial, c.email_1 from contacts c + Left join sitecontact sc on sc.contactid=c.contactid + $filterquery"; + $query = $db->query($sql); + $results = $query->getResultArray(); + $data['sitecontacts'] = $results; + + $data['siteid'] = $siteid; + + // Get Data Training User + if($actid != null) { + $certificateTrainingModel = new CertificateTrainingModel(); + $traininguser = $certificateTrainingModel->select('contacts.contactid, contacts.firstname, contacts.lastname, contacts.title, contacts.initial, contacts.email_1, certificates.issued_date') + ->join('certificates', 'certificates.cert_id = certificates_training.cert_id', 'inner') + ->join('contacts', 'contacts.contactid = certificates_training.contact_id', 'inner') + ->where('certificates.actid', $actid) + ->findAll(); + $data['traininguser'] = $traininguser; + } + + return view('activities_getsitecontacts', $data); + } } \ No newline at end of file diff --git a/app/Controllers/Certificates.php b/app/Controllers/Certificates.php index bc9c740..b110560 100644 --- a/app/Controllers/Certificates.php +++ b/app/Controllers/Certificates.php @@ -43,7 +43,7 @@ class Certificates extends BaseController { ') ->join('activities', 'activities.actid = certificates.actid', 'left') ->join('users', 'users.userid = certificates.user_id', 'left') - ->where('certificates.cert_type', 'IC');; + ->where('certificates.cert_type', 'IC'); // 2. Filter berdasarkan Role if (in_array($userPosId, [1, 3, 5])) { // Manager & IT: Tidak perlu filter tambahan (lihat semua) @@ -208,7 +208,7 @@ class Certificates extends BaseController { ') ->join('activities', 'activities.actid = certificates.actid', 'left') ->join('users', 'users.userid = certificates.user_id', 'left') - ->where('certificates.cert_type', 'MC');; + ->where('certificates.cert_type', 'MC'); // 2. Filter berdasarkan Role if (in_array($userPosId, [1, 3, 5])) { // Manager & IT: Tidak perlu filter tambahan (lihat semua) @@ -350,69 +350,189 @@ class Certificates extends BaseController { // Untuk Sertifikat Training [3] - // public function trainingIndex() { - // return view('certificate_training_index'); - // } - // public function getDataIndexTraining() { - // // $actid = $this->request->getVar('actid'); + public function trainingIndex() { + return view('certificate_training_index'); + } + public function getDataIndexTraining() { + $userPosId = session()->get('userposid'); + $userId = session()->get('userid'); + + $certificateModel = new CertificateModel(); - // // Sample data - replace with actual database query - // $certificates = [ - // [ - // 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11919', - // 'certname' => 'Jokoh Calibration Certificate', - // 'productname' => 'Jokoh', - // 'productnumber' => 'SN-2024-001', - // 'issuedate' => '2024-01-15', - // 'expirydate' => '2025-01-15', - // 'vendor' => 'Summit Calibration Lab', - // 'isval' => null - // ], - // [ - // 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11919', - // 'certname' => 'Electrical Safety Test', - // 'productname' => 'GE Healthcare VIVID', - // 'productnumber' => 'GE-VIV-Q992', - // 'issuedate' => '2024-06-12', - // 'expirydate' => '2026-10-01', - // 'vendor' => 'Pramita Medika Service', - // 'isval' => '2026-03-01' - // ] - // ]; + // 1. Mulai Query Builder + $builder = $certificateModel->select(' + certificates.cert_id, + certificates.cert_number, + certificates.cert_name, + certificates.cert_type, + certificates.actid, + certificates.issued_date, + certificates.expired_date, + certificates.status, + certificates.user_validation_at, + certificates.spv_validation_at, + certificates.manager_validation_at, + activities.subject as activity_subject, + CONCAT(users.firstname, " ", users.lastname) as fullname + ') + ->join('activities', 'activities.actid = certificates.actid', 'left') + ->join('users', 'users.userid = certificates.user_id', 'left') + ->where('certificates.cert_type', 'UTC'); - // // If no actid, return all certificates - // if (empty($certificates)) { - // return $this->response->setJSON(null); - // } + // 2. Filter berdasarkan Role + if (in_array($userPosId, [1, 3, 5])) { // Manager & IT: Tidak perlu filter tambahan (lihat semua) + } else if ($userPosId == 2) { // SPV: Melihat data user yang "reportto"-nya adalah ID supervisor ini + $builder->where('users.reportto', $userId); + } else if ($userPosId == 4) { // TSOIVD: Hanya melihat data milik sendiri + $builder->where('certificates.user_id', $userId); + } else {// Role lain: Tidak diberi akses + return $this->response->setJSON([]); + } - // return $this->response->setJSON($certificates); - // } - // public function createTrainingPreview($certid = null) { // Untuk Preview Sertifikat - // //Melakukan search data dari database + // 3. Eksekusi Query + $allData = $builder->findAll(); + + if (empty($allData)) { + return $this->response->setJSON([]); // Kembalikan array kosong agar frontend tidak error + } + + return $this->response->setJSON($allData); + } + public function showDataTraining() { // Untuk API Get Data + $certid = $this->request->getPost('certid'); + if (!$certid) { + return $this->response->setStatusCode(400)->setJSON(['error' => 'Certificate ID Not Found']); + } + $certificateModel = new CertificateModel(); + $data = $certificateModel->select(' + certificates.cert_id, + certificates.cert_number, + certificates.cert_name, + certificates.status, + activities.actid, + activities.subject, + productcatalog.productname, + sites.sitename, + products.productnumber, + CASE + WHEN certificates.cert_type = "MC" THEN "Maintenance" + WHEN certificates.cert_type = "IC" THEN "Installation" + WHEN certificates.cert_type = "UTC" THEN "User Training" + WHEN certificates.cert_type = "BAI" THEN "Berita Acara Instalasi" + WHEN certificates.cert_type = "BAP" THEN "Berita Acara Penarikan" + ELSE certificates.cert_type + END AS certtype, + CONCAT(us.firstname, " ", us.lastname) AS username, + certificates.user_validation_at, + CONCAT(spv.firstname, " ", spv.lastname) AS spvname, + certificates.spv_validation_at, + CONCAT(mgr.firstname, " ", mgr.lastname) AS managername, + certificates.manager_validation_at, + certificates.issued_date, + certificates.expired_date, + CONCAT(contacts.firstname, " ", contacts.lastname) AS fullname + ', false) + ->join('activities', 'activities.actid = certificates.actid', 'inner') + ->join('products', 'products.productid = activities.productid', 'inner') + ->join('productcatalog', 'productcatalog.catalogid = products.catalogid', 'inner') + ->join('sites', 'sites.siteid = activities.siteid', 'left') + ->join('users as us', 'us.userid = certificates.user_id', 'left') + ->join('users as spv', 'spv.userid = certificates.spv_id', 'left') + ->join('users as mgr', 'mgr.userid = certificates.manager_id', 'left') + ->join('userposition', 'userposition.userposid = us.userposid', 'left') + ->join('certificates_training', 'certificates_training.cert_id = certificates.cert_id', 'left') + ->join('contacts', 'contacts.contactid = certificates_training.contact_id', 'left') + ->where('certificates.cert_id', $certid) + ->first(); + + $data['issued_date'] = $data['issued_date'] ? date('d M Y', strtotime($data['issued_date'])) : null; + $data['user_validation_at'] = $data['user_validation_at'] ? date('d M Y H:i', strtotime($data['user_validation_at'])) : null; + $data['spv_validation_at'] = $data['spv_validation_at'] ? date('d M Y H:i', strtotime($data['spv_validation_at'])) : null; + $data['manager_validation_at'] = $data['manager_validation_at'] ? date('d M Y H:i', strtotime($data['manager_validation_at'])) : null; + + if (empty($data)) { // Jika Tidak Ada + return $this->response->setStatusCode(404)->setJSON(['error' => 'Maintenance certificate not found']); + } + return $this->response->setJSON($data); + } + public function createTrainingPreview($certid = null) { // Untuk Preview Sertifikat + + if (!$certid) { + return $this->response->setStatusCode(400)->setJSON(['error' => 'Certificate ID Not Found']); + } + $certificateModel = new CertificateModel(); + $data = $certificateModel->select(' + certificates.cert_name, + certificates.issued_date, + certificates.expired_date, + certificates.file_url, + productalias.productaliastext as productname, + sites.sitename as sitename, + products.productnumber, + CASE + WHEN certificates.cert_type = "MC" THEN "maintenance" + WHEN certificates.cert_type = "IC" THEN "installation" + WHEN certificates.cert_type = "UTC" THEN "training" + WHEN certificates.cert_type = "BAI" THEN "Berita Acara Instalasi" + WHEN certificates.cert_type = "BAP" THEN "Berita Acara Penarikan" + ELSE certificates.cert_type + END AS cert_type, + CONCAT(users.firstname, " ", users.lastname) AS fullname, + userposition.texts AS user_position, + certificates.issued_date, + certificates.expired_date, + CONCAT(contacts.firstname, " ", contacts.lastname) AS fullname, + contacts.title, + zones.zonename as city, + certificates.cert_number -- Penting agar callback UUID tetap jalan + ', false) + ->join('users', 'users.userid = certificates.user_id', 'left') + ->join('userposition', 'userposition.userposid = users.userposid', 'left') + ->join('activities', 'activities.actid = certificates.actid', 'left') + ->join('sites', 'sites.siteid = activities.siteid', 'left') + ->join('accounts', 'accounts.accountid = sites.accountid', 'left') + ->join('zones', 'zones.zoneid = accounts.zoneid', 'left') + ->join('products', 'products.productid = activities.productid', 'left') + ->join('productcatalog', 'productcatalog.catalogid = products.catalogid', 'left') + ->join('productalias', 'productalias.productaliasid = productcatalog.productaliasid', 'left') + ->join('certificates_training', 'certificates_training.cert_id = certificates.cert_id', 'left') + ->join('contacts', 'contacts.contactid = certificates_training.contact_id', 'left') + ->where('certificates.cert_id', $certid) + ->first(); + $certificate = [ + 'certname' => trim($data['cert_name']), + 'sitename' => $data['sitename'], + 'title' => empty($data['title']) ? '' : ', ' . $data['title'], + 'city' => empty($data['city']) ? '' : $data['city'], + 'certtype' => $data['cert_type'], + 'fullname' => $data['fullname'], + 'userposition' => $data['user_position'], + 'productname' => $data['productname'], + 'productnumber' => $data['productnumber'], + // 'issueddate' => $data['issued_date'], + 'expireddate' => $data['expired_date'] + ]; + if ($certificate['certtype'] == 'training') { + $certificate['issueddate'] = date('F d, Y', strtotime($data['issued_date'])); + } else { + $certificate['issueddate'] = date('d-M-Y', strtotime($data['issued_date'])); + } + + $builder = new Builder( + writer: new PngWriter(), + data: $data['file_url'], + size: 120, + margin: 0 + ); + $result = $builder->build(); + $certificate['qrcode'] = $result->getDataUri(); + + if (empty($certificate)) { // Jika Tidak Ada + return $this->response->setStatusCode(404)->setJSON(['error' => 'Maintenance certificate not found']); + } - // if (!$certid) { - // return $this->response->setStatusCode(400)->setJSON(['error' => 'Certificate ID is required']); - // } - - // // Get certificate data Berdasarkan certid - // $certificate = [ - // 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11919', - // 'certname' => 'Jokoh Calibration Certificate', - // 'productname' => 'Jokoh', - // 'productnumber' => 'SN-2024-001', - // 'issuedate' => '2024-01-15', - // 'expirydate' => '2025-01-15', - // 'vendor' => 'Summit Calibration Lab', - // 'isval' => null - // ]; - - // if (empty($certificate)) { // JIka Tidak Ada - // return $this->response->setStatusCode(404)->setJSON(['error' => 'Maintenance certificate not found']); - // } - - // return $this->previewPdf($certificate, 'training'); // Preview PDF - // } - + return $this->previewPdf($certificate, 'training'); // Preview PDF + } // Untuk Sertifikat Calibrate [4] // public function calibrateIndex() { @@ -490,10 +610,12 @@ class Certificates extends BaseController { $dompdf = new Dompdf($options); - // Format dates - $certificate['issueddate'] = date('d-M-Y', strtotime($certificate['issueddate'])); - - if(isset($certificate['expireddate'])) { + if ($type == 'training') { + $certificate['issueddate'] = date('F d, Y', strtotime($certificate['issueddate'])); + } else { + $certificate['issueddate'] = date('d-M-Y', strtotime($certificate['issueddate'])); + } + if (isset($certificate['expireddate'])) { $certificate['expireddate'] = date('d-M-Y', strtotime($certificate['expireddate'])); } @@ -619,51 +741,95 @@ class Certificates extends BaseController { $certificateModel->update($certid, ['status' => 'validated']); // Baru jalankan query berat JOIN di sini untuk keperluan PDF/Notifikasi + // $latestData = $certificateModel->select(' + // certificates.cert_name, + // certificates.issued_date, + // certificates.expired_date, + // certificates.file_url, + // productalias.productaliastext as productname, + // sites.sitename as sitename, + // products.productnumber, + // CASE + // WHEN certificates.cert_type = "MC" THEN "Maintenance" + // WHEN certificates.cert_type = "IC" THEN "Installation" + // WHEN certificates.cert_type = "UTC" THEN "Training" + // WHEN certificates.cert_type = "BAI" THEN "Berita Acara Instalasi" + // WHEN certificates.cert_type = "BAP" THEN "Berita Acara Penarikan" + // ELSE certificates.cert_type + // END AS cert_type, + // CONCAT(users.firstname, " ", users.lastname) AS fullname, + // userposition.texts AS user_position, + // certificates.issued_date, + // certificates.expired_date, + // certificates.cert_number -- Penting agar callback UUID tetap jalan + // ', false) + // ->join('users', 'users.userid = certificates.user_id', 'left') + // ->join('userposition', 'userposition.userposid = users.userposid', 'left') + // ->join('activities', 'activities.actid = certificates.actid', 'left') + // ->join('sites', 'sites.siteid = activities.siteid', 'left') + // ->join('products', 'products.productid = activities.productid', 'left') + // ->join('productcatalog', 'productcatalog.catalogid = products.catalogid', 'left') + // ->join('productalias', 'productalias.productaliasid = productcatalog.productaliasid', 'left') + // ->where('certificates.cert_id', $certid) + // ->first(); $latestData = $certificateModel->select(' - certificates.cert_name, - certificates.issued_date, - certificates.expired_date, - certificates.file_url, - productalias.productaliastext as productname, - sites.sitename as sitename, - products.productnumber, - CASE - WHEN certificates.cert_type = "MC" THEN "Maintenance" - WHEN certificates.cert_type = "IC" THEN "Installation" - WHEN certificates.cert_type = "UTC" THEN "Training" - WHEN certificates.cert_type = "BAI" THEN "Berita Acara Instalasi" - WHEN certificates.cert_type = "BAP" THEN "Berita Acara Penarikan" - ELSE certificates.cert_type - END AS cert_type, - CONCAT(users.firstname, " ", users.lastname) AS fullname, - userposition.texts AS user_position, - certificates.issued_date, - certificates.expired_date, - certificates.cert_number -- Penting agar callback UUID tetap jalan - ', false) - ->join('users', 'users.userid = certificates.user_id', 'left') - ->join('userposition', 'userposition.userposid = users.userposid', 'left') - ->join('activities', 'activities.actid = certificates.actid', 'left') - ->join('sites', 'sites.siteid = activities.siteid', 'left') - ->join('products', 'products.productid = activities.productid', 'left') - ->join('productcatalog', 'productcatalog.catalogid = products.catalogid', 'left') - ->join('productalias', 'productalias.productaliasid = productcatalog.productaliasid', 'left') - ->where('certificates.cert_id', $certid) - ->first(); + certificates.cert_name, + certificates.issued_date, + certificates.expired_date, + certificates.file_url, + productalias.productaliastext as productname, + sites.sitename as sitename, + products.productnumber, + CASE + WHEN certificates.cert_type = "MC" THEN "maintenance" + WHEN certificates.cert_type = "IC" THEN "installation" + WHEN certificates.cert_type = "UTC" THEN "training" + WHEN certificates.cert_type = "BAI" THEN "Berita Acara Instalasi" + WHEN certificates.cert_type = "BAP" THEN "Berita Acara Penarikan" + ELSE certificates.cert_type + END AS cert_type, + CONCAT(users.firstname, " ", users.lastname) AS fullname, + userposition.texts AS user_position, + certificates.issued_date, + certificates.expired_date, + CONCAT(contacts.firstname, " ", contacts.lastname) AS fullname, + contacts.title, + certificates.cert_number -- Penting agar callback UUID tetap jalan + ', false) + ->join('users', 'users.userid = certificates.user_id', 'left') + ->join('userposition', 'userposition.userposid = users.userposid', 'left') + ->join('activities', 'activities.actid = certificates.actid', 'left') + ->join('sites', 'sites.siteid = activities.siteid', 'left') + ->join('accounts', 'accounts.accountid = sites.accountid', 'left') + ->join('zones', 'zones.zoneid = accounts.zoneid', 'left') + ->join('products', 'products.productid = activities.productid', 'left') + ->join('productcatalog', 'productcatalog.catalogid = products.catalogid', 'left') + ->join('productalias', 'productalias.productaliasid = productcatalog.productaliasid', 'left') + ->join('certificates_training', 'certificates_training.cert_id = certificates.cert_id', 'left') + ->join('contacts', 'contacts.contactid = certificates_training.contact_id', 'left') + ->where('certificates.cert_id', $certid) + ->first(); $certificate = [ + 'title' => empty($latestData['title']) ? '' : ', ' . $latestData['title'], 'file_url' => $latestData['file_url'], 'certname' => $latestData['cert_name'], 'sitename' => $latestData['sitename'], + 'city' => empty($data['city']) ? '' : $data['city'], 'certtype' => $latestData['cert_type'], 'fullname' => $latestData['fullname'], 'userposition' => $latestData['user_position'], 'productname' => $latestData['productname'], 'productnumber' => $latestData['productnumber'], - 'issueddate' => date('d-M-Y', strtotime($latestData['issued_date'])), + // 'issueddate' => date('d-M-Y', strtotime($latestData['issued_date'])), 'expireddate' => date('d-M-Y', strtotime($latestData['expired_date'])), 'exportToPDF' => true ]; + if ($latestData['cert_type'] == 'training') { + $certificate['issueddate'] = date('F d, Y', strtotime($latestData['issued_date'])); + } else { + $certificate['issueddate'] = date('d-M-Y', strtotime($latestData['issued_date'])); + } try { diff --git a/app/Controllers/Contacts.php b/app/Controllers/Contacts.php index 0ec61e1..d1463a7 100644 --- a/app/Controllers/Contacts.php +++ b/app/Controllers/Contacts.php @@ -3,6 +3,7 @@ namespace App\Controllers; use App\Models\ContactsModel; +use App\Models\SiteContactModel; use CodeIgniter\Controller; class Contacts extends Controller { @@ -38,7 +39,7 @@ class Contacts extends Controller { } if ($this->request->getMethod() === 'POST') { $rules = [ - 'contactid' => 'required', + // 'contactid' => 'required', 'firstname' => 'required', 'email_1' => 'required', 'initial' => 'required' @@ -53,7 +54,8 @@ class Contacts extends Controller { 'email_2' => $this->request->getVar('email_2'), 'phone' => $this->request->getVar('phone'), 'mobile_1' => $this->request->getVar('mobile_1'), - 'mobile_2' => $this->request->getVar('mobile_2') + 'mobile_2' => $this->request->getVar('mobile_2'), + 'siteid' => $this->request->getVar('siteid') ?? null //Untuk Create dari AR ]; if($this->validate($rules)){ @@ -67,6 +69,18 @@ class Contacts extends Controller { $contactsModel->set('createdate', 'NOW()', FALSE); $contactsModel->set('enddate', NULL); $contactsModel->insert($data['new_value']); + $contactid = $contactsModel->getInsertID(); + + if($this->request->getVar('siteid') != null) { + $siteContactModel = new SiteContactModel(); + $siteContactValue = [ + 'siteid' => $this->request->getVar('siteid'), + 'contactid' => $contactid, + 'contactemail' => $this->request->getVar('email_1'), + ]; + $siteContactModel->insert($siteContactValue); + } + return view('form_success'); } } else { diff --git a/app/Models/CertificateTrainingModel.php b/app/Models/CertificateTrainingModel.php new file mode 100644 index 0000000..0c31dd6 --- /dev/null +++ b/app/Models/CertificateTrainingModel.php @@ -0,0 +1,63 @@ + 'required|numeric', + 'contact_id' => 'required|numeric', + ]; + + protected $validationMessages = [ + 'cert_id' => [ + 'required' => 'ID Sertifikat wajib diisi.', + 'numeric' => 'ID Sertifikat harus berupa angka.' + ], + 'contact_id' => [ + 'required' => 'ID Contact wajib diisi.', + 'numeric' => 'ID Contact harus berupa angka.' + ] + ]; + + protected $skipValidation = false; + + // /** + // * Contoh Method untuk mengambil data training lengkap dengan nama sertifikat dan contact + // */ + // public function getTrainingDetails($id = null) + // { + // $builder = $this->db->table($this->table); + // $builder->select('Certificates_Training.*, Certificates.cert_name, Contacts.contact_name'); // Asumsi nama tabel Contacts + // $builder->join('Certificates', 'Certificates.cert_id = Certificates_Training.cert_id'); + // $builder->join('Contacts', 'Contacts.contact_id = Certificates_Training.contact_id'); + // $builder->where('Certificates_Training.deleted_at', null); // Pastikan yang belum dihapus + + // if ($id) { + // return $builder->where('cert_training_id', $id)->get()->getRowArray(); + // } + + // return $builder->get()->getResultArray(); + // } +} \ No newline at end of file diff --git a/app/Views/activities_editor.php b/app/Views/activities_editor.php index 924c348..fe0ef5c 100644 --- a/app/Views/activities_editor.php +++ b/app/Views/activities_editor.php @@ -26,6 +26,7 @@ foreach($products as $qdata) { $now = date('Y-m-d\TH:i'); $siteid = ''; +$contactid = ''; $productid = ''; $vendorid = ''; $swversion = ''; @@ -62,6 +63,7 @@ if(isset($data)) { $acttypeid = $data['acttypeid']; $userid_owner = $data['userid_owner']; $activitystatus = $data['activitystatus']; + $contactid = $data['contactid']; // Untuk REFF : Menentukan mana yg dipakai untuk actid_ref if ($refer_page) { @@ -109,6 +111,9 @@ if(isset($data)) {
' /> + + + ' />
@@ -194,7 +199,7 @@ if(isset($data)) {
-
-
+
-->
@@ -259,7 +264,7 @@ if(isset($data)) { User Training Certificate
-
--> +
@@ -269,7 +274,8 @@ if(isset($data)) {
- $stat) { @@ -633,51 +639,7 @@ if(isset($data)) {
- - -
-
-
- - -
-
-
-
- - -
-
-
- -
-
-
-
- - - - - - - - - - ". - "". - ""; - } - } - ?> - -
Nama AnalisTanggalAction
$qname $qdate
-
+
@@ -804,14 +766,14 @@ $(document).ready(function() { // $("#calibration").prop('disabled', true); $("#installation").prop('disabled', true); // $("#offreport").prop('disabled', true); - // $("#training").prop('disabled', true); + $("#training").prop('disabled', true); } else if (this.value == '3') { $("#maintenance").prop('disabled', true); // $("#calibration").prop('disabled', false); $("#installation").prop('disabled', false); // $("#offreport").prop('disabled', false); - // $("#training").prop('disabled', false); + $("#training").prop('disabled', false); } else { // Ini akan menjadi default jika #acttypeid kosong atau bukan 5 dan 3 @@ -819,9 +781,30 @@ $(document).ready(function() { // $("#calibration").prop('disabled', true); $("#installation").prop('disabled', true); // $("#offreport").prop('disabled', true); - // $("#training").prop('disabled', true); + $("#training").prop('disabled', true); } }).trigger('change'); + + let siteid = $('#siteid').val(); + let current_actid = $('#current_actid').val(); + + // Perbaikan di sini: '!current_actid' otomatis mengecek null, undefined, atau string kosong ('') + if (!current_actid) { + current_actid = ''; + } else { + current_actid = '/' + current_actid; + } + + // Untuk Training + if (siteid !== '') { + $.get("activities/getsitecontact/" + siteid + current_actid, function(data) { + $('#training_form').html(data); + $('.select2').select2({ + theme: 'bootstrap-5', + width: '100%' + }); + }); + } }); // acttext @@ -832,7 +815,7 @@ function acttext_del(e, actdetailid) { var actdetailid = actdetailid.toString(); var d = $('#actdetailid_delete'); d.val(d.val()+' '+actdetailid); - console.log(d.val()); + // console.log(d.val()); } } @@ -884,35 +867,6 @@ function acttext_add() { }) } -// $('#actby').change(function() { -// var actby=this.value; -// if(actby == 'P') { -// var siteid=$('#siteid').val(); -// $.get("/activities/getproduct/"+siteid, function(data) { -// $('#actby_item').html(data); -// $('.select2').select2({ -// theme: 'bootstrap-5', -// width: '100%' -// }); -// }) -// } else if (actby == 'V') { -// $.get("/activities/getvendor/0", function(data) { -// $('#actby_item').html(data); -// }) -// } else if (actby == 'C') { -// $.get("/activities/getconsumable/0", function(data) { -// $('#actby_item').html(data); -// $('.select2').select2({ -// theme: 'bootstrap-5', -// width: '100%' -// }); -// }) -// }else { -// $('#actby_item').html(''); -// } - -// }) - // 1. Event ketika 'Activity by' diubah (Kode asli Anda dengan sedikit penyesuaian) $('#actby').change(function() { var actby = this.value; @@ -949,8 +903,27 @@ $('#actby').change(function() { // 2. --- MODIFIKASI TAMBAHAN --- // Event ketika 'Site' diubah $('#siteid').change(function() { - var actby = $('#actby').val(); // Cek status Activity by saat ini - var siteid = this.value; // Ambil nilai siteid yang baru dipilih + let actby = $('#actby').val(); // Cek status Activity by saat ini + + let siteid = $('#siteid').val(); + let current_actid = $('#current_actid').val(); + if (!current_actid) { + current_actid = ''; + } else { + current_actid = '/' + current_actid; + } + // Khusus Untuk Training + if(siteid == '') { + $('#training_form').html('
Please Fill Site First!
'); + } else { + $.get("activities/getsitecontact/" + siteid + current_actid, function(data) { + $('#training_form').html(data); + $('.select2').select2({ + theme: 'bootstrap-5', + width: '100%' + }); + }); + } // Hanya jalankan AJAX ulang JIKA Activity by sedang memilih 'P' if (actby == 'P') { @@ -988,12 +961,11 @@ $('#status').change(function() { // else { $("#maintenance").prop('disabled', true); $("#calibration").prop('disabled', true); $("#installation").prop('disabled', true); $("#offreport").prop('disabled', true); $("#training").prop('disabled', true);} // }) $('#acttypeid').change(function() { - if (this.value=='5'){ $("#maintenance").prop('disabled', false); $("#installation").prop('disabled', true);} - else if (this.value=='3'){ $("#maintenance").prop('disabled', true); $("#installation").prop('disabled', false);} - else { $("#maintenance").prop('disabled', true); $("#installation").prop('disabled', true);} + if (this.value=='5'){ $("#maintenance").prop('disabled', false); $("#installation").prop('disabled', true); $("#training").prop('disabled', true);} + else if (this.value=='3'){ $("#maintenance").prop('disabled', true); $("#installation").prop('disabled', false); $("#training").prop('disabled', false); } + else { $("#maintenance").prop('disabled', true); $("#installation").prop('disabled', true); $("#training").prop('disabled', true);} }) - // reportdate change => opendate.value = reportdate.value $('#reportdate').change(function() { $('#opendate').val(this.value); @@ -1012,7 +984,7 @@ function deleteRow(btn, itxid) { var itxid = itxid.toString(); var d = $('#itxid_delete'); d.val(d.val()+' '+itxid); - console.log(d.val()); + // console.log(d.val()); } } @@ -1097,41 +1069,10 @@ function triggerChange(element){ element.dispatchEvent(changeEvent); } -// Training Analyst -function addTrainingRow() { - var trainingname = $('.trainingname').val(); - var trainingdate = $('.trainingdate').val(); - - if (trainingname == "" || trainingdate == "") { - alert("Nama dan tanggal tidak boleh kosong"); - return; - } - - var newRow = " "+ - " "+trainingname+" "+trainingdate+""+ - " "; - $("#training_table").append(newRow); - - $('.trainingname').val(''); -} -function deleteTrainingRow(btn, trainingid) { - if(confirm('Are you sure?')) { - var row = btn.parentNode.parentNode; - row.parentNode.removeChild(row); - if (trainingid > 0) { - var trainingid = trainingid.toString(); - var d = $('#trainingid_delete'); - d.val(d.val()+' '+trainingid); - console.log(d.val()); - } - } -} -// flatpickr for training date -flatpickr(".trainingdate", { allowInput: true, dateFormat: "Y-m-d" }); // Training checkbox enable/disable accordion function toggleTrainingAccordion() { - var trainingChecked = $('#training').prop('checked'); - var trainingDisabled = $('#training').prop('disabled'); + let trainingChecked = $('#training').prop('checked'); + let trainingDisabled = $('#training').prop('disabled'); if (trainingChecked && !trainingDisabled) { // Enable accordion $('#accordionTraining').find('button').prop('disabled', false); @@ -1140,6 +1081,7 @@ function toggleTrainingAccordion() { $('#accordionTraining').find('button').removeClass('disabled'); $('#accordionTraining').removeClass('opacity-50').removeClass('pointer-events-none'); $('#accordionTraining').find('.accordion-button').attr('data-bs-toggle', 'collapse'); + } else { // Disable accordion $('#accordionTraining').find('button').prop('disabled', true); @@ -1184,53 +1126,48 @@ function toggleCalibrateAccordion() { $('#accordionCalibrate').find('.accordion-button').removeAttr('data-bs-toggle'); } } - // Initialize on page load -toggleCalibrateAccordion(); - +// toggleCalibrateAccordion(); // Event listener for calibration checkbox change -$('#calibration').change(function() { - toggleCalibrateAccordion(); -}); - +// $('#calibration').change(function() { +// toggleCalibrateAccordion(); +// }); // Event listener for calibration checkbox disable/enable (when acttypeid changes) -$('#acttypeid').change(function() { - toggleCalibrateAccordion(); -}); - +// $('#acttypeid').change(function() { +// toggleCalibrateAccordion(); +// }); // Calibrate -function addCalibrateRow() { - var calibratename = $('.calibratename').val(); - var calibratevalue = $('.calibratevalue').val(); - var calibrateunit = $('.calibrateunit').val(); +// function addCalibrateRow() { +// var calibratename = $('.calibratename').val(); +// var calibratevalue = $('.calibratevalue').val(); +// var calibrateunit = $('.calibrateunit').val(); - if (calibratename == "" || calibratevalue == "" || calibrateunit == "") { - alert("Nama parameter, nilai, dan satuan tidak boleh kosong"); - return; - } +// if (calibratename == "" || calibratevalue == "" || calibrateunit == "") { +// alert("Nama parameter, nilai, dan satuan tidak boleh kosong"); +// return; +// } - var newRow = " "+ - " "+calibratename+" "+calibratevalue+" "+calibrateunit+""+ - " "; - $("#calibrate_table").append(newRow); +// var newRow = " "+ +// " "+calibratename+" "+calibratevalue+" "+calibrateunit+""+ +// " "; +// $("#calibrate_table").append(newRow); - $('.calibratename').val(''); - $('.calibratevalue').val(''); - $('.calibrateunit').val(''); -} - -function deleteCalibrateRow(btn, calibrateid) { - if(confirm('Are you sure?')) { - var row = btn.parentNode.parentNode; - row.parentNode.removeChild(row); - if (calibrateid > 0) { - var calibrateid = calibrateid.toString(); - var d = $('#calibrateid_delete'); - d.val(d.val()+' '+calibrateid); - console.log(d.val()); - } - } -} +// $('.calibratename').val(''); +// $('.calibratevalue').val(''); +// $('.calibrateunit').val(''); +// } +// function deleteCalibrateRow(btn, calibrateid) { +// if(confirm('Are you sure?')) { +// var row = btn.parentNode.parentNode; +// row.parentNode.removeChild(row); +// if (calibrateid > 0) { +// var calibrateid = calibrateid.toString(); +// var d = $('#calibrateid_delete'); +// d.val(d.val()+' '+calibrateid); +// console.log(d.val()); +// } +// } +// } diff --git a/app/Views/activities_getsitecontacts.php b/app/Views/activities_getsitecontacts.php new file mode 100644 index 0000000..53440ef --- /dev/null +++ b/app/Views/activities_getsitecontacts.php @@ -0,0 +1,319 @@ +
+
+ +
+
+ + + + +
+
+ + +
+
+ + +
+ +
+
+ + +
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NoInitialNama AnalystTitleEmailTanggalAction
+ + + + + + +
+
+ + + \ No newline at end of file diff --git a/app/Views/certificate_training_index.php b/app/Views/certificate_training_index.php index 0e5a1b5..a9ae667 100644 --- a/app/Views/certificate_training_index.php +++ b/app/Views/certificate_training_index.php @@ -3,209 +3,166 @@ section('content') ?>
-
-
-
-

Certificates Training Management

-
-
+
+
+
+

Certificates Training Management

+
+
-
-
-
-
-
-
-
- - -
-
-
- -
-
- -
-
- -
-
+
+
+
+
+
+
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
-
- - - - - - - + + + + +
Certificate NameProduct/EquipmentActivity ReportIssue DateExpiry DateStatusActionCertificateAct ReportIssue DateValidationAction
-
-
-
-
-
-
-
- - - +
-
-
- -
- -
-
-
+ + +
+
endSection() ?> section('style') ?> - endSection() ?> section('script') ?> @@ -213,7 +170,7 @@ $(function () { let table = $('#certificatesTable').DataTable({ - order: [[5, 'asc']], + order: [[3, 'asc']], // Order by Validation Column pageLength: 25, dom: '<"row"<"col-md-6"l>>rtip', responsive: true, @@ -224,53 +181,43 @@ $(function () { .then(response => response.json()) .then(result => { callback({ - data: result.map(cert => { - let certid = cert.certid || ''; - let certname = cert.certname || '-'; - let productname = cert.productname || '-'; - let productnumber = cert.productnumber || ''; - let issuedateRaw = cert.issuedate || ''; - let expirydateRaw = cert.expirydate || ''; - let vendor = cert.vendor || '-'; - let isval = cert.isval || null; + data: result.map((cert, index) => { + + let certid = cert.cert_id || ''; + let certname = cert.cert_name || '-'; + let certnumber = cert.cert_number || ''; + let actid = cert.actid || ''; + let issuedateRaw = cert.issued_date || ''; + let status = cert.status; // Validation status + let fullname = cert.fullname; + let activity_subject = cert.activity_subject; let issuedate = '-'; - let expirydate = '-'; - let statusBadge = 'Need Validation'; + let validationBadge = ''; - if (isval != null) { - if (issuedateRaw && issuedateRaw !== '0000-00-00') { - issuedate = new Date(issuedateRaw).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }); - } + if (issuedateRaw && issuedateRaw !== '0000-00-00') { + let date = new Date(issuedateRaw); + let day = String(date.getDate()).padStart(2, '0'); + let month = date.toLocaleString('en-US', { month: 'short' }); + let year = date.getFullYear(); + issuedate = `${day} ${month} ${year}`; + } - if (expirydateRaw && expirydateRaw !== '0000-00-00') { - expirydate = new Date(expirydateRaw).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }); - let today = new Date(); - let expiryDate = new Date(expirydateRaw); - let days = Math.ceil((expiryDate - today) / (1000 * 60 * 60 * 24)); - - if (days < 0) { - statusBadge = 'Expired'; - } else if (days <= 30) { - statusBadge = 'Expiring Soon'; - } else { - statusBadge = 'Active'; - } - } else { - statusBadge = 'N/A'; - } + if (status == 'unvalidated') { + validationBadge = '
unvalidated
'; + } else { + validationBadge = '
validated
'; } return [ - `${certname}
ID: ${certid}`, - `${productname}${productnumber ? '
SN: ' + productnumber + '' : ''}`, - `Act ID - Nama AR - Nama User `, + `${certname}
Cert# : ${certnumber}`, + `#${actid} - ${activity_subject}  
Owner : ${fullname}
`, issuedate, - expirydate, - statusBadge, - isval == null - ? `
` - : `
` + validationBadge, + status == 'unvalidated' + ? `
` + : `
+
` ]; }) }); @@ -280,19 +227,26 @@ $(function () { callback({ data: [] }); }); }, - columnDefs: [{ - targets: 5, - render: function (data, type) { - if (type === 'sort') { - if (data.includes('Need Validation')) return 1; - if (data.includes('Expired')) return 2; - if (data.includes('Expiring Soon')) return 3; - if (data.includes('Active')) return 4; - return 5; + columnDefs: [ + { + // Kondisi untuk Kolom 3 (Validation) + targets: 3, + render: function (data, type) { + if (type === 'sort') { + let val = data.toLowerCase(); + if (val.includes('unvalidated')) return 1; + if (val.includes('validated')) return 2; + return 3; + } + return data; } - return data; + }, + { + // Kondisi untuk Kolom 4 (Action) + targets: [4], + orderable: false } - }] + ] }); $('#certificatesTable_filter').hide(); @@ -303,70 +257,111 @@ $(function () { }); // Type filter using DataTables column filter - $('#typeFilter').on('change', function () { + $('#productFilter').on('change', function () { let type = $(this).val(); - // Filter by type column (index 1 - Certificate Name contains type info) if (type === '') { - table.column(1).search('').draw(); + table.column(0).search('').draw(); } else { - // Capitalize first letter for search let typeText = type.charAt(0).toUpperCase() + type.slice(1); - table.column(1).search(typeText).draw(); + table.column(0).search(typeText).draw(); } }); - // Status filter - $('#statusFilter').on('change', function () { - let map = { - active: 'Active', - expired: 'Expired', - expiring: 'Expiring Soon', - isval: 'Need Validation' - }; - table.column(5).search(map[this.value] || '').draw(); + $('#validationFilter').on('change', function () { + let validation = $(this).val(); + if (validation === '') { + table.column(3).search('').draw(); + } else if (validation === 'unval') { + table.column(3).search('unv').draw(); + } else if (validation === 'valid') { + table.column(3).search('^validated$', true, false).draw(); + } }); // Reset window.resetFilters = function () { - $('#searchInput, #statusFilter').val(''); - table.search('').columns().search('').order([5,'asc']).draw(); + $('#searchInput, #productFilter, #validationFilter').val(''); + table.search('').columns().search('').draw(); }; // View PDF $(document).on('click', '.btn-view', function () { - let certid = $(this).data('certid'); - window.open('' + certid, '_blank'); + let certnumber = $(this).data('certnumber'); + window.open('' + certnumber, '_blank'); }); // Activity report $(document).on('click', '.activity-report-link', function () { - let certid = $(this).data('certid'); + let actid = $(this).data('actid'); window.open( - '' + certid, + '' + actid, '_blank', 'width=1200,height=800,scrollbars=yes,resizable=yes' ); }); // Open modal - $(document).on('click', '.btn-validate', function () { + $(document).on('click', '.btn-validate-modal', function () { let btn = $(this); + let certid = btn.data('certid'); - $('#modalCertId').text(btn.data('certid')); - $('#modalCertName').text(btn.data('certname')); - $('#modalProductName').text(btn.data('productname')); - $('#modalProductNumber').text(btn.data('productnumber')); - $('#modalIssueDate').text(btn.data('issuedate')); - $('#modalExpiryDate').text(btn.data('expirydate')); - $('#modalVendor').text(btn.data('vendor')); + // POST API call to fetch certificate data + $.post( + '', + { certid }, + function (data) { - $('#confirmValidateBtn').data('certid', btn.data('certid')); - $('#certificatePreview').attr( - 'src', - '' + btn.data('certid') - ); + // console.log(data); + $('#modalCertName').text(data.cert_name || '-'); + $('#modalCertNumber').text(data.cert_number || '-'); + $('#modalProductName').text(data.productname || '-'); + $('#modalProductNumber').text(data.productnumber || '-'); + $('#modalIssueDate').text(data.issued_date || '-'); + $('#modalAnalystName').text(data.fullname || '-'); + $('#modalSiteName').text(data.sitename || '-'); + + // Cek status validasi + const isValid = data.status === 'validated'; + const theme = isValid ? 'success' : 'warning'; + const icon = isValid ? 'fa-regular fa-circle-check' : 'fa-solid fa-triangle-exclamation'; + const note = isValid + ? 'Sertifikat Sudah Divalidasi' + : 'Review data berikut dengan teliti, setelah divalidasi maka sertifikat akan dinyatakan Valid dan sah secara sistem.'; + + $('#modalHeader').removeClass('bg-warning bg-success').addClass(`bg-${theme} text-dark`); + $('#modalValidation').html( + ` + ${data.status || '-'} + ` + ); + + $('#modalInfo').html( + `
+ +
+ Validation Note:
+ ${note} +
+
` + ); + + $('#modalActivity').text(data.actid ? `#${data.actid} - ${data.subject || '-'}` : '-'); + $('#modalActivityLink').attr('data-actid', data.actid || ''); + $('#modalValOwner').html(data.user_validation_at ? `${data.username} - ${data.user_validation_at}` : '-'); + $('#modalValSpv').html(data.spv_validation_at ? `${data.spvname} - ${data.spv_validation_at}` : '-'); + $('#modalValManager').html(data.manager_validation_at ? `${data.managername} - ${data.manager_validation_at}` : '-'); + }, + 'json' + ).fail(function (xhr) { + console.log(xhr); + alert(xhr.responseText); + }); + + // INI JANGAN DIUBAH + $('#confirmValidateBtn').data('certid', certid); + $('#certificatePreview').attr('src','' + certid); $('#validateModal').modal('show'); }); @@ -379,63 +374,25 @@ $(function () { if (!confirm('Are you sure?')) return; $.post( - '', + '', { certid, certificateType}, function (response) { if (response.success) { $('#validateModal').modal('hide'); alert(response.message); - - // Generate and save PDF after successful validation - $.post( - '', - { certid, certificateType }, - function (pdfResponse) { - if (pdfResponse.success) { - alert('PDF generated and saved successfully!'); - location.reload(); - } else { - alert('Validation successful but PDF generation failed: ' + (pdfResponse.message || 'Unknown error')); - location.reload(); - } - }, - 'json' - ).fail(function () { - alert('Validation successful but failed to generate PDF'); - location.reload(); - }); - + location.reload(); } else { alert(response.message || 'Validation failed'); } }, 'json' - ).fail(function () { - $('#validateModal').modal('hide'); - alert('Server error.'); + ).fail(function (xhr) { + console.log(xhr); + alert(xhr.responseText); }); - }); - // Delete training user - window.deleteTrainingUser = function(btn) { - if(confirm('Are you sure you want to delete this user?')) { - var row = btn.closest('tr'); - row.remove(); - updateRowNumbers(); - } - }; - - // Update row numbers after deletion - function updateRowNumbers() { - var tbody = $('#training-table'); - var rows = tbody.find('tr'); - rows.each(function(index) { - $(this).find('td:first').text(index + 1); - }); - } - }); endSection() ?> \ No newline at end of file diff --git a/app/Views/certificates/certificate_training.php b/app/Views/certificates/certificate_training.php index 740e85e..0da5785 100644 --- a/app/Views/certificates/certificate_training.php +++ b/app/Views/certificates/certificate_training.php @@ -2,14 +2,15 @@ - Maintenance Certificate - <?= $certificate['certname'] ?> + <?= $certificate['certname'] ?> + + - + +
+ + +
-

<<Nama Analis>>

+

-

at <<Nama Rumah Sakit / Laboratorium - Kota>>

+

~

-

In Recording of Participation and Successful

-

Completion of Mindray Hematology Analyzer Training

-

BC5140

-

Date : February 05, 2026

+ + + +

In Recording of Participation and Successful Completion of

+

User Training

+

+

Date:

+
+ - +
-
-
-
-
+ +
- Trainer, -
-
-
- <<Nama TSO>> - <<Jabatan>> -
-

<<FO>>

+

FO.III.12/14.00/2020

-
- + + +
+
+

+
+ +
+

~

+
+ +
+ + + +

In Recording of Participation and Successful Completion of

+

User Training

+

+

Date:

+ +
+ + + + + + + + +
+ +
+ +
+

FO.III.12/14.00/2020

+
+
- - + diff --git a/app/Views/layouts/_sidebar.php b/app/Views/layouts/_sidebar.php index 9e4344a..13325ab 100644 --- a/app/Views/layouts/_sidebar.php +++ b/app/Views/layouts/_sidebar.php @@ -42,11 +42,15 @@ + + +
  • +