286 lines
11 KiB
PHP
286 lines
11 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()
|
|
{
|
|
$internalPID = $this->createOrderTestPatient();
|
|
|
|
// 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(strip_tags($result->getBody()), true);
|
|
$this->assertIsArray($body);
|
|
$messages = $body['messages'] ?? $body['errors'] ?? [];
|
|
$this->assertIsArray($messages);
|
|
$this->assertArrayHasKey('InternalPID', $messages);
|
|
}
|
|
|
|
public function testCreateOrderFailsWithInvalidPatient()
|
|
{
|
|
$payload = [
|
|
'InternalPID' => 999999,
|
|
'Tests' => [
|
|
['TestSiteID' => 1]
|
|
]
|
|
];
|
|
|
|
$result = $this->withBodyFormat('json')->call('post', $this->endpoint, $payload);
|
|
|
|
$result->assertStatus(400);
|
|
|
|
$body = json_decode(strip_tags($result->getBody()), true);
|
|
$this->assertIsArray($body);
|
|
$messages = $body['messages'] ?? $body['errors'] ?? [];
|
|
$this->assertIsArray($messages);
|
|
$this->assertArrayHasKey('InternalPID', $messages);
|
|
}
|
|
|
|
public function testCreateOrderWithMultipleTests()
|
|
{
|
|
$internalPID = $this->createOrderTestPatient();
|
|
|
|
// 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');
|
|
}
|
|
|
|
public function testOrderShowIncludesDisciplineAndSequenceOrdering()
|
|
{
|
|
$internalPID = $this->createOrderTestPatient();
|
|
$testSiteIDs = $this->collectTestSiteIDs(2);
|
|
|
|
$orderID = $this->createOrderWithTests($internalPID, $testSiteIDs);
|
|
|
|
$response = $this->call('get', $this->endpoint . '/' . $orderID);
|
|
$response->assertStatus(200);
|
|
|
|
$body = json_decode($response->getBody(), true);
|
|
$this->assertEquals('success', $body['status']);
|
|
|
|
$tests = $body['data']['Tests'] ?? [];
|
|
$this->assertNotEmpty($tests, 'Tests payload should not be empty');
|
|
|
|
$lastKey = null;
|
|
foreach ($tests as $test) {
|
|
$this->assertArrayHasKey('Discipline', $test);
|
|
$this->assertArrayHasKey('TestType', $test);
|
|
$this->assertNotEmpty($test['TestType'], 'Each test should report a test type');
|
|
$this->assertArrayHasKey('SeqScr', $test);
|
|
$this->assertArrayHasKey('SeqRpt', $test);
|
|
|
|
$discipline = $test['Discipline'];
|
|
$this->assertArrayHasKey('DisciplineID', $discipline);
|
|
$this->assertArrayHasKey('DisciplineName', $discipline);
|
|
$this->assertArrayHasKey('SeqScr', $discipline);
|
|
$this->assertArrayHasKey('SeqRpt', $discipline);
|
|
|
|
$currentKey = $this->buildTestSortKey($test);
|
|
if ($lastKey !== null) {
|
|
$this->assertGreaterThanOrEqual($lastKey, $currentKey, 'Tests are not ordered by discipline/test sequence');
|
|
}
|
|
$lastKey = $currentKey;
|
|
}
|
|
}
|
|
|
|
private function createOrderTestPatient(): int
|
|
{
|
|
$faker = Factory::create('id_ID');
|
|
$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;
|
|
}
|
|
|
|
$patientModel = new \App\Models\Patient\PatientModel();
|
|
$internalPID = $patientModel->createPatient($patientPayload);
|
|
$this->assertNotNull($internalPID, 'Failed to create test patient. Response: ' . print_r($patientPayload, true));
|
|
|
|
return $internalPID;
|
|
}
|
|
|
|
private function createOrderWithTests(int $internalPID, array $testSiteIDs, string $priority = 'R'): string
|
|
{
|
|
$payload = [
|
|
'InternalPID' => $internalPID,
|
|
'Priority' => $priority,
|
|
'Tests' => array_map(fn ($testSiteID) => ['TestSiteID' => $testSiteID], $testSiteIDs),
|
|
];
|
|
|
|
$result = $this->withBodyFormat('json')->call('post', $this->endpoint, $payload);
|
|
$result->assertStatus(201);
|
|
|
|
$body = json_decode($result->getBody(), true);
|
|
$this->assertEquals('success', $body['status']);
|
|
$orderID = $body['data']['OrderID'] ?? null;
|
|
$this->assertNotNull($orderID, 'Order creation response is missing OrderID');
|
|
|
|
return $orderID;
|
|
}
|
|
|
|
private function collectTestSiteIDs(int $count = 2): array
|
|
{
|
|
$response = $this->call('get', 'api/test');
|
|
$body = json_decode($response->getBody(), true);
|
|
$availableTests = $body['data'] ?? [];
|
|
|
|
if (count($availableTests) < $count) {
|
|
$this->markTestSkipped('Need at least ' . $count . ' tests to validate ordering.');
|
|
}
|
|
|
|
$ids = array_values(array_filter(array_column($availableTests, 'TestSiteID')));
|
|
return array_slice($ids, 0, $count);
|
|
}
|
|
|
|
private function buildTestSortKey(array $test): string
|
|
{
|
|
$discipline = $test['Discipline'] ?? [];
|
|
$discSeqScr = $this->normalizeSequenceValue($discipline['SeqScr'] ?? null);
|
|
$discSeqRpt = $this->normalizeSequenceValue($discipline['SeqRpt'] ?? null);
|
|
$testSeqScr = $this->normalizeSequenceValue($test['SeqScr'] ?? null);
|
|
$testSeqRpt = $this->normalizeSequenceValue($test['SeqRpt'] ?? null);
|
|
$resultID = isset($test['ResultID']) ? (int)$test['ResultID'] : 0;
|
|
|
|
return sprintf('%06d-%06d-%06d-%06d-%010d', $discSeqScr, $discSeqRpt, $testSeqScr, $testSeqRpt, $resultID);
|
|
}
|
|
|
|
private function normalizeSequenceValue($value): int
|
|
{
|
|
if (is_numeric($value)) {
|
|
return (int)$value;
|
|
}
|
|
|
|
return 999999;
|
|
}
|
|
}
|