Add audit logging plan documentation and update test infrastructure
- Add audit-logging-plan.md with comprehensive logging implementation guide - Update AGENTS.md with project guidelines - Refactor test models: remove RefTHoldModel, RefVSetModel, TestDefTechModel - Update TestDefSiteModel and related migrations - Update seeder and test data files - Update API documentation (OpenAPI specs)
This commit is contained in:
parent
30c0c538d6
commit
ece101b6d2
3
.gitignore
vendored
3
.gitignore
vendored
@ -126,5 +126,4 @@ _modules/*
|
||||
/phpunit*.xml
|
||||
/public/.htaccess
|
||||
|
||||
/.serena
|
||||
AGENTS.md
|
||||
/.serena
|
||||
328
AGENTS.md
Normal file
328
AGENTS.md
Normal file
@ -0,0 +1,328 @@
|
||||
# AGENTS.md - Code Guidelines for CLQMS
|
||||
|
||||
> **CLQMS (Clinical Laboratory Quality Management System)** - A headless REST API backend for clinical laboratory workflows built with CodeIgniter 4.
|
||||
|
||||
---
|
||||
|
||||
## Build, Test & Lint Commands
|
||||
|
||||
### Running Tests
|
||||
```bash
|
||||
# Run all tests
|
||||
./vendor/bin/phpunit
|
||||
|
||||
# Run a specific test file
|
||||
./vendor/bin/phpunit tests/feature/Patients/PatientCreateTest.php
|
||||
|
||||
# Run a specific test method
|
||||
./vendor/bin/phpunit --filter testCreatePatientSuccess tests/feature/Patients/PatientCreateTest.php
|
||||
|
||||
# Run tests with coverage
|
||||
./vendor/bin/phpunit --coverage-html build/logs/html
|
||||
|
||||
# Run tests by suite
|
||||
./vendor/bin/phpunit --testsuite App
|
||||
```
|
||||
|
||||
### CodeIgniter CLI Commands
|
||||
```bash
|
||||
# Run spark commands
|
||||
php spark <command>
|
||||
|
||||
# Generate migration
|
||||
php spark make:migration <name>
|
||||
|
||||
# Generate model
|
||||
php spark make:model <name>
|
||||
|
||||
# Generate controller
|
||||
php spark make:controller <name>
|
||||
|
||||
# Generate seeder
|
||||
php spark make:seeder <name>
|
||||
|
||||
# Run migrations
|
||||
php spark migrate
|
||||
|
||||
# Rollback migrations
|
||||
php spark migrate:rollback
|
||||
```
|
||||
|
||||
### Composer Commands
|
||||
```bash
|
||||
# Install dependencies
|
||||
composer install
|
||||
|
||||
# Run tests via composer
|
||||
composer test
|
||||
|
||||
# Update autoloader
|
||||
composer dump-autoload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### PHP Standards
|
||||
- **PHP Version**: 8.1+
|
||||
- **PSR-4 Autoloading**: `App\` maps to `app/`, `Config\` maps to `app/Config/`
|
||||
- **PSR-12 Coding Style** (follow where applicable)
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
| Element | Convention | Example |
|
||||
|---------|-----------|---------|
|
||||
| Classes | PascalCase | `PatientController` |
|
||||
| Methods | camelCase | `createPatient()` |
|
||||
| Properties | snake_case (legacy) / camelCase (new) | `$patient_id` / `$patientId` |
|
||||
| Constants | UPPER_SNAKE_CASE | `MAX_RETRY_COUNT` |
|
||||
| Tables | snake_case | `patient_visits` |
|
||||
| Columns | PascalCase (legacy) | `PatientID`, `NameFirst` |
|
||||
| JSON fields | PascalCase | `"PatientID": "123"` |
|
||||
|
||||
### File Organization
|
||||
```
|
||||
app/
|
||||
├── Config/ # Configuration files
|
||||
├── Controllers/ # API controllers (grouped by feature)
|
||||
│ ├── Patient/
|
||||
│ ├── Organization/
|
||||
│ └── Specimen/
|
||||
├── Models/ # Data models
|
||||
├── Filters/ # Request filters (Auth, CORS)
|
||||
├── Traits/ # Reusable traits
|
||||
├── Libraries/ # Custom libraries
|
||||
├── Helpers/ # Helper functions
|
||||
└── Database/
|
||||
├── Migrations/
|
||||
└── Seeds/
|
||||
```
|
||||
|
||||
### Imports & Namespaces
|
||||
- Always use fully qualified namespaces at the top
|
||||
- Group imports: Framework first, then App, then external
|
||||
- Use statements must be in alphabetical order within groups
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use App\Traits\ResponseTrait;
|
||||
use Firebase\JWT\JWT;
|
||||
```
|
||||
|
||||
### Controller Structure
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Traits\ResponseTrait;
|
||||
|
||||
class ExampleController extends BaseController
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected $model;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->model = new \App\Models\ExampleModel();
|
||||
}
|
||||
|
||||
// GET /example
|
||||
public function index()
|
||||
{
|
||||
// Implementation
|
||||
}
|
||||
|
||||
// POST /example
|
||||
public function create()
|
||||
{
|
||||
// Implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response Format
|
||||
All API responses must use the standardized format:
|
||||
|
||||
```php
|
||||
// Success response
|
||||
return $this->respond([
|
||||
'status' => 'success',
|
||||
'message' => 'Operation completed',
|
||||
'data' => $data
|
||||
], 200);
|
||||
|
||||
// Error response
|
||||
return $this->respond([
|
||||
'status' => 'failed',
|
||||
'message' => 'Error description',
|
||||
'data' => []
|
||||
], 400);
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
- Use try-catch for JWT operations and external calls
|
||||
- Return structured error responses with appropriate HTTP status codes
|
||||
- Log errors using CodeIgniter's logging: `log_message('error', $message)`
|
||||
|
||||
```php
|
||||
try {
|
||||
$decoded = JWT::decode($token, new Key($key, 'HS256'));
|
||||
} catch (\Firebase\JWT\ExpiredException $e) {
|
||||
return $this->respond(['status' => 'failed', 'message' => 'Token expired'], 401);
|
||||
} catch (\Exception $e) {
|
||||
return $this->respond(['status' => 'failed', 'message' => 'Invalid token'], 401);
|
||||
}
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
- Use CodeIgniter's Query Builder or Model methods
|
||||
- Prefer parameterized queries over raw SQL
|
||||
- Use transactions for multi-table operations
|
||||
|
||||
```php
|
||||
$this->db->transStart();
|
||||
// ... database operations
|
||||
$this->db->transComplete();
|
||||
|
||||
if ($this->db->transStatus() === false) {
|
||||
return $this->respond(['status' => 'error', 'message' => 'Transaction failed'], 500);
|
||||
}
|
||||
```
|
||||
|
||||
### Testing Guidelines
|
||||
|
||||
#### Test Structure
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Patients;
|
||||
|
||||
use CodeIgniter\Test\FeatureTestTrait;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
|
||||
class PatientCreateTest extends CIUnitTestCase
|
||||
{
|
||||
use FeatureTestTrait;
|
||||
|
||||
protected $endpoint = 'api/patient';
|
||||
|
||||
public function testCreatePatientSuccess()
|
||||
{
|
||||
$payload = [...];
|
||||
$result = $this->withBodyFormat('json')
|
||||
->post($this->endpoint, $payload);
|
||||
|
||||
$result->assertStatus(201);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Test Naming
|
||||
- Use descriptive method names: `test<Action><Scenario><ExpectedResult>`
|
||||
- Example: `testCreatePatientValidationFail`, `testCreatePatientSuccess`
|
||||
|
||||
#### Test Status Codes
|
||||
- 200: Success (GET, PATCH)
|
||||
- 201: Created (POST)
|
||||
- 400: Validation Error
|
||||
- 401: Unauthorized
|
||||
- 404: Not Found
|
||||
- 500: Server Error
|
||||
|
||||
### API Design
|
||||
- **Base URL**: `/api/`
|
||||
- **Authentication**: JWT token via HttpOnly cookie
|
||||
- **Content-Type**: `application/json`
|
||||
- **HTTP Methods**:
|
||||
- `GET` - Read
|
||||
- `POST` - Create
|
||||
- `PATCH` - Update (partial)
|
||||
- `DELETE` - Delete
|
||||
|
||||
### Routes Pattern
|
||||
```php
|
||||
$routes->group('api/patient', function ($routes) {
|
||||
$routes->get('/', 'Patient\PatientController::index');
|
||||
$routes->post('/', 'Patient\PatientController::create');
|
||||
$routes->get('(:num)', 'Patient\PatientController::show/$1');
|
||||
$routes->patch('/', 'Patient\PatientController::update');
|
||||
$routes->delete('/', 'Patient\PatientController::delete');
|
||||
});
|
||||
```
|
||||
|
||||
### Security Guidelines
|
||||
- Always use the `auth` filter for protected routes
|
||||
- Sanitize all user inputs
|
||||
- Use parameterized queries to prevent SQL injection
|
||||
- Store JWT secret in `.env` file
|
||||
- Never commit `.env` files
|
||||
|
||||
---
|
||||
|
||||
## Project-Specific Conventions
|
||||
|
||||
### Legacy Field Naming
|
||||
Database uses PascalCase for column names (legacy convention):
|
||||
- `PatientID`, `NameFirst`, `NameLast`
|
||||
- `Birthdate`, `CreatedAt`, `UpdatedAt`
|
||||
|
||||
### ValueSet System
|
||||
Use the `App\Libraries\Lookups` class for static dropdown values:
|
||||
```php
|
||||
use App\Libraries\Lookups;
|
||||
|
||||
$genders = Lookups::get('gender');
|
||||
$options = Lookups::getOptions('gender');
|
||||
```
|
||||
|
||||
### Models
|
||||
Extend `BaseModel` for automatic UTC date handling:
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class PatientModel extends BaseModel
|
||||
{
|
||||
protected $table = 'patients';
|
||||
protected $primaryKey = 'PatientID';
|
||||
protected $allowedFields = ['NameFirst', 'NameLast', ...];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
### Database (`.env`)
|
||||
```ini
|
||||
database.default.hostname = localhost
|
||||
database.default.database = clqms01
|
||||
database.default.username = root
|
||||
database.default.password = adminsakti
|
||||
database.default.DBDriver = MySQLi
|
||||
```
|
||||
|
||||
### JWT Secret (`.env`)
|
||||
```ini
|
||||
JWT_SECRET = '5pandaNdutNdut'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Additional Notes
|
||||
|
||||
- **API-Only**: No view layer - this is a headless REST API
|
||||
- **Frontend Agnostic**: Any client can consume these APIs
|
||||
- **Stateless**: JWT-based authentication per request
|
||||
- **UTC Dates**: All dates stored in UTC, converted for display
|
||||
|
||||
*© 2025 5Panda Team. Engineering Precision in Clinical Diagnostics.*
|
||||
@ -13,7 +13,7 @@ class TestsController extends BaseController
|
||||
protected $rules;
|
||||
protected $model;
|
||||
protected $modelCal;
|
||||
protected $modelTech;
|
||||
|
||||
protected $modelGrp;
|
||||
protected $modelMap;
|
||||
protected $modelRefNum;
|
||||
@ -24,7 +24,7 @@ class TestsController extends BaseController
|
||||
$this->db = \Config\Database::connect();
|
||||
$this->model = new \App\Models\Test\TestDefSiteModel;
|
||||
$this->modelCal = new \App\Models\Test\TestDefCalModel;
|
||||
$this->modelTech = new \App\Models\Test\TestDefTechModel;
|
||||
|
||||
$this->modelGrp = new \App\Models\Test\TestDefGrpModel;
|
||||
$this->modelMap = new \App\Models\Test\TestMapModel;
|
||||
$this->modelRefNum = new \App\Models\RefRange\RefNumModel;
|
||||
@ -50,13 +50,12 @@ class TestsController extends BaseController
|
||||
->select("testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
|
||||
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.VisibleScr, testdefsite.VisibleRpt,
|
||||
testdefsite.CountStat, testdefsite.StartDate, testdefsite.EndDate,
|
||||
COALESCE(tech.DisciplineID, cal.DisciplineID) as DisciplineID,
|
||||
COALESCE(tech.DepartmentID, cal.DepartmentID) as DepartmentID,
|
||||
COALESCE(testdefsite.DisciplineID, cal.DisciplineID) as DisciplineID,
|
||||
COALESCE(testdefsite.DepartmentID, cal.DepartmentID) as DepartmentID,
|
||||
d.DisciplineName, dept.DepartmentName")
|
||||
->join('testdeftech tech', 'tech.TestSiteID = testdefsite.TestSiteID AND tech.EndDate IS NULL', 'left')
|
||||
->join('testdefcal cal', 'cal.TestSiteID = testdefsite.TestSiteID AND cal.EndDate IS NULL', 'left')
|
||||
->join('discipline d', 'd.DisciplineID = COALESCE(tech.DisciplineID, cal.DisciplineID)', 'left')
|
||||
->join('department dept', 'dept.DepartmentID = COALESCE(tech.DepartmentID, cal.DepartmentID)', '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 ($siteId) {
|
||||
@ -141,12 +140,13 @@ class TestsController extends BaseController
|
||||
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
|
||||
|
||||
} else {
|
||||
$row['testdeftech'] = $this->db->table('testdeftech')
|
||||
->select('testdeftech.*, d.DisciplineName, dept.DepartmentName')
|
||||
->join('discipline d', 'd.DisciplineID=testdeftech.DisciplineID', 'left')
|
||||
->join('department dept', 'dept.DepartmentID=testdeftech.DepartmentID', 'left')
|
||||
->where('testdeftech.TestSiteID', $id)
|
||||
->where('testdeftech.EndDate IS NULL')
|
||||
// Technical details are now stored directly in testdefsite
|
||||
$row['testdeftech'] = $this->db->table('testdefsite')
|
||||
->select('testdefsite.*, d.DisciplineName, dept.DepartmentName')
|
||||
->join('discipline d', 'd.DisciplineID=testdefsite.DisciplineID', 'left')
|
||||
->join('department dept', 'dept.DepartmentID=testdefsite.DepartmentID', 'left')
|
||||
->where('testdefsite.TestSiteID', $id)
|
||||
->where('testdefsite.EndDate IS NULL')
|
||||
->get()->getResultArray();
|
||||
|
||||
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
|
||||
@ -371,9 +371,6 @@ class TestsController extends BaseController
|
||||
->where('TestSiteID', $id)
|
||||
->update(['EndDate' => $now]);
|
||||
} elseif (in_array($typeCode, ['TEST', 'PARAM'])) {
|
||||
$this->db->table('testdeftech')
|
||||
->where('TestSiteID', $id)
|
||||
->update(['EndDate' => $now]);
|
||||
|
||||
$this->modelRefNum->where('TestSiteID', $id)->set('EndDate', $now)->update();
|
||||
$this->modelRefTxt->where('TestSiteID', $id)->set('EndDate', $now)->update();
|
||||
@ -459,8 +456,8 @@ class TestsController extends BaseController
|
||||
|
||||
private function saveTechDetails($testSiteID, $data, $action, $typeCode)
|
||||
{
|
||||
// Technical details are now stored directly in testdefsite table
|
||||
$techData = [
|
||||
'TestSiteID' => $testSiteID,
|
||||
'DisciplineID' => $data['DisciplineID'] ?? null,
|
||||
'DepartmentID' => $data['DepartmentID'] ?? null,
|
||||
'ResultType' => $data['ResultType'] ?? null,
|
||||
@ -477,20 +474,8 @@ class TestsController extends BaseController
|
||||
'ExpectedTAT' => $data['ExpectedTAT'] ?? null
|
||||
];
|
||||
|
||||
if ($action === 'update') {
|
||||
$exists = $this->db->table('testdeftech')
|
||||
->where('TestSiteID', $testSiteID)
|
||||
->where('EndDate IS NULL')
|
||||
->get()->getRowArray();
|
||||
|
||||
if ($exists) {
|
||||
$this->modelTech->update($exists['TestTechID'], $techData);
|
||||
} else {
|
||||
$this->modelTech->insert($techData);
|
||||
}
|
||||
} else {
|
||||
$this->modelTech->insert($techData);
|
||||
}
|
||||
// Update the testdefsite record directly
|
||||
$this->model->update($testSiteID, $techData);
|
||||
}
|
||||
|
||||
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
|
||||
|
||||
@ -13,23 +13,7 @@ class CreateTestDefinitions extends Migration {
|
||||
'TestSiteName' => ['type' => 'varchar', 'constraint'=> 100, 'null' => false],
|
||||
'TestType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => false],
|
||||
'Description' => ['type' => 'varchar', 'constraint'=> 255, 'null' => true],
|
||||
'SeqScr' => ['type' => 'int', 'null' => true],
|
||||
'SeqRpt' => ['type' => 'int', 'null' => true],
|
||||
'IndentLeft' => ['type' => 'int', 'null' => true, 'default' => 0],
|
||||
'FontStyle' => ['type' => 'varchar', 'constraint'=> 50, 'null' => true],
|
||||
'VisibleScr' => ['type' => 'int', 'null' => true, 'default' => 1],
|
||||
'VisibleRpt' => ['type' => 'int', 'null' => true, 'default' => 1],
|
||||
'CountStat' => ['type' => 'int', 'null' => true, 'default' => 1],
|
||||
'CreateDate' => ['type' => 'Datetime', 'null' => true],
|
||||
'StartDate' => ['type' => 'Datetime', 'null' => true],
|
||||
'EndDate' => ['type' => 'Datetime', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('TestSiteID', true);
|
||||
$this->forge->createTable('testdefsite');
|
||||
|
||||
$this->forge->addField([
|
||||
'TestTechID' => ['type' => 'INT', 'auto_increment' => true, 'unsigned' => true],
|
||||
'TestSiteID' => ['type' => 'INT', 'unsigned' => true, 'null' => false],
|
||||
// Technical details merged from testdeftech
|
||||
'DisciplineID' => ['type' => 'INT', 'null' => true],
|
||||
'DepartmentID' => ['type' => 'INT', 'null' => true],
|
||||
'ResultType' => ['type' => 'VARCHAR', 'constraint'=> 20, 'null' => true],
|
||||
@ -44,12 +28,22 @@ class CreateTestDefinitions extends Migration {
|
||||
'CollReq' => ['type' => 'varchar', 'constraint'=> 255, 'null' => true],
|
||||
'Method' => ['type' => 'varchar', 'constraint'=> 50, 'null' => true],
|
||||
'ExpectedTAT' => ['type' => 'INT', 'null' => true],
|
||||
'SeqScr' => ['type' => 'int', 'null' => true],
|
||||
'SeqRpt' => ['type' => 'int', 'null' => true],
|
||||
'IndentLeft' => ['type' => 'int', 'null' => true, 'default' => 0],
|
||||
'FontStyle' => ['type' => 'varchar', 'constraint'=> 50, 'null' => true],
|
||||
'VisibleScr' => ['type' => 'int', 'null' => true, 'default' => 1],
|
||||
'VisibleRpt' => ['type' => 'int', 'null' => true, 'default' => 1],
|
||||
'CountStat' => ['type' => 'int', 'null' => true, 'default' => 1],
|
||||
'Level' => ['type' => 'int', 'null' => true],
|
||||
'CreateDate' => ['type' => 'Datetime', 'null' => true],
|
||||
'EndDate' => ['type' => 'Datetime', 'null' => true]
|
||||
'StartDate' => ['type' => 'Datetime', 'null' => true],
|
||||
'EndDate' => ['type' => 'Datetime', 'null' => true],
|
||||
]);
|
||||
$this->forge->addKey('TestTechID', true);
|
||||
$this->forge->addForeignKey('TestSiteID', 'testdefsite', 'TestSiteID', 'CASCADE', 'CASCADE');
|
||||
$this->forge->createTable('testdeftech');
|
||||
$this->forge->addKey('TestSiteID', true);
|
||||
$this->forge->createTable('testdefsite');
|
||||
|
||||
// testdeftech table removed - merged into testdefsite
|
||||
|
||||
$this->forge->addField([
|
||||
'TestCalID' => ['type' => 'INT', 'auto_increment' => true, 'unsigned' => true],
|
||||
@ -166,7 +160,7 @@ class CreateTestDefinitions extends Migration {
|
||||
$this->forge->dropTable('testmap');
|
||||
$this->forge->dropTable('testdefgrp');
|
||||
$this->forge->dropTable('testdefcal');
|
||||
$this->forge->dropTable('testdeftech');
|
||||
// testdeftech table removed - merged into testdefsite
|
||||
$this->forge->dropTable('testdefsite');
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,142 +28,98 @@ class TestSeeder extends Seeder
|
||||
// ========================================
|
||||
// TEST TYPE - Actual Laboratory Tests
|
||||
// ========================================
|
||||
// Hematology Tests
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HB', 'TestSiteName' => 'Hemoglobin', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '2', 'SeqRpt' => '2', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
// Hematology Tests - Technical details merged into testdefsite
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HB', 'TestSiteName' => 'Hemoglobin', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '2', 'SeqRpt' => '2', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'g/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['HB'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['HB'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'g/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HCT', 'TestSiteName' => 'Hematocrit', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '3', 'SeqRpt' => '3', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HCT', 'TestSiteName' => 'Hematocrit', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '3', 'SeqRpt' => '3', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => '%', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['HCT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['HCT'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => '%', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'RBC', 'TestSiteName' => 'Red Blood Cell', 'TestType' => 'TEST', 'Description' => 'Eritrosit', 'SeqScr' => '4', 'SeqRpt' => '4', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'RBC', 'TestSiteName' => 'Red Blood Cell', 'TestType' => 'TEST', 'Description' => 'Eritrosit', 'SeqScr' => '4', 'SeqRpt' => '4', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^6/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '2', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['RBC'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['RBC'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^6/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '2', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'WBC', 'TestSiteName' => 'White Blood Cell', 'TestType' => 'TEST', 'Description' => 'Leukosit', 'SeqScr' => '5', 'SeqRpt' => '5', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'WBC', 'TestSiteName' => 'White Blood Cell', 'TestType' => 'TEST', 'Description' => 'Leukosit', 'SeqScr' => '5', 'SeqRpt' => '5', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^3/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '2', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['WBC'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['WBC'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^3/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '2', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'PLT', 'TestSiteName' => 'Platelet', 'TestType' => 'TEST', 'Description' => 'Trombosit', 'SeqScr' => '6', 'SeqRpt' => '6', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'PLT', 'TestSiteName' => 'Platelet', 'TestType' => 'TEST', 'Description' => 'Trombosit', 'SeqScr' => '6', 'SeqRpt' => '6', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^3/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['PLT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['PLT'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^3/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'MCV', 'TestSiteName' => 'MCV', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Volume', 'SeqScr' => '7', 'SeqRpt' => '7', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'MCV', 'TestSiteName' => 'MCV', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Volume', 'SeqScr' => '7', 'SeqRpt' => '7', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'fL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['MCV'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['MCV'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'fL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'MCH', 'TestSiteName' => 'MCH', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Hemoglobin', 'SeqScr' => '8', 'SeqRpt' => '8', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'MCH', 'TestSiteName' => 'MCH', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Hemoglobin', 'SeqScr' => '8', 'SeqRpt' => '8', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'pg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['MCH'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['MCH'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'pg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'MCHC', 'TestSiteName' => 'MCHC', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Hemoglobin Concentration', 'SeqScr' => '9', 'SeqRpt' => '9', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'MCHC', 'TestSiteName' => 'MCHC', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Hemoglobin Concentration', 'SeqScr' => '9', 'SeqRpt' => '9', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'g/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['MCHC'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['MCHC'], 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'g/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
// Chemistry Tests
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'GLU', 'TestSiteName' => 'Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Sewaktu', 'SeqScr' => '11', 'SeqRpt' => '11', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'GLU', 'TestSiteName' => 'Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Sewaktu', 'SeqScr' => '11', 'SeqRpt' => '11', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '0.0555', 'Unit2' => 'mmol/L', 'Decimal' => '0', 'Method' => 'Hexokinase', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['GLU'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['GLU'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '0.0555', 'Unit2' => 'mmol/L', 'Decimal' => '0', 'Method' => 'Hexokinase', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'CREA', 'TestSiteName' => 'Creatinine', 'TestType' => 'TEST', 'Description' => 'Kreatinin', 'SeqScr' => '12', 'SeqRpt' => '12', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'CREA', 'TestSiteName' => 'Creatinine', 'TestType' => 'TEST', 'Description' => 'Kreatinin', 'SeqScr' => '12', 'SeqRpt' => '12', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '88.4', 'Unit2' => 'umol/L', 'Decimal' => '2', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['CREA'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['CREA'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '88.4', 'Unit2' => 'umol/L', 'Decimal' => '2', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UREA', 'TestSiteName' => 'Blood Urea Nitrogen', 'TestType' => 'TEST', 'Description' => 'BUN', 'SeqScr' => '13', 'SeqRpt' => '13', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UREA', 'TestSiteName' => 'Blood Urea Nitrogen', 'TestType' => 'TEST', 'Description' => 'BUN', 'SeqScr' => '13', 'SeqRpt' => '13', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Urease-GLDH', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['UREA'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['UREA'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Urease-GLDH', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'SGOT', 'TestSiteName' => 'AST (SGOT)', 'TestType' => 'TEST', 'Description' => 'Aspartate Aminotransferase', 'SeqScr' => '14', 'SeqRpt' => '14', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'SGOT', 'TestSiteName' => 'AST (SGOT)', 'TestType' => 'TEST', 'Description' => 'Aspartate Aminotransferase', 'SeqScr' => '14', 'SeqRpt' => '14', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['SGOT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['SGOT'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'SGPT', 'TestSiteName' => 'ALT (SGPT)', 'TestType' => 'TEST', 'Description' => 'Alanine Aminotransferase', 'SeqScr' => '15', 'SeqRpt' => '15', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'SGPT', 'TestSiteName' => 'ALT (SGPT)', 'TestType' => 'TEST', 'Description' => 'Alanine Aminotransferase', 'SeqScr' => '15', 'SeqRpt' => '15', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['SGPT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['SGPT'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'CHOL', 'TestSiteName' => 'Total Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol Total', 'SeqScr' => '16', 'SeqRpt' => '16', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'CHOL', 'TestSiteName' => 'Total Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol Total', 'SeqScr' => '16', 'SeqRpt' => '16', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['CHOL'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['CHOL'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'TG', 'TestSiteName' => 'Triglycerides', 'TestType' => 'TEST', 'Description' => 'Trigliserida', 'SeqScr' => '17', 'SeqRpt' => '17', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'TG', 'TestSiteName' => 'Triglycerides', 'TestType' => 'TEST', 'Description' => 'Trigliserida', 'SeqScr' => '17', 'SeqRpt' => '17', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'GPO-PAP', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['TG'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['TG'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'GPO-PAP', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HDL', 'TestSiteName' => 'HDL Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol HDL', 'SeqScr' => '18', 'SeqRpt' => '18', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HDL', 'TestSiteName' => 'HDL Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol HDL', 'SeqScr' => '18', 'SeqRpt' => '18', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['HDL'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['HDL'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'LDL', 'TestSiteName' => 'LDL Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol LDL', 'SeqScr' => '19', 'SeqRpt' => '19', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'LDL', 'TestSiteName' => 'LDL Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol LDL', 'SeqScr' => '19', 'SeqRpt' => '19', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['LDL'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['LDL'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
// ========================================
|
||||
// PARAM TYPE - Parameters (non-lab values)
|
||||
// ========================================
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HEIGHT', 'TestSiteName' => 'Height', 'TestType' => 'PARAM', 'Description' => 'Tinggi Badan', 'SeqScr' => '40', 'SeqRpt' => '40', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'HEIGHT', 'TestSiteName' => 'Height', 'TestType' => 'PARAM', 'Description' => 'Tinggi Badan', 'SeqScr' => '40', 'SeqRpt' => '40', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'cm', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['HEIGHT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['HEIGHT'], 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'cm', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'WEIGHT', 'TestSiteName' => 'Weight', 'TestType' => 'PARAM', 'Description' => 'Berat Badan', 'SeqScr' => '41', 'SeqRpt' => '41', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'WEIGHT', 'TestSiteName' => 'Weight', 'TestType' => 'PARAM', 'Description' => 'Berat Badan', 'SeqScr' => '41', 'SeqRpt' => '41', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'kg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['WEIGHT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['WEIGHT'], 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'kg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'AGE', 'TestSiteName' => 'Age', 'TestType' => 'PARAM', 'Description' => 'Usia', 'SeqScr' => '42', 'SeqRpt' => '42', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'AGE', 'TestSiteName' => 'Age', 'TestType' => 'PARAM', 'Description' => 'Usia', 'SeqScr' => '42', 'SeqRpt' => '42', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'years', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['AGE'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['AGE'], 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'years', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'SYSTL', 'TestSiteName' => 'Systolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Sistolik', 'SeqScr' => '43', 'SeqRpt' => '43', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'SYSTL', 'TestSiteName' => 'Systolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Sistolik', 'SeqScr' => '43', 'SeqRpt' => '43', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['SYSTL'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['SYSTL'], 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'DIASTL', 'TestSiteName' => 'Diastolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Diastolik', 'SeqScr' => '44', 'SeqRpt' => '44', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'DIASTL', 'TestSiteName' => 'Diastolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Diastolik', 'SeqScr' => '44', 'SeqRpt' => '44', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['DIASTL'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['DIASTL'], 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
// ========================================
|
||||
// CALC TYPE - Calculated Tests
|
||||
@ -232,28 +188,20 @@ class TestSeeder extends Seeder
|
||||
]);
|
||||
|
||||
// Urinalysis Tests (with valueset result type)
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UCOLOR', 'TestSiteName' => 'Urine Color', 'TestType' => 'TEST', 'Description' => 'Warna Urine', 'SeqScr' => '31', 'SeqRpt' => '31', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UCOLOR', 'TestSiteName' => 'Urine Color', 'TestType' => 'TEST', 'Description' => 'Warna Urine', 'SeqScr' => '31', 'SeqRpt' => '31', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'TEXT', 'VSet' => '1001', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Visual', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['UCOLOR'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['UCOLOR'], 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'TEXT', 'VSet' => '1001', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Visual', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UGLUC', 'TestSiteName' => 'Urine Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Urine', 'SeqScr' => '32', 'SeqRpt' => '32', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UGLUC', 'TestSiteName' => 'Urine Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Urine', 'SeqScr' => '32', 'SeqRpt' => '32', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'TEXT', 'VSet' => '1002', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Dipstick', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['UGLUC'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['UGLUC'], 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'TEXT', 'VSet' => '1002', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Dipstick', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UPROT', 'TestSiteName' => 'Urine Protein', 'TestType' => 'TEST', 'Description' => 'Protein Urine', 'SeqScr' => '33', 'SeqRpt' => '33', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'UPROT', 'TestSiteName' => 'Urine Protein', 'TestType' => 'TEST', 'Description' => 'Protein Urine', 'SeqScr' => '33', 'SeqRpt' => '33', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'TEXT', 'VSet' => '1003', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Dipstick', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['UPROT'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['UPROT'], 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'TEXT', 'VSet' => '1003', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Dipstick', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'PH', 'TestSiteName' => 'Urine pH', 'TestType' => 'TEST', 'Description' => 'pH Urine', 'SeqScr' => '34', 'SeqRpt' => '34', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'CreateDate' => "$now"];
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'PH', 'TestSiteName' => 'Urine pH', 'TestType' => 'TEST', 'Description' => 'pH Urine', 'SeqScr' => '34', 'SeqRpt' => '34', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Dipstick', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdefsite')->insert($data);
|
||||
$tIDs['PH'] = $this->db->insertID();
|
||||
$data = ['TestSiteID' => $tIDs['PH'], 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'NMRIC', 'RefType' => 'NMRC', 'VSet' => '', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Dipstick', 'CreateDate' => "$now"];
|
||||
$this->db->table('testdeftech')->insert($data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
{"key": "NMRIC", "value": "Numeric"},
|
||||
{"key": "RANGE", "value": "Range"},
|
||||
{"key": "TEXT", "value": "Text"},
|
||||
{"key": "VSET", "value": "Value set"}
|
||||
{"key": "VSET", "value": "Value set"},
|
||||
{"key": "NORES", "value": "No Result"}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\RefRange;
|
||||
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class RefTHoldModel extends BaseModel {
|
||||
protected $table = 'refthold';
|
||||
protected $primaryKey = 'RefTHoldID';
|
||||
protected $allowedFields = ['SiteID', 'TestSiteID', 'SpcType', 'Sex', 'AgeStart', 'AgeEnd',
|
||||
'Threshold', 'BelowTxt', 'AboveTxt', 'GrayzoneLow', 'GrayzoneHigh', 'GrayzoneTxt',
|
||||
'CreateDate', 'EndDate'];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'CreateDate';
|
||||
protected $updatedField = '';
|
||||
protected $useSoftDeletes = true;
|
||||
protected $deletedField = "EndDate";
|
||||
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\RefRange;
|
||||
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class RefVSetModel extends BaseModel {
|
||||
protected $table = 'refvset';
|
||||
protected $primaryKey = 'RefVSetID';
|
||||
protected $allowedFields = ['SiteID', 'TestSiteID', 'SpcType', 'Sex', 'AgeStart', 'AgeEnd',
|
||||
'RefTxt', 'CreateDate', 'EndDate'];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'CreateDate';
|
||||
protected $updatedField = '';
|
||||
protected $useSoftDeletes = true;
|
||||
protected $deletedField = "EndDate";
|
||||
|
||||
}
|
||||
@ -10,20 +10,14 @@ class TestDefSiteModel extends BaseModel {
|
||||
protected $primaryKey = 'TestSiteID';
|
||||
protected $allowedFields = [
|
||||
'SiteID',
|
||||
'TestSiteCode',
|
||||
'TestSiteName',
|
||||
'TestType',
|
||||
'Description',
|
||||
'SeqScr',
|
||||
'SeqRpt',
|
||||
'IndentLeft',
|
||||
'FontStyle',
|
||||
'VisibleScr',
|
||||
'VisibleRpt',
|
||||
'CountStat',
|
||||
'CreateDate',
|
||||
'StartDate',
|
||||
'EndDate'
|
||||
'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',
|
||||
'CreateDate', 'StartDate','EndDate'
|
||||
];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
@ -131,13 +125,15 @@ class TestDefSiteModel extends BaseModel {
|
||||
$row['testmap'] = $testMapModel->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll();
|
||||
|
||||
} elseif (in_array($typeCode, ['TEST', 'PARAM'])) {
|
||||
$row['testdeftech'] = $db->table('testdeftech')
|
||||
->select('testdeftech.*, d.DisciplineName, dept.DepartmentName')
|
||||
->join('discipline d', 'd.DisciplineID=testdeftech.DisciplineID', 'left')
|
||||
->join('department dept', 'dept.DepartmentID=testdeftech.DepartmentID', 'left')
|
||||
->where('testdeftech.TestSiteID', $TestSiteID)
|
||||
->where('testdeftech.EndDate IS NULL')
|
||||
->get()->getResultArray();
|
||||
// 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();
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Test;
|
||||
|
||||
use App\Models\BaseModel;
|
||||
|
||||
class TestDefTechModel extends BaseModel {
|
||||
protected $table = 'testdeftech';
|
||||
protected $primaryKey = 'TestTechID';
|
||||
protected $allowedFields = [
|
||||
'TestSiteID',
|
||||
'DisciplineID',
|
||||
'DepartmentID',
|
||||
'ResultType',
|
||||
'RefType',
|
||||
'VSet',
|
||||
'ReqQty',
|
||||
'ReqQtyUnit',
|
||||
'Unit1',
|
||||
'Factor',
|
||||
'Unit2',
|
||||
'Decimal',
|
||||
'CollReq',
|
||||
'Method',
|
||||
'ExpectedTAT',
|
||||
'CreateDate',
|
||||
'EndDate'
|
||||
];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'CreateDate';
|
||||
protected $updatedField = '';
|
||||
protected $useSoftDeletes = true;
|
||||
protected $deletedField = "EndDate";
|
||||
|
||||
/**
|
||||
* Get technical details for a test
|
||||
*/
|
||||
public function getTechDetails($testSiteID) {
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
return $db->table('testdeftech')
|
||||
->select('testdeftech.*, d.DisciplineName, dept.DepartmentName')
|
||||
->join('discipline d', 'd.DisciplineID=testdeftech.DisciplineID', 'left')
|
||||
->join('department dept', 'dept.DepartmentID=testdeftech.DepartmentID', 'left')
|
||||
->where('testdeftech.TestSiteID', $testSiteID)
|
||||
->where('testdeftech.EndDate IS NULL')
|
||||
->get()->getResultArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tests by discipline
|
||||
*/
|
||||
public function getTestsByDiscipline($disciplineID, $siteID = null) {
|
||||
$builder = $this->select('testdeftech.*, testdefsite.TestSiteCode, testdefsite.TestSiteName')
|
||||
->join('testdefsite', 'testdefsite.TestSiteID=testdeftech.TestSiteID', 'left')
|
||||
->where('testdeftech.DisciplineID', $disciplineID)
|
||||
->where('testdeftech.EndDate IS NULL');
|
||||
|
||||
if ($siteID) {
|
||||
$builder->where('testdefsite.SiteID', $siteID);
|
||||
}
|
||||
|
||||
return $builder->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tests by department
|
||||
*/
|
||||
public function getTestsByDepartment($departmentID, $siteID = null) {
|
||||
$builder = $this->select('testdeftech.*, testdefsite.TestSiteCode, testdefsite.TestSiteName')
|
||||
->join('testdefsite', 'testdefsite.TestSiteID=testdeftech.TestSiteID', 'left')
|
||||
->where('testdeftech.DepartmentID', $departmentID)
|
||||
->where('testdeftech.EndDate IS NULL');
|
||||
|
||||
if ($siteID) {
|
||||
$builder->where('testdefsite.SiteID', $siteID);
|
||||
}
|
||||
|
||||
return $builder->findAll();
|
||||
}
|
||||
}
|
||||
473
docs/audit-logging-plan.md
Normal file
473
docs/audit-logging-plan.md
Normal file
@ -0,0 +1,473 @@
|
||||
# Audit Logging Architecture Plan for CLQMS
|
||||
|
||||
> **Clinical Laboratory Quality Management System (CLQMS)** - A comprehensive audit trail strategy for tracking changes across master data, patient records, and laboratory operations.
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document outlines a unified audit logging architecture for CLQMS, designed to provide complete traceability of data changes while maintaining optimal performance and maintainability. The approach separates audit logs into three domain-specific tables, utilizing JSON for flexible value storage.
|
||||
|
||||
---
|
||||
|
||||
## 1. Current State Analysis
|
||||
|
||||
### Existing Audit Infrastructure
|
||||
|
||||
| Aspect | Current Status |
|
||||
|--------|---------------|
|
||||
| **Database Tables** | 3 tables exist in migrations (patreglog, patvisitlog, specimenlog) |
|
||||
| **Implementation** | Tables created but not actively used |
|
||||
| **Structure** | Fixed column approach (FldName, FldValuePrev) |
|
||||
| **Code Coverage** | No models or controllers implemented |
|
||||
| **Application Logging** | Basic CodeIgniter file logging for debug/errors |
|
||||
|
||||
### Pain Points Identified
|
||||
|
||||
- ❌ **3 separate tables** with nearly identical schemas
|
||||
- ❌ **Fixed column structure** - rigid and requires schema changes for new entities
|
||||
- ❌ **No implementation** - audit tables exist but aren't populated
|
||||
- ❌ **Maintenance overhead** - adding new entities requires new migrations
|
||||
|
||||
---
|
||||
|
||||
## 2. Proposed Architecture
|
||||
|
||||
### 2.1 Domain Separation
|
||||
|
||||
We categorize audit logs by **data domain** and **access patterns**:
|
||||
|
||||
| Table | Domain | Volume | Retention | Use Case |
|
||||
|-------|--------|--------|-----------|----------|
|
||||
| `master_audit_log` | Reference Data | Low | Permanent | Organizations, Users, ValueSets |
|
||||
| `patient_audit_log` | Patient Records | Medium | 7 years | Demographics, Contacts, Insurance |
|
||||
| `order_audit_log` | Operations | High | 2 years | Orders, Tests, Specimens, Results |
|
||||
|
||||
### 2.2 Unified Table Structure
|
||||
|
||||
#### Master Audit Log
|
||||
|
||||
```sql
|
||||
CREATE TABLE master_audit_log (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_type VARCHAR(50) NOT NULL, -- 'organization', 'user', 'valueset'
|
||||
entity_id VARCHAR(36) NOT NULL, -- UUID or primary key
|
||||
action ENUM('CREATE', 'UPDATE', 'DELETE', 'PATCH') NOT NULL,
|
||||
|
||||
old_values JSON NULL, -- Complete snapshot before change
|
||||
new_values JSON NULL, -- Complete snapshot after change
|
||||
changed_fields JSON, -- Array of modified field names
|
||||
|
||||
-- Context
|
||||
user_id VARCHAR(36),
|
||||
site_id VARCHAR(36),
|
||||
ip_address VARCHAR(45),
|
||||
user_agent VARCHAR(500),
|
||||
app_version VARCHAR(20),
|
||||
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_entity (entity_type, entity_id),
|
||||
INDEX idx_created (created_at),
|
||||
INDEX idx_user (user_id, created_at)
|
||||
) ENGINE=InnoDB;
|
||||
```
|
||||
|
||||
#### Patient Audit Log
|
||||
|
||||
```sql
|
||||
CREATE TABLE patient_audit_log (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_type VARCHAR(50) NOT NULL, -- 'patient', 'contact', 'insurance'
|
||||
entity_id VARCHAR(36) NOT NULL,
|
||||
patient_id VARCHAR(36), -- Context FK for patient
|
||||
|
||||
action ENUM('CREATE', 'UPDATE', 'DELETE', 'MERGE', 'UNMERGE') NOT NULL,
|
||||
|
||||
old_values JSON NULL,
|
||||
new_values JSON NULL,
|
||||
changed_fields JSON,
|
||||
reason TEXT, -- Why the change was made
|
||||
|
||||
-- Context
|
||||
user_id VARCHAR(36),
|
||||
site_id VARCHAR(36),
|
||||
ip_address VARCHAR(45),
|
||||
session_id VARCHAR(100),
|
||||
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_entity (entity_type, entity_id),
|
||||
INDEX idx_patient (patient_id, created_at),
|
||||
INDEX idx_created (created_at),
|
||||
INDEX idx_user (user_id, created_at)
|
||||
) ENGINE=InnoDB;
|
||||
```
|
||||
|
||||
#### Order/Test Audit Log
|
||||
|
||||
```sql
|
||||
CREATE TABLE order_audit_log (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
entity_type VARCHAR(50) NOT NULL, -- 'order', 'test', 'specimen', 'result'
|
||||
entity_id VARCHAR(36) NOT NULL,
|
||||
|
||||
-- Context FKs
|
||||
patient_id VARCHAR(36),
|
||||
visit_id VARCHAR(36),
|
||||
order_id VARCHAR(36),
|
||||
|
||||
action ENUM('CREATE', 'UPDATE', 'DELETE', 'CANCEL', 'REORDER', 'COLLECT', 'RESULT') NOT NULL,
|
||||
|
||||
old_values JSON NULL,
|
||||
new_values JSON NULL,
|
||||
changed_fields JSON,
|
||||
status_transition VARCHAR(100), -- e.g., 'pending->collected'
|
||||
|
||||
-- Context
|
||||
user_id VARCHAR(36),
|
||||
site_id VARCHAR(36),
|
||||
device_id VARCHAR(36), -- Instrument/edge device
|
||||
ip_address VARCHAR(45),
|
||||
session_id VARCHAR(100),
|
||||
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
INDEX idx_entity (entity_type, entity_id),
|
||||
INDEX idx_order (order_id, created_at),
|
||||
INDEX idx_patient (patient_id, created_at),
|
||||
INDEX idx_created (created_at),
|
||||
INDEX idx_user (user_id, created_at)
|
||||
) ENGINE=InnoDB;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. JSON Value Structure
|
||||
|
||||
### Example Audit Entry
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 15243,
|
||||
"entity_type": "patient",
|
||||
"entity_id": "PAT-2026-001234",
|
||||
"action": "UPDATE",
|
||||
|
||||
"old_values": {
|
||||
"NameFirst": "John",
|
||||
"NameLast": "Doe",
|
||||
"Gender": "M",
|
||||
"BirthDate": "1990-01-15",
|
||||
"Phone": "+1-555-0100"
|
||||
},
|
||||
|
||||
"new_values": {
|
||||
"NameFirst": "Johnny",
|
||||
"NameLast": "Doe-Smith",
|
||||
"Gender": "M",
|
||||
"BirthDate": "1990-01-15",
|
||||
"Phone": "+1-555-0199"
|
||||
},
|
||||
|
||||
"changed_fields": ["NameFirst", "NameLast", "Phone"],
|
||||
|
||||
"user_id": "USR-001",
|
||||
"site_id": "SITE-001",
|
||||
"created_at": "2026-02-19T14:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Benefits of JSON Approach
|
||||
|
||||
✅ **Schema Evolution** - Add new fields without migrations
|
||||
✅ **Complete Snapshots** - Reconstruct full record state at any point
|
||||
✅ **Flexible Queries** - MySQL 8.0+ supports JSON indexing and extraction
|
||||
✅ **Audit Integrity** - Store exactly what changed, no data loss
|
||||
|
||||
---
|
||||
|
||||
## 4. Implementation Strategy
|
||||
|
||||
### 4.1 Central Audit Service
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
class AuditService
|
||||
{
|
||||
/**
|
||||
* Log an audit event to the appropriate table
|
||||
*/
|
||||
public static function log(
|
||||
string $category, // 'master', 'patient', 'order'
|
||||
string $entityType, // e.g., 'patient', 'order'
|
||||
string $entityId,
|
||||
string $action,
|
||||
?array $oldValues = null,
|
||||
?array $newValues = null,
|
||||
?string $reason = null,
|
||||
?array $context = null
|
||||
): void {
|
||||
$changedFields = self::calculateChangedFields($oldValues, $newValues);
|
||||
|
||||
$data = [
|
||||
'entity_type' => $entityType,
|
||||
'entity_id' => $entityId,
|
||||
'action' => $action,
|
||||
'old_values' => $oldValues ? json_encode($oldValues) : null,
|
||||
'new_values' => $newValues ? json_encode($newValues) : null,
|
||||
'changed_fields' => json_encode($changedFields),
|
||||
'user_id' => auth()->id() ?? 'SYSTEM',
|
||||
'site_id' => session('site_id') ?? 'MAIN',
|
||||
'created_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
// Route to appropriate table
|
||||
$table = match($category) {
|
||||
'master' => 'master_audit_log',
|
||||
'patient' => 'patient_audit_log',
|
||||
'order' => 'order_audit_log',
|
||||
default => throw new \InvalidArgumentException("Unknown category: $category")
|
||||
};
|
||||
|
||||
// Async logging recommended for high-volume operations
|
||||
self::dispatchAuditJob($table, $data);
|
||||
}
|
||||
|
||||
private static function calculateChangedFields(?array $old, ?array $new): array
|
||||
{
|
||||
if (!$old || !$new) return [];
|
||||
|
||||
$changes = [];
|
||||
$allKeys = array_unique(array_merge(array_keys($old), array_keys($new)));
|
||||
|
||||
foreach ($allKeys as $key) {
|
||||
if (($old[$key] ?? null) !== ($new[$key] ?? null)) {
|
||||
$changes[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
return $changes;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Model Integration
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Services\AuditService;
|
||||
|
||||
class PatientModel extends BaseModel
|
||||
{
|
||||
protected $table = 'patients';
|
||||
protected $primaryKey = 'PatientID';
|
||||
|
||||
protected function logAudit(
|
||||
string $action,
|
||||
?array $oldValues = null,
|
||||
?array $newValues = null
|
||||
): void {
|
||||
AuditService::log(
|
||||
category: 'patient',
|
||||
entityType: 'patient',
|
||||
entityId: $this->getPatientId(),
|
||||
action: $action,
|
||||
oldValues: $oldValues,
|
||||
newValues: $newValues
|
||||
);
|
||||
}
|
||||
|
||||
// Override save method to auto-log
|
||||
public function save($data): bool
|
||||
{
|
||||
$oldData = $this->find($data['PatientID'] ?? null);
|
||||
|
||||
$result = parent::save($data);
|
||||
|
||||
if ($result) {
|
||||
$this->logAudit(
|
||||
$oldData ? 'UPDATE' : 'CREATE',
|
||||
$oldData?->toArray(),
|
||||
$this->find($data['PatientID'])->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Query Patterns & Performance
|
||||
|
||||
### 5.1 Common Queries
|
||||
|
||||
```sql
|
||||
-- View entity history
|
||||
SELECT * FROM patient_audit_log
|
||||
WHERE entity_type = 'patient'
|
||||
AND entity_id = 'PAT-2026-001234'
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- User activity report
|
||||
SELECT entity_type, action, COUNT(*) as count
|
||||
FROM patient_audit_log
|
||||
WHERE user_id = 'USR-001'
|
||||
AND created_at > DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||
GROUP BY entity_type, action;
|
||||
|
||||
-- Find all changes to a specific field
|
||||
SELECT * FROM order_audit_log
|
||||
WHERE JSON_CONTAINS(changed_fields, '"result_value"')
|
||||
AND patient_id = 'PAT-001'
|
||||
AND created_at > '2026-01-01';
|
||||
```
|
||||
|
||||
### 5.2 Partitioning Strategy (Order/Test)
|
||||
|
||||
For high-volume tables, implement monthly partitioning:
|
||||
|
||||
```sql
|
||||
CREATE TABLE order_audit_log (
|
||||
-- ... columns
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB
|
||||
PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at)) (
|
||||
PARTITION p202601 VALUES LESS THAN (202602),
|
||||
PARTITION p202602 VALUES LESS THAN (202603),
|
||||
PARTITION p_future VALUES LESS THAN MAXVALUE
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Soft Delete Handling
|
||||
|
||||
Soft deletes ARE captured as audit entries with complete snapshots:
|
||||
|
||||
```php
|
||||
// When soft deleting a patient:
|
||||
AuditService::log(
|
||||
category: 'patient',
|
||||
entityType: 'patient',
|
||||
entityId: $patientId,
|
||||
action: 'DELETE',
|
||||
oldValues: $fullRecordBeforeDelete, // Complete last known state
|
||||
newValues: null,
|
||||
reason: 'Patient requested data removal'
|
||||
);
|
||||
```
|
||||
|
||||
This ensures:
|
||||
- ✅ Full audit trail even for deleted records
|
||||
- ✅ Compliance with "right to be forgotten" (GDPR)
|
||||
- ✅ Ability to restore accidentally deleted records
|
||||
|
||||
---
|
||||
|
||||
## 7. Migration Plan
|
||||
|
||||
### Phase 1: Foundation (Week 1)
|
||||
- [ ] Drop existing unused tables (patreglog, patvisitlog, specimenlog)
|
||||
- [ ] Create new audit tables with JSON columns
|
||||
- [ ] Create AuditService class
|
||||
- [ ] Add database indexes
|
||||
|
||||
### Phase 2: Core Implementation (Week 2)
|
||||
- [ ] Integrate AuditService into Patient model
|
||||
- [ ] Integrate AuditService into Order model
|
||||
- [ ] Integrate AuditService into Master data models
|
||||
- [ ] Add audit trail to authentication events
|
||||
|
||||
### Phase 3: API & UI (Week 3)
|
||||
- [ ] Create API endpoints for querying audit logs
|
||||
- [ ] Build admin interface for audit review
|
||||
- [ ] Add audit export functionality (CSV/PDF)
|
||||
|
||||
### Phase 4: Optimization (Week 4)
|
||||
- [ ] Implement async logging queue
|
||||
- [ ] Add table partitioning for order_audit_log
|
||||
- [ ] Set up retention policies and archiving
|
||||
- [ ] Performance testing and tuning
|
||||
|
||||
---
|
||||
|
||||
## 8. Retention & Archiving Strategy
|
||||
|
||||
| Table | Retention Period | Archive Action |
|
||||
|-------|---------------|----------------|
|
||||
| `master_audit_log` | Permanent | None (keep forever) |
|
||||
| `patient_audit_log` | 7 years | Move to cold storage after 7 years |
|
||||
| `order_audit_log` | 2 years | Partition rotation: drop old partitions |
|
||||
|
||||
### Automated Maintenance
|
||||
|
||||
```sql
|
||||
-- Monthly job: Archive old patient audit logs
|
||||
INSERT INTO patient_audit_log_archive
|
||||
SELECT * FROM patient_audit_log
|
||||
WHERE created_at < DATE_SUB(NOW(), INTERVAL 7 YEAR);
|
||||
|
||||
DELETE FROM patient_audit_log
|
||||
WHERE created_at < DATE_SUB(NOW(), INTERVAL 7 YEAR);
|
||||
|
||||
-- Monthly job: Drop old order partitions
|
||||
ALTER TABLE order_audit_log DROP PARTITION p202501;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Questions for Stakeholders
|
||||
|
||||
Before implementation, please confirm:
|
||||
|
||||
1. **Retention Policy**: Are the proposed retention periods (master=forever, patient=7 years, order=2 years) compliant with your regulatory requirements?
|
||||
|
||||
2. **Async vs Sync**: Should audit logging be synchronous (block on failure) or asynchronous (queue-based)? Recommended: async for order/test operations.
|
||||
|
||||
3. **Archive Storage**: Where should archived audit logs be stored? Options: separate database, file storage (S3), or compressed tables.
|
||||
|
||||
4. **User Access**: Which user roles need access to audit trails? Should users see their own audit history?
|
||||
|
||||
5. **Compliance**: Do you need specific compliance features (e.g., HIPAA audit trail requirements, 21 CFR Part 11 for FDA)?
|
||||
|
||||
---
|
||||
|
||||
## 10. Key Design Decisions Summary
|
||||
|
||||
| Decision | Choice | Rationale |
|
||||
|----------|--------|-----------|
|
||||
| **Table Count** | 3 tables | Separates concerns, optimizes queries, different retention |
|
||||
| **JSON vs Columns** | JSON for values | Flexible, handles schema changes, complete snapshots |
|
||||
| **Full vs Diff** | Full snapshots | Easier to reconstruct history, no data loss |
|
||||
| **Soft Deletes** | Captured in audit | Compliance and restore capability |
|
||||
| **Partitioning** | Order table only | High volume, time-based queries |
|
||||
| **Async Logging** | Recommended | Don't block user operations |
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
This unified audit logging architecture provides:
|
||||
|
||||
✅ **Complete traceability** across all data domains
|
||||
✅ **Regulatory compliance** with proper retention
|
||||
✅ **Performance optimization** through domain separation
|
||||
✅ **Flexibility** via JSON value storage
|
||||
✅ **Maintainability** with centralized service
|
||||
|
||||
The approach balances audit integrity with system performance, ensuring CLQMS can scale while maintaining comprehensive audit trails.
|
||||
|
||||
---
|
||||
|
||||
*Document Version: 1.0*
|
||||
*Author: CLQMS Development Team*
|
||||
*Date: February 19, 2026*
|
||||
@ -2644,10 +2644,118 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TestDefinition'
|
||||
type: object
|
||||
properties:
|
||||
SiteID:
|
||||
type: integer
|
||||
description: Site ID (required)
|
||||
TestSiteCode:
|
||||
type: string
|
||||
description: Test code (required)
|
||||
TestSiteName:
|
||||
type: string
|
||||
description: Test name (required)
|
||||
TestType:
|
||||
type: string
|
||||
enum:
|
||||
- TEST
|
||||
- PARAM
|
||||
- CALC
|
||||
- GROUP
|
||||
- TITLE
|
||||
description: Test type (required)
|
||||
Description:
|
||||
type: string
|
||||
DisciplineID:
|
||||
type: integer
|
||||
DepartmentID:
|
||||
type: integer
|
||||
ResultType:
|
||||
type: string
|
||||
enum:
|
||||
- NMRIC
|
||||
- VSET
|
||||
RefType:
|
||||
type: string
|
||||
enum:
|
||||
- NMRC
|
||||
- TEXT
|
||||
- THOLD
|
||||
- VSET
|
||||
VSet:
|
||||
type: integer
|
||||
ReqQty:
|
||||
type: number
|
||||
format: decimal
|
||||
ReqQtyUnit:
|
||||
type: string
|
||||
Unit1:
|
||||
type: string
|
||||
Factor:
|
||||
type: number
|
||||
format: decimal
|
||||
Unit2:
|
||||
type: string
|
||||
Decimal:
|
||||
type: integer
|
||||
CollReq:
|
||||
type: string
|
||||
Method:
|
||||
type: string
|
||||
ExpectedTAT:
|
||||
type: integer
|
||||
SeqScr:
|
||||
type: integer
|
||||
SeqRpt:
|
||||
type: integer
|
||||
IndentLeft:
|
||||
type: integer
|
||||
FontStyle:
|
||||
type: string
|
||||
VisibleScr:
|
||||
type: integer
|
||||
VisibleRpt:
|
||||
type: integer
|
||||
CountStat:
|
||||
type: integer
|
||||
details:
|
||||
type: object
|
||||
description: Type-specific details
|
||||
refnum:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
reftxt:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
testmap:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- SiteID
|
||||
- TestSiteCode
|
||||
- TestSiteName
|
||||
- TestType
|
||||
responses:
|
||||
'201':
|
||||
description: Test definition created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: created
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteId:
|
||||
type: integer
|
||||
patch:
|
||||
tags:
|
||||
- Tests
|
||||
@ -2659,10 +2767,112 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TestDefinition'
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
description: Test Site ID (required)
|
||||
TestSiteCode:
|
||||
type: string
|
||||
TestSiteName:
|
||||
type: string
|
||||
TestType:
|
||||
type: string
|
||||
enum:
|
||||
- TEST
|
||||
- PARAM
|
||||
- CALC
|
||||
- GROUP
|
||||
- TITLE
|
||||
Description:
|
||||
type: string
|
||||
DisciplineID:
|
||||
type: integer
|
||||
DepartmentID:
|
||||
type: integer
|
||||
ResultType:
|
||||
type: string
|
||||
enum:
|
||||
- NMRIC
|
||||
- VSET
|
||||
RefType:
|
||||
type: string
|
||||
enum:
|
||||
- NMRC
|
||||
- TEXT
|
||||
- THOLD
|
||||
- VSET
|
||||
VSet:
|
||||
type: integer
|
||||
ReqQty:
|
||||
type: number
|
||||
format: decimal
|
||||
ReqQtyUnit:
|
||||
type: string
|
||||
Unit1:
|
||||
type: string
|
||||
Factor:
|
||||
type: number
|
||||
format: decimal
|
||||
Unit2:
|
||||
type: string
|
||||
Decimal:
|
||||
type: integer
|
||||
CollReq:
|
||||
type: string
|
||||
Method:
|
||||
type: string
|
||||
ExpectedTAT:
|
||||
type: integer
|
||||
SeqScr:
|
||||
type: integer
|
||||
SeqRpt:
|
||||
type: integer
|
||||
IndentLeft:
|
||||
type: integer
|
||||
FontStyle:
|
||||
type: string
|
||||
VisibleScr:
|
||||
type: integer
|
||||
VisibleRpt:
|
||||
type: integer
|
||||
CountStat:
|
||||
type: integer
|
||||
details:
|
||||
type: object
|
||||
description: Type-specific details
|
||||
refnum:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
reftxt:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
testmap:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- TestSiteID
|
||||
responses:
|
||||
'200':
|
||||
description: Test definition updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: success
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteId:
|
||||
type: integer
|
||||
/api/tests/{id}:
|
||||
get:
|
||||
tags:
|
||||
@ -2676,9 +2886,70 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
description: Test Site ID
|
||||
responses:
|
||||
'200':
|
||||
description: Test definition details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
$ref: '#/components/schemas/TestDefinition'
|
||||
'404':
|
||||
description: Test not found
|
||||
delete:
|
||||
tags:
|
||||
- Tests
|
||||
summary: Soft delete test definition
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
description: Test Site ID to delete
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
description: Optional - can be provided in body instead of path
|
||||
responses:
|
||||
'200':
|
||||
description: Test disabled successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: success
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteId:
|
||||
type: integer
|
||||
EndDate:
|
||||
type: string
|
||||
format: date-time
|
||||
'404':
|
||||
description: Test not found
|
||||
'422':
|
||||
description: Test already disabled
|
||||
/api/valueset:
|
||||
get:
|
||||
tags:
|
||||
@ -3832,11 +4103,13 @@ components:
|
||||
TestDefinition:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
TestCode:
|
||||
SiteID:
|
||||
type: integer
|
||||
TestSiteCode:
|
||||
type: string
|
||||
TestName:
|
||||
TestSiteName:
|
||||
type: string
|
||||
TestType:
|
||||
type: string
|
||||
@ -3852,6 +4125,8 @@ components:
|
||||
CALC: Calculated
|
||||
GROUP: Panel/Profile
|
||||
TITLE: Section header
|
||||
Description:
|
||||
type: string
|
||||
DisciplineID:
|
||||
type: integer
|
||||
DisciplineName:
|
||||
@ -3860,10 +4135,112 @@ components:
|
||||
type: integer
|
||||
DepartmentName:
|
||||
type: string
|
||||
Unit:
|
||||
ResultType:
|
||||
type: string
|
||||
Formula:
|
||||
enum:
|
||||
- NMRIC
|
||||
- VSET
|
||||
description: |
|
||||
NMRIC: Numeric result
|
||||
VSET: Value set result
|
||||
RefType:
|
||||
type: string
|
||||
enum:
|
||||
- NMRC
|
||||
- TEXT
|
||||
- THOLD
|
||||
- VSET
|
||||
description: |
|
||||
NMRC: Numeric reference range
|
||||
TEXT: Text reference
|
||||
THOLD: Threshold reference
|
||||
VSET: Value set reference
|
||||
VSet:
|
||||
type: integer
|
||||
description: Value set ID for VSET result type
|
||||
ReqQty:
|
||||
type: number
|
||||
format: decimal
|
||||
description: Required sample quantity
|
||||
ReqQtyUnit:
|
||||
type: string
|
||||
description: Unit for required quantity
|
||||
Unit1:
|
||||
type: string
|
||||
description: Primary unit
|
||||
Factor:
|
||||
type: number
|
||||
format: decimal
|
||||
description: Conversion factor
|
||||
Unit2:
|
||||
type: string
|
||||
description: Secondary unit (after conversion)
|
||||
Decimal:
|
||||
type: integer
|
||||
description: Number of decimal places
|
||||
CollReq:
|
||||
type: string
|
||||
description: Collection requirements
|
||||
Method:
|
||||
type: string
|
||||
description: Test method
|
||||
ExpectedTAT:
|
||||
type: integer
|
||||
description: Expected turnaround time
|
||||
SeqScr:
|
||||
type: integer
|
||||
description: Screen sequence
|
||||
SeqRpt:
|
||||
type: integer
|
||||
description: Report sequence
|
||||
IndentLeft:
|
||||
type: integer
|
||||
default: 0
|
||||
FontStyle:
|
||||
type: string
|
||||
VisibleScr:
|
||||
type: integer
|
||||
default: 1
|
||||
description: Screen visibility (0=hidden, 1=visible)
|
||||
VisibleRpt:
|
||||
type: integer
|
||||
default: 1
|
||||
description: Report visibility (0=hidden, 1=visible)
|
||||
CountStat:
|
||||
type: integer
|
||||
default: 1
|
||||
Level:
|
||||
type: integer
|
||||
CreateDate:
|
||||
type: string
|
||||
format: date-time
|
||||
StartDate:
|
||||
type: string
|
||||
format: date-time
|
||||
EndDate:
|
||||
type: string
|
||||
format: date-time
|
||||
FormulaInput:
|
||||
type: string
|
||||
description: Input variables for calculated tests
|
||||
FormulaCode:
|
||||
type: string
|
||||
description: Formula expression for calculated tests
|
||||
testdefcal:
|
||||
type: array
|
||||
description: Calculated test details (only for CALC type)
|
||||
items:
|
||||
type: object
|
||||
testdefgrp:
|
||||
type: array
|
||||
description: Group members (only for GROUP type)
|
||||
items:
|
||||
type: object
|
||||
testmap:
|
||||
type: array
|
||||
description: Test mappings
|
||||
items:
|
||||
$ref: '#/components/schemas/TestMap'
|
||||
refnum:
|
||||
type: array
|
||||
description: Numeric reference ranges (optional). Mutually exclusive with reftxt - a test can only have ONE reference type.
|
||||
@ -3939,36 +4316,66 @@ components:
|
||||
Flag:
|
||||
type: string
|
||||
examples:
|
||||
$1:
|
||||
Unit: mg/dL
|
||||
refnum:
|
||||
- RefNumID: 1
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
RangeType: REF
|
||||
RangeTypeLabel: Reference Range
|
||||
Sex: '2'
|
||||
SexLabel: Male
|
||||
LowSign: GE
|
||||
LowSignLabel: '>='
|
||||
HighSign: LE
|
||||
HighSignLabel: <=
|
||||
Low: 70
|
||||
High: 100
|
||||
AgeStart: 18
|
||||
AgeEnd: 99
|
||||
Flag: 'N'
|
||||
Interpretation: Normal
|
||||
TEST_numeric_thold:
|
||||
summary: Technical test - threshold reference (THOLD)
|
||||
TEST_numeric:
|
||||
summary: Technical test with numeric reference
|
||||
value:
|
||||
id: 1
|
||||
TestCode: GLU
|
||||
TestName: Glucose
|
||||
TestSiteID: 1
|
||||
SiteID: 1
|
||||
TestSiteCode: GLU
|
||||
TestSiteName: Glucose
|
||||
TestType: TEST
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: mg/dL
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
ResultType: NMRIC
|
||||
RefType: NMRC
|
||||
Unit1: mg/dL
|
||||
ReqQty: 300
|
||||
ReqQtyUnit: uL
|
||||
Decimal: 0
|
||||
Method: Hexokinase
|
||||
SeqScr: 11
|
||||
SeqRpt: 11
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
refnum:
|
||||
- RefNumID: 1
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
RangeType: REF
|
||||
RangeTypeLabel: Reference Range
|
||||
Sex: '2'
|
||||
SexLabel: Male
|
||||
LowSign: GE
|
||||
LowSignLabel: '>='
|
||||
HighSign: LE
|
||||
HighSignLabel: <=
|
||||
Low: 70
|
||||
High: 100
|
||||
AgeStart: 18
|
||||
AgeEnd: 99
|
||||
Flag: 'N'
|
||||
Interpretation: Normal
|
||||
TEST_threshold:
|
||||
summary: Technical test with threshold reference (panic)
|
||||
value:
|
||||
TestSiteID: 2
|
||||
SiteID: 1
|
||||
TestSiteCode: GLU
|
||||
TestSiteName: Glucose
|
||||
TestType: TEST
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
ResultType: NMRIC
|
||||
RefType: THOLD
|
||||
Unit1: mg/dL
|
||||
Decimal: 0
|
||||
Method: Hexokinase
|
||||
SeqScr: 11
|
||||
SeqRpt: 11
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
refnum:
|
||||
- RefNumID: 2
|
||||
NumRefType: THOLD
|
||||
@ -3984,136 +4391,179 @@ components:
|
||||
AgeEnd: 120
|
||||
Flag: L
|
||||
Interpretation: Critical Low
|
||||
$2:
|
||||
Unit: null
|
||||
reftxt:
|
||||
- RefTxtID: 1
|
||||
TxtRefType: TEXT
|
||||
TxtRefTypeLabel: Text
|
||||
Sex: '2'
|
||||
SexLabel: Male
|
||||
AgeStart: 18
|
||||
AgeEnd: 99
|
||||
RefTxt: NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic
|
||||
Flag: 'N'
|
||||
TEST_text_vset:
|
||||
summary: Technical test - text reference (VSET)
|
||||
TEST_text:
|
||||
summary: Technical test with text reference
|
||||
value:
|
||||
id: 1
|
||||
TestCode: STAGE
|
||||
TestName: Disease Stage
|
||||
TestSiteID: 3
|
||||
SiteID: 1
|
||||
TestSiteCode: STAGE
|
||||
TestSiteName: Disease Stage
|
||||
TestType: TEST
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: null
|
||||
ResultType: VSET
|
||||
RefType: TEXT
|
||||
SeqScr: 50
|
||||
SeqRpt: 50
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
reftxt:
|
||||
- RefTxtID: 2
|
||||
TxtRefType: VSET
|
||||
TxtRefTypeLabel: Value Set
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
AgeStart: 0
|
||||
AgeEnd: 120
|
||||
RefTxt: STG1=Stage 1;STG2=Stage 2;STG3=Stage 3;STG4=Stage 4
|
||||
- RefTxtID: 1
|
||||
TxtRefType: TEXT
|
||||
TxtRefTypeLabel: Text
|
||||
Sex: '2'
|
||||
SexLabel: Male
|
||||
AgeStart: 18
|
||||
AgeEnd: 99
|
||||
RefTxt: NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic
|
||||
Flag: 'N'
|
||||
PARAM:
|
||||
summary: Parameter - no reference range allowed
|
||||
summary: Parameter test
|
||||
value:
|
||||
id: 2
|
||||
TestCode: GLU_FAST
|
||||
TestName: Fasting Glucose
|
||||
TestSiteID: 4
|
||||
SiteID: 1
|
||||
TestSiteCode: HEIGHT
|
||||
TestSiteName: Height
|
||||
TestType: PARAM
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: mg/dL
|
||||
$3:
|
||||
Unit: null
|
||||
Formula: BUN / Creatinine
|
||||
refnum:
|
||||
- RefNumID: 5
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
RangeType: REF
|
||||
RangeTypeLabel: Reference Range
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
LowSign: GE
|
||||
LowSignLabel: '>='
|
||||
HighSign: LE
|
||||
HighSignLabel: <=
|
||||
Low: 10
|
||||
High: 20
|
||||
AgeStart: 18
|
||||
AgeEnd: 120
|
||||
Flag: 'N'
|
||||
Interpretation: Normal
|
||||
$4:
|
||||
Unit: null
|
||||
Formula: BUN / Creatinine
|
||||
refnum:
|
||||
- RefNumID: 6
|
||||
NumRefType: THOLD
|
||||
NumRefTypeLabel: Threshold
|
||||
RangeType: PANIC
|
||||
RangeTypeLabel: Panic Range
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
LowSign: GT
|
||||
LowSignLabel: '>'
|
||||
Low: 20
|
||||
AgeStart: 18
|
||||
AgeEnd: 120
|
||||
Flag: H
|
||||
Interpretation: Elevated - possible prerenal cause
|
||||
DisciplineID: 10
|
||||
ResultType: NMRIC
|
||||
Unit1: cm
|
||||
Decimal: 0
|
||||
SeqScr: 40
|
||||
SeqRpt: 40
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 0
|
||||
CountStat: 0
|
||||
CALC:
|
||||
summary: Calculated test with reference
|
||||
value:
|
||||
TestSiteID: 5
|
||||
SiteID: 1
|
||||
TestSiteCode: EGFR
|
||||
TestSiteName: eGFR
|
||||
TestType: CALC
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
Unit1: mL/min/1.73m2
|
||||
Decimal: 0
|
||||
SeqScr: 20
|
||||
SeqRpt: 20
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 0
|
||||
testdefcal:
|
||||
- TestCalID: 1
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
FormulaInput: CREA,AGE,GENDER
|
||||
FormulaCode: CKD_EPI(CREA,AGE,GENDER)
|
||||
Unit1: mL/min/1.73m2
|
||||
Decimal: 0
|
||||
refnum:
|
||||
- RefNumID: 5
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
RangeType: REF
|
||||
RangeTypeLabel: Reference Range
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
LowSign: GE
|
||||
LowSignLabel: '>='
|
||||
HighSign: LE
|
||||
HighSignLabel: <=
|
||||
Low: 10
|
||||
High: 20
|
||||
AgeStart: 18
|
||||
AgeEnd: 120
|
||||
Flag: 'N'
|
||||
Interpretation: Normal
|
||||
GROUP:
|
||||
summary: Panel/Profile - no reference range allowed
|
||||
summary: Panel/Profile test
|
||||
value:
|
||||
id: 4
|
||||
TestCode: LIPID
|
||||
TestName: Lipid Panel
|
||||
TestSiteID: 6
|
||||
SiteID: 1
|
||||
TestSiteCode: LIPID
|
||||
TestSiteName: Lipid Panel
|
||||
TestType: GROUP
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: null
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
SeqScr: 51
|
||||
SeqRpt: 51
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
testdefgrp:
|
||||
- TestGrpID: 1
|
||||
Member: 100
|
||||
TestSiteCode: CHOL
|
||||
TestSiteName: Total Cholesterol
|
||||
- TestGrpID: 2
|
||||
Member: 101
|
||||
TestSiteCode: TG
|
||||
TestSiteName: Triglycerides
|
||||
TITLE:
|
||||
summary: Section header - no reference range allowed
|
||||
summary: Section header
|
||||
value:
|
||||
id: 5
|
||||
TestCode: CHEM_HEADER
|
||||
TestName: '--- CHEMISTRY ---'
|
||||
TestSiteID: 7
|
||||
SiteID: 1
|
||||
TestSiteCode: CHEM_HEADER
|
||||
TestSiteName: '--- CHEMISTRY ---'
|
||||
TestType: TITLE
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: null
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
SeqScr: 100
|
||||
SeqRpt: 100
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 0
|
||||
TestMap:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
TestMapID:
|
||||
type: integer
|
||||
TestCode:
|
||||
type: string
|
||||
HostCode:
|
||||
type: string
|
||||
HostName:
|
||||
type: string
|
||||
ClientCode:
|
||||
type: string
|
||||
ClientName:
|
||||
type: string
|
||||
TestSiteID:
|
||||
type: integer
|
||||
HostType:
|
||||
type: string
|
||||
description: Host type code
|
||||
HostTypeLabel:
|
||||
HostID:
|
||||
type: string
|
||||
description: Host type display text
|
||||
description: Host identifier
|
||||
HostDataSource:
|
||||
type: string
|
||||
description: Host data source
|
||||
HostTestCode:
|
||||
type: string
|
||||
description: Test code in host system
|
||||
HostTestName:
|
||||
type: string
|
||||
description: Test name in host system
|
||||
ClientType:
|
||||
type: string
|
||||
description: Client type code
|
||||
ClientTypeLabel:
|
||||
ClientID:
|
||||
type: string
|
||||
description: Client type display text
|
||||
description: Client identifier
|
||||
ClientDataSource:
|
||||
type: string
|
||||
description: Client data source
|
||||
ConDefID:
|
||||
type: integer
|
||||
description: Connection definition ID
|
||||
ClientTestCode:
|
||||
type: string
|
||||
description: Test code in client system
|
||||
ClientTestName:
|
||||
type: string
|
||||
description: Test name in client system
|
||||
CreateDate:
|
||||
type: string
|
||||
format: date-time
|
||||
EndDate:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Soft delete timestamp
|
||||
OrderTest:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
TestDefinition:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
TestCode:
|
||||
SiteID:
|
||||
type: integer
|
||||
TestSiteCode:
|
||||
type: string
|
||||
TestName:
|
||||
TestSiteName:
|
||||
type: string
|
||||
TestType:
|
||||
type: string
|
||||
@ -16,6 +18,8 @@ TestDefinition:
|
||||
CALC: Calculated
|
||||
GROUP: Panel/Profile
|
||||
TITLE: Section header
|
||||
Description:
|
||||
type: string
|
||||
DisciplineID:
|
||||
type: integer
|
||||
DisciplineName:
|
||||
@ -24,10 +28,106 @@ TestDefinition:
|
||||
type: integer
|
||||
DepartmentName:
|
||||
type: string
|
||||
Unit:
|
||||
ResultType:
|
||||
type: string
|
||||
Formula:
|
||||
enum: [NMRIC, VSET]
|
||||
description: |
|
||||
NMRIC: Numeric result
|
||||
VSET: Value set result
|
||||
RefType:
|
||||
type: string
|
||||
enum: [NMRC, TEXT, THOLD, VSET]
|
||||
description: |
|
||||
NMRC: Numeric reference range
|
||||
TEXT: Text reference
|
||||
THOLD: Threshold reference
|
||||
VSET: Value set reference
|
||||
VSet:
|
||||
type: integer
|
||||
description: Value set ID for VSET result type
|
||||
ReqQty:
|
||||
type: number
|
||||
format: decimal
|
||||
description: Required sample quantity
|
||||
ReqQtyUnit:
|
||||
type: string
|
||||
description: Unit for required quantity
|
||||
Unit1:
|
||||
type: string
|
||||
description: Primary unit
|
||||
Factor:
|
||||
type: number
|
||||
format: decimal
|
||||
description: Conversion factor
|
||||
Unit2:
|
||||
type: string
|
||||
description: Secondary unit (after conversion)
|
||||
Decimal:
|
||||
type: integer
|
||||
description: Number of decimal places
|
||||
CollReq:
|
||||
type: string
|
||||
description: Collection requirements
|
||||
Method:
|
||||
type: string
|
||||
description: Test method
|
||||
ExpectedTAT:
|
||||
type: integer
|
||||
description: Expected turnaround time
|
||||
SeqScr:
|
||||
type: integer
|
||||
description: Screen sequence
|
||||
SeqRpt:
|
||||
type: integer
|
||||
description: Report sequence
|
||||
IndentLeft:
|
||||
type: integer
|
||||
default: 0
|
||||
FontStyle:
|
||||
type: string
|
||||
VisibleScr:
|
||||
type: integer
|
||||
default: 1
|
||||
description: Screen visibility (0=hidden, 1=visible)
|
||||
VisibleRpt:
|
||||
type: integer
|
||||
default: 1
|
||||
description: Report visibility (0=hidden, 1=visible)
|
||||
CountStat:
|
||||
type: integer
|
||||
default: 1
|
||||
Level:
|
||||
type: integer
|
||||
CreateDate:
|
||||
type: string
|
||||
format: date-time
|
||||
StartDate:
|
||||
type: string
|
||||
format: date-time
|
||||
EndDate:
|
||||
type: string
|
||||
format: date-time
|
||||
FormulaInput:
|
||||
type: string
|
||||
description: Input variables for calculated tests
|
||||
FormulaCode:
|
||||
type: string
|
||||
description: Formula expression for calculated tests
|
||||
testdefcal:
|
||||
type: array
|
||||
description: Calculated test details (only for CALC type)
|
||||
items:
|
||||
type: object
|
||||
testdefgrp:
|
||||
type: array
|
||||
description: Group members (only for GROUP type)
|
||||
items:
|
||||
type: object
|
||||
testmap:
|
||||
type: array
|
||||
description: Test mappings
|
||||
items:
|
||||
$ref: '#/TestMap'
|
||||
refnum:
|
||||
type: array
|
||||
description: Numeric reference ranges (optional). Mutually exclusive with reftxt - a test can only have ONE reference type.
|
||||
@ -99,9 +199,29 @@ TestDefinition:
|
||||
Flag:
|
||||
type: string
|
||||
examples:
|
||||
$1:
|
||||
Unit: mg/dL
|
||||
refnum:
|
||||
TEST_numeric:
|
||||
summary: Technical test with numeric reference
|
||||
value:
|
||||
TestSiteID: 1
|
||||
SiteID: 1
|
||||
TestSiteCode: GLU
|
||||
TestSiteName: Glucose
|
||||
TestType: TEST
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
ResultType: NMRIC
|
||||
RefType: NMRC
|
||||
Unit1: mg/dL
|
||||
ReqQty: 300
|
||||
ReqQtyUnit: uL
|
||||
Decimal: 0
|
||||
Method: Hexokinase
|
||||
SeqScr: 11
|
||||
SeqRpt: 11
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
refnum:
|
||||
- RefNumID: 1
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
@ -119,16 +239,26 @@ TestDefinition:
|
||||
AgeEnd: 99
|
||||
Flag: N
|
||||
Interpretation: Normal
|
||||
TEST_numeric_thold:
|
||||
summary: Technical test - threshold reference (THOLD)
|
||||
TEST_threshold:
|
||||
summary: Technical test with threshold reference (panic)
|
||||
value:
|
||||
id: 1
|
||||
TestCode: GLU
|
||||
TestName: Glucose
|
||||
TestSiteID: 2
|
||||
SiteID: 1
|
||||
TestSiteCode: GLU
|
||||
TestSiteName: Glucose
|
||||
TestType: TEST
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: mg/dL
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
ResultType: NMRIC
|
||||
RefType: THOLD
|
||||
Unit1: mg/dL
|
||||
Decimal: 0
|
||||
Method: Hexokinase
|
||||
SeqScr: 11
|
||||
SeqRpt: 11
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
refnum:
|
||||
- RefNumID: 2
|
||||
NumRefType: THOLD
|
||||
@ -144,9 +274,24 @@ TestDefinition:
|
||||
AgeEnd: 120
|
||||
Flag: L
|
||||
Interpretation: Critical Low
|
||||
$2:
|
||||
Unit: null
|
||||
reftxt:
|
||||
TEST_text:
|
||||
summary: Technical test with text reference
|
||||
value:
|
||||
TestSiteID: 3
|
||||
SiteID: 1
|
||||
TestSiteCode: STAGE
|
||||
TestSiteName: Disease Stage
|
||||
TestType: TEST
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
ResultType: VSET
|
||||
RefType: TEXT
|
||||
SeqScr: 50
|
||||
SeqRpt: 50
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
reftxt:
|
||||
- RefTxtID: 1
|
||||
TxtRefType: TEXT
|
||||
TxtRefTypeLabel: Text
|
||||
@ -156,123 +301,150 @@ TestDefinition:
|
||||
AgeEnd: 99
|
||||
RefTxt: 'NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic'
|
||||
Flag: N
|
||||
TEST_text_vset:
|
||||
summary: Technical test - text reference (VSET)
|
||||
PARAM:
|
||||
summary: Parameter test
|
||||
value:
|
||||
id: 1
|
||||
TestCode: STAGE
|
||||
TestName: Disease Stage
|
||||
TestType: TEST
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: null
|
||||
reftxt:
|
||||
- RefTxtID: 2
|
||||
TxtRefType: VSET
|
||||
TxtRefTypeLabel: Value Set
|
||||
TestSiteID: 4
|
||||
SiteID: 1
|
||||
TestSiteCode: HEIGHT
|
||||
TestSiteName: Height
|
||||
TestType: PARAM
|
||||
DisciplineID: 10
|
||||
ResultType: NMRIC
|
||||
Unit1: cm
|
||||
Decimal: 0
|
||||
SeqScr: 40
|
||||
SeqRpt: 40
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 0
|
||||
CountStat: 0
|
||||
CALC:
|
||||
summary: Calculated test with reference
|
||||
value:
|
||||
TestSiteID: 5
|
||||
SiteID: 1
|
||||
TestSiteCode: EGFR
|
||||
TestSiteName: eGFR
|
||||
TestType: CALC
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
Unit1: mL/min/1.73m2
|
||||
Decimal: 0
|
||||
SeqScr: 20
|
||||
SeqRpt: 20
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 0
|
||||
testdefcal:
|
||||
- TestCalID: 1
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
FormulaInput: CREA,AGE,GENDER
|
||||
FormulaCode: CKD_EPI(CREA,AGE,GENDER)
|
||||
Unit1: mL/min/1.73m2
|
||||
Decimal: 0
|
||||
refnum:
|
||||
- RefNumID: 5
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
RangeType: REF
|
||||
RangeTypeLabel: Reference Range
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
AgeStart: 0
|
||||
LowSign: GE
|
||||
LowSignLabel: ">="
|
||||
HighSign: LE
|
||||
HighSignLabel: "<="
|
||||
Low: 10
|
||||
High: 20
|
||||
AgeStart: 18
|
||||
AgeEnd: 120
|
||||
RefTxt: 'STG1=Stage 1;STG2=Stage 2;STG3=Stage 3;STG4=Stage 4'
|
||||
Flag: N
|
||||
PARAM:
|
||||
summary: Parameter - no reference range allowed
|
||||
value:
|
||||
id: 2
|
||||
TestCode: GLU_FAST
|
||||
TestName: Fasting Glucose
|
||||
TestType: PARAM
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: mg/dL
|
||||
$3:
|
||||
Unit: null
|
||||
Formula: "BUN / Creatinine"
|
||||
refnum:
|
||||
- RefNumID: 5
|
||||
NumRefType: NMRC
|
||||
NumRefTypeLabel: Numeric
|
||||
RangeType: REF
|
||||
RangeTypeLabel: Reference Range
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
LowSign: GE
|
||||
LowSignLabel: ">="
|
||||
HighSign: LE
|
||||
HighSignLabel: "<="
|
||||
Low: 10
|
||||
High: 20
|
||||
AgeStart: 18
|
||||
AgeEnd: 120
|
||||
Flag: N
|
||||
Interpretation: Normal
|
||||
$4:
|
||||
Unit: null
|
||||
Formula: "BUN / Creatinine"
|
||||
refnum:
|
||||
- RefNumID: 6
|
||||
NumRefType: THOLD
|
||||
NumRefTypeLabel: Threshold
|
||||
RangeType: PANIC
|
||||
RangeTypeLabel: Panic Range
|
||||
Sex: '1'
|
||||
SexLabel: Female
|
||||
LowSign: GT
|
||||
LowSignLabel: ">"
|
||||
Low: 20
|
||||
AgeStart: 18
|
||||
AgeEnd: 120
|
||||
Flag: H
|
||||
Interpretation: Elevated - possible prerenal cause
|
||||
|
||||
Interpretation: Normal
|
||||
GROUP:
|
||||
summary: Panel/Profile - no reference range allowed
|
||||
summary: Panel/Profile test
|
||||
value:
|
||||
id: 4
|
||||
TestCode: LIPID
|
||||
TestName: Lipid Panel
|
||||
TestSiteID: 6
|
||||
SiteID: 1
|
||||
TestSiteCode: LIPID
|
||||
TestSiteName: Lipid Panel
|
||||
TestType: GROUP
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: null
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
SeqScr: 51
|
||||
SeqRpt: 51
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 1
|
||||
testdefgrp:
|
||||
- TestGrpID: 1
|
||||
Member: 100
|
||||
TestSiteCode: CHOL
|
||||
TestSiteName: Total Cholesterol
|
||||
- TestGrpID: 2
|
||||
Member: 101
|
||||
TestSiteCode: TG
|
||||
TestSiteName: Triglycerides
|
||||
TITLE:
|
||||
summary: Section header - no reference range allowed
|
||||
summary: Section header
|
||||
value:
|
||||
id: 5
|
||||
TestCode: CHEM_HEADER
|
||||
TestName: '--- CHEMISTRY ---'
|
||||
TestSiteID: 7
|
||||
SiteID: 1
|
||||
TestSiteCode: CHEM_HEADER
|
||||
TestSiteName: '--- CHEMISTRY ---'
|
||||
TestType: TITLE
|
||||
DisciplineID: 1
|
||||
DepartmentID: 1
|
||||
Unit: null
|
||||
DisciplineID: 2
|
||||
DepartmentID: 2
|
||||
SeqScr: 100
|
||||
SeqRpt: 100
|
||||
VisibleScr: 1
|
||||
VisibleRpt: 1
|
||||
CountStat: 0
|
||||
|
||||
TestMap:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
TestMapID:
|
||||
type: integer
|
||||
TestCode:
|
||||
type: string
|
||||
HostCode:
|
||||
type: string
|
||||
HostName:
|
||||
type: string
|
||||
ClientCode:
|
||||
type: string
|
||||
ClientName:
|
||||
type: string
|
||||
TestSiteID:
|
||||
type: integer
|
||||
HostType:
|
||||
type: string
|
||||
description: Host type code
|
||||
HostTypeLabel:
|
||||
HostID:
|
||||
type: string
|
||||
description: Host type display text
|
||||
description: Host identifier
|
||||
HostDataSource:
|
||||
type: string
|
||||
description: Host data source
|
||||
HostTestCode:
|
||||
type: string
|
||||
description: Test code in host system
|
||||
HostTestName:
|
||||
type: string
|
||||
description: Test name in host system
|
||||
ClientType:
|
||||
type: string
|
||||
description: Client type code
|
||||
ClientTypeLabel:
|
||||
ClientID:
|
||||
type: string
|
||||
description: Client type display text
|
||||
description: Client identifier
|
||||
ClientDataSource:
|
||||
type: string
|
||||
description: Client data source
|
||||
ConDefID:
|
||||
type: integer
|
||||
description: Connection definition ID
|
||||
ClientTestCode:
|
||||
type: string
|
||||
description: Test code in client system
|
||||
ClientTestName:
|
||||
type: string
|
||||
description: Test name in client system
|
||||
CreateDate:
|
||||
type: string
|
||||
format: date-time
|
||||
EndDate:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Soft delete timestamp
|
||||
|
||||
@ -76,10 +76,107 @@
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../components/schemas/tests.yaml#/TestDefinition'
|
||||
type: object
|
||||
properties:
|
||||
SiteID:
|
||||
type: integer
|
||||
description: Site ID (required)
|
||||
TestSiteCode:
|
||||
type: string
|
||||
description: Test code (required)
|
||||
TestSiteName:
|
||||
type: string
|
||||
description: Test name (required)
|
||||
TestType:
|
||||
type: string
|
||||
enum: [TEST, PARAM, CALC, GROUP, TITLE]
|
||||
description: Test type (required)
|
||||
Description:
|
||||
type: string
|
||||
DisciplineID:
|
||||
type: integer
|
||||
DepartmentID:
|
||||
type: integer
|
||||
ResultType:
|
||||
type: string
|
||||
enum: [NMRIC, VSET]
|
||||
RefType:
|
||||
type: string
|
||||
enum: [NMRC, TEXT, THOLD, VSET]
|
||||
VSet:
|
||||
type: integer
|
||||
ReqQty:
|
||||
type: number
|
||||
format: decimal
|
||||
ReqQtyUnit:
|
||||
type: string
|
||||
Unit1:
|
||||
type: string
|
||||
Factor:
|
||||
type: number
|
||||
format: decimal
|
||||
Unit2:
|
||||
type: string
|
||||
Decimal:
|
||||
type: integer
|
||||
CollReq:
|
||||
type: string
|
||||
Method:
|
||||
type: string
|
||||
ExpectedTAT:
|
||||
type: integer
|
||||
SeqScr:
|
||||
type: integer
|
||||
SeqRpt:
|
||||
type: integer
|
||||
IndentLeft:
|
||||
type: integer
|
||||
FontStyle:
|
||||
type: string
|
||||
VisibleScr:
|
||||
type: integer
|
||||
VisibleRpt:
|
||||
type: integer
|
||||
CountStat:
|
||||
type: integer
|
||||
details:
|
||||
type: object
|
||||
description: Type-specific details
|
||||
refnum:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
reftxt:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
testmap:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- SiteID
|
||||
- TestSiteCode
|
||||
- TestSiteName
|
||||
- TestType
|
||||
responses:
|
||||
'201':
|
||||
description: Test definition created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: created
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteId:
|
||||
type: integer
|
||||
|
||||
patch:
|
||||
tags: [Tests]
|
||||
@ -91,10 +188,101 @@
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../components/schemas/tests.yaml#/TestDefinition'
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
description: Test Site ID (required)
|
||||
TestSiteCode:
|
||||
type: string
|
||||
TestSiteName:
|
||||
type: string
|
||||
TestType:
|
||||
type: string
|
||||
enum: [TEST, PARAM, CALC, GROUP, TITLE]
|
||||
Description:
|
||||
type: string
|
||||
DisciplineID:
|
||||
type: integer
|
||||
DepartmentID:
|
||||
type: integer
|
||||
ResultType:
|
||||
type: string
|
||||
enum: [NMRIC, VSET]
|
||||
RefType:
|
||||
type: string
|
||||
enum: [NMRC, TEXT, THOLD, VSET]
|
||||
VSet:
|
||||
type: integer
|
||||
ReqQty:
|
||||
type: number
|
||||
format: decimal
|
||||
ReqQtyUnit:
|
||||
type: string
|
||||
Unit1:
|
||||
type: string
|
||||
Factor:
|
||||
type: number
|
||||
format: decimal
|
||||
Unit2:
|
||||
type: string
|
||||
Decimal:
|
||||
type: integer
|
||||
CollReq:
|
||||
type: string
|
||||
Method:
|
||||
type: string
|
||||
ExpectedTAT:
|
||||
type: integer
|
||||
SeqScr:
|
||||
type: integer
|
||||
SeqRpt:
|
||||
type: integer
|
||||
IndentLeft:
|
||||
type: integer
|
||||
FontStyle:
|
||||
type: string
|
||||
VisibleScr:
|
||||
type: integer
|
||||
VisibleRpt:
|
||||
type: integer
|
||||
CountStat:
|
||||
type: integer
|
||||
details:
|
||||
type: object
|
||||
description: Type-specific details
|
||||
refnum:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
reftxt:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
testmap:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
required:
|
||||
- TestSiteID
|
||||
responses:
|
||||
'200':
|
||||
description: Test definition updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: success
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteId:
|
||||
type: integer
|
||||
|
||||
/api/tests/{id}:
|
||||
get:
|
||||
@ -108,6 +296,67 @@
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
description: Test Site ID
|
||||
responses:
|
||||
'200':
|
||||
description: Test definition details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
$ref: '../components/schemas/tests.yaml#/TestDefinition'
|
||||
'404':
|
||||
description: Test not found
|
||||
|
||||
delete:
|
||||
tags: [Tests]
|
||||
summary: Soft delete test definition
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
description: Test Site ID to delete
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteID:
|
||||
type: integer
|
||||
description: Optional - can be provided in body instead of path
|
||||
responses:
|
||||
'200':
|
||||
description: Test disabled successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: success
|
||||
message:
|
||||
type: string
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
TestSiteId:
|
||||
type: integer
|
||||
EndDate:
|
||||
type: string
|
||||
format: date-time
|
||||
'404':
|
||||
description: Test not found
|
||||
'422':
|
||||
description: Test already disabled
|
||||
|
||||
@ -4,7 +4,7 @@ namespace Tests\Unit\TestDef;
|
||||
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use App\Models\Test\TestDefSiteModel;
|
||||
use App\Models\Test\TestDefTechModel;
|
||||
|
||||
use App\Models\Test\TestDefCalModel;
|
||||
use App\Models\Test\TestDefGrpModel;
|
||||
use App\Models\Test\TestMapModel;
|
||||
@ -12,7 +12,7 @@ use App\Models\Test\TestMapModel;
|
||||
class TestDefModelsTest extends CIUnitTestCase
|
||||
{
|
||||
protected $testDefSiteModel;
|
||||
protected $testDefTechModel;
|
||||
|
||||
protected $testDefCalModel;
|
||||
protected $testDefGrpModel;
|
||||
protected $testMapModel;
|
||||
@ -21,7 +21,7 @@ class TestDefModelsTest extends CIUnitTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
$this->testDefSiteModel = new TestDefSiteModel();
|
||||
$this->testDefTechModel = new TestDefTechModel();
|
||||
|
||||
$this->testDefCalModel = new TestDefCalModel();
|
||||
$this->testDefGrpModel = new TestDefGrpModel();
|
||||
$this->testMapModel = new TestMapModel();
|
||||
@ -76,43 +76,6 @@ class TestDefModelsTest extends CIUnitTestCase
|
||||
$this->assertEquals('EndDate', $this->testDefSiteModel->deletedField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test TestDefTechModel has correct table name
|
||||
*/
|
||||
public function testTestDefTechModelTable()
|
||||
{
|
||||
$this->assertEquals('testdeftech', $this->testDefTechModel->table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test TestDefTechModel has correct primary key
|
||||
*/
|
||||
public function testTestDefTechModelPrimaryKey()
|
||||
{
|
||||
$this->assertEquals('TestTechID', $this->testDefTechModel->primaryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test TestDefTechModel has correct allowed fields
|
||||
*/
|
||||
public function testTestDefTechModelAllowedFields()
|
||||
{
|
||||
$allowedFields = $this->testDefTechModel->allowedFields;
|
||||
|
||||
$this->assertContains('TestSiteID', $allowedFields);
|
||||
$this->assertContains('DisciplineID', $allowedFields);
|
||||
$this->assertContains('DepartmentID', $allowedFields);
|
||||
$this->assertContains('ResultType', $allowedFields);
|
||||
$this->assertContains('RefType', $allowedFields);
|
||||
$this->assertContains('VSet', $allowedFields);
|
||||
$this->assertContains('Unit1', $allowedFields);
|
||||
$this->assertContains('Factor', $allowedFields);
|
||||
$this->assertContains('Unit2', $allowedFields);
|
||||
$this->assertContains('Decimal', $allowedFields);
|
||||
$this->assertContains('Method', $allowedFields);
|
||||
$this->assertContains('ExpectedTAT', $allowedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test TestDefCalModel has correct table name
|
||||
*/
|
||||
@ -218,7 +181,6 @@ class TestDefModelsTest extends CIUnitTestCase
|
||||
*/
|
||||
public function testAllModelsUseSoftDeletes()
|
||||
{
|
||||
$this->assertTrue($this->testDefTechModel->useSoftDeletes);
|
||||
$this->assertTrue($this->testDefCalModel->useSoftDeletes);
|
||||
$this->assertTrue($this->testDefGrpModel->useSoftDeletes);
|
||||
$this->assertTrue($this->testMapModel->useSoftDeletes);
|
||||
@ -229,7 +191,6 @@ class TestDefModelsTest extends CIUnitTestCase
|
||||
*/
|
||||
public function testAllModelsUseEndDateAsDeletedField()
|
||||
{
|
||||
$this->assertEquals('EndDate', $this->testDefTechModel->deletedField);
|
||||
$this->assertEquals('EndDate', $this->testDefCalModel->deletedField);
|
||||
$this->assertEquals('EndDate', $this->testDefGrpModel->deletedField);
|
||||
$this->assertEquals('EndDate', $this->testMapModel->deletedField);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user