clqms-be/app/Models/Test/TestDefSiteModel.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

227 lines
8.0 KiB
PHP

<?php
namespace App\Models\Test;
use App\Models\BaseModel;
use App\Libraries\ValueSet;
use App\Libraries\TestValidationService;
class TestDefSiteModel extends BaseModel {
protected $table = 'testdefsite';
protected $primaryKey = 'TestSiteID';
protected $allowedFields = [
'SiteID',
'TestSiteCode', 'TestSiteName', 'TestType', 'Description',
'DisciplineID', 'DepartmentID',
'ResultType', 'RefType', 'Vset',
'Unit1', 'Factor', 'Unit2', 'Decimal',
'ReqQty', 'ReqQtyUnit', 'CollReq', 'Method', 'ExpectedTAT',
'SeqScr', 'SeqRpt', 'IndentLeft', 'FontStyle', 'VisibleScr', 'VisibleRpt',
'CountStat', 'Level', 'Requestable',
'CreateDate', 'StartDate','EndDate'
];
protected $useTimestamps = true;
protected $createdField = 'CreateDate';
protected $updatedField = 'StartDate';
protected $useSoftDeletes = true;
protected $deletedField = "EndDate";
public function getTests($siteId = null, $testType = null, $visibleScr = null, $visibleRpt = null, $search = null, $page = 1, $perPage = 20) {
$builder = $this->select("testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.VisibleScr, testdefsite.VisibleRpt,
testdefsite.CountStat, testdefsite.StartDate, testdefsite.EndDate")
->where('testdefsite.EndDate IS NULL');
if ($siteId) {
$builder->where('testdefsite.SiteID', $siteId);
}
if ($testType) {
$builder->where('testdefsite.TestType', $testType);
}
if ($visibleScr !== null) {
$builder->where('testdefsite.VisibleScr', $visibleScr);
}
if ($visibleRpt !== null) {
$builder->where('testdefsite.VisibleRpt', $visibleRpt);
}
if ($search) {
$builder->groupStart()
->like('testdefsite.TestSiteCode', $search)
->orLike('testdefsite.TestSiteName', $search)
->groupEnd();
}
// Get total count before pagination
$totalBuilder = clone $builder;
$total = $totalBuilder->countAllResults();
// Apply pagination
$offset = ($page - 1) * $perPage;
$rows = $builder->orderBy('testdefsite.SeqScr', 'ASC')
->limit($perPage, $offset)
->findAll();
$rows = ValueSet::transformLabels($rows, [
'TestType' => 'test_type',
]);
return [
'data' => $rows,
'pagination' => [
'total' => $total
]
];
}
/**
* Get tests list with discipline and department info
*/
public function getTestsWithRelations($filters = []) {
$builder = $this->db->table('testdefsite')
->select(
"testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.VisibleScr, testdefsite.VisibleRpt,
testdefsite.CountStat, testdefsite.StartDate, testdefsite.EndDate,
COALESCE(testdefsite.DisciplineID, cal.DisciplineID) as DisciplineID,
COALESCE(testdefsite.DepartmentID, cal.DepartmentID) as DepartmentID,
d.DisciplineName, dept.DepartmentName"
)
->join('testdefcal cal', 'cal.TestSiteID = testdefsite.TestSiteID AND cal.EndDate IS NULL', 'left')
->join('discipline d', 'd.DisciplineID = COALESCE(testdefsite.DisciplineID, cal.DisciplineID)', 'left')
->join('department dept', 'dept.DepartmentID = COALESCE(testdefsite.DepartmentID, cal.DepartmentID)', 'left')
->where('testdefsite.EndDate IS NULL');
if (!empty($filters['SiteID'])) {
$builder->where('testdefsite.SiteID', $filters['SiteID']);
}
if (!empty($filters['TestType'])) {
$builder->where('testdefsite.TestType', $filters['TestType']);
}
if (isset($filters['VisibleScr'])) {
$builder->where('testdefsite.VisibleScr', $filters['VisibleScr']);
}
if (isset($filters['VisibleRpt'])) {
$builder->where('testdefsite.VisibleRpt', $filters['VisibleRpt']);
}
if (!empty($filters['TestSiteName'])) {
$builder->like('testdefsite.TestSiteName', $filters['TestSiteName']);
}
if (!empty($filters['TestSiteCode'])) {
$builder->like('testdefsite.TestSiteCode', $filters['TestSiteCode']);
}
return $builder->orderBy('testdefsite.SeqScr', 'ASC')->get()->getResultArray();
}
public function getTest($TestSiteID) {
$db = \Config\Database::connect();
$row = $this->select("testdefsite.*")
->where("testdefsite.TestSiteID", $TestSiteID)
->find($TestSiteID);
if (!$row) return null;
$row = ValueSet::transformLabels([$row], [
'TestType' => 'test_type',
])[0];
$typeCode = $row['TestType'] ?? '';
if (TestValidationService::isCalc($typeCode)) {
$row['testdefcal'] = $db->table('testdefcal')
->select('testdefcal.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID=testdefcal.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID=testdefcal.DepartmentID', 'left')
->where('testdefcal.TestSiteID', $TestSiteID)
->where('testdefcal.EndDate IS NULL')
->get()->getResultArray();
$testMapModel = new \App\Models\Test\TestMapModel();
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
} elseif (TestValidationService::isGroup($typeCode)) {
$row['testdefgrp'] = $db->table('testdefgrp')
->select('testdefgrp.*, t.TestSiteCode, t.TestSiteName, t.TestType')
->join('testdefsite t', 't.TestSiteID=testdefgrp.Member', 'left')
->where('testdefgrp.TestSiteID', $TestSiteID)
->where('testdefgrp.EndDate IS NULL')
->orderBy('testdefgrp.TestGrpID', 'ASC')
->get()->getResultArray();
$row['testdefgrp'] = ValueSet::transformLabels($row['testdefgrp'], [
'TestType' => 'test_type',
]);
$testMapModel = new \App\Models\Test\TestMapModel();
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
} elseif (TestValidationService::isTitle($typeCode)) {
$testMapModel = new \App\Models\Test\TestMapModel();
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
} elseif (TestValidationService::isTechnicalTest($typeCode)) {
// Technical details are now flattened into the main row
if ($row['DisciplineID']) {
$discipline = $db->table('discipline')->where('DisciplineID', $row['DisciplineID'])->get()->getRowArray();
$row['DisciplineName'] = $discipline['DisciplineName'] ?? null;
}
if ($row['DepartmentID']) {
$department = $db->table('department')->where('DepartmentID', $row['DepartmentID'])->get()->getRowArray();
$row['DepartmentName'] = $department['DepartmentName'] ?? null;
}
$testMapModel = new \App\Models\Test\TestMapModel();
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
}
return $row;
}
/**
* Validate test type combination
*
* @param string $testType
* @param string $resultType
* @param string $refType
* @return array ['valid' => bool, 'error' => string|null]
*/
public function validateTypes(string $testType, string $resultType, string $refType): array
{
return TestValidationService::validate($testType, $resultType, $refType);
}
/**
* Check if test needs reference ranges
*
* @param string $resultType
* @return bool
*/
public function needsReferenceRanges(string $resultType): bool
{
return TestValidationService::needsReferenceRanges($resultType);
}
/**
* Get reference table name
*
* @param string $resultType
* @param string $refType
* @return string|null
*/
public function getReferenceTable(string $resultType, string $refType): ?string
{
return TestValidationService::getReferenceTable($resultType, $refType);
}
}