controlModel = new MasterControlsModel(); $this->testModel = new MasterTestsModel(); $this->resultModel = new ResultsModel(); $this->controlTestModel = new ControlTestsModel(); $this->commentModel = new ResultCommentsModel(); } /** * GET /api/entry/controls * Get controls by dept (optional dept param) * Optionally filter by date: only non-expired controls */ public function getControls() { try { $deptId = $this->request->getGet('dept_id'); $date = $this->request->getGet('date'); if ($deptId) { $controls = $this->controlModel->where('dept_id', $deptId)->where('deleted_at', null)->findAll(); } else { $controls = $this->controlModel->where('deleted_at', null)->findAll(); } // Filter expired controls if date provided if ($date) { $controls = array_filter($controls, function ($c) use ($date) { return $c['expDate'] === null || $c['expDate'] >= $date; }); } // Convert to camelCase (BaseModel already returns camelCase) $data = array_map(function ($c) { return [ 'id' => $c['controlId'], 'controlId' => $c['controlId'], 'controlName' => $c['controlName'], 'lot' => $c['lot'], 'producer' => $c['producer'], 'expDate' => $c['expDate'] ]; }, $controls); return $this->respond([ 'status' => 'success', 'message' => 'fetch success', 'data' => $data ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } /** * GET /api/entry/tests * Get tests for a control (by control_id) */ public function getTests() { try { $controlId = $this->request->getGet('control_id'); if (!$controlId) { return $this->failValidationErrors(['control_id' => 'Required']); } $tests = $this->controlTestModel->getByControl((int) $controlId); return $this->respond([ 'status' => 'success', 'message' => 'fetch success', 'data' => $tests ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } /** * GET /api/entry/daily * Get existing results for date+control */ public function getDailyData() { try { $date = $this->request->getGet('date'); $controlId = $this->request->getGet('control_id'); if (!$date || !$controlId) { return $this->failValidationErrors(['date' => 'Required', 'control_id' => 'Required']); } // Get tests for this control $tests = $this->controlTestModel->getByControl((int) $controlId); // Get existing results for this date $existingResults = $this->resultModel->getByDateAndControl($date, (int) $controlId); // Map existing results by test_id $resultsByTest = []; foreach ($existingResults as $r) { $resultsByTest[$r['testId']] = [ 'resultId' => $r['id'], 'resValue' => $r['resValue'], 'resComment' => $r['resComment'] ]; } // Merge tests with existing values $data = []; foreach ($tests as $t) { $existing = $resultsByTest[$t['testId']] ?? null; $data[] = [ 'controlTestId' => $t['id'], 'controlId' => $t['controlId'], 'testId' => $t['testId'], 'testName' => $t['testName'], 'testUnit' => $t['testUnit'], 'mean' => $t['mean'], 'sd' => $t['sd'], 'existingResult' => $existing ]; } return $this->respond([ 'status' => 'success', 'message' => 'fetch success', 'data' => $data ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } /** * POST /api/entry/daily * Save/update daily results (batch) */ public function saveDaily() { try { $input = $this->request->getJSON(true); if (!isset($input['date']) || !isset($input['results']) || !is_array($input['results'])) { return $this->failValidationErrors(['Invalid input']); } $date = $input['date']; $results = $input['results']; $savedIds = []; // Start transaction $this->resultModel->db->transBegin(); foreach ($results as $r) { if (!isset($r['controlId']) || !isset($r['testId']) || !isset($r['value'])) { continue; } $data = [ 'control_id' => $r['controlId'], 'test_id' => $r['testId'], 'res_date' => $date, 'res_value' => $r['value'] !== '' ? (float) $r['value'] : null, 'res_comment' => $r['comment'] ?? null ]; if ($data['res_value'] === null) { continue; // Skip empty values } $savedIds[] = $this->resultModel->upsertResult($data); } // Commit transaction $this->resultModel->db->transCommit(); return $this->respond([ 'status' => 'success', 'message' => 'Saved ' . count($savedIds) . ' results', 'data' => ['savedIds' => $savedIds] ], 200); } catch (\Exception $e) { // Rollback transaction on error $this->resultModel->db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } /** * GET /api/entry/monthly * Get monthly data by test */ public function getMonthlyData() { try { $testId = $this->request->getGet('test_id'); $month = $this->request->getGet('month'); // YYYY-MM if (!$testId || !$month) { return $this->failValidationErrors(['test_id' => 'Required', 'month' => 'Required']); } // Get test details $test = $this->testModel->find($testId); if (!$test) { return $this->failNotFound('Test not found'); } // Get controls for this test with QC parameters $controls = $this->controlTestModel->getByTest((int) $testId); // Get existing results for this month $results = $this->resultModel->getByMonth((int) $testId, $month); // Get comments for this month $comments = $this->commentModel->getByTestMonth((int) $testId, $month); // Map results by control_id and day $resultsByControl = []; foreach ($results as $r) { $day = (int) date('j', strtotime($r['resDate'])); $resultsByControl[$r['controlId']][$day] = [ 'resultId' => $r['id'], 'resValue' => $r['resValue'], 'resComment' => $r['resComment'] ]; } // Map comments by control_id (BaseModel returns camelCase) $commentsByControl = []; foreach ($comments as $c) { $commentsByControl[$c['controlId']] = [ 'commentId' => $c['resultCommentId'], 'comText' => $c['comText'] ]; } // Build controls with results array[31] $controlsWithData = []; foreach ($controls as $c) { $resultsByDay = $resultsByControl[$c['controlId']] ?? []; $resultsArray = array_fill(1, 31, null); foreach ($resultsByDay as $day => $val) { $resultsArray[$day] = $val; } $comment = $commentsByControl[$c['controlId']] ?? null; $controlsWithData[] = [ 'controlTestId' => $c['id'], 'controlId' => $c['controlId'], 'controlName' => $c['controlName'], 'lot' => $c['lot'], 'producer' => $c['producer'], 'mean' => $c['mean'], 'sd' => $c['sd'], 'results' => $resultsArray, 'comment' => $comment ]; } $data = [ 'test' => [ 'testId' => $test['testId'], 'testName' => $test['testName'], 'testUnit' => $test['testUnit'] ], 'month' => $month, 'controls' => $controlsWithData ]; return $this->respond([ 'status' => 'success', 'message' => 'fetch success', 'data' => $data ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } /** * POST /api/entry/monthly * Save monthly batch (results + comments) */ public function saveMonthly() { try { $input = $this->request->getJSON(true); if (!isset($input['testId']) || !isset($input['month']) || !isset($input['controls'])) { return $this->failValidationErrors(['Invalid input']); } $testId = $input['testId']; $month = $input['month']; $controls = $input['controls']; // Validate month has valid days $daysInMonth = (int) date('t', strtotime($month . '-01')); $savedCount = 0; $commentCount = 0; // Start transaction $this->resultModel->db->transBegin(); foreach ($controls as $c) { $controlId = $c['controlId']; $results = $c['results'] ?? []; $commentText = $c['comment'] ?? null; // Save results foreach ($results as $day => $value) { if ($value === null || $value === '') { continue; } // Validate day exists in month if ($day < 1 || $day > $daysInMonth) { continue; } $date = $month . '-' . str_pad($day, 2, '0', STR_PAD_LEFT); $data = [ 'control_id' => $controlId, 'test_id' => $testId, 'res_date' => $date, 'res_value' => (float) $value ]; $this->resultModel->upsertResult($data); $savedCount++; } // Save comment if ($commentText !== null) { $commentData = [ 'control_id' => $controlId, 'test_id' => $testId, 'comment_month' => $month, 'com_text' => trim($commentText) ]; $this->commentModel->upsertComment($commentData); $commentCount++; } } // Commit transaction $this->resultModel->db->transCommit(); return $this->respond([ 'status' => 'success', 'message' => "Saved {$savedCount} results and {$commentCount} comments", 'data' => ['savedCount' => $savedCount, 'commentCount' => $commentCount] ], 200); } catch (\Exception $e) { // Rollback transaction on error $this->resultModel->db->transRollback(); return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } /** * POST /api/entry/comment * Save monthly comment (single) */ public function saveComment() { try { $input = $this->request->getJSON(true); $required = ['controlId', 'testId', 'month', 'comment']; foreach ($required as $field) { if (!isset($input[$field])) { return $this->failValidationErrors([$field => 'Required']); } } $commentData = [ 'control_id' => $input['controlId'], 'test_id' => $input['testId'], 'comment_month' => $input['month'], 'com_text' => trim($input['comment']) ]; $id = $this->commentModel->upsertComment($commentData); return $this->respond([ 'status' => 'success', 'message' => 'Comment saved', 'data' => ['id' => $id] ], 200); } catch (\Exception $e) { return $this->failServerError('Something went wrong: ' . $e->getMessage()); } } }