Add DepartmentID filter to tests index endpoint

- Adds DepartmentID query parameter filter to /api/tests
- Filters by COALESCE(testdefsite.DepartmentID, cal.DepartmentID) for calculated tests
- Updates TestDefSiteModel::getTestsWithRelations() for backend filtering
This commit is contained in:
mahdahar 2026-04-23 16:24:49 +07:00
parent 66e9be2a04
commit 83278d332a
2 changed files with 421 additions and 416 deletions

View File

@ -2,16 +2,16 @@
namespace App\Controllers\Test; namespace App\Controllers\Test;
use App\Controllers\BaseController; use App\Controllers\BaseController;
use App\Libraries\TestValidationService; use App\Libraries\TestValidationService;
use App\Libraries\ValueSet; use App\Libraries\ValueSet;
use App\Traits\PatchValidationTrait; use App\Traits\PatchValidationTrait;
use App\Traits\ResponseTrait; use App\Traits\ResponseTrait;
class TestsController extends BaseController class TestsController extends BaseController
{ {
use ResponseTrait; use ResponseTrait;
use PatchValidationTrait; use PatchValidationTrait;
protected $model; protected $model;
protected $modelCal; protected $modelCal;
@ -32,24 +32,25 @@ class TestsController extends BaseController
$this->modelRefNum = new \App\Models\RefRange\RefNumModel; $this->modelRefNum = new \App\Models\RefRange\RefNumModel;
$this->modelRefTxt = new \App\Models\RefRange\RefTxtModel; $this->modelRefTxt = new \App\Models\RefRange\RefTxtModel;
$this->rules = [ $this->rules = [
'TestSiteCode' => 'required', 'TestSiteCode' => 'required',
'TestSiteName' => 'required', 'TestSiteName' => 'required',
'TestType' => 'required', 'TestType' => 'required',
]; ];
} }
public function index() public function index()
{ {
$search = $this->request->getGet('search'); $search = $this->request->getGet('search');
$filters = [ $filters = [
'SiteID' => $this->request->getGet('SiteID'), 'SiteID' => $this->request->getGet('SiteID'),
'TestType' => $this->request->getGet('TestType'), 'TestType' => $this->request->getGet('TestType'),
'isVisibleScr' => $this->request->getGet('isVisibleScr'), 'isVisibleScr' => $this->request->getGet('isVisibleScr'),
'isVisibleRpt' => $this->request->getGet('isVisibleRpt'), 'isVisibleRpt' => $this->request->getGet('isVisibleRpt'),
'TestSiteName' => $this->request->getGet('TestSiteName'), 'TestSiteName' => $this->request->getGet('TestSiteName'),
'TestSiteCode' => $this->request->getGet('TestSiteCode'), 'TestSiteCode' => $this->request->getGet('TestSiteCode'),
'DepartmentID' => $this->request->getGet('DepartmentID'),
'search' => $search, 'search' => $search,
]; ];
@ -92,36 +93,36 @@ class TestsController extends BaseController
$typeCode = $row['TestType'] ?? ''; $typeCode = $row['TestType'] ?? '';
if ($typeCode === 'CALC') { if ($typeCode === 'CALC') {
$row['testdefcal'] = $this->modelCal->getByTestSiteID($id); $row['testdefcal'] = $this->modelCal->getByTestSiteID($id);
$row['testdefgrp'] = [ $row['testdefgrp'] = [
'members' => $this->modelGrp->getGroupMembers($id), 'members' => $this->modelGrp->getGroupMembers($id),
]; ];
} elseif ($typeCode === 'GROUP') { } elseif ($typeCode === 'GROUP') {
$row['testdefgrp'] = [ $row['testdefgrp'] = [
'members' => $this->modelGrp->getGroupMembers($id), 'members' => $this->modelGrp->getGroupMembers($id),
]; ];
} elseif ($typeCode !== 'TITLE') { } elseif ($typeCode !== 'TITLE') {
$refType = $row['RefType'] ?? ''; $refType = $row['RefType'] ?? '';
$resultType = $row['ResultType'] ?? ''; $resultType = $row['ResultType'] ?? '';
if (TestValidationService::usesRefNum($resultType, $refType)) { if (TestValidationService::usesRefNum($resultType, $refType)) {
$row['refnum'] = $this->modelRefNum->getFormattedByTestSiteID($id); $row['refnum'] = $this->modelRefNum->getFormattedByTestSiteID($id);
} }
if (TestValidationService::usesRefTxt($resultType, $refType)) { if (TestValidationService::usesRefTxt($resultType, $refType)) {
$row['reftxt'] = $this->modelRefTxt->getFormattedByTestSiteID($id); $row['reftxt'] = $this->modelRefTxt->getFormattedByTestSiteID($id);
} }
} }
// Keep /api/test payload focused on test definition fields. // Keep /api/test payload focused on test definition fields.
unset($row['testmap']); unset($row['testmap']);
return $this->respond([ return $this->respond([
'status' => 'success', 'status' => 'success',
'message' => 'Data fetched successfully', 'message' => 'Data fetched successfully',
'data' => $row, 'data' => $row,
], 200); ], 200);
} }
public function create() public function create()
@ -156,50 +157,50 @@ class TestsController extends BaseController
$db->transStart(); $db->transStart();
try { try {
$testSiteData = [ $testSiteData = [
'SiteID' => array_key_exists('SiteID', $input) ? $input['SiteID'] : null, 'SiteID' => array_key_exists('SiteID', $input) ? $input['SiteID'] : null,
'TestSiteCode'=> $input['TestSiteCode'], 'TestSiteCode'=> $input['TestSiteCode'],
'TestSiteName'=> $input['TestSiteName'], 'TestSiteName'=> $input['TestSiteName'],
'TestType' => $input['TestType'], 'TestType' => $input['TestType'],
'Description' => $input['Description'] ?? null, 'Description' => $input['Description'] ?? null,
'SeqScr' => array_key_exists('SeqScr', $input) ? $input['SeqScr'] : null, 'SeqScr' => array_key_exists('SeqScr', $input) ? $input['SeqScr'] : null,
'SeqRpt' => array_key_exists('SeqRpt', $input) ? $input['SeqRpt'] : null, 'SeqRpt' => array_key_exists('SeqRpt', $input) ? $input['SeqRpt'] : null,
'IndentLeft' => $input['IndentLeft'] ?? 0, 'IndentLeft' => $input['IndentLeft'] ?? 0,
'FontStyle' => $input['FontStyle'] ?? null, 'FontStyle' => $input['FontStyle'] ?? null,
'isVisibleScr' => $input['isVisibleScr'] ?? 1, 'isVisibleScr' => $input['isVisibleScr'] ?? 1,
'isVisibleRpt' => $input['isVisibleRpt'] ?? 1, 'isVisibleRpt' => $input['isVisibleRpt'] ?? 1,
'isCountStat' => $input['isCountStat'] ?? 1, 'isCountStat' => $input['isCountStat'] ?? 1,
'isRequestable' => $input['isRequestable'] ?? 1, 'isRequestable' => $input['isRequestable'] ?? 1,
'StartDate' => $input['StartDate'] ?? date('Y-m-d H:i:s'), 'StartDate' => $input['StartDate'] ?? date('Y-m-d H:i:s'),
]; ];
$id = $this->model->insert($testSiteData); $id = $this->model->insert($testSiteData);
if (!$id) { if (!$id) {
$dbError = $db->error(); $dbError = $db->error();
log_message('error', 'Test insert failed: ' . json_encode($dbError, JSON_UNESCAPED_SLASHES)); log_message('error', 'Test insert failed: ' . json_encode($dbError, JSON_UNESCAPED_SLASHES));
$message = $dbError['message'] ?? 'Failed to insert main test definition'; $message = $dbError['message'] ?? 'Failed to insert main test definition';
throw new \Exception('Failed to insert main test definition: ' . $message); throw new \Exception('Failed to insert main test definition: ' . $message);
} }
$this->handleDetails($id, $input, 'insert'); $this->handleDetails($id, $input, 'insert');
$db->transComplete(); $db->transComplete();
if ($db->transStatus() === false) { if ($db->transStatus() === false) {
$dbError = $db->error(); $dbError = $db->error();
$lastQuery = $db->showLastQuery(); $lastQuery = $db->showLastQuery();
log_message('error', 'TestController transaction failed: ' . json_encode([ log_message('error', 'TestController transaction failed: ' . json_encode([
'error' => $dbError, 'error' => $dbError,
'last_query' => $lastQuery, 'last_query' => $lastQuery,
], JSON_UNESCAPED_SLASHES)); ], JSON_UNESCAPED_SLASHES));
return $this->failServerError('Transaction failed'); return $this->failServerError('Transaction failed');
} }
return $this->respondCreated([ return $this->respondCreated([
'status' => 'success', 'status' => 'success',
'message' => 'Test created successfully', 'message' => 'Test created successfully',
'data' => ['TestSiteId' => $id], 'data' => ['TestSiteId' => $id],
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
$db->transRollback(); $db->transRollback();
@ -207,30 +208,30 @@ class TestsController extends BaseController
} }
} }
public function update($id = null) public function update($id = null)
{ {
$input = $this->requirePatchPayload($this->request->getJSON(true)); $input = $this->requirePatchPayload($this->request->getJSON(true));
if ($input === null) { if ($input === null) {
return; return;
} }
if (!$id && isset($input['TestSiteID'])) { if (!$id && isset($input['TestSiteID'])) {
$id = $input['TestSiteID']; $id = $input['TestSiteID'];
} }
$id = $this->requirePatchId($id, 'TestSiteID'); $id = $this->requirePatchId($id, 'TestSiteID');
if ($id === null) { if ($id === null) {
return; return;
} }
$existing = $this->model->find($id); $existing = $this->model->find($id);
if (!$existing) { if (!$existing) {
return $this->respond([ return $this->respond([
'status' => 'failed', 'status' => 'failed',
'message' => 'Test not found', 'message' => 'Test not found',
'data' => [] 'data' => []
], 404); ], 404);
} }
$testType = $input['TestType'] ?? $existing['TestType'] ?? ''; $testType = $input['TestType'] ?? $existing['TestType'] ?? '';
$details = $input['details'] ?? $input; $details = $input['details'] ?? $input;
@ -266,18 +267,18 @@ class TestsController extends BaseController
'SeqRpt', 'SeqRpt',
'IndentLeft', 'IndentLeft',
'FontStyle', 'FontStyle',
'isVisibleScr', 'isVisibleScr',
'isVisibleRpt', 'isVisibleRpt',
'isCountStat', 'isCountStat',
'isRequestable', 'isRequestable',
'StartDate', 'StartDate',
]; ];
foreach ($allowedUpdateFields as $field) { foreach ($allowedUpdateFields as $field) {
if (array_key_exists($field, $input)) { if (array_key_exists($field, $input)) {
$testSiteData[$field] = $input[$field]; $testSiteData[$field] = $input[$field];
} }
} }
if (!empty($testSiteData)) { if (!empty($testSiteData)) {
$this->model->update($id, $testSiteData); $this->model->update($id, $testSiteData);
@ -389,9 +390,9 @@ class TestsController extends BaseController
$typeCode = $testTypeID; $typeCode = $testTypeID;
$details = $input['details'] ?? $input; $details = $input['details'] ?? $input;
$details['TestSiteID'] = $testSiteID; $details['TestSiteID'] = $testSiteID;
$details['SiteID'] = array_key_exists('SiteID', $input) ? $input['SiteID'] : null; $details['SiteID'] = array_key_exists('SiteID', $input) ? $input['SiteID'] : null;
switch ($typeCode) { switch ($typeCode) {
case 'CALC': case 'CALC':
@ -404,8 +405,8 @@ class TestsController extends BaseController
break; break;
case 'TITLE': case 'TITLE':
break; break;
case 'TEST': case 'TEST':
case 'PARAM': case 'PARAM':
@ -416,53 +417,53 @@ class TestsController extends BaseController
$refType = (string) $details['RefType']; $refType = (string) $details['RefType'];
$resultType = $details['ResultType'] ?? ''; $resultType = $details['ResultType'] ?? '';
if (TestValidationService::usesRefNum($resultType, $refType) && isset($input['refnum']) && is_array($input['refnum'])) { if (TestValidationService::usesRefNum($resultType, $refType) && isset($input['refnum']) && is_array($input['refnum'])) {
$this->saveRefNumRanges($testSiteID, $input['refnum'], $action, array_key_exists('SiteID', $input) ? $input['SiteID'] : null); $this->saveRefNumRanges($testSiteID, $input['refnum'], $action, array_key_exists('SiteID', $input) ? $input['SiteID'] : null);
} }
if (TestValidationService::usesRefTxt($resultType, $refType) && isset($input['reftxt']) && is_array($input['reftxt'])) { if (TestValidationService::usesRefTxt($resultType, $refType) && isset($input['reftxt']) && is_array($input['reftxt'])) {
$this->saveRefTxtRanges($testSiteID, $input['reftxt'], $action, array_key_exists('SiteID', $input) ? $input['SiteID'] : null); $this->saveRefTxtRanges($testSiteID, $input['reftxt'], $action, array_key_exists('SiteID', $input) ? $input['SiteID'] : null);
} }
} }
break; break;
} }
} }
private function saveTechDetails($testSiteID, $data, $action, $typeCode) private function saveTechDetails($testSiteID, $data, $action, $typeCode)
{ {
$allowedFields = [ $allowedFields = [
'DisciplineID', 'DisciplineID',
'DepartmentID', 'DepartmentID',
'ResultType', 'ResultType',
'RefType', 'RefType',
'VSet', 'VSet',
'ReqQty', 'ReqQty',
'ReqQtyUnit', 'ReqQtyUnit',
'Unit1', 'Unit1',
'Factor', 'Factor',
'Unit2', 'Unit2',
'Decimal', 'Decimal',
'CollReq', 'CollReq',
'Method', 'Method',
'ExpectedTAT', 'ExpectedTAT',
]; ];
$techData = []; $techData = [];
foreach ($allowedFields as $field) { foreach ($allowedFields as $field) {
if (array_key_exists($field, $data)) { if (array_key_exists($field, $data)) {
$techData[$field] = $data[$field]; $techData[$field] = $data[$field];
} }
} }
if ($techData !== []) { if ($techData !== []) {
$this->model->update($testSiteID, $techData); $this->model->update($testSiteID, $techData);
} }
} }
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID) private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
{ {
if ($action === 'update') { if ($action === 'update') {
$this->modelRefNum->disableByTestSiteID($testSiteID); $this->modelRefNum->disableByTestSiteID($testSiteID);
} }
@ -479,104 +480,104 @@ class TestsController extends BaseController
$this->modelRefTxt->batchInsert($testSiteID, $siteID, $ranges); $this->modelRefTxt->batchInsert($testSiteID, $siteID, $ranges);
} }
private function saveCalcDetails($testSiteID, $data, $input, $action) private function saveCalcDetails($testSiteID, $data, $input, $action)
{ {
$calcData = []; $calcData = [];
$fieldMap = [ $fieldMap = [
'DisciplineID' => 'DisciplineID', 'DisciplineID' => 'DisciplineID',
'DepartmentID' => 'DepartmentID', 'DepartmentID' => 'DepartmentID',
'Factor' => 'Factor', 'Factor' => 'Factor',
'Unit2' => 'Unit2', 'Unit2' => 'Unit2',
'Decimal' => 'Decimal', 'Decimal' => 'Decimal',
'Method' => 'Method', 'Method' => 'Method',
]; ];
foreach ($fieldMap as $source => $target) { foreach ($fieldMap as $source => $target) {
if (array_key_exists($source, $data)) { if (array_key_exists($source, $data)) {
$calcData[$target] = $data[$source]; $calcData[$target] = $data[$source];
} }
} }
if (array_key_exists('FormulaCode', $data) || array_key_exists('Formula', $data)) { if (array_key_exists('FormulaCode', $data) || array_key_exists('Formula', $data)) {
$calcData['FormulaCode'] = $data['FormulaCode'] ?? $data['Formula'] ?? null; $calcData['FormulaCode'] = $data['FormulaCode'] ?? $data['Formula'] ?? null;
} }
if (array_key_exists('RefType', $data)) { if (array_key_exists('RefType', $data)) {
$calcData['RefType'] = $data['RefType']; $calcData['RefType'] = $data['RefType'];
} }
if (array_key_exists('Unit1', $data) || array_key_exists('ResultUnit', $data)) { if (array_key_exists('Unit1', $data) || array_key_exists('ResultUnit', $data)) {
$calcData['Unit1'] = $data['Unit1'] ?? $data['ResultUnit'] ?? null; $calcData['Unit1'] = $data['Unit1'] ?? $data['ResultUnit'] ?? null;
} }
$hasMemberPayload = isset($input['testdefgrp']) $hasMemberPayload = isset($input['testdefgrp'])
&& is_array($input['testdefgrp']) && is_array($input['testdefgrp'])
&& array_key_exists('members', $input['testdefgrp']); && array_key_exists('members', $input['testdefgrp']);
if ($action === 'insert' && !array_key_exists('ResultType', $calcData)) { if ($action === 'insert' && !array_key_exists('ResultType', $calcData)) {
$calcData['ResultType'] = 'NMRIC'; $calcData['ResultType'] = 'NMRIC';
} }
if ($action === 'insert' && !array_key_exists('RefType', $calcData)) { if ($action === 'insert' && !array_key_exists('RefType', $calcData)) {
$calcData['RefType'] = 'RANGE'; $calcData['RefType'] = 'RANGE';
} }
if ($calcData !== []) { if ($calcData !== []) {
$calcData['TestSiteID'] = $testSiteID; $calcData['TestSiteID'] = $testSiteID;
if ($action === 'update') { if ($action === 'update') {
$exists = $this->modelCal->existsByTestSiteID($testSiteID); $exists = $this->modelCal->existsByTestSiteID($testSiteID);
if ($exists) { if ($exists) {
unset($calcData['TestSiteID']); unset($calcData['TestSiteID']);
$this->modelCal->update($exists['TestCalID'], $calcData); $this->modelCal->update($exists['TestCalID'], $calcData);
} else { } else {
if (!array_key_exists('ResultType', $calcData)) { if (!array_key_exists('ResultType', $calcData)) {
$calcData['ResultType'] = 'NMRIC'; $calcData['ResultType'] = 'NMRIC';
} }
if (!array_key_exists('RefType', $calcData)) { if (!array_key_exists('RefType', $calcData)) {
$calcData['RefType'] = 'RANGE'; $calcData['RefType'] = 'RANGE';
} }
$this->modelCal->insert($calcData); $this->modelCal->insert($calcData);
} }
} else { } else {
$this->modelCal->insert($calcData); $this->modelCal->insert($calcData);
} }
} }
if ($action === 'update' && !$hasMemberPayload) { if ($action === 'update' && !$hasMemberPayload) {
return; return;
} }
if ($action === 'update') { if ($action === 'update') {
$this->modelGrp->disableByTestSiteID($testSiteID); $this->modelGrp->disableByTestSiteID($testSiteID);
} }
$memberIDs = $this->resolveMemberIDs($input); $memberIDs = $this->resolveMemberIDs($input);
$validation = $this->validateMemberIDs($memberIDs); $validation = $this->validateMemberIDs($memberIDs);
if (!$validation['valid']) { if (!$validation['valid']) {
throw new \Exception('Invalid member TestSiteID(s): ' . implode(', ', $validation['invalid']) . '. Make sure to use TestSiteID, not SeqScr or other values.'); throw new \Exception('Invalid member TestSiteID(s): ' . implode(', ', $validation['invalid']) . '. Make sure to use TestSiteID, not SeqScr or other values.');
} }
foreach ($memberIDs as $memberID) { foreach ($memberIDs as $memberID) {
$this->modelGrp->insert([ $this->modelGrp->insert([
'TestSiteID' => $testSiteID, 'TestSiteID' => $testSiteID,
'Member' => $memberID, 'Member' => $memberID,
]); ]);
} }
} }
private function resolveMemberIDs(array $input): array private function resolveMemberIDs(array $input): array
{ {
$memberIDs = []; $memberIDs = [];
$rawMembers = $input['testdefgrp']['members'] ?? []; $rawMembers = $input['testdefgrp']['members'] ?? [];
if (is_array($rawMembers)) { if (is_array($rawMembers)) {
foreach ($rawMembers as $member) { foreach ($rawMembers as $member) {
if (is_array($member)) { if (is_array($member)) {
$rawID = $member['TestSiteID'] ?? null; $rawID = $member['TestSiteID'] ?? null;
} else { } else {
$rawID = is_numeric($member) ? $member : null; $rawID = is_numeric($member) ? $member : null;
} }
if ($rawID !== null && is_numeric($rawID)) { if ($rawID !== null && is_numeric($rawID)) {
@ -615,21 +616,21 @@ class TestsController extends BaseController
]; ];
} }
private function saveGroupDetails($testSiteID, $data, $input, $action) private function saveGroupDetails($testSiteID, $data, $input, $action)
{ {
$hasMemberPayload = isset($input['testdefgrp']) $hasMemberPayload = isset($input['testdefgrp'])
&& is_array($input['testdefgrp']) && is_array($input['testdefgrp'])
&& array_key_exists('members', $input['testdefgrp']); && array_key_exists('members', $input['testdefgrp']);
if ($action === 'update' && !$hasMemberPayload) { if ($action === 'update' && !$hasMemberPayload) {
return; return;
} }
if ($action === 'update') { if ($action === 'update') {
$this->modelGrp->disableByTestSiteID($testSiteID); $this->modelGrp->disableByTestSiteID($testSiteID);
} }
$memberIDs = $this->resolveMemberIDs($input); $memberIDs = $this->resolveMemberIDs($input);
// Validate member IDs before insertion // Validate member IDs before insertion
$validation = $this->validateMemberIDs($memberIDs); $validation = $this->validateMemberIDs($memberIDs);
@ -645,9 +646,9 @@ class TestsController extends BaseController
} }
} }
private function saveTestMap($testSiteID, $testSiteCode, $mappings, $action) private function saveTestMap($testSiteID, $testSiteCode, $mappings, $action)
{ {
if ($action === 'update' && $testSiteCode) { if ($action === 'update' && $testSiteCode) {
// Find existing mappings by test code through testmapdetail // Find existing mappings by test code through testmapdetail
$existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode); $existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode);
@ -658,78 +659,78 @@ class TestsController extends BaseController
// Soft delete the testmap headers // Soft delete the testmap headers
foreach ($existingMaps as $existingMap) { foreach ($existingMaps as $existingMap) {
$this->modelMap->update($existingMap['TestMapID'], ['EndDate' => date('Y-m-d H:i:s')]); $this->modelMap->update($existingMap['TestMapID'], ['EndDate' => date('Y-m-d H:i:s')]);
} }
} }
foreach ($this->normalizeTestMapPayload($mappings) as $map) { foreach ($this->normalizeTestMapPayload($mappings) as $map) {
$mapData = [ $mapData = [
'HostType' => $map['HostType'] ?? null, 'HostType' => $map['HostType'] ?? null,
'HostID' => $map['HostID'] ?? null, 'HostID' => $map['HostID'] ?? null,
'ClientType' => $map['ClientType'] ?? null, 'ClientType' => $map['ClientType'] ?? null,
'ClientID' => $map['ClientID'] ?? null, 'ClientID' => $map['ClientID'] ?? null,
]; ];
$testMapID = $this->modelMap->insert($mapData); $testMapID = $this->modelMap->insert($mapData);
if (!$testMapID) { if (!$testMapID) {
continue; continue;
} }
foreach ($this->extractTestMapDetails($map) as $detail) { foreach ($this->extractTestMapDetails($map) as $detail) {
$detailData = [ $detailData = [
'TestMapID' => $testMapID, 'TestMapID' => $testMapID,
'HostTestCode' => $detail['HostTestCode'] ?? null, 'HostTestCode' => $detail['HostTestCode'] ?? null,
'HostTestName' => $detail['HostTestName'] ?? null, 'HostTestName' => $detail['HostTestName'] ?? null,
'ConDefID' => $detail['ConDefID'] ?? null, 'ConDefID' => $detail['ConDefID'] ?? null,
'ClientTestCode' => $detail['ClientTestCode'] ?? null, 'ClientTestCode' => $detail['ClientTestCode'] ?? null,
'ClientTestName' => $detail['ClientTestName'] ?? null, 'ClientTestName' => $detail['ClientTestName'] ?? null,
]; ];
$this->modelMapDetail->insert($detailData); $this->modelMapDetail->insert($detailData);
} }
} }
} }
private function normalizeTestMapPayload($mappings): array private function normalizeTestMapPayload($mappings): array
{ {
if (!is_array($mappings)) { if (!is_array($mappings)) {
return []; return [];
} }
if ($this->isAssoc($mappings)) { if ($this->isAssoc($mappings)) {
return [$mappings]; return [$mappings];
} }
return array_values(array_filter($mappings, static fn ($map) => is_array($map))); return array_values(array_filter($mappings, static fn ($map) => is_array($map)));
} }
private function extractTestMapDetails(array $map): array private function extractTestMapDetails(array $map): array
{ {
if (isset($map['details']) && is_array($map['details'])) { if (isset($map['details']) && is_array($map['details'])) {
return array_values(array_filter($map['details'], static fn ($detail) => is_array($detail))); return array_values(array_filter($map['details'], static fn ($detail) => is_array($detail)));
} }
$flatDetail = [ $flatDetail = [
'HostTestCode' => $map['HostTestCode'] ?? null, 'HostTestCode' => $map['HostTestCode'] ?? null,
'HostTestName' => $map['HostTestName'] ?? null, 'HostTestName' => $map['HostTestName'] ?? null,
'ConDefID' => $map['ConDefID'] ?? null, 'ConDefID' => $map['ConDefID'] ?? null,
'ClientTestCode' => $map['ClientTestCode'] ?? null, 'ClientTestCode' => $map['ClientTestCode'] ?? null,
'ClientTestName' => $map['ClientTestName'] ?? null, 'ClientTestName' => $map['ClientTestName'] ?? null,
]; ];
foreach ($flatDetail as $value) { foreach ($flatDetail as $value) {
if ($value !== null && $value !== '') { if ($value !== null && $value !== '') {
return [$flatDetail]; return [$flatDetail];
} }
} }
return []; return [];
} }
private function isAssoc(array $array): bool private function isAssoc(array $array): bool
{ {
if ($array === []) { if ($array === []) {
return false; return false;
} }
return array_keys($array) !== range(0, count($array) - 1); return array_keys($array) !== range(0, count($array) - 1);
} }
} }

View File

@ -16,8 +16,8 @@ class TestDefSiteModel extends BaseModel {
'ResultType', 'RefType', 'Vset', 'ResultType', 'RefType', 'Vset',
'Unit1', 'Factor', 'Unit2', 'Decimal', 'Unit1', 'Factor', 'Unit2', 'Decimal',
'ReqQty', 'ReqQtyUnit', 'CollReq', 'Method', 'ExpectedTAT', 'ReqQty', 'ReqQtyUnit', 'CollReq', 'Method', 'ExpectedTAT',
'SeqScr', 'SeqRpt', 'IndentLeft', 'FontStyle', 'isVisibleScr', 'isVisibleRpt', 'SeqScr', 'SeqRpt', 'IndentLeft', 'FontStyle', 'isVisibleScr', 'isVisibleRpt',
'isCountStat', 'Level', 'isRequestable', 'isCountStat', 'Level', 'isRequestable',
'CreateDate', 'StartDate','EndDate' 'CreateDate', 'StartDate','EndDate'
]; ];
@ -28,9 +28,9 @@ class TestDefSiteModel extends BaseModel {
protected $deletedField = "EndDate"; protected $deletedField = "EndDate";
public function getTests($siteId = null, $testType = null, $visibleScr = null, $visibleRpt = null, $search = null, $page = 1, $perPage = 20) { 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, $builder = $this->select("testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.isVisibleScr, testdefsite.isVisibleRpt, testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.isVisibleScr, testdefsite.isVisibleRpt,
testdefsite.isCountStat, testdefsite.StartDate, testdefsite.EndDate") testdefsite.isCountStat, testdefsite.StartDate, testdefsite.EndDate")
->where('testdefsite.EndDate IS NULL'); ->where('testdefsite.EndDate IS NULL');
if ($siteId) { if ($siteId) {
@ -41,13 +41,13 @@ class TestDefSiteModel extends BaseModel {
$builder->where('testdefsite.TestType', $testType); $builder->where('testdefsite.TestType', $testType);
} }
if ($visibleScr !== null) { if ($visibleScr !== null) {
$builder->where('testdefsite.isVisibleScr', $visibleScr); $builder->where('testdefsite.isVisibleScr', $visibleScr);
} }
if ($visibleRpt !== null) { if ($visibleRpt !== null) {
$builder->where('testdefsite.isVisibleRpt', $visibleRpt); $builder->where('testdefsite.isVisibleRpt', $visibleRpt);
} }
if ($search) { if ($search) {
$builder->groupStart() $builder->groupStart()
@ -83,10 +83,10 @@ class TestDefSiteModel extends BaseModel {
*/ */
public function getTestsWithRelations($filters = []) { public function getTestsWithRelations($filters = []) {
$builder = $this->db->table('testdefsite') $builder = $this->db->table('testdefsite')
->select( ->select(
"testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType, "testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.isVisibleScr, testdefsite.isVisibleRpt, testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.isVisibleScr, testdefsite.isVisibleRpt,
testdefsite.isCountStat, testdefsite.StartDate, testdefsite.EndDate, testdefsite.isCountStat, testdefsite.StartDate, testdefsite.EndDate,
COALESCE(testdefsite.DisciplineID, cal.DisciplineID) as DisciplineID, COALESCE(testdefsite.DisciplineID, cal.DisciplineID) as DisciplineID,
COALESCE(testdefsite.DepartmentID, cal.DepartmentID) as DepartmentID, COALESCE(testdefsite.DepartmentID, cal.DepartmentID) as DepartmentID,
d.DisciplineName, dept.DepartmentName" d.DisciplineName, dept.DepartmentName"
@ -104,13 +104,13 @@ class TestDefSiteModel extends BaseModel {
$builder->where('testdefsite.TestType', $filters['TestType']); $builder->where('testdefsite.TestType', $filters['TestType']);
} }
if (isset($filters['isVisibleScr'])) { if (isset($filters['isVisibleScr'])) {
$builder->where('testdefsite.isVisibleScr', $filters['isVisibleScr']); $builder->where('testdefsite.isVisibleScr', $filters['isVisibleScr']);
} }
if (isset($filters['isVisibleRpt'])) { if (isset($filters['isVisibleRpt'])) {
$builder->where('testdefsite.isVisibleRpt', $filters['isVisibleRpt']); $builder->where('testdefsite.isVisibleRpt', $filters['isVisibleRpt']);
} }
if (!empty($filters['TestSiteName'])) { if (!empty($filters['TestSiteName'])) {
$builder->like('testdefsite.TestSiteName', $filters['TestSiteName']); $builder->like('testdefsite.TestSiteName', $filters['TestSiteName']);
@ -120,6 +120,10 @@ class TestDefSiteModel extends BaseModel {
$builder->like('testdefsite.TestSiteCode', $filters['TestSiteCode']); $builder->like('testdefsite.TestSiteCode', $filters['TestSiteCode']);
} }
if (!empty($filters['DepartmentID'])) {
$builder->where('COALESCE(testdefsite.DepartmentID, cal.DepartmentID)', $filters['DepartmentID']);
}
if (!empty($filters['search'])) { if (!empty($filters['search'])) {
$builder->groupStart() $builder->groupStart()
->like('testdefsite.TestSiteCode', $filters['search']) ->like('testdefsite.TestSiteCode', $filters['search'])
@ -145,32 +149,32 @@ class TestDefSiteModel extends BaseModel {
$typeCode = $row['TestType'] ?? ''; $typeCode = $row['TestType'] ?? '';
if (TestValidationService::isCalc($typeCode)) { if (TestValidationService::isCalc($typeCode)) {
$row['testdefcal'] = $db->table('testdefcal') $row['testdefcal'] = $db->table('testdefcal')
->select('testdefcal.*, d.DisciplineName, dept.DepartmentName') ->select('testdefcal.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID=testdefcal.DisciplineID', 'left') ->join('discipline d', 'd.DisciplineID=testdefcal.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID=testdefcal.DepartmentID', 'left') ->join('department dept', 'dept.DepartmentID=testdefcal.DepartmentID', 'left')
->where('testdefcal.TestSiteID', $TestSiteID) ->where('testdefcal.TestSiteID', $TestSiteID)
->where('testdefcal.EndDate IS NULL') ->where('testdefcal.EndDate IS NULL')
->get()->getResultArray(); ->get()->getResultArray();
} elseif (TestValidationService::isGroup($typeCode)) { } elseif (TestValidationService::isGroup($typeCode)) {
$testDefGrpModel = new \App\Models\Test\TestDefGrpModel(); $testDefGrpModel = new \App\Models\Test\TestDefGrpModel();
$row['testdefgrp'] = $testDefGrpModel->getGroupMembers($TestSiteID); $row['testdefgrp'] = $testDefGrpModel->getGroupMembers($TestSiteID);
} elseif (TestValidationService::isTitle($typeCode)) { } elseif (TestValidationService::isTitle($typeCode)) {
} elseif (TestValidationService::isTechnicalTest($typeCode)) { } elseif (TestValidationService::isTechnicalTest($typeCode)) {
// Technical details are now flattened into the main row // Technical details are now flattened into the main row
if ($row['DisciplineID']) { if ($row['DisciplineID']) {
$discipline = $db->table('discipline')->where('DisciplineID', $row['DisciplineID'])->get()->getRowArray(); $discipline = $db->table('discipline')->where('DisciplineID', $row['DisciplineID'])->get()->getRowArray();
$row['DisciplineName'] = $discipline['DisciplineName'] ?? null; $row['DisciplineName'] = $discipline['DisciplineName'] ?? null;
} }
if ($row['DepartmentID']) { if ($row['DepartmentID']) {
$department = $db->table('department')->where('DepartmentID', $row['DepartmentID'])->get()->getRowArray(); $department = $db->table('department')->where('DepartmentID', $row['DepartmentID'])->get()->getRowArray();
$row['DepartmentName'] = $department['DepartmentName'] ?? null; $row['DepartmentName'] = $department['DepartmentName'] ?? null;
} }
} }
return $row; return $row;
} }
@ -217,16 +221,16 @@ class TestDefSiteModel extends BaseModel {
* @param int $id * @param int $id
* @return array|null * @return array|null
*/ */
public function getTestById($id) public function getTestById($id)
{ {
$row = $this->db->table('testdefsite') $row = $this->db->table('testdefsite')
->select('testdefsite.*, d.DisciplineName, dept.DepartmentName') ->select('testdefsite.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID = testdefsite.DisciplineID', 'left') ->join('discipline d', 'd.DisciplineID = testdefsite.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID = testdefsite.DepartmentID', 'left') ->join('department dept', 'dept.DepartmentID = testdefsite.DepartmentID', 'left')
->where('testdefsite.TestSiteID', $id) ->where('testdefsite.TestSiteID', $id)
->where('testdefsite.EndDate IS NULL') ->where('testdefsite.EndDate IS NULL')
->get() ->get()
->getRowArray(); ->getRowArray();
if (!$row) { if (!$row) {
return null; return null;
@ -239,4 +243,4 @@ class TestDefSiteModel extends BaseModel {
return $rows[0]; return $rows[0];
} }
} }