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->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll(); } 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->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll(); } elseif (TestValidationService::isTitle($typeCode)) { $testMapModel = new \App\Models\Test\TestMapModel(); $row['testmap'] = $testMapModel->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll(); } 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->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll(); } 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); } }