db = \Config\Database::connect(); } // OK - Done public function index() { try { $InternalPID = $this->request->getVar('InternalPID'); $PatientID = $this->request->getVar('PatientID'); $Name = $this->request->getVar('Name'); $Birthdate = $this->request->getVar('Birthdate'); $qname = "LOWER(CONCAT_WS(' ', IFNULL(Prefix,''), IFNULL(NameFirst,''), IFNULL(NameMiddle,''), IFNULL(NameLast,''), IFNULL(NameMaiden,''), IFNULL(Suffix,'')))"; $builder = $this->db->table('patient'); $builder->select("InternalPID, PatientID, $qname as FullName, Gender, Birthdate, EmailAddress1 as Email, MobilePhone"); if ($Name !== null) { $sql = $qname; $rawSql = new RawSql($sql); $builder->like($rawSql, $Name, 'both'); } if ($InternalPID !== null) { $builder->where('InternalPID', $InternalPID); } if ($PatientID !== null) { $builder->like('PatientID', $PatientID, 'both'); } if ($Birthdate !== null) { $builder->where('Birthdate', $Birthdate); } $filteredPatients = $builder->get()->getResultArray(); // Data pasien tidak ada mengembalikan - success 200 if (empty($filteredPatients)) { return $this->respond([ 'status' => 'success', 'message' => 'No patient records found matching the criteria.', 'data' => [] ], 200); } // Data pasien ditemukan dan mengembalikan - success 200 return $this->respond([ 'status' => 'success', 'message'=> "Patients fetched successfully", 'data' => $filteredPatients, ], 200); } catch (\Exception $e) { // Error Server Mengembalikan 500 return $this->failServerError('Something went wrong.'.$e->getMessage()); } } // OK - Done public function show($InternalPID = null) { try { $patient = $this->db->table('patient') ->select('patient.*, country.Country as CountryName, race.Race as RaceName, religion.Religion as ReligionName, ethnic.Ethnic as EthnicName') ->join('country', 'country.IntCountryID = patient.IntCountryID', 'left') ->join('race', 'race.RaceID = patient.RaceID', 'left') ->join('religion', 'religion.ReligionID = patient.ReligionID', 'left') ->join('ethnic', 'ethnic.EthnicID = patient.EthnicID', 'left') ->where('InternalPID', (int) $InternalPID) ->get() ->getRowArray(); // Data pasien tidak ada mengembalikan - success 200 if (empty($patient)) { return $this->respond([ 'status' => 'success', 'message' => 'Patient with ID ' . $InternalPID . ' not found.', 'data' => [], ], 200); } else { $patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"]); $date = \DateTime::createFromFormat('Y-m-d H:i', $patient["Birthdate"]); if ($date) { // Simpan versi format database $patient["Birthdate"] = $date->format('Y-m-d H:i'); // Simpan versi format tampilan $patient["BirthdateConversion"] = $date->format('j M Y'); } else { $patient["BirthdateConversion"] = null; // Jika parsing gagal } if ($patient['LinkTo'] != null) { $ids = explode(',', $patient['LinkTo']); // dari string jadi array $patientLinkTo = $this->db->table('patient') ->select('InternalPID, PatientID') ->whereIn('InternalPID', $ids) ->get() ->getResultArray(); $patient["LinkTo"] = $patientLinkTo == [] ? null : $patientLinkTo[0]; } $patidt = $this->db->table('patidt') ->select('IdentifierType, Identifier') ->where('InternalPID', (int) $InternalPID) ->get() ->getResultArray(); $patient['Identity'] = $patidt == [] ? null : $patidt[0]; } // Data pasien ditemukan dan mengembalikan - success 200 return $this->respond([ 'status' => 'success', 'message'=> "Patient Show Successfully", 'data' => $patient, ], 200); } catch (\Exception $e) { // Error Server Mengembalikan 500 return $this->failServerError('Something went wrong'.$e->getMessage()); } } // OK - Done public function create() { try { $input = $this->request->getJSON(true); $LinkTo = null; if (!empty($input['LinkTo'])) { $ids = []; // Temporary foreach ($input['LinkTo'] as $row) { $ids[] = $row['InternalPID']; } $LinkTo = implode(',', $ids); } // ========================= // 1. Data untuk tabel patient // ========================= $dataPatient = [ "PatientID" => $input['PatientID'] ?? null, "AlternatePID" => $input['AlternatePID'] ?? null, "Prefix" => $input['Prefix'] ?? null, "NameFirst" => $input['NameFirst'] ?? null, "NameMiddle" => $input['NameMiddle'] ?? null, "NameMaiden" => $input['NameMaiden'] ?? null, "NameLast" => $input['NameLast'] ?? null, "Suffix" => $input['Suffix'] ?? null, "NameAlias" => $input['NameAlias'] ?? null, "Gender" => isset($input['Gender']) ? (int) $input['Gender'] : null, "PlaceOfBirth" => $input['PlaceOfBirth'] ?? null, "Birthdate" => $input['Birthdate'] ?: null, "Street_1" => $input['Street_1'] ?? null, "Street_2" => $input['Street_2'] ?? null, "Street_3" => $input['Street_3'] ?? null, "City" => $input['City'] ?? null, "Province" => $input['Province'] ?? null, "ZIP" => $input['ZIP'] ?? null, "EmailAddress1" => $input['EmailAddress1'] ?? null, "EmailAddress2" => $input['EmailAddress2'] ?? null, "Phone" => $input['Phone'] ?? null, "MobilePhone" => $input['MobilePhone'] ?? null, "RaceID" => isset($input['RaceID']) ? (int) $input['RaceID'] : null, "IntCountryID" => isset($input['IntCountryID']) ? (int) $input['IntCountryID'] : null, "MaritalStatus" => $input['MaritalStatus'] ?? null, "ReligionID" => isset($input['ReligionID']) ? (int) $input['ReligionID'] : null, "EthnicID" => isset($input['EthnicID']) ? (int) $input['EthnicID'] : null, "Citizenship" => $input['Citizenship'] ?? null, "DeathIndicator" => isset($input['DeathIndicator']) ? (int) $input['DeathIndicator'] : null, 'DeathDateTime' => $input['DeathDateTime'] ?: null, "CreateDate" => date('Y-m-d H:i:s'), "DelDate" => null, "LinkTo" => $LinkTo // Mother // AccountNumber ]; $rulesDataPatient = [ 'PatientID' => 'required|is_unique[patient.PatientID]|max_length[50]', 'AlternatePID' => 'permit_empty|max_length[50]', 'NameFirst' => 'required|min_length[1]|max_length[255]', 'EmailAddress1' => 'required|is_unique[patient.EmailAddress1]', 'DeathIndicator' => 'required', 'Gender' => 'required' ]; $dataPatidt = [ "IdentifierType" => $input['Identity']['IdentifierType'] ?? null, "Identifier" => $input['Identity']['Identifier'] ?? null, "CreateDate" => date('Y-m-d H:i:s'), ]; $rulesDataPatidt = [ 'Identifier' => 'required|is_unique[patidt.Identifier]', ]; // ========================= // Validasi semua sebelum insert // ========================= if (!$this->validateData($dataPatient, $rulesDataPatient)) { return $this->respond([ 'status' => 'error', 'message' => 'Validation failed (patient)', 'errors' => $this->validator->getErrors() ], 400); } if (!$this->validateData($dataPatidt, $rulesDataPatidt)) { return $this->respond([ 'status' => 'error', 'message' => 'Validation failed (patidt)', 'errors' => $this->validator->getErrors() ], 400); } // ========================= // Mulai transaksi // ========================= $this->db->transStart(); $this->db->table('patient')->insert($dataPatient); $newInternalPatientId = $this->db->insertID(); $dbError = $this->db->error(); if (!empty($dbError['message'])) { $this->db->transRollback(); return $this->failServerError('Insert patient failed: ' . $dbError['message']); } $dataPatidt['InternalPID'] = $newInternalPatientId; $this->db->table('patidt')->insert($dataPatidt); $this->db->transComplete(); if ($this->db->transStatus() === false) { $dbError = $this->db->error(); return $this->failServerError( 'Failed to create patient data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown database error') ); } return $this->respondCreated([ 'status' => 'success', 'message' => 'Patient created successfully', 'data' => $newInternalPatientId ], 201); } catch (\Exception $e) { $this->db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } // OK - Done // public function update($InternalPID = null) { // try { // $InternalPID = (int) $InternalPID; // $input = $this->request->getJSON(true); // $dataPatient = [ // "PatientID" => $input['PatientID'] ?? null, // "AlternatePID" => $input['AlternatePID'] ?? null, // "Prefix" => $input['Prefix'] ?? null, // "NameFirst" => $input['NameFirst'] ?? null, // "NameMiddle" => $input['NameMiddle'] ?? null, // "NameMaiden" => $input['NameMaiden'] ?? null, // "NameLast" => $input['NameLast'] ?? null, // "Suffix" => $input['Suffix'] ?? null, // "NameAlias" => $input['NameAlias'] ?? null, // "Gender" => isset($input['Gender']) ? (int) $input['Gender'] : null, // "PlaceOfBirth" => $input['PlaceOfBirth'] ?? null, // "Birthdate" => $input['Birthdate'] ?: null, // "Street_1" => $input['Street_1'] ?? null, // "Street_2" => $input['Street_2'] ?? null, // "Street_3" => $input['Street_3'] ?? null, // "City" => $input['City'] ?? null, // "Province" => $input['Province'] ?? null, // "ZIP" => $input['ZIP'] ?? null, // "EmailAddress1" => $input['EmailAddress1'] ?? null, // "EmailAddress2" => $input['EmailAddress2'] ?? null, // "Phone" => $input['Phone'] ?? null, // "MobilePhone" => $input['MobilePhone'] ?? null, // "RaceID" => isset($input['RaceID']) ? (int) $input['RaceID'] : null, // "IntCountryID" => isset($input['IntCountryID']) ? (int) $input['IntCountryID'] : null, // "MaritalStatus" => $input['MaritalStatus'] ?? null, // "ReligionID" => isset($input['ReligionID']) ? (int) $input['ReligionID'] : null, // "EthnicID" => isset($input['EthnicID']) ? (int) $input['EthnicID'] : null, // "Citizenship" => $input['Citizenship'] ?? null, // "DeathIndicator" => isset($input['DeathIndicator']) ? (int) $input['DeathIndicator'] : null, // 'DeathDateTime' => $input['DeathDateTime'] ?: null, // "CreateDate" => date('Y-m-d H:i:s'), // "DelDate" => null, // // Linkto // // Mother // // AccountNumber // ]; // $rulesDataPatient = [ // 'PatientID' => 'required|is_unique[patient.PatientID]|max_length[50]', // 'AlternatePID' => 'permit_empty|max_length[50]', // 'NameFirst' => 'required|min_length[1]|max_length[255]', // 'EmailAddress1' => 'required|is_unique[patient.EmailAddress1]', // 'DeathIndicator' => 'required', // 'Gender' => 'required' // ]; // $dataPatidt = [ // "IdentifierType" => $input['IdentifierType'] ?? null, // "Identifier" => $input['Identifier'] ?? null, // "CreateDate" => date('Y-m-d H:i:s'), // ]; // $rulesDataPatidt = [ // 'Identifier' => 'required|is_unique[patidt.Identifier]', // ]; // $existingPatient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRowArray(); // // Mengembalikan 404 // if (empty($existingPatient)) { // return $this->failNotFound('Patient with ID ' . $InternalPID . ' not found.'); // } // // Request dari client tidak valid atau tidak bisa diproses oleh server - 400 // if (!$this->validateData($dataPatient, $rules)) { // return $this->failValidationErrors($this->validator->getErrors()); // } // $allowedUpdateFields = [ // 'NameFirst', 'NameLast', 'NameMiddle', // 'PatientID', 'AlternatePID', 'Birthdate', 'PlaceOfBirth', // 'Street_1', 'Street_2', 'Street_3', 'City', 'Province', 'ZIP', // 'EmailAddress1', 'EmailAddress2', 'Phone', 'MobilePhone', 'Mother', 'AccountNumber' // ]; // $datas = []; // foreach ($allowedUpdateFields as $field) { // if (isset($dataPatient[$field])) { // $datas[$field] = $dataPatient[$field]; // } // } // if (empty($dataPatient)) { // return $this->failValidationError('No data provided for update.'); // } // $this->db->table('patient')->where('InternalPID', $InternalPID)->update($dataPatient); // // Sukses & Insert = 201 - Kirim data patient ID // return $this->respondCreated([ // 'status' => 'success', // 'message' => 'Patient updated successfully', // 'data' => $dataPatient // ], 201); // } catch (\Exception $e) { // // Error Server = 500 // return $this->failServerError('Something went wrong '.$e->getMessage()); // } // } public function update($InternalPID = null) { try { if (!$InternalPID || !is_numeric($InternalPID)) { return $this->respond(['status' => 'error', 'message' => 'Invalid or missing InternalPID'], 400); } $input = $this->request->getJSON(true); if (!$input) { return $this->respond(['status' => 'error', 'message' => 'Invalid JSON input'], 400); } // Cek apakah data patient ada $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRowArray(); if (!$patient) { return $this->respond(['status' => 'error', 'message' => 'Patient not found'], 404); } $LinkTo = null; if (!empty($input['LinkTo']) && is_array($input['LinkTo'])) { $ids = []; foreach ($input['LinkTo'] as $row) { if (isset($row['InternalPID']) && is_numeric($row['InternalPID'])) { $ids[] = (int)$row['InternalPID']; } } $LinkTo = implode(',', $ids); } // Data untuk update patient $dataPatient = [ "PatientID" => $input['PatientID'] ?? $patient['PatientID'], "AlternatePID" => $input['AlternatePID'] ?? $patient['AlternatePID'], "Prefix" => $input['Prefix'] ?? $patient['Prefix'], "NameFirst" => $input['NameFirst'] ?? $patient['NameFirst'], "NameMiddle" => $input['NameMiddle'] ?? $patient['NameMiddle'], "NameMaiden" => $input['NameMaiden'] ?? $patient['NameMaiden'], "NameLast" => $input['NameLast'] ?? $patient['NameLast'], "Suffix" => $input['Suffix'] ?? $patient['Suffix'], "NameAlias" => $input['NameAlias'] ?? $patient['NameAlias'], "Gender" => isset($input['Gender']) && is_numeric($input['Gender']) ? (int)$input['Gender'] : $patient['Gender'], "PlaceOfBirth" => $input['PlaceOfBirth'] ?? $patient['PlaceOfBirth'], "Birthdate" => $input['Birthdate'] ?: $patient['Birthdate'], "Street_1" => $input['Street_1'] ?? $patient['Street_1'], "Street_2" => $input['Street_2'] ?? $patient['Street_2'], "Street_3" => $input['Street_3'] ?? $patient['Street_3'], "City" => $input['City'] ?? $patient['City'], "Province" => $input['Province'] ?? $patient['Province'], "ZIP" => $input['ZIP'] ?? $patient['ZIP'], "EmailAddress1" => $input['EmailAddress1'] ?? $patient['EmailAddress1'], "EmailAddress2" => $input['EmailAddress2'] ?? $patient['EmailAddress2'], "Phone" => $input['Phone'] ?? $patient['Phone'], "MobilePhone" => $input['MobilePhone'] ?? $patient['MobilePhone'], "RaceID" => isset($input['RaceID']) && is_numeric($input['RaceID']) ? (int)$input['RaceID'] : $patient['RaceID'], "IntCountryID" => isset($input['IntCountryID']) && is_numeric($input['IntCountryID']) ? (int)$input['IntCountryID'] : $patient['IntCountryID'], "MaritalStatus" => $input['MaritalStatus'] ?? $patient['MaritalStatus'], "ReligionID" => isset($input['ReligionID']) && is_numeric($input['ReligionID']) ? (int)$input['ReligionID'] : $patient['ReligionID'], "EthnicID" => isset($input['EthnicID']) && is_numeric($input['EthnicID']) ? (int)$input['EthnicID'] : $patient['EthnicID'], "Citizenship" => $input['Citizenship'] ?? $patient['Citizenship'], "DeathIndicator" => isset($input['DeathIndicator']) && is_numeric($input['DeathIndicator']) ? (int)$input['DeathIndicator'] : $patient['DeathIndicator'], 'DeathDateTime' => $input['DeathDateTime'] ?: $patient['DeathDateTime'], "LinkTo" => $LinkTo, ]; // Atur aturan validasi dengan pengecualian is_unique untuk InternalPID ini $rulesDataPatient = [ 'PatientID' => "required|max_length[50]|is_unique[patient.PatientID,InternalPID,{$InternalPID}]", 'AlternatePID' => 'permit_empty|max_length[50]', 'NameFirst' => 'required|min_length[1]|max_length[255]', 'EmailAddress1' => "required|is_unique[patient.EmailAddress1,InternalPID,{$InternalPID}]", 'DeathIndicator' => 'required', 'Gender' => 'required' ]; // Ambil data patidt $patidt = $this->db->table('patidt')->where('InternalPID', $InternalPID)->get()->getRowArray(); $dataPatidt = [ "IdentifierType" => $input['Identity']['IdentifierType'] ?? ($patidt['IdentifierType'] ?? null), "Identifier" => $input['Identity']['Identifier'] ?? ($patidt['Identifier'] ?? null), ]; $rulesDataPatidt = [ 'Identifier' => "required|is_unique[patidt.Identifier,InternalPID,{$InternalPID}]" ]; // Validasi if (!$this->validateData($dataPatient, $rulesDataPatient)) { return $this->respond([ 'status' => 'error', 'message' => 'Validation failed (patient)', 'errors' => $this->validator->getErrors() ], 400); } if (!$this->validateData($dataPatidt, $rulesDataPatidt)) { return $this->respond([ 'status' => 'error', 'message' => 'Validation failed (patidt)', 'errors' => $this->validator->getErrors() ], 400); } // Transaksi update $this->db->transStart(); $this->db->table('patient')->where('InternalPID', $InternalPID)->update($dataPatient); $dbError = $this->db->error(); if (!empty($dbError['message'])) { $this->db->transRollback(); return $this->failServerError('Update patient failed: ' . $dbError['message']); } $this->db->table('patidt')->where('InternalPID', $InternalPID)->update($dataPatidt); $dbError = $this->db->error(); if (!empty($dbError['message'])) { $this->db->transRollback(); return $this->failServerError('Update patidt failed: ' . $dbError['message']); } $this->db->transComplete(); if ($this->db->transStatus() === false) { $dbError = $this->db->error(); return $this->failServerError('Failed to update patient data (transaction rolled back): ' . ($dbError['message'] ?? 'Unknown error')); } return $this->respond([ 'status' => 'success', 'message' => 'Patient updated successfully', 'data' => $InternalPID ], 200); } catch (\Exception $e) { $this->db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } // OK - Done public function delete($InternalPID = null) { try { $InternalPID = (int) $InternalPID; if (!$InternalPID) { return $this->failValidationError('Patient ID is required.'); } // Cari data pasien $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRow(); if (!$patient) { return $this->failNotFound("Patient ID with {$InternalPID} not found."); } // Update kolom DelDate sebagai soft delete $this->db->table('patient')->where('InternalPID', $InternalPID)->update(['DelDate' => date('Y-m-d H:i:s')]); // Mengembalikan 200 return $this->respondDeleted([ 'status' => 'success', 'message' => "Patient ID with {$InternalPID} deleted successfully." ]); } catch (\Exception $e) { return $this->failServerError("Internal server error: " . $e->getMessage()); } } private function calculateAgeFromBirthdate($birthdate) { $dob = new \DateTime($birthdate); $today = new \DateTime(); $diff = $today->diff($dob); $formattedAge = ""; if ($diff->y > 0){ $formattedAge .= "{$diff->y} Tahun "; } if ($diff->m > 0){ $formattedAge .= "{$diff->m} Bulan "; } if ($diff->d > 0){ $formattedAge .= "{$diff->d} Hari"; } return $formattedAge; } }