diff --git a/app/Controllers/Location.php b/app/Controllers/Location.php new file mode 100644 index 0000000..6cde0b4 --- /dev/null +++ b/app/Controllers/Location.php @@ -0,0 +1,19 @@ +db = \Config\Database::connect(); + $this->now = date('Y-m-d H:i:s'); + } + + public function index() { + + } +} \ No newline at end of file diff --git a/app/Controllers/Patient_Admission.php b/app/Controllers/Patient_Admission.php index 1ef580d..73bbe23 100644 --- a/app/Controllers/Patient_Admission.php +++ b/app/Controllers/Patient_Admission.php @@ -12,575 +12,4 @@ class Patient_Admission extends Controller { $this->db = \Config\Database::connect(); $this->now = date('Y-m-d H:i:s'); } - - // 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()); - } - } - - public function show($InternalPID = null) { - try { - $rows = $this->db->table('patient') - ->select(" - patient.*, - country.Country as CountryName, - race.Race as RaceName, - religion.Religion as ReligionName, - ethnic.Ethnic as EthnicName, - patcom.Comment as Comment, - patidt.IdentifierType, - patidt.Identifier, - patatt.Address - ") - ->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') - ->join('patcom', 'patcom.InternalPID = patient.InternalPID', 'left') - ->join('patidt', 'patidt.InternalPID = patient.InternalPID', 'left') - ->join('patatt', 'patatt.InternalPID = patient.InternalPID and patatt.DelDate is null', 'left') - ->where('patient.InternalPID', (int) $InternalPID) - ->get() - ->getResultArray(); - - if (empty($rows)) { - return $this->respond([ - 'status' => 'success', - 'message' => "Patient with ID {$InternalPID} not found.", - 'data' => [], - ], 200); - } - - // Use first row as base patient data - $patient = $rows[0]; - - $patient = $this->transformPatientData($patient); - - $patient['Identity'] = null; - $patient['Attachments'] = []; - - foreach ($rows as $row) { - if ($row['IdentifierType'] && $row['Identifier'] && !$patient['Identity']) { - $patient['Identity'] = [ - 'IdentifierType' => $row['IdentifierType'], - 'Identifier' => $row['Identifier'], - ]; - } - if ($row['Address']) { - $patient['Attachments'][] = ['Address' => $row['Address']]; - } - } - - if (empty($patient['Identity'])) { $patient['Identity'] = null; } - if (empty($patient['Attachments'])) { $patient['Attachments'] = null; } - - return $this->respond([ - 'status' => 'success', - 'message' => "Patient Show Successfully", - 'data' => $patient, - ], 200); - - } catch (\Exception $e) { - return $this->failServerError('Something went wrong: ' . $e->getMessage()); - } - } - - - private function transformPatientData(array $patient): array { - $patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"]); - $patient["Birthdate"] = $this->formatedDate($patient["Birthdate"]); - $patient["CreateDate"] = $this->formatedDate($patient["CreateDate"]); - $patient["DelDate"] = $this->formatedDate($patient["DelDate"]); - $patient["DeathDateTime"] = $this->formatedDate($patient["DeathDateTime"]); - $patient["BirthdateConversion"] = $this->formatedDateForDisplay($patient["Birthdate"]); - - $patient["LinkTo"] = $this->getLinkedPatients($patient['LinkTo']); - $patient["Custodian"] = $this->getCustodian($patient['Custodian']); - - return $patient; - } - - private function getLinkedPatients(?string $linkTo): ?array { - if (empty($linkTo)) { - return null; - } - - $ids = array_filter(explode(',', $linkTo)); - - return $this->db->table('patient') - ->select('InternalPID, PatientID') - ->whereIn('InternalPID', $ids) - ->get() - ->getResultArray() ?: null; - } - - private function getCustodian($custodianId): ?array { - if (empty($custodianId)) { - return null; - } - - return $this->db->table('patient') - ->select('InternalPID, PatientID') - ->where('InternalPID', (int) $custodianId) - ->get() - ->getRowArray() ?: null; - } - - - public function create() { - try { - $input = $this->request->getJSON(true); - $now = date('Y-m-d H:i:s'); - - // Prepare data - $dataPatient = $this->preparePatientData($input, $now, 'create'); - $dataPatidt = $this->preparePatidtData($input, $now, 'create'); - $dataPatatt = $this->preparePatattData($input, $now, 'create'); - $dataPatcom = $this->preparePatcomData($input, $now, 'create'); - - // Validation rules - $rulesPatient = [ - '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]', - 'Gender' => 'required' - ]; - $rulesPatidt = ['Identifier' => 'required|is_unique[patidt.Identifier]']; - //$rulesPatatt = ['Address' => 'required|is_unique[patatt.Address]']; - - // Validate patient - if (!$this->validateData($dataPatient, $rulesPatient)) { - return $this->validationError('patient', $this->validator->getErrors()); - } - // Validate patidt - if (!$this->validateData($dataPatidt, $rulesPatidt)) { - return $this->validationError('patidt', $this->validator->getErrors()); - } - /* Validate patatt (if exists, validate only the first row) - if (!empty($dataPatatt) && !$this->validateData($dataPatatt[0], $rulesPatatt)) { - return $this->validationError('patatt', $this->validator->getErrors()); - } - */ - - - $this->db->transStart(); - - - $this->db->table('patient')->insert($dataPatient); - $newInternalPatientId = $this->db->insertID(); - - - $dataPatidt['InternalPID'] = $newInternalPatientId; - $this->db->table('patidt')->insert($dataPatidt); - - - if (!empty($dataPatatt)) { - foreach ($dataPatatt as &$row) { - $row['InternalPID'] = $newInternalPatientId; - } - $this->db->table('patatt')->upsertBatch($dataPatatt); - } - - - if (!empty($dataPatcom['Comment'])) { - $dataPatcom['InternalPID'] = $newInternalPatientId; - $this->db->table('patcom')->insert($dataPatcom); - } - - $dbError = $this->db->error(); - if (!empty($dbError['message'])) { - $this->db->transRollback(); - return $this->failServerError('Insert patient failed: ' . $dbError['message']); - } - - $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()); - } - } - - private function preparePatientData(array $input, string $now, string $mode = 'create'): array { - $LinkTo = null; - if (!empty($input['LinkTo'])) { - $ids = array_column($input['LinkTo'], 'InternalPID'); - $LinkTo = implode(',', $ids); - } - - $data = [ - "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" => !empty($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, - "Custodian" => isset($input['Custodian']) ? (int)$input['Custodian'] : null, - "DelDate" => null, - "LinkTo" => $LinkTo - ]; - - // Only set CreateDate when creating - if ($mode === 'create') { - $data["CreateDate"] = $now; - } - - return $data; - } - - private function preparePatidtData(array $input, string $now, string $mode = 'create'): array { - $data = [ - "IdentifierType" => $input['Identity']['IdentifierType'] ?? null, - "Identifier" => $input['Identity']['Identifier'] ?? null, - ]; - - if ($mode === 'create') { - $data["CreateDate"] = $now; - } - - return $data; - } - - private function preparePatattData(array $input, string $now, string $mode = 'create'): array { - if (empty($input['Attachments'])) { - return []; - } - - return array_map(function ($attachment) use ($now, $mode) { - $row = [ - "Address" => $attachment['Address'] ?? null, - ]; - if ($mode === 'create') { - $row["CreateDate"] = $now; - } - return $row; - }, $input['Attachments']); - } - - private function preparePatcomData(array $input, string $now, string $mode = 'create'): array { - $data = [ - "Comment" => $input['Comment'] ?? null, - ]; - - if ($mode === 'create') { - $data["CreateDate"] = $now; - } - - return $data; - } - - - private function validationError(string $context, array $errors) - { - return $this->respond([ - 'status' => 'error', - 'message' => "Validation failed ({$context})", - 'errors' => $errors - ], 400); - } - - - // OK - Done - public function update($InternalPID = null) { - try { - $now = $this->now; - 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); } - - $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRowArray(); - if (!$patient) { return $this->respond(['status' => 'error', 'message' => 'Patient not found'], 404); } - - $dataPatient = $this->preparePatientData($input, $now, 'update'); - $dataPatidt = $this->preparePatidtData($input, $now, 'update'); - $dataPatcom = $this->preparePatcomData($input, $now, 'update'); - $dataPatatt = $this->preparePatattData($input, $now, 'update'); - - // 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}]", - 'Gender' => 'required' - ]; - - $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); - } - - $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']); - } - - if (!empty($dataPatatt)) { - foreach ($dataPatatt as &$row) { - $row['InternalPID'] = $InternalPID; - } - $this->db->table('patatt')->upsertBatch($dataPatatt); - $addresses = array_column($dataPatatt, 'Address'); - $this->db->table('patatt')->where('InternalPID', $InternalPID)->WhereNotIn('Address', $addresses)->update(['DelDate' => date('Y-m-d H:i:s')]); - } else { - $this->db->table('patatt')->where('InternalPID', $InternalPID)->update(['DelDate' => date('Y-m-d H:i:s')]); - } - - if(!empty($dataPatcom['Comment'])) { - $dataPatcom['InternalPID'] = $InternalPID; - $dataPatcom['CreateDate'] = $this->now; - $this->db->table('patcom')->upsert($dataPatcom); - } - - $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()); - } - } - - // OK - Done - public function patientCheck() { - - try { - - $PatientID = $this->request->getVar('PatientID'); - $EmailAddress1 = $this->request->getVar('EmailAddress1'); - - if ($PatientID!=null){ - $tableName = 'PatientID'; - $searchName = $PatientID; - } - - if ($EmailAddress1!=null){ - $tableName = 'EmailAddress1'; - $searchName = $EmailAddress1; - } - - $patient = $this->db->table('patient') - ->where($tableName, $searchName) - ->get() - ->getRowArray(); - - if (!$patient) { - return $this->respond([ - 'status' => 'success', - 'message' => "$tableName not found.", - 'data' => true, - ], 200); - } - - return $this->respond([ - 'status' => 'success', - 'message' => "$tableName already exists.", - 'data' => false, - ], 200); - - - } catch (\Exception $e) { - // Error Server Mengembalikan 500 - return $this->failServerError('Something went wrong.'.$e->getMessage()); - } - } - - - // Ubah ke format Years Months Days - private function calculateAgeFromBirthdate($birthdate) { - $dob = new \DateTime($birthdate); - $today = new \DateTime(); - $diff = $today->diff($dob); - - $formattedAge = ""; - if ($diff->y > 0){ - $formattedAge .= "{$diff->y} Years "; - } - if ($diff->m > 0){ - $formattedAge .= "{$diff->m} Months "; - } - if ($diff->d > 0){ - $formattedAge .= "{$diff->d} Days"; - } - - return $formattedAge; - } - - // Ubah ke format Y-m-d H:i - private function formatedDate($dateString) { - $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); - - if (!$date) { - $timestamp = strtotime($dateString); - if ($timestamp) { - return date('Y-m-d H:i', $timestamp); - } - return null; - } - - return $date->format('Y-m-d H:i'); - } - - // Ubah ke format j M Y - private function formatedDateForDisplay($dateString) { - $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); - - if (!$date) { - $timestamp = strtotime($dateString); - if ($timestamp) { - return date('j M Y', $timestamp); - } - return null; - } - - return $date->format('j M Y'); - } - } \ No newline at end of file diff --git a/app/Database/Migrations/2025-09-10-141522_Location.php b/app/Database/Migrations/2025-09-10-141522_Location.php new file mode 100644 index 0000000..1fbffc4 --- /dev/null +++ b/app/Database/Migrations/2025-09-10-141522_Location.php @@ -0,0 +1,43 @@ +forge->addField([ + 'LocationID' => ['type' => 'INT', 'auto_increment' => true, 'unsigned' => true], + 'SiteID' => ['type' => 'INT', 'null' => true], + 'LocCode' => ['type' => 'VARCHAR', 'constraint' => 6, 'null' => false], + 'Parent' => ['type' => 'INT', 'null' => true], + 'LocFull' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], + 'Description' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], + 'CreateDate' => ['type' => 'DATETIME', 'null' => true], + 'EndDate' => ['type' => 'DATETIME', 'null' => true] + ]); + $this->forge->addKey('LocationID', true); + $this->forge->createTable('location'); + + $this->forge->addField([ + 'LocationID' => ['type' => 'INT', 'auto_increment' => true, 'unsigned' => true], + 'Street1' => ['type' => 'INT', 'null' => true], + 'Street2' => ['type' => 'VARCHAR', 'constraint' => 6, 'null' => false], + 'City' => ['type' => 'INT', 'null' => true], + 'Province' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], + 'PostCode' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], + 'GeoLocationSystem' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], + 'GeoLocationData' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], + 'CreateDate' => ['type' => 'DATETIME', 'null' => true], + 'EndDate' => ['type' => 'DATETIME', 'null' => true] + ]); + $this->forge->addKey('LocationID', true); + $this->forge->createTable('locationaddress'); + } + + public function down() { + $this->forge->dropTable('location'); + $this->forge->dropTable('locationaddress'); + } +} \ No newline at end of file