clqms-be/tests/feature/Orders/OrderCreateTest.php
mahdahar 42006e1af9 feat: implement comprehensive order management with specimens and tests
Major updates to order system:
- Add specimen and test data to order responses (index, show, create, update, status update)
- Implement getOrderSpecimens() and getOrderTests() private methods in OrderTestController
- Support 'include=details' query parameter for expanded order data
- Update OrderTestModel with enhanced query capabilities and transaction handling

API documentation:
- Update OpenAPI specs for orders, patient-visits, and tests
- Add new schemas for order specimens and tests
- Regenerate bundled API documentation

Database:
- Add Requestable field to TestDefSite migration
- Create OrderSeeder and ClearOrderDataSeeder for test data
- Update DBSeeder to include order seeding

Patient visits:
- Add filtering by PatientID, PatientName, and date ranges
- Include LastLocation in visit queries

Testing:
- Add OrderCreateTest with comprehensive test coverage

Documentation:
- Update AGENTS.md with improved controller structure examples
2026-03-03 13:51:27 +07:00

211 lines
8.1 KiB
PHP

<?php
namespace Tests\Feature\Orders;
use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Test\CIUnitTestCase;
use Faker\Factory;
class OrderCreateTest extends CIUnitTestCase
{
use FeatureTestTrait;
protected $endpoint = 'api/ordertest';
public function testCreateOrderSuccess()
{
$faker = Factory::create('id_ID');
// First create a patient using the same approach as PatientCreateTest
$patientPayload = [
"PatientID" => "ORD" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"AlternatePID" => "DMY" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"Prefix" => $faker->title,
"NameFirst" => "Order",
"NameMiddle" => $faker->firstName,
"NameMaiden" => $faker->firstName,
"NameLast" => "Test",
"Suffix" => "S.Kom",
"NameAlias" => $faker->userName,
"Sex" => $faker->numberBetween(5, 6),
"PlaceOfBirth" => $faker->city,
"Birthdate" => "1990-01-01",
"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" => "A" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000).'@gmail.com',
"EmailAddress2" => "B" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000).'@gmail.com',
"Phone" => $faker->numerify('08##########'),
"MobilePhone" => $faker->numerify('08##########'),
"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" => [
[ "Address" => "/api/upload/" . $faker->uuid . ".jpg" ]
],
"PatCom" => $faker->sentence,
];
if($patientPayload['DeathIndicator'] == '16') {
$patientPayload['DeathDateTime'] = $faker->date('Y-m-d H:i:s');
} else {
$patientPayload['DeathDateTime'] = null;
}
$patientResult = $this->withBodyFormat('json')->call('post', 'api/patient', $patientPayload);
// Check patient creation succeeded
$patientResult->assertStatus(201);
$patientBody = json_decode($patientResult->getBody(), true);
$internalPID = $patientBody['data']['InternalPID'] ?? null;
$this->assertNotNull($internalPID, 'Failed to create test patient. Response: ' . print_r($patientBody, true));
// Get available tests from testdefsite
$testsResult = $this->call('get', 'api/test');
$testsBody = json_decode($testsResult->getBody(), true);
$availableTests = $testsBody['data'] ?? [];
// Skip if no tests available
if (empty($availableTests)) {
$this->markTestSkipped('No tests available in testdefsite table');
}
$testSiteID = $availableTests[0]['TestSiteID'];
// Create order with tests
$payload = [
'InternalPID' => $internalPID,
'Priority' => 'R',
'Tests' => [
['TestSiteID' => $testSiteID]
]
];
$result = $this->withBodyFormat('json')->call('post', $this->endpoint, $payload);
// Assertions
$result->assertStatus(201);
$body = json_decode($result->getBody(), true);
$this->assertEquals('success', $body['status']);
$this->assertArrayHasKey('data', $body);
$this->assertArrayHasKey('OrderID', $body['data']);
$this->assertArrayHasKey('Specimens', $body['data']);
$this->assertArrayHasKey('Tests', $body['data']);
$this->assertIsArray($body['data']['Specimens']);
$this->assertIsArray($body['data']['Tests']);
$this->assertNotEmpty($body['data']['Tests'], 'Tests array should not be empty');
return $body['data']['OrderID'];
}
public function testCreateOrderValidationFailsWithoutInternalPID()
{
$payload = [
'Tests' => [
['TestSiteID' => 1]
]
];
$result = $this->withBodyFormat('json')->call('post', $this->endpoint, $payload);
$result->assertStatus(400);
$body = json_decode($result->getBody(), true);
$this->assertIsArray($body);
$this->assertArrayHasKey('errors', $body);
}
public function testCreateOrderFailsWithInvalidPatient()
{
$payload = [
'InternalPID' => 999999,
'Tests' => [
['TestSiteID' => 1]
]
];
$result = $this->withBodyFormat('json')->call('post', $this->endpoint, $payload);
$result->assertStatus(400);
$body = json_decode($result->getBody(), true);
$this->assertIsArray($body);
$this->assertArrayHasKey('errors', $body);
}
public function testCreateOrderWithMultipleTests()
{
$faker = Factory::create('id_ID');
// First create a patient
$patientPayload = [
"PatientID" => "ORDM" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000),
"NameFirst" => "Multi",
"NameLast" => "Test",
"Sex" => "2",
"Birthdate" => "1985-05-15",
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->numerify('################')
]
];
$patientResult = $this->withBodyFormat('json')->call('post', 'api/patient', $patientPayload);
$patientBody = json_decode($patientResult->getBody(), true);
$internalPID = $patientBody['data']['InternalPID'] ?? null;
$this->assertNotNull($internalPID, 'Failed to create test patient');
// Get available tests
$testsResult = $this->call('get', 'api/test');
$testsBody = json_decode($testsResult->getBody(), true);
$availableTests = $testsBody['data'] ?? [];
if (count($availableTests) < 2) {
$this->markTestSkipped('Need at least 2 tests for this test');
}
$testSiteID1 = $availableTests[0]['TestSiteID'];
$testSiteID2 = $availableTests[1]['TestSiteID'];
// Create order with multiple tests
$payload = [
'InternalPID' => $internalPID,
'Priority' => 'S',
'Comment' => 'Urgent order for multiple tests',
'Tests' => [
['TestSiteID' => $testSiteID1],
['TestSiteID' => $testSiteID2]
]
];
$result = $this->withBodyFormat('json')->call('post', $this->endpoint, $payload);
$result->assertStatus(201);
$body = json_decode($result->getBody(), true);
$this->assertEquals('success', $body['status']);
$this->assertGreaterThanOrEqual(1, count($body['data']['Specimens']), 'Should have at least one specimen');
$this->assertGreaterThanOrEqual(2, count($body['data']['Tests']), 'Should have at least two tests');
}
}