Support test lifecycle updates in order patch
- add Tests delta handling to order patch endpoint\n- create/edit/soft-delete patres rows in transaction\n- update OpenAPI request schema for Tests payload\n- add feature coverage for create/edit/delete lifecycle
This commit is contained in:
parent
e869ec4ac4
commit
6b4ffe017c
@ -220,22 +220,63 @@ class OrderTestController extends Controller {
|
||||
return $this->failValidationErrors(['OrderID' => 'OrderID in URL does not match body']);
|
||||
}
|
||||
|
||||
$transactionStarted = false;
|
||||
|
||||
try {
|
||||
$input['OrderID'] = $OrderID;
|
||||
$order = $this->model->getOrder($OrderID);
|
||||
if (!$order) {
|
||||
return $this->failNotFound('Order not found');
|
||||
}
|
||||
|
||||
$updateData = [];
|
||||
if (isset($input['Priority'])) $updateData['Priority'] = $input['Priority'];
|
||||
if (isset($input['OrderStatus'])) $updateData['OrderStatus'] = $input['OrderStatus'];
|
||||
if (isset($input['OrderingProvider'])) $updateData['OrderingProvider'] = $input['OrderingProvider'];
|
||||
if (isset($input['DepartmentID'])) $updateData['DepartmentID'] = $input['DepartmentID'];
|
||||
if (isset($input['WorkstationID'])) $updateData['WorkstationID'] = $input['WorkstationID'];
|
||||
if (array_key_exists('Priority', $input)) {
|
||||
$updateData['Priority'] = $input['Priority'];
|
||||
}
|
||||
if (array_key_exists('OrderStatus', $input)) {
|
||||
$updateData['OrderStatus'] = $input['OrderStatus'];
|
||||
}
|
||||
if (array_key_exists('OrderingProvider', $input)) {
|
||||
$updateData['OrderingProvider'] = $input['OrderingProvider'];
|
||||
}
|
||||
if (array_key_exists('DepartmentID', $input)) {
|
||||
$updateData['DepartmentID'] = $input['DepartmentID'];
|
||||
}
|
||||
if (array_key_exists('WorkstationID', $input)) {
|
||||
$updateData['WorkstationID'] = $input['WorkstationID'];
|
||||
}
|
||||
|
||||
if (!empty($updateData)) {
|
||||
$this->model->update($order['InternalOID'], $updateData);
|
||||
$testsDelta = null;
|
||||
if (array_key_exists('Tests', $input)) {
|
||||
$testsDelta = $this->normalizeTestsDelta($input['Tests']);
|
||||
}
|
||||
|
||||
if (empty($updateData) && $testsDelta === null) {
|
||||
return $this->failValidationErrors(['error' => 'Update payload is required']);
|
||||
}
|
||||
|
||||
$hasUpdates = !empty($updateData) || $testsDelta !== null;
|
||||
if ($hasUpdates) {
|
||||
$this->db->transStart();
|
||||
$transactionStarted = true;
|
||||
|
||||
if (!empty($updateData)) {
|
||||
$updated = $this->model->update($order['InternalOID'], $updateData);
|
||||
if (!$updated) {
|
||||
throw new \RuntimeException('Failed to update order');
|
||||
}
|
||||
}
|
||||
|
||||
if ($testsDelta !== null) {
|
||||
$this->model->applyTestDelta((int) $order['InternalOID'], $testsDelta, $order);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
if ($this->db->transStatus() === false) {
|
||||
throw new \RuntimeException('Transaction failed');
|
||||
}
|
||||
|
||||
$transactionStarted = false;
|
||||
}
|
||||
|
||||
$updatedOrder = $this->model->getOrder($OrderID);
|
||||
@ -247,11 +288,51 @@ class OrderTestController extends Controller {
|
||||
'message' => 'Order updated successfully',
|
||||
'data' => $updatedOrder
|
||||
], 200);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
if ($transactionStarted) {
|
||||
$this->db->transRollback();
|
||||
}
|
||||
|
||||
return $this->failValidationErrors(['Tests' => $e->getMessage()]);
|
||||
} catch (\Exception $e) {
|
||||
if ($transactionStarted) {
|
||||
$this->db->transRollback();
|
||||
}
|
||||
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function normalizeTestsDelta($tests): ?array {
|
||||
if (!is_array($tests)) {
|
||||
throw new \InvalidArgumentException('Tests must be an object');
|
||||
}
|
||||
|
||||
$delta = [
|
||||
'created' => [],
|
||||
'edited' => [],
|
||||
'deleted' => [],
|
||||
];
|
||||
|
||||
foreach (array_keys($delta) as $key) {
|
||||
if (!array_key_exists($key, $tests)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_array($tests[$key])) {
|
||||
throw new \InvalidArgumentException(ucfirst($key) . ' tests must be an array');
|
||||
}
|
||||
|
||||
$delta[$key] = $tests[$key];
|
||||
}
|
||||
|
||||
if (empty($delta['created']) && empty($delta['edited']) && empty($delta['deleted'])) {
|
||||
throw new \InvalidArgumentException('Tests delta is required');
|
||||
}
|
||||
|
||||
return $delta;
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
$input = $this->request->getJSON(true);
|
||||
$orderID = $input['OrderID'] ?? null;
|
||||
|
||||
@ -231,6 +231,168 @@ class OrderTestModel extends BaseModel {
|
||||
}
|
||||
}
|
||||
|
||||
public function applyTestDelta(int $orderOID, array $testsDelta, ?array $order = null): array {
|
||||
$order ??= $this->find($orderOID);
|
||||
if (!$order) {
|
||||
throw new \InvalidArgumentException('Order not found');
|
||||
}
|
||||
|
||||
$summary = [
|
||||
'created' => [],
|
||||
'edited' => [],
|
||||
'deleted' => [],
|
||||
];
|
||||
|
||||
foreach (($testsDelta['created'] ?? []) as $item) {
|
||||
if (!is_array($item)) {
|
||||
throw new \InvalidArgumentException('Invalid created test payload');
|
||||
}
|
||||
|
||||
$summary['created'][] = $this->createTestRow($order, $item);
|
||||
}
|
||||
|
||||
foreach (($testsDelta['edited'] ?? []) as $item) {
|
||||
if (!is_array($item)) {
|
||||
throw new \InvalidArgumentException('Invalid edited test payload');
|
||||
}
|
||||
|
||||
$summary['edited'][] = $this->editTestRow($orderOID, $item);
|
||||
}
|
||||
|
||||
foreach (($testsDelta['deleted'] ?? []) as $item) {
|
||||
$testSiteID = is_array($item) ? (int) ($item['TestSiteID'] ?? 0) : (int) $item;
|
||||
if ($testSiteID <= 0) {
|
||||
throw new \InvalidArgumentException('TestSiteID is required for deleted tests');
|
||||
}
|
||||
|
||||
$summary['deleted'][] = $this->deleteTestRow($orderOID, $testSiteID);
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
private function createTestRow(array $order, array $item): array {
|
||||
$testSiteID = (int) ($item['TestSiteID'] ?? 0);
|
||||
if ($testSiteID <= 0) {
|
||||
throw new \InvalidArgumentException('TestSiteID is required');
|
||||
}
|
||||
|
||||
$testSite = $this->db->table('testdefsite')
|
||||
->select('TestSiteID, TestSiteCode')
|
||||
->where('TestSiteID', $testSiteID)
|
||||
->where('EndDate', null)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (!$testSite) {
|
||||
throw new \InvalidArgumentException('Test site not found');
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'OrderID' => (int) $order['InternalOID'],
|
||||
'TestSiteID' => $testSiteID,
|
||||
'TestSiteCode' => $testSite['TestSiteCode'],
|
||||
'SID' => (string) ($order['OrderID'] ?? ''),
|
||||
'SampleID' => (string) ($order['OrderID'] ?? ''),
|
||||
'ResultDateTime' => $item['ResultDateTime'] ?? ($order['TrnDate'] ?? date('Y-m-d H:i:s')),
|
||||
'CreateDate' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$payload['Result'] = $item['Result'] ?? $item['ResultValue'] ?? null;
|
||||
|
||||
$extraFields = array_intersect_key($item, array_flip([
|
||||
'InternalSID',
|
||||
'AspCnt',
|
||||
'ResultCode',
|
||||
'SampleType',
|
||||
'WorkstationID',
|
||||
'EquipmentID',
|
||||
'RefNumID',
|
||||
'RefTxtID',
|
||||
]));
|
||||
|
||||
$payload = array_merge($payload, $extraFields);
|
||||
|
||||
if (!$this->db->table('patres')->insert($payload)) {
|
||||
throw new \RuntimeException('Failed to create test row');
|
||||
}
|
||||
|
||||
return [
|
||||
'ResultID' => (int) $this->db->insertID(),
|
||||
'TestSiteID' => $testSiteID,
|
||||
];
|
||||
}
|
||||
|
||||
private function editTestRow(int $orderOID, array $item): array {
|
||||
$testSiteID = (int) ($item['TestSiteID'] ?? 0);
|
||||
if ($testSiteID <= 0) {
|
||||
throw new \InvalidArgumentException('TestSiteID is required');
|
||||
}
|
||||
|
||||
$row = $this->getLatestActiveTestRow($orderOID, $testSiteID);
|
||||
if (!$row) {
|
||||
throw new \InvalidArgumentException('Test row not found');
|
||||
}
|
||||
|
||||
$updateData = array_intersect_key($item, array_flip([
|
||||
'InternalSID',
|
||||
'AspCnt',
|
||||
'Result',
|
||||
'ResultCode',
|
||||
'SampleType',
|
||||
'ResultDateTime',
|
||||
'WorkstationID',
|
||||
'EquipmentID',
|
||||
'RefNumID',
|
||||
'RefTxtID',
|
||||
]));
|
||||
|
||||
if (empty($updateData)) {
|
||||
throw new \InvalidArgumentException('Edit payload is empty');
|
||||
}
|
||||
|
||||
if (!$this->db->table('patres')
|
||||
->where('ResultID', $row['ResultID'])
|
||||
->update($updateData)) {
|
||||
throw new \RuntimeException('Failed to update test row');
|
||||
}
|
||||
|
||||
return [
|
||||
'ResultID' => (int) $row['ResultID'],
|
||||
'TestSiteID' => $testSiteID,
|
||||
];
|
||||
}
|
||||
|
||||
private function deleteTestRow(int $orderOID, int $testSiteID): array {
|
||||
$row = $this->getLatestActiveTestRow($orderOID, $testSiteID);
|
||||
if (!$row) {
|
||||
throw new \InvalidArgumentException('Test row not found');
|
||||
}
|
||||
|
||||
if (!$this->db->table('patres')
|
||||
->where('ResultID', $row['ResultID'])
|
||||
->update(['DelDate' => date('Y-m-d H:i:s')])) {
|
||||
throw new \RuntimeException('Failed to delete test row');
|
||||
}
|
||||
|
||||
return [
|
||||
'ResultID' => (int) $row['ResultID'],
|
||||
'TestSiteID' => $testSiteID,
|
||||
];
|
||||
}
|
||||
|
||||
private function getLatestActiveTestRow(int $orderOID, int $testSiteID): ?array {
|
||||
$row = $this->db->table('patres')
|
||||
->where('OrderID', $orderOID)
|
||||
->where('TestSiteID', $testSiteID)
|
||||
->where('DelDate', null)
|
||||
->orderBy('ResultID', 'DESC')
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
private function getContainerRequirement($testSiteID, $testMapDetailModel, $containerDefModel): array {
|
||||
// Try to find container requirement from test mapping
|
||||
$containerDef = $this->db->table('testmapdetail tmd')
|
||||
|
||||
@ -1502,6 +1502,44 @@ paths:
|
||||
type: integer
|
||||
WorkstationID:
|
||||
type: integer
|
||||
Tests:
|
||||
type: object
|
||||
properties:
|
||||
created:
|
||||
type: array
|
||||
description: New tests to create for this order
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
Result:
|
||||
type: string
|
||||
nullable: true
|
||||
ResultDateTime:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
edited:
|
||||
type: array
|
||||
description: Existing tests to edit by OrderID + TestSiteID
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
Result:
|
||||
type: string
|
||||
nullable: true
|
||||
ResultDateTime:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
deleted:
|
||||
type: array
|
||||
description: TestSiteID values to soft delete by latest active row
|
||||
items:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Order updated
|
||||
|
||||
@ -252,6 +252,44 @@
|
||||
type: integer
|
||||
WorkstationID:
|
||||
type: integer
|
||||
Tests:
|
||||
type: object
|
||||
properties:
|
||||
created:
|
||||
type: array
|
||||
description: New tests to create for this order
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
Result:
|
||||
type: string
|
||||
nullable: true
|
||||
ResultDateTime:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
edited:
|
||||
type: array
|
||||
description: Existing tests to edit by OrderID + TestSiteID
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
Result:
|
||||
type: string
|
||||
nullable: true
|
||||
ResultDateTime:
|
||||
type: string
|
||||
format: date-time
|
||||
nullable: true
|
||||
deleted:
|
||||
type: array
|
||||
description: TestSiteID values to soft delete by latest active row
|
||||
items:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Order updated
|
||||
|
||||
@ -1,121 +1,222 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\OrderTest;
|
||||
|
||||
use CodeIgniter\Test\FeatureTestTrait;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use Firebase\JWT\JWT;
|
||||
|
||||
class OrderTestPatchTest extends CIUnitTestCase
|
||||
{
|
||||
use FeatureTestTrait;
|
||||
|
||||
protected string $token;
|
||||
protected string $endpoint = 'api/ordertest';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$key = getenv('JWT_SECRET') ?: 'my-secret-key';
|
||||
$payload = [
|
||||
'iss' => 'localhost',
|
||||
'aud' => 'localhost',
|
||||
'iat' => time(),
|
||||
'nbf' => time(),
|
||||
'exp' => time() + 3600,
|
||||
'uid' => 1,
|
||||
'email' => 'admin@admin.com',
|
||||
];
|
||||
$this->token = JWT::encode($payload, $key, 'HS256');
|
||||
}
|
||||
|
||||
private function authHeaders(): array
|
||||
{
|
||||
return ['Cookie' => 'token=' . $this->token];
|
||||
}
|
||||
|
||||
private function createOrderTest(array $data = []): array
|
||||
{
|
||||
$payload = array_merge([
|
||||
'OrderCode' => 'ORD_' . uniqid(),
|
||||
'OrderName' => 'Test Order ' . uniqid(),
|
||||
], $data);
|
||||
|
||||
$response = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('post', $this->endpoint, $payload);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$decoded = json_decode($response->getJSON(), true);
|
||||
return $decoded['data'];
|
||||
}
|
||||
|
||||
public function testPartialUpdateOrderTestSuccess()
|
||||
{
|
||||
$order = $this->createOrderTest();
|
||||
$id = $order['OrderID'];
|
||||
|
||||
$patch = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$id}", ['OrderName' => 'Updated Order']);
|
||||
|
||||
$patch->assertStatus(200);
|
||||
$patchData = json_decode($patch->getJSON(), true);
|
||||
$this->assertEquals('success', $patchData['status']);
|
||||
|
||||
$show = $this->withHeaders($this->authHeaders())->call('get', "{$this->endpoint}/{$id}");
|
||||
$show->assertStatus(200);
|
||||
$showData = json_decode($show->getJSON(), true)['data'];
|
||||
|
||||
$this->assertEquals('Updated Order', $showData['OrderName']);
|
||||
$this->assertEquals($order['OrderCode'], $showData['OrderCode']);
|
||||
}
|
||||
|
||||
public function testPartialUpdateOrderTestNotFound()
|
||||
{
|
||||
$patch = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/999999", ['OrderName' => 'Updated']);
|
||||
|
||||
$patch->assertStatus(404);
|
||||
}
|
||||
|
||||
public function testPartialUpdateOrderTestInvalidId()
|
||||
{
|
||||
$patch = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/invalid", ['OrderName' => 'Updated']);
|
||||
|
||||
$patch->assertStatus(400);
|
||||
}
|
||||
|
||||
public function testPartialUpdateOrderTestEmptyPayload()
|
||||
{
|
||||
$order = $this->createOrderTest();
|
||||
$id = $order['OrderID'];
|
||||
|
||||
$patch = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$id}", []);
|
||||
|
||||
$patch->assertStatus(400);
|
||||
}
|
||||
|
||||
public function testPartialUpdateOrderTestSingleField()
|
||||
{
|
||||
$order = $this->createOrderTest();
|
||||
$id = $order['OrderID'];
|
||||
|
||||
$patch = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$id}", ['OrderCode' => 'NEW_' . uniqid()]);
|
||||
|
||||
$patch->assertStatus(200);
|
||||
$showData = json_decode($this->withHeaders($this->authHeaders())
|
||||
->call('get', "{$this->endpoint}/{$id}")
|
||||
->getJSON(), true)['data'];
|
||||
|
||||
$this->assertNotEquals($order['OrderCode'], $showData['OrderCode']);
|
||||
$this->assertEquals($order['OrderName'], $showData['OrderName']);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Feature\OrderTest;
|
||||
|
||||
use App\Models\OrderTest\OrderTestModel;
|
||||
use App\Models\PatResultModel;
|
||||
use App\Models\Patient\PatientModel;
|
||||
use App\Models\Test\TestDefSiteModel;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use CodeIgniter\Test\FeatureTestTrait;
|
||||
use Firebase\JWT\JWT;
|
||||
|
||||
class OrderTestPatchTest extends CIUnitTestCase
|
||||
{
|
||||
use FeatureTestTrait;
|
||||
|
||||
protected string $token;
|
||||
protected string $endpoint = 'api/ordertest';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$key = getenv('JWT_SECRET') ?: 'my-secret-key';
|
||||
$payload = [
|
||||
'iss' => 'localhost',
|
||||
'aud' => 'localhost',
|
||||
'iat' => time(),
|
||||
'nbf' => time(),
|
||||
'exp' => time() + 3600,
|
||||
'uid' => 1,
|
||||
'email' => 'admin@admin.com',
|
||||
];
|
||||
$this->token = JWT::encode($payload, $key, 'HS256');
|
||||
}
|
||||
|
||||
private function authHeaders(): array
|
||||
{
|
||||
return ['Cookie' => 'token=' . $this->token];
|
||||
}
|
||||
|
||||
private function findResultByOrderAndSite(int $internalOID, int $testSiteID): ?array
|
||||
{
|
||||
$resultModel = new PatResultModel();
|
||||
|
||||
return $resultModel->where('OrderID', $internalOID)
|
||||
->where('TestSiteID', $testSiteID)
|
||||
->where('DelDate', null)
|
||||
->orderBy('ResultID', 'DESC')
|
||||
->first();
|
||||
}
|
||||
|
||||
private function findRowBySite(array $rows, int $testSiteID): ?array
|
||||
{
|
||||
foreach ($rows as $row) {
|
||||
if ((int) ($row['TestSiteID'] ?? 0) === $testSiteID) {
|
||||
return $row;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function createOrderWithTest(): array
|
||||
{
|
||||
$patientModel = new PatientModel();
|
||||
$patient = $patientModel->where('DelDate', null)->first();
|
||||
$this->assertNotEmpty($patient, 'No active patient found for order patch test.');
|
||||
|
||||
$testModel = new TestDefSiteModel();
|
||||
$tests = $testModel->where('EndDate', null)
|
||||
->where('TestType', 'TEST')
|
||||
->findAll(2);
|
||||
|
||||
if (count($tests) < 2) {
|
||||
$tests = $testModel->where('EndDate', null)->findAll(2);
|
||||
}
|
||||
|
||||
$this->assertGreaterThanOrEqual(2, count($tests), 'Need at least 2 test definitions for lifecycle patch test.');
|
||||
|
||||
$response = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('post', $this->endpoint, [
|
||||
'InternalPID' => (int) $patient['InternalPID'],
|
||||
'SiteID' => (int) ($tests[0]['SiteID'] ?? 1),
|
||||
'Tests' => [
|
||||
[
|
||||
'TestSiteID' => (int) $tests[0]['TestSiteID'],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertStatus(201);
|
||||
$decoded = json_decode($response->getJSON(), true);
|
||||
$this->assertSame('success', $decoded['status'] ?? null);
|
||||
|
||||
return [
|
||||
'order' => $decoded['data'],
|
||||
'baseTest' => $tests[0],
|
||||
'extraTest' => $tests[1],
|
||||
];
|
||||
}
|
||||
|
||||
public function testPatchTestsLifecycleCreatedEditedDeleted(): void
|
||||
{
|
||||
$fixture = $this->createOrderWithTest();
|
||||
$order = $fixture['order'];
|
||||
$baseTest = $fixture['baseTest'];
|
||||
$extraTest = $fixture['extraTest'];
|
||||
$orderID = $order['OrderID'];
|
||||
$internalOID = (int) $order['InternalOID'];
|
||||
$baseSiteID = (int) $baseTest['TestSiteID'];
|
||||
$extraSiteID = (int) $extraTest['TestSiteID'];
|
||||
|
||||
$createResponse = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$orderID}", [
|
||||
'Tests' => [
|
||||
'created' => [
|
||||
[
|
||||
'TestSiteID' => $extraSiteID,
|
||||
'Result' => 'CREATED',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$createResponse->assertStatus(200);
|
||||
$createJson = json_decode($createResponse->getJSON(), true);
|
||||
$this->assertSame('success', $createJson['status'] ?? null);
|
||||
|
||||
$createdRow = $this->findRowBySite($createJson['data']['Tests'] ?? [], $extraSiteID);
|
||||
$this->assertNotNull($createdRow, 'Created test not returned by patch response.');
|
||||
$this->assertSame('CREATED', $createdRow['Result'] ?? null);
|
||||
$createdResultID = (int) ($createdRow['ResultID'] ?? 0);
|
||||
$this->assertGreaterThan(0, $createdResultID, 'Created test missing ResultID.');
|
||||
|
||||
$createdDbRow = $this->findResultByOrderAndSite($internalOID, $extraSiteID);
|
||||
$this->assertNotNull($createdDbRow, 'Created test not found in DB.');
|
||||
$this->assertSame('CREATED', $createdDbRow['Result'] ?? null);
|
||||
|
||||
$editResponse = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$orderID}", [
|
||||
'Tests' => [
|
||||
'edited' => [
|
||||
[
|
||||
'TestSiteID' => $baseSiteID,
|
||||
'Result' => 'EDITED',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$editResponse->assertStatus(200);
|
||||
$editJson = json_decode($editResponse->getJSON(), true);
|
||||
$this->assertSame('success', $editJson['status'] ?? null);
|
||||
|
||||
$editedRow = $this->findRowBySite($editJson['data']['Tests'] ?? [], $baseSiteID);
|
||||
$this->assertNotNull($editedRow, 'Edited test not returned by patch response.');
|
||||
$this->assertSame('EDITED', $editedRow['Result'] ?? null);
|
||||
|
||||
$deleteResponse = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$orderID}", [
|
||||
'Tests' => [
|
||||
'deleted' => [
|
||||
$extraSiteID,
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$deleteResponse->assertStatus(200);
|
||||
$deleteJson = json_decode($deleteResponse->getJSON(), true);
|
||||
$this->assertSame('success', $deleteJson['status'] ?? null);
|
||||
$this->assertNull($this->findRowBySite($deleteJson['data']['Tests'] ?? [], $extraSiteID), 'Deleted test still returned by patch response.');
|
||||
|
||||
$deletedDbRow = (new PatResultModel())->find($createdResultID);
|
||||
$this->assertNotNull($deletedDbRow, 'Deleted test row missing from DB.');
|
||||
$this->assertNotNull($deletedDbRow['DelDate'] ?? null, 'Deleted test row not soft deleted.');
|
||||
}
|
||||
|
||||
public function testPatchTestsNotFound(): void
|
||||
{
|
||||
$response = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/999999999", [
|
||||
'Tests' => [
|
||||
'deleted' => [1],
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertStatus(404);
|
||||
}
|
||||
|
||||
public function testPatchTestsInvalidId(): void
|
||||
{
|
||||
$response = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/invalid", [
|
||||
'Tests' => [
|
||||
'deleted' => [1],
|
||||
],
|
||||
]);
|
||||
|
||||
$response->assertStatus(404);
|
||||
}
|
||||
|
||||
public function testPatchTestsEmptyPayload(): void
|
||||
{
|
||||
$fixture = $this->createOrderWithTest();
|
||||
$orderID = $fixture['order']['OrderID'];
|
||||
|
||||
$response = $this->withHeaders($this->authHeaders())
|
||||
->withBodyFormat('json')
|
||||
->call('patch', "{$this->endpoint}/{$orderID}", []);
|
||||
|
||||
$response->assertStatus(400);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user