From 88f2633bb6891a356af8327412117b7848fba378 Mon Sep 17 00:00:00 2001 From: mikael-zakaria Date: Sun, 19 Oct 2025 22:36:31 +0700 Subject: [PATCH] Update Patient (Patcom & Unit Testing) --- app/Database/Seeds/DummySeeder.php | 11 +- app/Models/Patient/PatComModel.php | 12 +- tests/feature/Patients/PatientCreateTest.php | 67 +++- tests/feature/Patients/PatientShowTest.php | 69 +++- tests/feature/Patients/PatientUpdateTest.php | 340 ++++++++++++------- 5 files changed, 351 insertions(+), 148 deletions(-) diff --git a/app/Database/Seeds/DummySeeder.php b/app/Database/Seeds/DummySeeder.php index fdb59c6..5a6686c 100644 --- a/app/Database/Seeds/DummySeeder.php +++ b/app/Database/Seeds/DummySeeder.php @@ -62,10 +62,19 @@ class DummySeeder extends Seeder { $this->db->table('patient')->insertBatch($data); $data = [ [ 'InternalPID'=>1, 'IdentifierType'=>'KTP', 'Identifier'=>'9901', 'CreateDate'=> "$now" ], - [ 'InternalPID'=>2, 'IdentifierType'=>'KTP', 'Identifier'=>'9902', 'CreateDate'=> "$now" ], + // [ 'InternalPID'=>2, 'IdentifierType'=>'KTP', 'Identifier'=>'9902', 'CreateDate'=> "$now" ], [ 'InternalPID'=>3, 'IdentifierType'=>'KTP', 'Identifier'=>'9903', 'CreateDate'=> "$now" ] ]; $this->db->table('patidt')->insertBatch($data); + $data = [ + [ "InternalPID" => 1, "Address" => "/api/upload/assasasasd" . 1 . ".jpg", 'CreateDate'=> "$now" ], + [ "InternalPID" => 1, "Address" => "/api/upload/adsasasds" . 2 . ".jpg", 'CreateDate'=> "$now" ], + [ "InternalPID" => 1, "Address" => "/api/upload/sasaasadjs" . 6 . ".jpg", 'CreateDate'=> "$now" ], + [ "InternalPID" => 1, "Address" => "/api/upload/sdjasass" . 5 . ".jpg", 'CreateDate'=> "$now" ], + [ "InternalPID" => 1, "Address" => "/api/upload/sdasasjs" . 4 . ".jpg", 'CreateDate'=> "$now" ], + + ]; + $this->db->table('patatt')->insertBatch($data); // containerdef $data = [ diff --git a/app/Models/Patient/PatComModel.php b/app/Models/Patient/PatComModel.php index f3937e8..1502a7d 100644 --- a/app/Models/Patient/PatComModel.php +++ b/app/Models/Patient/PatComModel.php @@ -7,7 +7,7 @@ use App\Models\BaseUtcModel; class PatComModel extends BaseModel { protected $table = 'patcom'; protected $primaryKey = 'PatComID '; - protected $allowedFields = ['InternalPID', 'Comment', 'CreateDate', 'DelDate']; + protected $allowedFields = ['InternalPID', 'Comment', 'CreateDate', 'EndDate']; protected $useTimestamps = true; protected $createdField = 'CreateDate'; @@ -26,14 +26,14 @@ class PatComModel extends BaseModel { } public function updatePatCom(string $patcom, string $InternalPID) { - $exists = $this->where('InternalPID', $InternalPID)->first(); + $exists = $this->withDeleted()->where('InternalPID', $InternalPID)->first(); if ($exists) { - //Update - $this->where('InternalPID', $InternalPID)->set('Comment', $patcom)->update(); + //Update + $this->where('InternalPID', $InternalPID)->set(['EndDate' => null,'Comment' => $patcom])->update(); } else { - //Insert - $this->insert(['InternalPID' => $InternalPID, 'Comment' => $patcom]); + //Insert + $this->insert(['InternalPID' => $InternalPID, 'Comment' => $patcom]); } } diff --git a/tests/feature/Patients/PatientCreateTest.php b/tests/feature/Patients/PatientCreateTest.php index 919175c..319ad28 100644 --- a/tests/feature/Patients/PatientCreateTest.php +++ b/tests/feature/Patients/PatientCreateTest.php @@ -11,14 +11,14 @@ class PatientCreateTest extends CIUnitTestCase use FeatureTestTrait; protected $endpoint = 'api/patient'; - // 400 - Passed + // 400 - Passed + // Validation Gagal - Array Tidak Complete public function testCreatePatientValidationFail() { // Test dengan payload yg tidak lengkap // error 400 yg diharapkan $payload = ['Name' => 'Ngawur']; - $result = $this->withBodyFormat('json') - ->call('post', 'api/patient', $payload); + $result = $this->withBodyFormat('json')->call('post', 'api/patient', $payload); $result->assertStatus(400); // Test dengan PatiD yg sudah ada @@ -35,14 +35,13 @@ class PatientCreateTest extends CIUnitTestCase "NameAlias"=> "Bud", "Gender"=> "1", ]; - $result = $this->withBodyFormat('json') - ->call('post', 'api/patient', $payload); + $result = $this->withBodyFormat('json')->call('post', 'api/patient', $payload); $result->assertStatus(400); } // 201 - Passed - // Test dengan user dummy + // Test Sukses Dengan User Dummy public function testCreatePatientSuccess() { $faker = Factory::create('id_ID'); @@ -141,8 +140,8 @@ class PatientCreateTest extends CIUnitTestCase "Custodian" => 1, "PatIdt" => [ "IdentifierType" => "KTP", + // Identifier lebih dari 255 karakter - error validasi "Identifier" => "numberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetween" - // "Identifier" => $faker->nik() ?? $faker->numerify('################') ], "PatAtt" => [ [ "Address" => "/api/upload/" . $faker->word . ".jpg" ] @@ -163,6 +162,60 @@ class PatientCreateTest extends CIUnitTestCase $result->assertArrayHasKey("error", $data); } + public function testCreateWithoutAttachments() { + $faker = Factory::create('id_ID'); + + $payload = [ + "PatientID" => "DUAU" . $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000), + "AlternatePID" => "DMAU" . $faker->numberBetween(5, 1000).$faker->numberBetween(1, 1000), + "Prefix" => $faker->title, + "NameFirst" => $faker->firstName, + "NameMiddle" => $faker->firstName, + "NameMaiden" => $faker->firstName, + "NameLast" => $faker->lastName, + "Suffix" => "S.Kom", + "NameAlias" => $faker->userName, + "Gender" => $faker->numberBetween(5, 6), + "PlaceOfBirth" => $faker->city, + "Birthdate" => $faker->date('Y-m-d'), + "ZIP" => $faker->postcode, + "Street_1" => $faker->streetAddress, + "Street_2" => "RT " . $faker->numberBetween(1, 10) . " RW " . $faker->numberBetween(1, 10), + "Street_3" => "Blok " . $faker->numberBetween(1, 20), + "City" => $faker->city, + "Province" => $faker->state, + "EmailAddress1" => "AiA" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com', + "EmailAddress2" => "BiA" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com', + "Phone" => $faker->phoneNumber, + "MobilePhone" => $faker->phoneNumber, + "Race" => (string) $faker->numberBetween(175, 205), + "Country" => (string) $faker->numberBetween(221, 469), + "MaritalStatus" => (string) $faker->numberBetween(8, 15), + "Religion" => (string) $faker->numberBetween(206, 212), + "Ethnic" => (string) $faker->numberBetween(213, 220), + "Citizenship" => "WNI", + "DeathIndicator" => (string) $faker->numberBetween(16, 17), + "LinkTo" => (string) $faker->numberBetween(2, 3), + "Custodian" => 1, + "PatIdt" => [ + "IdentifierType" => "KTP", + "Identifier" => $faker->nik() ?? $faker->numerify('################') + ], + "PatAtt" => [], + "PatCom" => $faker->sentence, + ]; + + if($payload['DeathIndicator'] == '16') { + $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s'); + } else { + $payload['DeathDateTime'] = null; + } + + $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + $result->assertStatus(201); + } + // 201 - Passed // Test dengan user dummy dan harus berhasil - Attachment kosong public function testCreateWithoutAttachments() { diff --git a/tests/feature/Patients/PatientShowTest.php b/tests/feature/Patients/PatientShowTest.php index 754de63..06e61fb 100644 --- a/tests/feature/Patients/PatientShowTest.php +++ b/tests/feature/Patients/PatientShowTest.php @@ -11,16 +11,6 @@ class PatientShowTest extends CIUnitTestCase protected $endpoint = 'api/patient'; - // 200 ok not found - Passed - public function testShowNotFound() { - $result = $this->get($this->endpoint . '/90909090'); - $result->assertStatus(200); - $result->assertJSONFragment([ - 'status' => 'success', - "message" => "data not found." - ]); - } - // 200 ok found - Passed public function testShowSingleRow() { // Pastikan DB test punya seed patient InternalPID=10 tanpa id/addr @@ -33,5 +23,62 @@ class PatientShowTest extends CIUnitTestCase $result->assertArrayHasKey('data', $data); $result->assertIsArray($data['data']); } + + // 200 ok - Test validasi respons selalu sukses - Passed + public function testShowAlwaysReturnSuccessStatus() { + $result = $this->get($this->endpoint . '/99999'); + $result->assertJSONFragment(['status' => 'success']); + } -} + // 200 ok not found - Passed + public function testShowNotFound() { + $result = $this->get($this->endpoint . '/90909090'); + $result->assertStatus(200); + $result->assertJSONFragment([ + 'status' => 'success', + "message" => "data not found." + ]); + } + + // 200 ok found - PatIdt null - Passed + public function testShowWithNullPatIdt() { + $result = $this->get($this->endpoint . '/2'); + $data = $result->getJSON(); + $data = json_decode($data, true); + + $result->assertStatus(200); + $this->assertNull($data['data']['PatIdt']); + } + + // 200 ok found - PatAtt null - Passed + public function testShowWithNullPatAtt() { + $result = $this->get($this->endpoint . '/2'); + $data = $result->getJSON(); + $data = json_decode($data, true); + + $result->assertStatus(200); + $this->assertNull($data['data']['PatAtt']); + } + + // 200 ok found - PatCom null - Passed + public function testShowWithNullPatCom() { + $result = $this->get($this->endpoint . '/2'); + $data = $result->getJSON(); + $data = json_decode($data, true); + + $result->assertStatus(200); + $this->assertNull($data['data']['PatCom']); + } + + // 200 ok found - PatAtt greater dan 1 - Passed + public function testShowWithMultipleAddresses() { + $result = $this->get($this->endpoint . '/1'); + $data = $result->getJSON(); + $data = json_decode($data, true); + + $result->assertStatus(200); + $this->assertIsArray($data['data']['PatAtt']); + $this->assertGreaterThan(1, count($data['data']['PatAtt'])); + } + +} \ No newline at end of file diff --git a/tests/feature/Patients/PatientUpdateTest.php b/tests/feature/Patients/PatientUpdateTest.php index 0cd5ed5..071ecdc 100644 --- a/tests/feature/Patients/PatientUpdateTest.php +++ b/tests/feature/Patients/PatientUpdateTest.php @@ -10,149 +10,243 @@ class PatientUpdateTest extends CIUnitTestCase { use FeatureTestTrait; protected $endpoint = 'api/patient'; - + /** + * 400 - Validation Fail + * Coba update tanpa field wajib → harus gagal validasi. + */ + public function testUpdatePatientValidationFail() + { + $payload = [ 'InternalPID' => null, 'NameFirst' => '' ]; // Tidak valid + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); + + $result->assertStatus(400); + $json = $result->getJSON(); + $data = json_decode($json, true); + $this->assertArrayHasKey('messages', $data); + } + + /** + * 404 / 500 - Update Nonexistent Patient + * Coba update InternalPID yang tidak ada. + */ + public function testUpdateNonexistentPatientShouldFail() + { + $faker = Factory::create('id_ID'); + + $payload = [ + 'InternalPID' => 999999, // Asumsi tidak ada di DB + "PatientID" => "SMAJ1", + "EmailAddress1" => 'asaas7890@gmail.com', + 'NameFirst' => $faker->firstName, + 'NameLast' => $faker->lastName, + 'Gender' => '1', + 'Birthdate' => $faker->date('Y-m-d'), + 'PatIdt' => [ 'IdentifierType' => 'KTP', 'Identifier' => $faker->nik() ], + 'PatCom' => $faker->sentence, + 'PatAtt' => [], + ]; + + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); + + $result->assertStatus(500); // karena di model akan trigger rollback dan failServerError + } + + /** + * 201 - Update Success + * Pastikan bisa update data yang valid (gunakan dummy data dari database). + */ public function testUpdatePatientSuccess() { $faker = Factory::create('id_ID'); + // NOTE: Sebaiknya ambil InternalPID yang sudah ada (mock atau dari DB fixture) + // Untuk contoh ini kita asumsikan ada ID 1 $payload = [ - "InternalPID" => 1, - "PatientID" => "UPDT" . $faker->numberBetween(100, 999), - "NameFirst" => $faker->firstName, - "NameLast" => $faker->lastName, - "Gender" => (string) $faker->numberBetween(5, 6), - "Birthdate" => $faker->date('Y-m-d'), - "DeathDateTime" => null, - "EmailAddress1" => "asasa@gmail.com", - "PlaceOfBirth" => $faker->city, - "Race" => (string) $faker->numberBetween(175, 205), - "Religion" => (string) $faker->numberBetween(206, 212), - "Country" => (string) $faker->numberBetween(221, 469), - "MaritalStatus" => (string) $faker->numberBetween(8, 15), - "Citizenship" => "WNI", - "LinkTo" => null, - "PatIdt" => [ - "IdentifierType" => "KTP", - "Identifier" => $faker->nik(), + 'InternalPID' => 1, + "PatientID" => "SMAJ1", + 'NameFirst' => $faker->firstName, + 'NameMiddle' => $faker->firstName, + 'NameLast' => $faker->lastName, + 'Gender' => '1', + 'Birthdate' => $faker->date('Y-m-d'), + 'EmailAddress1' => 'update_' . $faker->numberBetween(1,999) . '@gmail.com', + 'PlaceOfBirth' => $faker->city, + 'LinkTo' => null, + 'PatIdt' => [ + 'IdentifierType' => 'KTP', + 'Identifier' => $faker->nik(), + ], + "DeathIndicator" => (string) $faker->numberBetween(16, 17), + 'PatCom' => 'Update be', + 'PatAtt' => [ + [ 'Address' => '/api/upload/' . $faker->word . '.jpg' ], ], - "PatCom" => $faker->sentence(5), - "PatAtt" => [ - [ "Address" => "/api/upload/" . $faker->word . ".jpg" ], - [ "Address" => "/api/upload/" . $faker->word . ".jpg" ] - ] ]; + if($payload['DeathIndicator'] == '16') { + $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s'); + } else { + $payload['DeathDateTime'] = null; + } - $result = $this->withBodyFormat('json')->patch($this->endpoint, $payload); - + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); $result->assertStatus(201); + $json = $result->getJSON(); + $data = json_decode($json, true); + $this->assertEquals('success', $data['status']); } - // /** - // * Test gagal karena InternalPID kosong (validasi) - // */ - public function testUpdatePatientValidationError() + /** + * 201 - Update dengan PatCom kosong + */ + public function testUpdateWithoutPatCom() { $faker = Factory::create('id_ID'); $payload = [ - "NameFirst" => $faker->firstName, - "Gender" => (string) $faker->numberBetween(5, 6), - "Birthdate" => $faker->date('Y-m-d'), - // Tidak kirim InternalPID + 'InternalPID' => 1, + "PatientID" => "SMAJ1", + 'NameFirst' => $faker->firstName, + 'NameMiddle' => $faker->firstName, + 'NameLast' => $faker->lastName, + 'Gender' => '1', + 'Birthdate' => $faker->date('Y-m-d'), + 'EmailAddress1' => 'update_' . $faker->numberBetween(1,999) . '@gmail.com', + 'PlaceOfBirth' => $faker->city, + 'LinkTo' => null, + 'PatIdt' => [ + 'IdentifierType' => 'KTP', + 'Identifier' => $faker->nik(), + ], + "DeathIndicator" => (string) $faker->numberBetween(16, 17), + 'PatCom' => null, + 'PatAtt' => [ + [ 'Address' => '/api/upload/' . $faker->word . '.jpg' ], + ], ]; + if($payload['DeathIndicator'] == '16') { + $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s'); + } else { + $payload['DeathDateTime'] = null; + } - $result = $this->withBodyFormat('json')->patch($this->endpoint, $payload); + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); + $result->assertStatus(201); + } + + /** + * 201 - Update tanpa PatAtt + */ + public function testUpdateWithoutAttachments() + { + $faker = Factory::create('id_ID'); + + $payload = [ + 'InternalPID' => 1, + "PatientID" => "SMAJ1", + 'NameFirst' => $faker->firstName, + 'NameMiddle' => $faker->firstName, + 'NameLast' => $faker->lastName, + 'Gender' => '1', + 'Birthdate' => $faker->date('Y-m-d'), + 'EmailAddress1' => 'update_' . $faker->numberBetween(1,999) . '@gmail.com', + 'PlaceOfBirth' => $faker->city, + 'LinkTo' => null, + 'PatIdt' => [ + 'IdentifierType' => 'KTP', + 'Identifier' => $faker->nik(), + ], + "DeathIndicator" => (string) $faker->numberBetween(16, 17), + 'PatCom' => null, + 'PatAtt' => [], + ]; + if($payload['DeathIndicator'] == '16') { + $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s'); + } else { + $payload['DeathDateTime'] = null; + } + + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); + $result->assertStatus(201); + } + + /** + * 201 - Update tanpa PatAtt + */ + public function testUpdateWithAttachments() + { + $faker = Factory::create('id_ID'); + + $payload = [ + 'InternalPID' => 1, + "PatientID" => "SMAJ1", + 'NameFirst' => $faker->firstName, + 'NameMiddle' => $faker->firstName, + 'NameLast' => $faker->lastName, + 'Gender' => '1', + 'Birthdate' => $faker->date('Y-m-d'), + 'EmailAddress1' => 'update_' . $faker->numberBetween(1,999) . '@gmail.com', + 'PlaceOfBirth' => $faker->city, + 'LinkTo' => null, + 'PatIdt' => [ + 'IdentifierType' => 'KTP', + 'Identifier' => $faker->nik(), + ], + "DeathIndicator" => (string) $faker->numberBetween(16, 17), + 'PatCom' => null, + 'PatAtt' => [ + [ 'Address' => '/api/upload/' . $faker->word . '.jpg' ], + ], + ]; + if($payload['DeathIndicator'] == '16') { + $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s'); + } else { + $payload['DeathDateTime'] = null; + } + + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); + $result->assertStatus(201); + } + + // /** + // * 500 - Invalid PatIdt + // */ + public function testUpdatePatIdtInvalid() + { + $faker = Factory::create('id_ID'); + + $payload = [ + 'InternalPID' => 1, + "PatientID" => "SMAJ1", + 'NameFirst' => $faker->firstName, + 'NameMiddle' => $faker->firstName, + 'NameLast' => $faker->lastName, + 'Gender' => '1', + 'Birthdate' => $faker->date('Y-m-d'), + 'EmailAddress1' => 'update_' . $faker->numberBetween(1,999) . '@gmail.com', + 'PlaceOfBirth' => $faker->city, + 'LinkTo' => null, + 'PatIdt' => [ + 'IdentifierType' => [], + 'Identifier' => $faker->nik(), + ], + "DeathIndicator" => (string) $faker->numberBetween(16, 17), + 'PatCom' => null, + 'PatAtt' => [ + [ 'Address' => '/api/upload/' . $faker->word . '.jpg' ], + ], + ]; + if($payload['DeathIndicator'] == '16') { + $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s'); + } else { + $payload['DeathDateTime'] = null; + } + + $result = $this->withBodyFormat('json')->call('patch', $this->endpoint, $payload); + + $result->assertStatus(500); $json = $result->getJSON(); $data = json_decode($json, true); - - $result->assertStatus(400); $this->assertArrayHasKey('error', $data); } - // /** - // * Test update dengan address baru & hapus address lama - // */ - public function testUpdatePatientWithAddressChange() - { - $faker = Factory::create('id_ID'); - - $payload = [ - "InternalPID" => 1, - "PatientID" => "UPDT" . $faker->numberBetween(100, 999), - "NameFirst" => $faker->firstName, - "NameLast" => $faker->lastName, - "Gender" => (string) $faker->numberBetween(5, 6), - "Birthdate" => $faker->date('Y-m-d'), - "DeathDateTime" => null, - "EmailAddress1" => "asasa@gmail.com", - "PlaceOfBirth" => $faker->city, - "Race" => (string) $faker->numberBetween(175, 205), - "Religion" => (string) $faker->numberBetween(206, 212), - "Country" => (string) $faker->numberBetween(221, 469), - "MaritalStatus" => (string) $faker->numberBetween(8, 15), - "Citizenship" => "WNI", - "LinkTo" => null, - "PatIdt" => [ - "IdentifierType" => "KTP", - "Identifier" => $faker->nik(), - ], - "PatCom" => $faker->sentence(5), - "PatAtt" => [ - [ "Address" => "/api/upload/" . $faker->word . ".jpg" ], - [ "Address" => "/api/upload/" . $faker->word . ".jpg" ], - [ "Address" => "/api/upload/" . $faker->word . ".jpg" ], - [ "Address" => "/api/upload/" . $faker->word . ".jpg" ] - ] - ]; - - $result = $this->withBodyFormat('json')->patch($this->endpoint, $payload); - - $result->assertStatus(201); - - $json = $result->getJSON(); - $data = json_decode($json, true); - - $this->assertEquals('success', $data['status']); - } - - // /** - // * Test update kosong → semua pattat address dihapus (soft delete) - // */ - public function testUpdatePatientEmptyAddress() - { - $faker = Factory::create('id_ID'); - - $payload = [ - "InternalPID" => 1, - "PatientID" => "UPDT" . $faker->numberBetween(100, 999), - "NameFirst" => $faker->firstName, - "NameLast" => $faker->lastName, - "Gender" => (string) $faker->numberBetween(5, 6), - "Birthdate" => $faker->date('Y-m-d'), - "DeathDateTime" => null, - "EmailAddress1" => "asasa@gmail.com", - "PlaceOfBirth" => $faker->city, - "Race" => (string) $faker->numberBetween(175, 205), - "Religion" => (string) $faker->numberBetween(206, 212), - "Country" => (string) $faker->numberBetween(221, 469), - "MaritalStatus" => (string) $faker->numberBetween(8, 15), - "Citizenship" => "WNI", - "LinkTo" => null, - "PatIdt" => [ - "IdentifierType" => "KTP", - "Identifier" => $faker->nik(), - ], - "PatCom" => $faker->sentence(5), - "PatAtt" => [] - ]; - - $result = $this->withBodyFormat('json')->patch($this->endpoint, $payload); - - $json = $result->getJSON(); - $data = json_decode($json, true); - - $result->assertStatus(201); - $this->assertEquals('success', $data['status']); - } - }