feat(ordertest): add PVADTID filter support and sync order API docs
- Add PVADTID query param handling in OrderTestController::index() (supports both PVADTID and pvadtid, with numeric casting). - Extend OrderTestModel::getOrdersByPatient() with optional PVADTID filtering. - Apply PVADTID filtering to general order listing queries. - Update public/paths/orders.yaml to document PVADTID on GET /api/ordertest. - Regenerate public/api-docs.bundled.yaml to keep OpenAPI bundle in sync.
This commit is contained in:
parent
0ec13e404a
commit
4aad7d331a
@ -4,9 +4,9 @@ namespace App\Controllers;
|
|||||||
use App\Traits\ResponseTrait;
|
use App\Traits\ResponseTrait;
|
||||||
use CodeIgniter\Controller;
|
use CodeIgniter\Controller;
|
||||||
use App\Libraries\ValueSet;
|
use App\Libraries\ValueSet;
|
||||||
use App\Models\OrderTest\OrderTestModel;
|
use App\Models\OrderTest\OrderTestModel;
|
||||||
use App\Models\Patient\PatientModel;
|
use App\Models\Patient\PatientModel;
|
||||||
use App\Models\PatVisit\PatVisitModel;
|
use App\Models\PatVisit\PatVisitModel;
|
||||||
|
|
||||||
class OrderTestController extends Controller {
|
class OrderTestController extends Controller {
|
||||||
use ResponseTrait;
|
use ResponseTrait;
|
||||||
@ -29,14 +29,22 @@ class OrderTestController extends Controller {
|
|||||||
|
|
||||||
public function index() {
|
public function index() {
|
||||||
$internalPID = $this->request->getVar('InternalPID');
|
$internalPID = $this->request->getVar('InternalPID');
|
||||||
|
$pvadtid = $this->request->getVar('PVADTID') ?? $this->request->getVar('pvadtid');
|
||||||
|
$pvadtid = is_numeric($pvadtid) ? (int) $pvadtid : null;
|
||||||
$includeDetails = $this->request->getVar('include') === 'details';
|
$includeDetails = $this->request->getVar('include') === 'details';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($internalPID) {
|
if ($internalPID) {
|
||||||
$rows = $this->model->getOrdersByPatient($internalPID);
|
$rows = $this->model->getOrdersByPatient((int) $internalPID, $pvadtid);
|
||||||
} else {
|
} else {
|
||||||
$rows = $this->db->table('ordertest')
|
$builder = $this->db->table('ordertest')
|
||||||
->where('DelDate', null)
|
->where('DelDate', null);
|
||||||
|
|
||||||
|
if ($pvadtid !== null) {
|
||||||
|
$builder->where('PVADTID', $pvadtid);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $builder
|
||||||
->orderBy('TrnDate', 'DESC')
|
->orderBy('TrnDate', 'DESC')
|
||||||
->get()
|
->get()
|
||||||
->getResultArray();
|
->getResultArray();
|
||||||
@ -179,35 +187,35 @@ class OrderTestController extends Controller {
|
|||||||
$order['Specimens'] = $this->getOrderSpecimens($order['InternalOID']);
|
$order['Specimens'] = $this->getOrderSpecimens($order['InternalOID']);
|
||||||
$order['Tests'] = $this->getOrderTests($order['InternalOID']);
|
$order['Tests'] = $this->getOrderTests($order['InternalOID']);
|
||||||
|
|
||||||
// Rule engine triggers are fired at the test/result level (test_created, result_updated)
|
// Rule engine triggers are fired at the test/result level (test_created, result_updated)
|
||||||
|
|
||||||
return $this->respondCreated([
|
return $this->respondCreated([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'message' => 'Order created successfully',
|
'message' => 'Order created successfully',
|
||||||
'data' => $order
|
'data' => $order
|
||||||
], 201);
|
], 201);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update($OrderID = null) {
|
public function update($OrderID = null) {
|
||||||
$input = $this->request->getJSON(true);
|
$input = $this->request->getJSON(true);
|
||||||
|
|
||||||
if ($OrderID === null || $OrderID === '') {
|
if ($OrderID === null || $OrderID === '') {
|
||||||
return $this->failValidationErrors(['OrderID' => 'OrderID is required']);
|
return $this->failValidationErrors(['OrderID' => 'OrderID is required']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($input['OrderID']) && (string) $input['OrderID'] !== (string) $OrderID) {
|
if (isset($input['OrderID']) && (string) $input['OrderID'] !== (string) $OrderID) {
|
||||||
return $this->failValidationErrors(['OrderID' => 'OrderID in URL does not match body']);
|
return $this->failValidationErrors(['OrderID' => 'OrderID in URL does not match body']);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$input['OrderID'] = $OrderID;
|
$input['OrderID'] = $OrderID;
|
||||||
$order = $this->model->getOrder($OrderID);
|
$order = $this->model->getOrder($OrderID);
|
||||||
if (!$order) {
|
if (!$order) {
|
||||||
return $this->failNotFound('Order not found');
|
return $this->failNotFound('Order not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
$updateData = [];
|
$updateData = [];
|
||||||
if (isset($input['Priority'])) $updateData['Priority'] = $input['Priority'];
|
if (isset($input['Priority'])) $updateData['Priority'] = $input['Priority'];
|
||||||
@ -220,9 +228,9 @@ class OrderTestController extends Controller {
|
|||||||
$this->model->update($order['InternalOID'], $updateData);
|
$this->model->update($order['InternalOID'], $updateData);
|
||||||
}
|
}
|
||||||
|
|
||||||
$updatedOrder = $this->model->getOrder($OrderID);
|
$updatedOrder = $this->model->getOrder($OrderID);
|
||||||
$updatedOrder['Specimens'] = $this->getOrderSpecimens($updatedOrder['InternalOID']);
|
$updatedOrder['Specimens'] = $this->getOrderSpecimens($updatedOrder['InternalOID']);
|
||||||
$updatedOrder['Tests'] = $this->getOrderTests($updatedOrder['InternalOID']);
|
$updatedOrder['Tests'] = $this->getOrderTests($updatedOrder['InternalOID']);
|
||||||
|
|
||||||
return $this->respond([
|
return $this->respond([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
|
|||||||
@ -161,25 +161,25 @@ class OrderTestModel extends BaseModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert unique tests into patres with specimen links
|
// Insert unique tests into patres with specimen links
|
||||||
if (!empty($testToOrder)) {
|
if (!empty($testToOrder)) {
|
||||||
$resModel = new \App\Models\PatResultModel();
|
$resModel = new \App\Models\PatResultModel();
|
||||||
$patientModel = new \App\Models\Patient\PatientModel();
|
$patientModel = new \App\Models\Patient\PatientModel();
|
||||||
$patient = $patientModel->find((int) $data['InternalPID']);
|
$patient = $patientModel->find((int) $data['InternalPID']);
|
||||||
$age = null;
|
$age = null;
|
||||||
if (is_array($patient) && !empty($patient['Birthdate'])) {
|
if (is_array($patient) && !empty($patient['Birthdate'])) {
|
||||||
try {
|
try {
|
||||||
$birthdate = new \DateTime((string) $patient['Birthdate']);
|
$birthdate = new \DateTime((string) $patient['Birthdate']);
|
||||||
$age = (new \DateTime())->diff($birthdate)->y;
|
$age = (new \DateTime())->diff($birthdate)->y;
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$age = null;
|
$age = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$ruleEngine = new \App\Services\RuleEngineService();
|
$ruleEngine = new \App\Services\RuleEngineService();
|
||||||
|
|
||||||
foreach ($testToOrder as $tid => $tinfo) {
|
foreach ($testToOrder as $tid => $tinfo) {
|
||||||
$specimenInfo = $specimenConDefMap[$tid] ?? null;
|
$specimenInfo = $specimenConDefMap[$tid] ?? null;
|
||||||
|
|
||||||
$patResData = [
|
$patResData = [
|
||||||
'OrderID' => $internalOID,
|
'OrderID' => $internalOID,
|
||||||
@ -191,32 +191,32 @@ class OrderTestModel extends BaseModel {
|
|||||||
'CreateDate' => date('Y-m-d H:i:s')
|
'CreateDate' => date('Y-m-d H:i:s')
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($specimenInfo) {
|
if ($specimenInfo) {
|
||||||
$patResData['InternalSID'] = $specimenInfo['InternalSID'];
|
$patResData['InternalSID'] = $specimenInfo['InternalSID'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$resModel->insert($patResData);
|
$resModel->insert($patResData);
|
||||||
|
|
||||||
// Fire test_created rules after the test row is persisted
|
// Fire test_created rules after the test row is persisted
|
||||||
try {
|
try {
|
||||||
$ruleEngine->run('test_created', [
|
$ruleEngine->run('test_created', [
|
||||||
'order' => [
|
'order' => [
|
||||||
'InternalOID' => $internalOID,
|
'InternalOID' => $internalOID,
|
||||||
'Priority' => $orderData['Priority'] ?? 'R',
|
'Priority' => $orderData['Priority'] ?? 'R',
|
||||||
'TestSiteID' => $tid,
|
'TestSiteID' => $tid,
|
||||||
],
|
],
|
||||||
'patient' => [
|
'patient' => [
|
||||||
'Sex' => is_array($patient) ? ($patient['Sex'] ?? null) : null,
|
'Sex' => is_array($patient) ? ($patient['Sex'] ?? null) : null,
|
||||||
],
|
],
|
||||||
'age' => $age,
|
'age' => $age,
|
||||||
'testSiteID' => $tid,
|
'testSiteID' => $tid,
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
log_message('error', 'OrderTestModel::createOrder rule engine error: ' . $e->getMessage());
|
log_message('error', 'OrderTestModel::createOrder rule engine error: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->db->transComplete();
|
$this->db->transComplete();
|
||||||
|
|
||||||
@ -299,10 +299,16 @@ class OrderTestModel extends BaseModel {
|
|||||||
->getRowArray();
|
->getRowArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getOrdersByPatient(int $internalPID): array {
|
public function getOrdersByPatient(int $internalPID, ?int $pvadtid = null): array {
|
||||||
return $this->select('*')
|
$builder = $this->select('*')
|
||||||
->where('InternalPID', $internalPID)
|
->where('InternalPID', $internalPID)
|
||||||
->where('DelDate', null)
|
->where('DelDate', null);
|
||||||
|
|
||||||
|
if ($pvadtid !== null) {
|
||||||
|
$builder->where('PVADTID', $pvadtid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $builder
|
||||||
->orderBy('TrnDate', 'DESC')
|
->orderBy('TrnDate', 'DESC')
|
||||||
->get()
|
->get()
|
||||||
->getResultArray();
|
->getResultArray();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
/api/ordertest:
|
/api/ordertest:
|
||||||
get:
|
get:
|
||||||
tags: [Order]
|
tags: [Order]
|
||||||
summary: List orders
|
summary: List orders
|
||||||
security:
|
security:
|
||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
@ -18,6 +18,11 @@
|
|||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
description: Filter by internal patient ID
|
description: Filter by internal patient ID
|
||||||
|
- name: PVADTID
|
||||||
|
in: query
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: Filter by patient visit ADT ID
|
||||||
- name: OrderStatus
|
- name: OrderStatus
|
||||||
in: query
|
in: query
|
||||||
schema:
|
schema:
|
||||||
@ -47,8 +52,8 @@
|
|||||||
items:
|
items:
|
||||||
$ref: '../components/schemas/orders.yaml#/OrderTestList'
|
$ref: '../components/schemas/orders.yaml#/OrderTestList'
|
||||||
|
|
||||||
post:
|
post:
|
||||||
tags: [Order]
|
tags: [Order]
|
||||||
summary: Create order with specimens and tests
|
summary: Create order with specimens and tests
|
||||||
description: Creates an order with associated specimens and patres records. Tests are grouped by container type to minimize specimen creation.
|
description: Creates an order with associated specimens and patres records. Tests are grouped by container type to minimize specimen creation.
|
||||||
security:
|
security:
|
||||||
@ -124,8 +129,8 @@
|
|||||||
description: Server error
|
description: Server error
|
||||||
|
|
||||||
|
|
||||||
delete:
|
delete:
|
||||||
tags: [Order]
|
tags: [Order]
|
||||||
summary: Delete order
|
summary: Delete order
|
||||||
security:
|
security:
|
||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
@ -144,9 +149,9 @@
|
|||||||
'200':
|
'200':
|
||||||
description: Order deleted
|
description: Order deleted
|
||||||
|
|
||||||
/api/ordertest/status:
|
/api/ordertest/status:
|
||||||
post:
|
post:
|
||||||
tags: [Order]
|
tags: [Order]
|
||||||
summary: Update order status
|
summary: Update order status
|
||||||
security:
|
security:
|
||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
@ -187,9 +192,9 @@
|
|||||||
data:
|
data:
|
||||||
$ref: '../components/schemas/orders.yaml#/OrderTest'
|
$ref: '../components/schemas/orders.yaml#/OrderTest'
|
||||||
|
|
||||||
/api/ordertest/{id}:
|
/api/ordertest/{id}:
|
||||||
get:
|
get:
|
||||||
tags: [Order]
|
tags: [Order]
|
||||||
summary: Get order by ID
|
summary: Get order by ID
|
||||||
description: Returns order details with associated specimens and tests
|
description: Returns order details with associated specimens and tests
|
||||||
security:
|
security:
|
||||||
@ -201,63 +206,63 @@
|
|||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
description: Order ID (e.g., 0025030300001)
|
description: Order ID (e.g., 0025030300001)
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Order details with specimens and tests
|
description: Order details with specimens and tests
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
data:
|
data:
|
||||||
$ref: '../components/schemas/orders.yaml#/OrderTest'
|
$ref: '../components/schemas/orders.yaml#/OrderTest'
|
||||||
|
|
||||||
patch:
|
patch:
|
||||||
tags: [Order]
|
tags: [Order]
|
||||||
summary: Update order
|
summary: Update order
|
||||||
security:
|
security:
|
||||||
- bearerAuth: []
|
- bearerAuth: []
|
||||||
parameters:
|
parameters:
|
||||||
- name: id
|
- name: id
|
||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
description: Order ID
|
description: Order ID
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
Priority:
|
Priority:
|
||||||
type: string
|
type: string
|
||||||
enum: [R, S, U]
|
enum: [R, S, U]
|
||||||
OrderStatus:
|
OrderStatus:
|
||||||
type: string
|
type: string
|
||||||
enum: [ORD, SCH, ANA, VER, REV, REP]
|
enum: [ORD, SCH, ANA, VER, REV, REP]
|
||||||
OrderingProvider:
|
OrderingProvider:
|
||||||
type: string
|
type: string
|
||||||
DepartmentID:
|
DepartmentID:
|
||||||
type: integer
|
type: integer
|
||||||
WorkstationID:
|
WorkstationID:
|
||||||
type: integer
|
type: integer
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Order updated
|
description: Order updated
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
data:
|
data:
|
||||||
$ref: '../components/schemas/orders.yaml#/OrderTest'
|
$ref: '../components/schemas/orders.yaml#/OrderTest'
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user