diff --git a/app/Config/Filters.php b/app/Config/Filters.php
index fb757f0..74e7326 100644
--- a/app/Config/Filters.php
+++ b/app/Config/Filters.php
@@ -76,7 +76,7 @@ class Filters extends BaseFilters
'before' => [
// 'cors',
'auth' => [ 'except' => [
- 'auth/*', 'lqms/*', 'key/*', 'api/*'
+ 'auth/*', 'lqms/*', 'key/*', 'api/*', 'certificates/number/*'
]]
// 'honeypot',
// 'csrf',
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 24bfcbb..1130749 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -211,24 +211,30 @@ $routes->group('certificates', function($routes) {
// Untuk Index Tiap Menu
$routes->get('maintenance', 'Certificates::maintenanceIndex'); // OK
- $routes->get('installation', 'Certificates::installationIndex');
- $routes->get('training', 'Certificates::trainingIndex');
- $routes->get('calibration', 'Certificates::calibrateIndex');
-
+ // $routes->get('installation', 'Certificates::installationIndex'); // 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/getindextraining', 'Certificates::getDataIndexTraining');
+ // $routes->get('api/getindexinstallation', 'Certificates::getDataIndexInstallation'); // OK
+ // $routes->get('api/getindextraining', 'Certificates::getDataIndexTraining'); // OK
+ // $routes->get('api/getindexcalibrate', 'Certificates::getDataIndexCalibrate');
+ $routes->post('api/showmaintenance', 'Certificates::showDataMaintenance'); // OK
- $routes->post('api/validateCertificate', 'Certificates::validateCertificate'); // OK
- $routes->post('api/generatepdf', 'Certificates::generatePdf'); // OK
-
-
- // Untuk View Cerificate
+ // Untuk Preview Cerificate
$routes->get('maintenance/show/(:any)', 'Certificates::createMaintenancePreview/$1'); // OK
- $routes->get('training/show/(:any)', 'Certificates::createTraining/$1');
- $routes->get('calibration/show/(:any)/(:any)', 'Certificates::createCalibrate/$1/$2');
+ // $routes->get('installation/show/(:any)', 'Certificates::createInstallationPreview/$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
+
+ $routes->get('maintenance/number/$1', 'Certificates::getMaintenanceCertificate'); // OK
+
+ $routes->get('number/(:segment)', 'Certificates::view/$1');
+
});
diff --git a/app/Controllers/Activities.php b/app/Controllers/Activities.php
index d1260f7..9ffc600 100644
--- a/app/Controllers/Activities.php
+++ b/app/Controllers/Activities.php
@@ -2,6 +2,7 @@
namespace App\Controllers;
+use App\Models\CertificateModel;
use App\Models\ActivitiesModel;
use App\Models\ActdetailModel;
use App\Models\InvTransModel;
@@ -441,7 +442,6 @@ class Activities extends Controller {
$sql = "INSERT INTO actstatus_log (activityid, activitystatus, userid, logdate)
VALUES ($actid,'$actstatus', $userid, NOW())";
$query = $db->query($sql);
-
$acttextid = $data['new_value']['acttextid'];
$textvalue = $data['new_value']['textvalue'];
foreach($data['new_value']['acttextid'] as $qindex => $qacttextid) {
@@ -449,6 +449,33 @@ class Activities extends Controller {
$sql = "insert into actdetail (actid, acttextid, textvalue, createdate) values ('$actid','$qacttextid', '$qtextvalue', NOW())";
$query = $db->query($sql);
}
+
+ // UNTUK CERTIFICATES
+ $sql = "SELECT prl.productaliastext as productname, pr.productnumber as snnumber, st.sitename
+ FROM `activities` act
+ LEFT JOIN sites st ON st.siteid = act.siteid
+ 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();
+ if ($this->request->getVar('maintenance')) { // Maintenance
+ $issuedDate = $data['new_value']['closedate'] ?? null;
+ $expiredDate = date('Y-m-d', strtotime($issuedDate . ' + 6 months'));
+ $insertCert = [
+ 'cert_name' => "MC_" . ($result['productname'] ?? 'UNKNOWN') . "_" . ($result['snnumber'] ?? '0') . "_" . $actid,
+ 'cert_type' => "MC",
+ 'actid' => $actid,
+ 'issued_date' => $issuedDate,
+ 'expired_date' => $expiredDate,
+ 'user_id' => $data['new_value']['userid_owner']
+ ];
+ $certificateModel = new CertificateModel();
+ $certificateModel->insert($insertCert);
+ }
+
+
} else {
// update edit
$activitiesModel = new ActivitiesModel();
diff --git a/app/Controllers/Certificates.php b/app/Controllers/Certificates.php
index 89c2a29..6945779 100644
--- a/app/Controllers/Certificates.php
+++ b/app/Controllers/Certificates.php
@@ -6,6 +6,8 @@ use App\Controllers\BaseController;
use Dompdf\Dompdf;
use Dompdf\Options;
+use App\Models\CertificateModel;
+
class Certificates extends BaseController {
protected array $data;
@@ -16,17 +18,6 @@ class Certificates extends BaseController {
}
public function getDataIndexInstallation() { // Untuk API Get Data
// $actid = $this->request->getVar('actid'); Siapa Tahu Buat
- }
- public function createinstallationPreview($certid = null) { // Untuk Preview Sertifikat
- //Melakukan search data dari database
- }
-
- // Untuk Sertifikat Maintenance [2]
- public function maintenanceIndex() { // Index
- return view('certificate_maintenance_index');
- }
- public function getDataIndexMaintenance() { // Untuk API Get Data
- // $actid = $this->request->getVar('actid'); Siapa Tahu Buat
$certificates = [
[
@@ -45,10 +36,30 @@ class Certificates extends BaseController {
'productname' => 'GE Healthcare VIVID',
'productnumber' => 'GE-VIV-Q992',
'issuedate' => '2024-06-12',
- 'expirydate' => '2026-10-01',
+ 'expirydate' => '2026-03-01',
'vendor' => 'Pramita Medika Service',
'isval' => '2026-03-01'
- ]
+ ],
+ [
+ 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11915',
+ '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-09-01'
+ ],
+ [
+ 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11915',
+ 'certname' => 'Electrical Safety Test',
+ 'productname' => 'GE Healthcare VIVID',
+ 'productnumber' => 'GE-VIV-Q992',
+ 'issuedate' => '2024-06-12',
+ 'expirydate' => '2026-01-01',
+ 'vendor' => 'Pramita Medika Service',
+ 'isval' => '2026-09-01'
+ ],
];
// If no actid, return all certificates
@@ -58,7 +69,7 @@ class Certificates extends BaseController {
return $this->response->setJSON($certificates);
}
- public function createMaintenancePreview($certid = null) { // Untuk Preview Sertifikat
+ public function createinstallationPreview($certid = null) { // Untuk Preview Sertifikat
//Melakukan search data dari database
if (!$certid) {
@@ -81,9 +92,167 @@ class Certificates extends BaseController {
return $this->response->setStatusCode(404)->setJSON(['error' => 'Maintenance certificate not found']);
}
+ return $this->previewPdf($certificate, 'installation'); // Preview PDF
+ }
+
+
+ // Untuk Sertifikat Maintenance [2]
+ public function maintenanceIndex() { // Index
+ return view('certificate_maintenance_index');
+ }
+ public function getDataIndexMaintenance() {
+ $userPosId = session()->get('userposid');
+ $userId = session()->get('userid');
+
+ $certificateModel = new CertificateModel();
+
+ // 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');
+
+ // 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([]);
+ }
+
+ // 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 showDataMaintenance() { // 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 "Before After Inspection"
+ WHEN certificates.cert_type = "BAP" THEN "Berita Acara Pengerjaan"
+ 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
+ ', 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')
+ ->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 createMaintenancePreview($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,
+ productcatalog.productname 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 "User Training"
+ WHEN certificates.cert_type = "BAI" THEN "Before After Inspection"
+ WHEN certificates.cert_type = "BAP" THEN "Berita Acara Pengerjaan"
+ 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')
+ ->where('certificates.cert_id', $certid)
+ ->first();
+ $certificate = [
+ 'certname' => $data['cert_name'],
+ 'sitename' => $data['sitename'],
+ '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 (empty($certificate)) { // Jika Tidak Ada
+ return $this->response->setStatusCode(404)->setJSON(['error' => 'Maintenance certificate not found']);
+ }
+
return $this->previewPdf($certificate, 'maintenance'); // Preview PDF
}
+
// Untuk Sertifikat Training [3]
public function trainingIndex() {
return view('certificate_training_index');
@@ -94,40 +263,24 @@ class Certificates extends BaseController {
// Sample data - replace with actual database query
$certificates = [
[
- 'certid' => 'CERT001',
+ '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',
- 'type' => 'joko',
- 'sitename' => 'Jakarta Office',
- 'siteid' => 'SITE001'
+ 'isval' => null
],
[
- 'certid' => 'CERT002',
- 'certname' => 'TMS50i Calibration Certificate',
- 'productname' => 'TMS50i',
- 'productnumber' => 'SN-2024-002',
- 'issuedate' => '2024-02-15',
- 'expirydate' => '2025-02-15',
- 'vendor' => 'Summit Calibration Lab',
- 'type' => 'tms',
- 'sitename' => 'Surabaya Office',
- 'siteid' => 'SITE002'
- ],
- [
- 'certid' => 'CERT003',
- 'certname' => 'Tokyo Boeki Calibration Certificate',
- 'productname' => 'Tokyo Boeki',
- 'productnumber' => 'SN-2024-003',
- 'issuedate' => '2024-03-15',
- 'expirydate' => '2025-03-15',
- 'vendor' => 'Summit Calibration Lab',
- 'type' => 'boeki',
- 'sitename' => 'Bandung Office',
- 'siteid' => 'SITE003'
+ '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'
]
];
@@ -138,15 +291,100 @@ class Certificates extends BaseController {
return $this->response->setJSON($certificates);
}
+ public function createTrainingPreview($certid = null) { // Untuk Preview Sertifikat
+ //Melakukan search data dari database
+
+ 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
+ }
+
// Untuk Sertifikat Calibrate [4]
public function calibrateIndex() {
- return view('certificate_calibration_index');
+ return view('certificate_calibrate_index');
+ }
+ public function getDataIndexCalibrate() {
+ // $actid = $this->request->getVar('actid');
+
+ // 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'
+ ]
+ ];
+
+ // If no actid, return all certificates
+ if (empty($certificates)) {
+ return $this->response->setJSON(null);
+ }
+
+ return $this->response->setJSON($certificates);
+ }
+ public function createCalibratePreview($certid = null) { // Untuk Preview Sertifikat
+ //Melakukan search data dari database
+
+ 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, 'calibrate', 'tms24i'); // Preview PDF
}
// Helper Function Preview dan Validate
- private function previewPdf($certificate, $type, $productType=null) { // Untuk Show/Preview PDF
+ private function previewPdf($certificate, $type) { // Untuk Show/Preview PDF
// Generate PDF
$options = new Options();
$options->set('isRemoteEnabled', true);
@@ -156,27 +394,11 @@ class Certificates extends BaseController {
$dompdf = new Dompdf($options);
// Format dates
- $issuedate = date('F d, Y', strtotime($certificate['issuedate']));
- $expirydate = date('F d, Y', strtotime($certificate['expirydate']));
-
- // Get status
- $today = date('Y-m-d');
- $expiryCheck = date('Y-m-d', strtotime($certificate['expirydate']));
- $daysUntilExpiry = (strtotime($expiryCheck) - strtotime($today)) / (60 * 60 * 24);
-
- if ($daysUntilExpiry < 0) {
- $status = 'Expired';
- $statusColor = '#dc3545';
- } elseif ($daysUntilExpiry <= 30) {
- $status = 'Expiring Soon';
- $statusColor = '#ffc107';
- } else {
- $status = 'Active';
- $statusColor = '#28a745';
- }
+ $certificate['issueddate'] = date('d-M-Y', strtotime($certificate['issueddate']));
+ $certificate['expireddate'] = date('d-M-Y', strtotime($certificate['expireddate']));
// Select template and orientation based on type
- $template = 'certificate_pdf';
+ $template = '';
$orientation = 'portrait';
switch($type) {
@@ -210,15 +432,13 @@ class Certificates extends BaseController {
$template = 'certificates/certificate_maintenance';
$orientation = 'landscape';
break;
+ case 'installation':
+ $template = 'certificates/certificate_installation';
+ $orientation = 'landscape';
+ break;
}
- $html = view($template, [
- 'certificate' => $certificate,
- 'issuedate' => $issuedate,
- 'expirydate' => $expirydate,
- 'status' => $status,
- 'statusColor' => $statusColor
- ]);
+ $html = view($template, [ 'certificate' => $certificate]);
$dompdf->loadHtml($html);
// $dompdf->set_option('isRemoteEnabled', true);
@@ -226,203 +446,283 @@ class Certificates extends BaseController {
$dompdf->render();
// Output PDF
- $filename = 'Certificate_' . $certificate['certid'] . '.pdf';
+ $filename = $certificate['certname']. '.pdf';
$dompdf->stream($filename, ['Attachment' => false]);
}
- public function validateCertificate() { // Untuk Validasi Certificate
+ public function validateCertificate() {
$certid = $this->request->getPost('certid');
- $certificateType = $this->request->getPost('certificateType');
+ $certificateType = $this->request->getPost('certificateType');
- if (!$certid) {
- return $this->response->setJSON([
- 'success' => false,
- 'message' => 'Certificate ID is required'
- ]);
+ if (!$certid || !$certificateType) {
+ return $this->response->setJSON(['success' => false, 'message' => 'Parameter tidak lengkap.']);
}
- // Dummy data certificates
- $certificates = [
- 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11914',
- 'certname' => 'Jokoh Calibration Certificate',
- 'productname' => 'Jokoh',
- 'productnumber' => 'SN-2024-001',
- 'issuedate' => '2024-01-15',
- 'expirydate' => '2025-01-15',
- 'vendor' => 'Summit Calibration Lab',
- 'isval' => null
- ];
+ $userId = session()->get('userid');
+ $userPosId = session()->get('userposid');
+ $certificateModel = new CertificateModel();
- if ($certificates['certid'] === $certid) {
- return $this->response->setJSON([
- 'success' => true,
- 'message' => 'Certificate has already been validateda'
- ]);
- } else {
- return $this->response->setJSON([
- 'success' => false,
- 'message' => 'Certificate not found'
- ]);
+ // 1. Ambil data dasar saja dulu untuk pengecekan awal
+ $currentCert = $certificateModel->find($certid);
+
+ if (!$currentCert) {
+ return $this->response->setJSON(['success' => false, 'message' => 'Data tidak ditemukan.']);
}
- // $validationDate = date('Y-m-d');
+ $updateData = [];
+ $currentTime = date('Y-m-d H:i:s');
- // return $this->response->setJSON([
- // 'success' => true,
- // 'message' => 'Certificate validated ' . $certificateType,
- // 'validationDate' => $validationDate
- // ]);
- }
-
-
- // Helper Generate dan Save PDF
- public function generatePdf() {
- $certid = $this->request->getPost('certid');
- $certificateType = $this->request->getPost('certificateType');
-
- if (!$certid) {
- return $this->response->setJSON([
- 'success' => false,
- 'message' => 'Certificate ID is required'
- ]);
+ // 2. Filter Role & Cek Duplikasi
+ switch ($userPosId) {
+ case 1: // Manager
+ if (!empty($currentCert['manager_validation_at']))
+ return $this->response->setJSON(['success' => false, 'message' => 'Anda sudah Melakukan Validasi.']);
+ $updateData = ['manager_id' => $userId, 'manager_validation_at' => $currentTime];
+ break;
+ case 2: // SPV
+ if (!empty($currentCert['spv_validation_at']))
+ return $this->response->setJSON(['success' => false, 'message' => 'Anda sudah Melakukan Validasi.']);
+ $updateData = ['spv_id' => $userId, 'spv_validation_at' => $currentTime];
+ break;
+ case 4: // TSOIVD
+ if ($currentCert['user_id'] != $userId)
+ return $this->response->setJSON(['success' => false, 'message' => 'Bukan pemilik sertifikat.']);
+ if (!empty($currentCert['user_validation_at']))
+ return $this->response->setJSON(['success' => false, 'message' => 'Anda sudah Melakukan Validasi.']);
+ $updateData = ['user_validation_at' => $currentTime];
+ break;
+ default:
+ return $this->response->setJSON(['success' => false, 'message' => 'Akses ditolak.'], 403);
}
- // Dummy data certificates
- $certificate = [
- 'certid' => 'f353ca91-4fc5-49f2-9b9e-304f83d11914',
- 'certname' => 'Jokoh Calibration Certificate',
- 'productname' => 'Jokoh',
- 'productnumber' => 'SN-2024-001',
- 'issuedate' => '2024-01-15',
- 'expirydate' => '2025-01-15',
- 'vendor' => 'Summit Calibration Lab',
- 'isval' => null
- ];
+ // 3. Eksekusi Update Validasi Role
+ if ($certificateModel->update($certid, $updateData)) {
+
+ // 4. Cek apakah ini validasi terakhir?
+ // Ambil ulang data terbaru (cukup kolom validation saja untuk efisiensi)
+ $checkFinal = $certificateModel->select('user_validation_at, spv_validation_at, manager_validation_at')
+ ->find($certid);
- if (empty($certificate)) {
- return $this->response->setJSON([
- 'success' => false,
- 'message' => 'Certificate not found'
- ]);
- }
+ if (!empty($checkFinal['user_validation_at']) &&
+ !empty($checkFinal['spv_validation_at']) &&
+ !empty($checkFinal['manager_validation_at'])) {
+
+ // Update Status Utama
+ $certificateModel->update($certid, ['status' => 'validated']);
- try {
- $filePath = $this->savePdf($certificate, $certificateType, null);
+ // Baru jalankan query berat JOIN di sini untuk keperluan PDF/Notifikasi
+ $latestData = $certificateModel->select('
+ certificates.cert_name,
+ certificates.issued_date,
+ certificates.expired_date,
+ productcatalog.productname 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 "Before After Inspection"
+ WHEN certificates.cert_type = "BAP" THEN "Berita Acara Pengerjaan"
+ 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')
+ ->where('certificates.cert_id', $certid)
+ ->first();
+ $certificate = [
+ 'certname' => $latestData['cert_name'],
+ 'sitename' => $latestData['sitename'],
+ 'certtype' => $latestData['cert_type'],
+ 'fullname' => $latestData['fullname'],
+ 'userposition' => $latestData['user_position'],
+ 'productname' => $latestData['productname'],
+ 'productnumber' => $latestData['productnumber'],
+ 'issueddate' => $latestData['issued_date'],
+ 'expireddate' => $latestData['expired_date']
+ ];
+
+ try {
+ $pdfAfterValidation = $this->savePdf($certificate, $latestData['cert_type']); // Simpan ke PDF
+
+ $certificateModel->update($certid, [ // Update ke tabel certificates
+ 'file_location' => $pdfAfterValidation['file_relative'],
+ 'metadata_title' => $pdfAfterValidation['metadata_title'],
+ 'metadata_keywords' => $pdfAfterValidation['metadata_keywords'],
+ 'file_url' => base_url('certificates/number/'.$latestData['cert_number'])
+ ]);
+
+ return $this->response->setJSON([
+ 'success' => true,
+ 'message' => 'Semua validasi telah dilakukan, PDF sudah di generate'
+ ]);
+
+ } catch (\Throwable $e) {
+
+ return $this->response->setStatusCode(500)->setJSON([
+ 'success' => false,
+ 'message' => $e->getMessage()
+ ]);
+ }
- if (!$filePath) {
- return $this->response->setJSON([
- 'success' => false,
- 'message' => 'Failed to generate PDF'
- ]);
}
-
- $relativePath = str_replace(FCPATH, '', $filePath);
-
return $this->response->setJSON([
'success' => true,
- 'message' => 'PDF generated and saved successfully',
- 'filePath' => $relativePath
- ]);
-
- } catch (\Exception $e) {
- return $this->response->setJSON([
- 'success' => false,
- 'message' => 'Failed to generate PDF: ' . $e->getMessage()
+ 'message' => "Sertifikat {$certificateType} berhasil divalidasi."
]);
}
+
+ return $this->response->setJSON(['success' => false, 'message' => 'Gagal memperbarui data.']);
}
- private function savePdf($certificate, $type, $productType=null) {
- // Generate PDF
+ public function savePdf($certificate, $certificateType, $productType = null) {
+ $certificateType = strtolower($certificateType);
+
+ switch ($certificateType) {
+ case 'training':
+ $template = 'certificates/certificate_training';
+ $orientation = 'landscape';
+ $subDir = 'training';
+ break;
+
+ case 'calibration':
+ $orientation = 'portrait';
+ $subDir = 'calibration';
+
+ switch ($productType) {
+ case 'tms50i':
+ $template = 'certificates/callibrations_template/certificate_tms50i_calibration';
+ break;
+ case 'tms24i':
+ $template = 'certificates/callibrations_template/certificate_tms24i_calibration';
+ break;
+ case 'tms30i':
+ $template = 'certificates/callibrations_template/certificate_tms30i_calibration';
+ break;
+ case 'bs430':
+ $template = 'certificates/callibrations_template/certificate_bs430_calibration';
+ break;
+ case 'cl900i':
+ $template = 'certificates/callibrations_template/certificate_cl900i_calibration';
+ break;
+ case 'jokoh':
+ $template = 'certificates/callibrations_template/certificate_jokoh_calibration';
+ break;
+ case 'bc760r':
+ $template = 'certificates/callibrations_template/certificate_bc760r_calibration';
+ break;
+ case 'bc5140':
+ $template = 'certificates/callibrations_template/certificate_bc5140_calibration';
+ break;
+ default:
+ throw new \Exception('Product type calibration tidak valid');
+ }
+ break;
+
+ case 'maintenance':
+ $template = 'certificates/certificate_maintenance';
+ $orientation = 'landscape';
+ $subDir = 'maintenance';
+ break;
+
+ case 'installation':
+ $template = 'certificates/certificate_installation';
+ $orientation = 'landscape';
+ $subDir = 'installation';
+ break;
+
+ default:
+ throw new \Exception('Certificate type tidak valid');
+ }
+
+ if (empty($template)) {
+ throw new \Exception('Template tidak ditemukan');
+ }
+
+ // Dompdf
$options = new Options();
$options->set('isRemoteEnabled', true);
$options->set('isHtml5ParserEnabled', true);
$dompdf = new Dompdf($options);
-
- // Format dates
- $issuedate = date('F d, Y', strtotime($certificate['issuedate']));
- $expirydate = date('F d, Y', strtotime($certificate['expirydate']));
-
- // Get status
- $today = date('Y-m-d');
- $expiryCheck = date('Y-m-d', strtotime($certificate['expirydate']));
- $daysUntilExpiry = (strtotime($expiryCheck) - strtotime($today)) / (60 * 60 * 24);
-
- if ($daysUntilExpiry < 0) {
- $status = 'Expired';
- $statusColor = '#dc3545';
- } elseif ($daysUntilExpiry <= 30) {
- $status = 'Expiring Soon';
- $statusColor = '#ffc107';
- } else {
- $status = 'Active';
- $statusColor = '#28a745';
- }
-
- // Select template and orientation based on type
- $template = 'certificate_pdf';
- $orientation = 'portrait';
-
- switch($type) {
- case 'training':
- $template = 'certificates/certificate_training';
- $orientation = 'landscape';
- break;
- case 'calibration':
- if ($productType == 'tms50i') {
- $template = 'certificates/callibrations_template/certificate_tms50i_calibration';
- } else if ($productType == 'tms24i') {
- $template = 'certificates/callibrations_template/certificate_tms24i_calibration';
- } else if ($productType == 'tms30i') {
- $template = 'certificates/callibrations_template/certificate_tms30i_calibration';
- } else if ($productType == 'bs430') {
- $template = 'certificates/callibrations_template/certificate_bs430_calibration';
- } else if ($productType == 'cl900i') {
- $template = 'certificates/callibrations_template/certificate_cl900i_calibration';
- } else if ($productType == 'jokoh') {
- $template = 'certificates/callibrations_template/certificate_jokoh_calibration';
- } else if ($productType == 'bc760r') {
- $template = 'certificates/callibrations_template/certificate_bc760r_calibration';
- } else if ($productType == 'bc5140') {
- $template = 'certificates/callibrations_template/certificate_bc5140_calibration';
- } else {
- return $this->response->setStatusCode(404)->setJSON(['error' => 'Not Found']);
- }
- $orientation = 'portrait';
- break;
- case 'maintenance':
- $template = 'certificates/certificate_maintenance';
- $orientation = 'landscape';
- break;
- }
-
- $html = view($template, [
- 'certificate' => $certificate,
- 'issuedate' => $issuedate,
- 'expirydate' => $expirydate,
- 'status' => $status,
- 'statusColor' => $statusColor
- ]);
+ $html = view($template, ['certificate' => $certificate]);
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', $orientation);
$dompdf->render();
- // Generate filename with timestamp
- $timestamp = date('YmdHis');
- $filename = 'Certificate_' . $certificate['certid'] . '_' . $timestamp . '.pdf';
+ // Metadata
+ $dompdf->addInfo('Title', $certificate['certname']);
+ $dompdf->addInfo('Keywords', $certificate['certtype'] . ' Certificate');
+
+ // Folder
+ $uploadDir = FCPATH . 'upload/documents/' . $subDir;
- // Ensure upload directory exists
- $uploadDir = FCPATH . 'upload' . DIRECTORY_SEPARATOR . 'documents';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
- // Save PDF to file
+ // Safe filename
+ $cleanName = preg_replace('/[^A-Za-z0-9_\-]/', '_', $certificate['certname']);
+ $timestamp = date('YmdHis');
+ $filename = $cleanName . '_' . $timestamp . '.pdf';
+
$filePath = $uploadDir . DIRECTORY_SEPARATOR . $filename;
- file_put_contents($filePath, $dompdf->output());
- // Return file path
- return $filePath;
+ if (!file_put_contents($filePath, $dompdf->output())) {
+ throw new \Exception('Gagal menyimpan file PDF');
+ }
+
+ return [
+ 'file_name' => $filename,
+ 'file_path' => $filePath,
+ 'file_relative' => 'upload/documents/' . $subDir . '/' . $filename,
+ 'metadata_title' => $certificate['certname'],
+ 'metadata_keywords' => $certificate['certtype'] . ' Certificate'
+ ];
}
+ public function view($uuid) {
+ try {
+ $certificateModel = new CertificateModel();
+ // Ambil dari model (UUID → binary otomatis)
+ $certificate = $certificateModel->getByUuid($uuid);
+
+ if (!$certificate) {
+ throw new \Exception('Certificate tidak ditemukan');
+ }
+
+ if (empty($certificate['file_location'])) {
+ throw new \Exception('File PDF belum tersedia');
+ }
+
+ $filePath = FCPATH . $certificate['file_location'];
+
+ if (!file_exists($filePath)) {
+ throw new \Exception('File tidak ditemukan di server');
+ }
+
+ return $this->response
+ ->setHeader('Content-Type', 'application/pdf')
+ ->setHeader(
+ 'Content-Disposition',
+ 'inline; filename="' . basename($filePath) . '"'
+ )
+ ->setBody(file_get_contents($filePath));
+
+ } catch (\Throwable $e) {
+ return $this->response->setStatusCode(404)->setJSON([
+ // 'success' => false,
+ 'message' => "404 Not Found"
+ ]);
+ }
+ }
}
\ No newline at end of file
diff --git a/app/Models/CertificateModel.php b/app/Models/CertificateModel.php
new file mode 100644
index 0000000..ed3b77d
--- /dev/null
+++ b/app/Models/CertificateModel.php
@@ -0,0 +1,76 @@
+getBytes();
+ }
+ return $data;
+ }
+
+ /**
+ * Otomatis ubah Binary ke String UUID setelah data diambil (Get)
+ */
+ protected function convertBinaryToUuidString(array $data)
+ {
+ if (empty($data['data'])) return $data;
+
+ // Cek apakah data berupa single row atau multiple rows
+ if (isset($data['data']['cert_number'])) {
+ // Single row (find/first)
+ $data['data']['cert_number'] = Uuid::fromBytes($data['data']['cert_number'])->toString();
+ } else {
+ // Multiple rows (findAll)
+ foreach ($data['data'] as &$row) {
+ if (isset($row['cert_number'])) {
+ $row['cert_number'] = Uuid::fromBytes($row['cert_number'])->toString();
+ }
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Helper untuk mencari data berdasarkan String UUID
+ */
+ public function getByUuid(string $uuidString)
+ {
+ $binary = Uuid::fromString($uuidString)->getBytes();
+ return $this->where('cert_number', $binary)->first();
+ }
+}
\ No newline at end of file
diff --git a/app/Views/activities_editor.php b/app/Views/activities_editor.php
index 3b07d47..e96681f 100644
--- a/app/Views/activities_editor.php
+++ b/app/Views/activities_editor.php
@@ -609,6 +609,144 @@ if(isset($data)) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Nama Analis
+ Tanggal
+ Action
+
+
+
+ $qname $qdate ".
+ " Hapus ".
+ "";
+ }
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tambah
+
+
+
+
+
+
+ Nama Parameter
+ Nilai
+ Satuan
+ Action
+
+
+
+ $qname $qvalue $qunit ".
+ " Hapus ".
+ "";
+ }
+ }
+ ?>
+
+
+
+
+
+
+
+
+
@@ -634,6 +772,14 @@ if(isset($data)) {
= $this->endSection() ?>
= $this->section('script') ?>
+
= $this->endSection() ?>
+
diff --git a/app/Views/certificate_calibrate_index.php b/app/Views/certificate_calibrate_index.php
new file mode 100644
index 0000000..34777a9
--- /dev/null
+++ b/app/Views/certificate_calibrate_index.php
@@ -0,0 +1,382 @@
+= $this->extend('layouts/main.php') ?>
+
+= $this->section('content') ?>
+
+
+
+
+
+
Certificates Training Management
+
+
+
+
+
+
+
+
+
+
+
+ All Status
+ Active
+ Expired
+ Expiring Soon
+ Need Validation
+
+
+
+
+ All Types
+ TMS
+ Jokoh
+ Tokyo Boeki
+
+
+
+
+ Reset Filters
+
+
+
+
+
+
+
+
+
+ Certificate Name
+ Product/Equipment
+ Activity Report
+ Issue Date
+ Expiry Date
+ Status
+ Action
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Product/Equipment
+
-
+
+
+
+
+
+
+
+ Validation Information: Please review the certificate details above before validating. Once validated, the certificate status will change from "Need Validation" to "Active".
+
+
+
+
+
Certificate Preview
+
+
+
+
+
+
+
+
+
+
+
+
+= $this->endSection() ?>
+
+= $this->section('style') ?>
+
+= $this->endSection() ?>
+
+= $this->section('script') ?>
+
+= $this->endSection() ?>
\ No newline at end of file
diff --git a/app/Views/certificate_installation_index.php b/app/Views/certificate_installation_index.php
new file mode 100644
index 0000000..4a199a4
--- /dev/null
+++ b/app/Views/certificate_installation_index.php
@@ -0,0 +1,381 @@
+= $this->extend('layouts/main.php') ?>
+
+= $this->section('content') ?>
+
+
+
+
+
+
Certificates Installation Management
+
+
+
+
+
+
+
+
+
+
+
+ All Status
+ Active
+ Expired
+ Expiring Soon
+ Need Validation
+
+
+
+
+ All Types
+ TMS
+ Jokoh
+ Tokyo Boeki
+
+
+
+
+ Reset Filters
+
+
+
+
+
+
+
+
+
+ Certificate Name
+ Product/Equipment
+ Activity Report
+ Issue Date
+ Expiry Date
+ Status
+ Action
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Product/Equipment
+
-
+
+
+
+
+
+
+
+ Validation Information: Please review the certificate details above before validating. Once validated, the certificate status will change from "Need Validation" to "Active".
+
+
+
+
+
Certificate Preview
+
+
+
+
+
+
+
+
+
+
+
+
+= $this->endSection() ?>
+
+= $this->section('style') ?>
+
+= $this->endSection() ?>
+
+= $this->section('script') ?>
+
+= $this->endSection() ?>
\ No newline at end of file
diff --git a/app/Views/certificate_maintenance_index.php b/app/Views/certificate_maintenance_index.php
index 2441cf1..038621a 100644
--- a/app/Views/certificate_maintenance_index.php
+++ b/app/Views/certificate_maintenance_index.php
@@ -22,24 +22,30 @@
placeholder="Search certificates by name, product, type, vendor, or dates...">
-
+
- All Status
+ --Status Filter--
Active
Expired
Expiring Soon
- Need Validation
-
+
+
+ --Validation Filter--
+ Validated
+ Unvalidated
+
+
+
- All Types
+ --Product Filter--
TMS
- Jokoh
+ Jokoh
Tokyo Boeki
-
+
Reset Filters
@@ -51,13 +57,14 @@
- Certificate Name
- Product/Equipment
- Activity Report
- Issue Date
- Expiry Date
- Status
- Action
+ No
+ Certificate
+ Act Report
+ Issue Date
+ Expiry Date
+ Status
+ Validation
+ Action
@@ -77,63 +84,88 @@
-
-
-
-
Product/Equipment
-
-
-
-
-
-
-
-
+
+
+
+ Certificate Name
+
-
+
+
+
-
+
+
+
+
-
-
- Validation Information: Please review the certificate details above before validating. Once validated, the certificate status will change from "Need Validation" to "Active".
-
+
Certificate Number
+
-
+
+
+
Product/Equipment
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
Manager Validation
+
-
+
+
+
+
+
+
+ Validation Note:
+ Review data di berikut dengan teliti, setelah divalidasi maka sertifikat akan dinyatakan Valid dan sah secara sistem.
+
+
-
Certificate Preview
+
Certificate Preview
@@ -156,14 +188,6 @@
= $this->endSection() ?>
= $this->section('style') ?>
-
= $this->endSection() ?>
= $this->section('script') ?>
@@ -171,7 +195,7 @@
$(function () {
let table = $('#certificatesTable').DataTable({
- order: [[5, 'asc']],
+ order: [[4, 'asc']],
pageLength: 25,
dom: '<"row"<"col-md-6"l>>rtip',
responsive: true,
@@ -182,53 +206,73 @@ $(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) => {
+
+ // console.log(result);
+ 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 expirydateRaw = cert.expired_date || '';
+ let managerValidation = cert.manager_validation_at || null;
+ let spvValidation = cert.spv_validation_at || null;
+ let userValidation = cert.user_validation_at || null;
+ let status = cert.status;
+ let fullname = cert.fullname;
+ let activity_subject = cert.activity_subject;
let issuedate = '-';
let expirydate = '-';
- let statusBadge = '
Need Validation ';
+ // 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 ';
- }
+ if (expirydateRaw && expirydateRaw !== '0000-00-00') {
+ let date = new Date(expirydateRaw);
+ let day = String(date.getDate()).padStart(2, '0');
+ let month = date.toLocaleString('en-US', { month: 'short' });
+ let year = date.getFullYear();
+ expirydate = `${day} ${month} ${year}`;
+ 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 = '
N/A ';
+ 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 `,
+ index + 1,
+ `
${certname} Cert# : ${certnumber} `,
+ `
#${actid} - ${activity_subject} Owner : ${fullname} `,
issuedate,
expirydate,
statusBadge,
- isval == null
- ? `
`
- : `
`
+ validationBadge,
+ status == 'unvalidated'
+ ? `
`
+ : `
`
];
})
});
@@ -238,19 +282,29 @@ $(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: [
+ {
+ targets: 4,
+ 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;
+ }
+ return data;
}
- return data;
+ },
+ {
+ targets: [5, 6],
+ orderable: false
+ },
+ {
+ targets: 7,
+ orderable: false
}
- }]
+ ]
});
$('#certificatesTable_filter').hide();
@@ -274,57 +328,103 @@ $(function () {
}
});
- // 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();
+ let status = $(this).val();
+
+ if (status === '') {
+ table.column(5).search('').draw();
+ } else if (status === 'active') {
+ table.column(5).search('active').draw();
+ } else if (status === 'expired') {
+ table.column(5).search('expired').draw();
+ } else if (status === 'expiring') {
+ table.column(5).search('expiring soon').draw();
+ }
});
// Reset
window.resetFilters = function () {
- $('#searchInput, #statusFilter').val('');
- table.search('').columns().search('').order([5,'asc']).draw();
+ $('#searchInput, #statusFilter, #typeFilter').val('');
+ table.search('').columns().search('').order([4,'asc']).draw();
};
// View PDF
$(document).on('click', '.btn-view', function () {
- let certid = $(this).data('certid');
- window.open('= base_url('certificates/maintenance/show/') ?>' + certid, '_blank');
+ let certnumber = $(this).data('certnumber');
+ window.open('= base_url('certificates/number/') ?>' + certnumber, '_blank');
});
// Activity report
$(document).on('click', '.activity-report-link', function () {
- let certid = $(this).data('certid');
+ let actid = $(this).data('actid');
window.open(
- '= base_url('certificates/maintenance/activity/') ?>' + certid,
+ '= base_url('activities/detail/') ?>' + 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(
+ '= base_url('certificates/api/showmaintenance') ?>',
+ { certid },
+ function (data) {
+ // console.log(data);
+ // Populate modal with data
+ $('#modalCertName').text(data.cert_name || '-');
+ $('#modalCertNumber').text(data.cert_number || '-');
+ $('#modalProductName').text(data.productname || '-');
+ $('#modalProductNumber').text(data.productnumber || '-');
+ $('#modalIssueDate').text(data.issued_date || '-');
- $('#confirmValidateBtn').data('certid', btn.data('certid'));
- $('#certificatePreview').attr(
- 'src',
- '= base_url('certificates/maintenance/show/') ?>' + btn.data('certid')
- );
+ const formattedDate = data.expired_date
+ ? new Date(data.expired_date).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })
+ : '-';
+ $('#modalExpiryDate').text(formattedDate);
+
+ $('#modalSiteName').text(data.sitename || '-');
+ $('#modalValidation').html(`
${data.status || '-'}`);
+
+ const today = new Date();
+ today.setHours(0, 0, 0, 0);
+ const expiryDate = new Date(data.expired_date);
+ expiryDate.setHours(0, 0, 0, 0);
+ const diffTime = expiryDate - today;
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+ let badge = '';
+ if (diffDays < 0) {
+ // Sudah melewati tanggal expired
+ badge = '
Expired ';
+ } else if (diffDays <= 30) {
+ // Masih aktif tapi sisa 30 hari atau kurang
+ badge = '
Expiring Soon ';
+ } else {
+ // Lebih dari 30 hari
+ badge = '
Active ';
+ }
+ $('#modalExpiryStatus').html(badge);
+
+ $('#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 () {
+ console.error('Error fetching certificate data');
+ });
+
+ // INI JANGAN DIUBAH
+ $('#confirmValidateBtn').data('certid', certid);
+ $('#certificatePreview').attr('src','= base_url('certificates/maintenance/show/') ?>' + certid);
$('#validateModal').modal('show');
});
@@ -337,33 +437,14 @@ $(function () {
if (!confirm('Are you sure?')) return;
$.post(
- '= base_url('certificates/api/validateCertificate') ?>',
+ '= base_url('certificates/api/validatecertificate') ?>',
{ certid, certificateType},
function (response) {
if (response.success) {
$('#validateModal').modal('hide');
alert(response.message);
-
- // Generate and save PDF after successful validation
- $.post(
- '= base_url('certificates/api/generatepdf') ?>',
- { 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');
}
diff --git a/app/Views/certificate_training_index.php b/app/Views/certificate_training_index.php
index 20cafe9..0e5a1b5 100644
--- a/app/Views/certificate_training_index.php
+++ b/app/Views/certificate_training_index.php
@@ -1,4 +1,3 @@
-
= $this->extend('layouts/main.php') ?>
= $this->section('content') ?>
@@ -6,16 +5,9 @@
-
+
Certificates Training Management
-
-
-
- Create
-
-
@@ -30,7 +22,16 @@
placeholder="Search certificates by name, product, type, vendor, or dates...">
-
+
+
+ All Status
+ Active
+ Expired
+ Expiring Soon
+ Need Validation
+
+
+
All Types
TMS
@@ -38,29 +39,30 @@
Tokyo Boeki
-
-
-
-
-
- No
- Certificate Name
- Product/Equipment
- Issue Date
- Vendor
- Action
-
-
-
-
-
-
+
+
+
+
+
+ Certificate Name
+ Product/Equipment
+ Activity Report
+ Issue Date
+ Expiry Date
+ Status
+ Action
+
+
+
+
+
@@ -69,366 +71,371 @@
-
-