426 lines
14 KiB
PHP
426 lines
14 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Controllers\Api;
|
||
|
|
|
||
|
|
use App\Controllers\BaseController;
|
||
|
|
use CodeIgniter\API\ResponseTrait;
|
||
|
|
use App\Models\Master\MasterControlsModel;
|
||
|
|
use App\Models\Master\MasterTestsModel;
|
||
|
|
use App\Models\Qc\ResultsModel;
|
||
|
|
use App\Models\Qc\ControlTestsModel;
|
||
|
|
use App\Models\Qc\ResultCommentsModel;
|
||
|
|
|
||
|
|
class EntryApiController extends BaseController
|
||
|
|
{
|
||
|
|
use ResponseTrait;
|
||
|
|
|
||
|
|
protected $controlModel;
|
||
|
|
protected $testModel;
|
||
|
|
protected $resultModel;
|
||
|
|
protected $controlTestModel;
|
||
|
|
protected $commentModel;
|
||
|
|
|
||
|
|
public function __construct()
|
||
|
|
{
|
||
|
|
$this->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());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|