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
1
.gitignore
vendored
1
.gitignore
vendored
@ -127,4 +127,3 @@ _modules/*
|
|||||||
/public/.htaccess
|
/public/.htaccess
|
||||||
|
|
||||||
/.serena
|
/.serena
|
||||||
AGENTS.md
|
|
||||||
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 $rules;
|
||||||
protected $model;
|
protected $model;
|
||||||
protected $modelCal;
|
protected $modelCal;
|
||||||
protected $modelTech;
|
|
||||||
protected $modelGrp;
|
protected $modelGrp;
|
||||||
protected $modelMap;
|
protected $modelMap;
|
||||||
protected $modelRefNum;
|
protected $modelRefNum;
|
||||||
@ -24,7 +24,7 @@ class TestsController extends BaseController
|
|||||||
$this->db = \Config\Database::connect();
|
$this->db = \Config\Database::connect();
|
||||||
$this->model = new \App\Models\Test\TestDefSiteModel;
|
$this->model = new \App\Models\Test\TestDefSiteModel;
|
||||||
$this->modelCal = new \App\Models\Test\TestDefCalModel;
|
$this->modelCal = new \App\Models\Test\TestDefCalModel;
|
||||||
$this->modelTech = new \App\Models\Test\TestDefTechModel;
|
|
||||||
$this->modelGrp = new \App\Models\Test\TestDefGrpModel;
|
$this->modelGrp = new \App\Models\Test\TestDefGrpModel;
|
||||||
$this->modelMap = new \App\Models\Test\TestMapModel;
|
$this->modelMap = new \App\Models\Test\TestMapModel;
|
||||||
$this->modelRefNum = new \App\Models\RefRange\RefNumModel;
|
$this->modelRefNum = new \App\Models\RefRange\RefNumModel;
|
||||||
@ -50,13 +50,12 @@ class TestsController extends BaseController
|
|||||||
->select("testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
|
->select("testdefsite.TestSiteID, testdefsite.TestSiteCode, testdefsite.TestSiteName, testdefsite.TestType,
|
||||||
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.VisibleScr, testdefsite.VisibleRpt,
|
testdefsite.SeqScr, testdefsite.SeqRpt, testdefsite.VisibleScr, testdefsite.VisibleRpt,
|
||||||
testdefsite.CountStat, testdefsite.StartDate, testdefsite.EndDate,
|
testdefsite.CountStat, testdefsite.StartDate, testdefsite.EndDate,
|
||||||
COALESCE(tech.DisciplineID, cal.DisciplineID) as DisciplineID,
|
COALESCE(testdefsite.DisciplineID, cal.DisciplineID) as DisciplineID,
|
||||||
COALESCE(tech.DepartmentID, cal.DepartmentID) as DepartmentID,
|
COALESCE(testdefsite.DepartmentID, cal.DepartmentID) as DepartmentID,
|
||||||
d.DisciplineName, dept.DepartmentName")
|
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('testdefcal cal', 'cal.TestSiteID = testdefsite.TestSiteID AND cal.EndDate IS NULL', 'left')
|
||||||
->join('discipline d', 'd.DisciplineID = COALESCE(tech.DisciplineID, cal.DisciplineID)', 'left')
|
->join('discipline d', 'd.DisciplineID = COALESCE(testdefsite.DisciplineID, cal.DisciplineID)', 'left')
|
||||||
->join('department dept', 'dept.DepartmentID = COALESCE(tech.DepartmentID, cal.DepartmentID)', 'left')
|
->join('department dept', 'dept.DepartmentID = COALESCE(testdefsite.DepartmentID, cal.DepartmentID)', 'left')
|
||||||
->where('testdefsite.EndDate IS NULL');
|
->where('testdefsite.EndDate IS NULL');
|
||||||
|
|
||||||
if ($siteId) {
|
if ($siteId) {
|
||||||
@ -141,12 +140,13 @@ class TestsController extends BaseController
|
|||||||
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
|
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$row['testdeftech'] = $this->db->table('testdeftech')
|
// Technical details are now stored directly in testdefsite
|
||||||
->select('testdeftech.*, d.DisciplineName, dept.DepartmentName')
|
$row['testdeftech'] = $this->db->table('testdefsite')
|
||||||
->join('discipline d', 'd.DisciplineID=testdeftech.DisciplineID', 'left')
|
->select('testdefsite.*, d.DisciplineName, dept.DepartmentName')
|
||||||
->join('department dept', 'dept.DepartmentID=testdeftech.DepartmentID', 'left')
|
->join('discipline d', 'd.DisciplineID=testdefsite.DisciplineID', 'left')
|
||||||
->where('testdeftech.TestSiteID', $id)
|
->join('department dept', 'dept.DepartmentID=testdefsite.DepartmentID', 'left')
|
||||||
->where('testdeftech.EndDate IS NULL')
|
->where('testdefsite.TestSiteID', $id)
|
||||||
|
->where('testdefsite.EndDate IS NULL')
|
||||||
->get()->getResultArray();
|
->get()->getResultArray();
|
||||||
|
|
||||||
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
|
$row['testmap'] = $this->modelMap->where('TestSiteID', $id)->where('EndDate IS NULL')->findAll();
|
||||||
@ -371,9 +371,6 @@ class TestsController extends BaseController
|
|||||||
->where('TestSiteID', $id)
|
->where('TestSiteID', $id)
|
||||||
->update(['EndDate' => $now]);
|
->update(['EndDate' => $now]);
|
||||||
} elseif (in_array($typeCode, ['TEST', 'PARAM'])) {
|
} 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->modelRefNum->where('TestSiteID', $id)->set('EndDate', $now)->update();
|
||||||
$this->modelRefTxt->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)
|
private function saveTechDetails($testSiteID, $data, $action, $typeCode)
|
||||||
{
|
{
|
||||||
|
// Technical details are now stored directly in testdefsite table
|
||||||
$techData = [
|
$techData = [
|
||||||
'TestSiteID' => $testSiteID,
|
|
||||||
'DisciplineID' => $data['DisciplineID'] ?? null,
|
'DisciplineID' => $data['DisciplineID'] ?? null,
|
||||||
'DepartmentID' => $data['DepartmentID'] ?? null,
|
'DepartmentID' => $data['DepartmentID'] ?? null,
|
||||||
'ResultType' => $data['ResultType'] ?? null,
|
'ResultType' => $data['ResultType'] ?? null,
|
||||||
@ -477,20 +474,8 @@ class TestsController extends BaseController
|
|||||||
'ExpectedTAT' => $data['ExpectedTAT'] ?? null
|
'ExpectedTAT' => $data['ExpectedTAT'] ?? null
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($action === 'update') {
|
// Update the testdefsite record directly
|
||||||
$exists = $this->db->table('testdeftech')
|
$this->model->update($testSiteID, $techData);
|
||||||
->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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
|
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
|
||||||
|
|||||||
@ -13,23 +13,7 @@ class CreateTestDefinitions extends Migration {
|
|||||||
'TestSiteName' => ['type' => 'varchar', 'constraint'=> 100, 'null' => false],
|
'TestSiteName' => ['type' => 'varchar', 'constraint'=> 100, 'null' => false],
|
||||||
'TestType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => false],
|
'TestType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => false],
|
||||||
'Description' => ['type' => 'varchar', 'constraint'=> 255, 'null' => true],
|
'Description' => ['type' => 'varchar', 'constraint'=> 255, 'null' => true],
|
||||||
'SeqScr' => ['type' => 'int', 'null' => true],
|
// Technical details merged from testdeftech
|
||||||
'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],
|
|
||||||
'DisciplineID' => ['type' => 'INT', 'null' => true],
|
'DisciplineID' => ['type' => 'INT', 'null' => true],
|
||||||
'DepartmentID' => ['type' => 'INT', 'null' => true],
|
'DepartmentID' => ['type' => 'INT', 'null' => true],
|
||||||
'ResultType' => ['type' => 'VARCHAR', 'constraint'=> 20, 'null' => true],
|
'ResultType' => ['type' => 'VARCHAR', 'constraint'=> 20, 'null' => true],
|
||||||
@ -44,12 +28,22 @@ class CreateTestDefinitions extends Migration {
|
|||||||
'CollReq' => ['type' => 'varchar', 'constraint'=> 255, 'null' => true],
|
'CollReq' => ['type' => 'varchar', 'constraint'=> 255, 'null' => true],
|
||||||
'Method' => ['type' => 'varchar', 'constraint'=> 50, 'null' => true],
|
'Method' => ['type' => 'varchar', 'constraint'=> 50, 'null' => true],
|
||||||
'ExpectedTAT' => ['type' => 'INT', '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],
|
'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->addKey('TestSiteID', true);
|
||||||
$this->forge->addForeignKey('TestSiteID', 'testdefsite', 'TestSiteID', 'CASCADE', 'CASCADE');
|
$this->forge->createTable('testdefsite');
|
||||||
$this->forge->createTable('testdeftech');
|
|
||||||
|
// testdeftech table removed - merged into testdefsite
|
||||||
|
|
||||||
$this->forge->addField([
|
$this->forge->addField([
|
||||||
'TestCalID' => ['type' => 'INT', 'auto_increment' => true, 'unsigned' => true],
|
'TestCalID' => ['type' => 'INT', 'auto_increment' => true, 'unsigned' => true],
|
||||||
@ -166,7 +160,7 @@ class CreateTestDefinitions extends Migration {
|
|||||||
$this->forge->dropTable('testmap');
|
$this->forge->dropTable('testmap');
|
||||||
$this->forge->dropTable('testdefgrp');
|
$this->forge->dropTable('testdefgrp');
|
||||||
$this->forge->dropTable('testdefcal');
|
$this->forge->dropTable('testdefcal');
|
||||||
$this->forge->dropTable('testdeftech');
|
// testdeftech table removed - merged into testdefsite
|
||||||
$this->forge->dropTable('testdefsite');
|
$this->forge->dropTable('testdefsite');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,142 +28,98 @@ class TestSeeder extends Seeder
|
|||||||
// ========================================
|
// ========================================
|
||||||
// TEST TYPE - Actual Laboratory Tests
|
// TEST TYPE - Actual Laboratory Tests
|
||||||
// ========================================
|
// ========================================
|
||||||
// Hematology Tests
|
// 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', 'CreateDate' => "$now"];
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['HB'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['HCT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['RBC'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['WBC'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['PLT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['MCV'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['MCH'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['MCHC'] = $this->db->insertID();
|
$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
|
// 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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['GLU'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['CREA'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['UREA'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['SGOT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['SGPT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['CHOL'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['TG'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['HDL'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['LDL'] = $this->db->insertID();
|
$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)
|
// 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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['HEIGHT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['WEIGHT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['AGE'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['SYSTL'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['DIASTL'] = $this->db->insertID();
|
$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
|
// CALC TYPE - Calculated Tests
|
||||||
@ -232,28 +188,20 @@ class TestSeeder extends Seeder
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Urinalysis Tests (with valueset result type)
|
// 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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['UCOLOR'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['UGLUC'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['UPROT'] = $this->db->insertID();
|
$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);
|
$this->db->table('testdefsite')->insert($data);
|
||||||
$tIDs['PH'] = $this->db->insertID();
|
$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": "NMRIC", "value": "Numeric"},
|
||||||
{"key": "RANGE", "value": "Range"},
|
{"key": "RANGE", "value": "Range"},
|
||||||
{"key": "TEXT", "value": "Text"},
|
{"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 $primaryKey = 'TestSiteID';
|
||||||
protected $allowedFields = [
|
protected $allowedFields = [
|
||||||
'SiteID',
|
'SiteID',
|
||||||
'TestSiteCode',
|
'TestSiteCode', 'TestSiteName', 'TestType', 'Description',
|
||||||
'TestSiteName',
|
'DisciplineID', 'DepartmentID',
|
||||||
'TestType',
|
'ResultType', 'RefType', 'Vset',
|
||||||
'Description',
|
'Unit1', 'Factor', 'Unit2', 'Decimal',
|
||||||
'SeqScr',
|
'ReqQty', 'ReqQtyUnit', 'CollReq', 'Method', 'ExpectedTAT',
|
||||||
'SeqRpt',
|
'SeqScr', 'SeqRpt', 'IndentLeft', 'FontStyle', 'VisibleScr', 'VisibleRpt',
|
||||||
'IndentLeft',
|
'CountStat', 'Level',
|
||||||
'FontStyle',
|
'CreateDate', 'StartDate','EndDate'
|
||||||
'VisibleScr',
|
|
||||||
'VisibleRpt',
|
|
||||||
'CountStat',
|
|
||||||
'CreateDate',
|
|
||||||
'StartDate',
|
|
||||||
'EndDate'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $useTimestamps = true;
|
protected $useTimestamps = true;
|
||||||
@ -131,13 +125,15 @@ class TestDefSiteModel extends BaseModel {
|
|||||||
$row['testmap'] = $testMapModel->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll();
|
$row['testmap'] = $testMapModel->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll();
|
||||||
|
|
||||||
} elseif (in_array($typeCode, ['TEST', 'PARAM'])) {
|
} elseif (in_array($typeCode, ['TEST', 'PARAM'])) {
|
||||||
$row['testdeftech'] = $db->table('testdeftech')
|
// Technical details are now flattened into the main row
|
||||||
->select('testdeftech.*, d.DisciplineName, dept.DepartmentName')
|
if ($row['DisciplineID']) {
|
||||||
->join('discipline d', 'd.DisciplineID=testdeftech.DisciplineID', 'left')
|
$discipline = $db->table('discipline')->where('DisciplineID', $row['DisciplineID'])->get()->getRowArray();
|
||||||
->join('department dept', 'dept.DepartmentID=testdeftech.DepartmentID', 'left')
|
$row['DisciplineName'] = $discipline['DisciplineName'] ?? null;
|
||||||
->where('testdeftech.TestSiteID', $TestSiteID)
|
}
|
||||||
->where('testdeftech.EndDate IS NULL')
|
if ($row['DepartmentID']) {
|
||||||
->get()->getResultArray();
|
$department = $db->table('department')->where('DepartmentID', $row['DepartmentID'])->get()->getRowArray();
|
||||||
|
$row['DepartmentName'] = $department['DepartmentName'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
$testMapModel = new \App\Models\Test\TestMapModel();
|
$testMapModel = new \App\Models\Test\TestMapModel();
|
||||||
$row['testmap'] = $testMapModel->where('TestSiteID', $TestSiteID)->where('EndDate IS NULL')->findAll();
|
$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:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
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:
|
responses:
|
||||||
'201':
|
'201':
|
||||||
description: Test definition created
|
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:
|
patch:
|
||||||
tags:
|
tags:
|
||||||
- Tests
|
- Tests
|
||||||
@ -2659,10 +2767,112 @@ paths:
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
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:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Test definition updated
|
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}:
|
/api/tests/{id}:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -2676,9 +2886,70 @@ paths:
|
|||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
|
description: Test Site ID
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Test definition details
|
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:
|
/api/valueset:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -3832,11 +4103,13 @@ components:
|
|||||||
TestDefinition:
|
TestDefinition:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
id:
|
TestSiteID:
|
||||||
type: integer
|
type: integer
|
||||||
TestCode:
|
SiteID:
|
||||||
|
type: integer
|
||||||
|
TestSiteCode:
|
||||||
type: string
|
type: string
|
||||||
TestName:
|
TestSiteName:
|
||||||
type: string
|
type: string
|
||||||
TestType:
|
TestType:
|
||||||
type: string
|
type: string
|
||||||
@ -3852,6 +4125,8 @@ components:
|
|||||||
CALC: Calculated
|
CALC: Calculated
|
||||||
GROUP: Panel/Profile
|
GROUP: Panel/Profile
|
||||||
TITLE: Section header
|
TITLE: Section header
|
||||||
|
Description:
|
||||||
|
type: string
|
||||||
DisciplineID:
|
DisciplineID:
|
||||||
type: integer
|
type: integer
|
||||||
DisciplineName:
|
DisciplineName:
|
||||||
@ -3860,10 +4135,112 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
DepartmentName:
|
DepartmentName:
|
||||||
type: string
|
type: string
|
||||||
Unit:
|
ResultType:
|
||||||
type: string
|
type: string
|
||||||
Formula:
|
enum:
|
||||||
|
- NMRIC
|
||||||
|
- VSET
|
||||||
|
description: |
|
||||||
|
NMRIC: Numeric result
|
||||||
|
VSET: Value set result
|
||||||
|
RefType:
|
||||||
type: string
|
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:
|
refnum:
|
||||||
type: array
|
type: array
|
||||||
description: Numeric reference ranges (optional). Mutually exclusive with reftxt - a test can only have ONE reference type.
|
description: Numeric reference ranges (optional). Mutually exclusive with reftxt - a test can only have ONE reference type.
|
||||||
@ -3939,8 +4316,28 @@ components:
|
|||||||
Flag:
|
Flag:
|
||||||
type: string
|
type: string
|
||||||
examples:
|
examples:
|
||||||
$1:
|
TEST_numeric:
|
||||||
Unit: mg/dL
|
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:
|
refnum:
|
||||||
- RefNumID: 1
|
- RefNumID: 1
|
||||||
NumRefType: NMRC
|
NumRefType: NMRC
|
||||||
@ -3959,16 +4356,26 @@ components:
|
|||||||
AgeEnd: 99
|
AgeEnd: 99
|
||||||
Flag: 'N'
|
Flag: 'N'
|
||||||
Interpretation: Normal
|
Interpretation: Normal
|
||||||
TEST_numeric_thold:
|
TEST_threshold:
|
||||||
summary: Technical test - threshold reference (THOLD)
|
summary: Technical test with threshold reference (panic)
|
||||||
value:
|
value:
|
||||||
id: 1
|
TestSiteID: 2
|
||||||
TestCode: GLU
|
SiteID: 1
|
||||||
TestName: Glucose
|
TestSiteCode: GLU
|
||||||
|
TestSiteName: Glucose
|
||||||
TestType: TEST
|
TestType: TEST
|
||||||
DisciplineID: 1
|
DisciplineID: 2
|
||||||
DepartmentID: 1
|
DepartmentID: 2
|
||||||
Unit: mg/dL
|
ResultType: NMRIC
|
||||||
|
RefType: THOLD
|
||||||
|
Unit1: mg/dL
|
||||||
|
Decimal: 0
|
||||||
|
Method: Hexokinase
|
||||||
|
SeqScr: 11
|
||||||
|
SeqRpt: 11
|
||||||
|
VisibleScr: 1
|
||||||
|
VisibleRpt: 1
|
||||||
|
CountStat: 1
|
||||||
refnum:
|
refnum:
|
||||||
- RefNumID: 2
|
- RefNumID: 2
|
||||||
NumRefType: THOLD
|
NumRefType: THOLD
|
||||||
@ -3984,8 +4391,23 @@ components:
|
|||||||
AgeEnd: 120
|
AgeEnd: 120
|
||||||
Flag: L
|
Flag: L
|
||||||
Interpretation: Critical Low
|
Interpretation: Critical Low
|
||||||
$2:
|
TEST_text:
|
||||||
Unit: null
|
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:
|
reftxt:
|
||||||
- RefTxtID: 1
|
- RefTxtID: 1
|
||||||
TxtRefType: TEXT
|
TxtRefType: TEXT
|
||||||
@ -3996,39 +4418,48 @@ components:
|
|||||||
AgeEnd: 99
|
AgeEnd: 99
|
||||||
RefTxt: NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic
|
RefTxt: NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic
|
||||||
Flag: 'N'
|
Flag: 'N'
|
||||||
TEST_text_vset:
|
|
||||||
summary: Technical test - text reference (VSET)
|
|
||||||
value:
|
|
||||||
id: 1
|
|
||||||
TestCode: STAGE
|
|
||||||
TestName: Disease Stage
|
|
||||||
TestType: TEST
|
|
||||||
DisciplineID: 1
|
|
||||||
DepartmentID: 1
|
|
||||||
Unit: null
|
|
||||||
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
|
|
||||||
Flag: 'N'
|
|
||||||
PARAM:
|
PARAM:
|
||||||
summary: Parameter - no reference range allowed
|
summary: Parameter test
|
||||||
value:
|
value:
|
||||||
id: 2
|
TestSiteID: 4
|
||||||
TestCode: GLU_FAST
|
SiteID: 1
|
||||||
TestName: Fasting Glucose
|
TestSiteCode: HEIGHT
|
||||||
|
TestSiteName: Height
|
||||||
TestType: PARAM
|
TestType: PARAM
|
||||||
DisciplineID: 1
|
DisciplineID: 10
|
||||||
DepartmentID: 1
|
ResultType: NMRIC
|
||||||
Unit: mg/dL
|
Unit1: cm
|
||||||
$3:
|
Decimal: 0
|
||||||
Unit: null
|
SeqScr: 40
|
||||||
Formula: BUN / Creatinine
|
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:
|
refnum:
|
||||||
- RefNumID: 5
|
- RefNumID: 5
|
||||||
NumRefType: NMRC
|
NumRefType: NMRC
|
||||||
@ -4047,73 +4478,92 @@ components:
|
|||||||
AgeEnd: 120
|
AgeEnd: 120
|
||||||
Flag: 'N'
|
Flag: 'N'
|
||||||
Interpretation: Normal
|
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
|
|
||||||
GROUP:
|
GROUP:
|
||||||
summary: Panel/Profile - no reference range allowed
|
summary: Panel/Profile test
|
||||||
value:
|
value:
|
||||||
id: 4
|
TestSiteID: 6
|
||||||
TestCode: LIPID
|
SiteID: 1
|
||||||
TestName: Lipid Panel
|
TestSiteCode: LIPID
|
||||||
|
TestSiteName: Lipid Panel
|
||||||
TestType: GROUP
|
TestType: GROUP
|
||||||
DisciplineID: 1
|
DisciplineID: 2
|
||||||
DepartmentID: 1
|
DepartmentID: 2
|
||||||
Unit: null
|
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:
|
TITLE:
|
||||||
summary: Section header - no reference range allowed
|
summary: Section header
|
||||||
value:
|
value:
|
||||||
id: 5
|
TestSiteID: 7
|
||||||
TestCode: CHEM_HEADER
|
SiteID: 1
|
||||||
TestName: '--- CHEMISTRY ---'
|
TestSiteCode: CHEM_HEADER
|
||||||
|
TestSiteName: '--- CHEMISTRY ---'
|
||||||
TestType: TITLE
|
TestType: TITLE
|
||||||
DisciplineID: 1
|
DisciplineID: 2
|
||||||
DepartmentID: 1
|
DepartmentID: 2
|
||||||
Unit: null
|
SeqScr: 100
|
||||||
|
SeqRpt: 100
|
||||||
|
VisibleScr: 1
|
||||||
|
VisibleRpt: 1
|
||||||
|
CountStat: 0
|
||||||
TestMap:
|
TestMap:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
TestMapID:
|
TestMapID:
|
||||||
type: integer
|
type: integer
|
||||||
TestCode:
|
TestSiteID:
|
||||||
type: string
|
type: integer
|
||||||
HostCode:
|
|
||||||
type: string
|
|
||||||
HostName:
|
|
||||||
type: string
|
|
||||||
ClientCode:
|
|
||||||
type: string
|
|
||||||
ClientName:
|
|
||||||
type: string
|
|
||||||
HostType:
|
HostType:
|
||||||
type: string
|
type: string
|
||||||
description: Host type code
|
description: Host type code
|
||||||
HostTypeLabel:
|
HostID:
|
||||||
type: string
|
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:
|
ClientType:
|
||||||
type: string
|
type: string
|
||||||
description: Client type code
|
description: Client type code
|
||||||
ClientTypeLabel:
|
ClientID:
|
||||||
type: string
|
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:
|
OrderTest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
TestDefinition:
|
TestDefinition:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
id:
|
TestSiteID:
|
||||||
type: integer
|
type: integer
|
||||||
TestCode:
|
SiteID:
|
||||||
|
type: integer
|
||||||
|
TestSiteCode:
|
||||||
type: string
|
type: string
|
||||||
TestName:
|
TestSiteName:
|
||||||
type: string
|
type: string
|
||||||
TestType:
|
TestType:
|
||||||
type: string
|
type: string
|
||||||
@ -16,6 +18,8 @@ TestDefinition:
|
|||||||
CALC: Calculated
|
CALC: Calculated
|
||||||
GROUP: Panel/Profile
|
GROUP: Panel/Profile
|
||||||
TITLE: Section header
|
TITLE: Section header
|
||||||
|
Description:
|
||||||
|
type: string
|
||||||
DisciplineID:
|
DisciplineID:
|
||||||
type: integer
|
type: integer
|
||||||
DisciplineName:
|
DisciplineName:
|
||||||
@ -24,10 +28,106 @@ TestDefinition:
|
|||||||
type: integer
|
type: integer
|
||||||
DepartmentName:
|
DepartmentName:
|
||||||
type: string
|
type: string
|
||||||
Unit:
|
ResultType:
|
||||||
type: string
|
type: string
|
||||||
Formula:
|
enum: [NMRIC, VSET]
|
||||||
|
description: |
|
||||||
|
NMRIC: Numeric result
|
||||||
|
VSET: Value set result
|
||||||
|
RefType:
|
||||||
type: string
|
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:
|
refnum:
|
||||||
type: array
|
type: array
|
||||||
description: Numeric reference ranges (optional). Mutually exclusive with reftxt - a test can only have ONE reference type.
|
description: Numeric reference ranges (optional). Mutually exclusive with reftxt - a test can only have ONE reference type.
|
||||||
@ -99,8 +199,28 @@ TestDefinition:
|
|||||||
Flag:
|
Flag:
|
||||||
type: string
|
type: string
|
||||||
examples:
|
examples:
|
||||||
$1:
|
TEST_numeric:
|
||||||
Unit: mg/dL
|
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:
|
refnum:
|
||||||
- RefNumID: 1
|
- RefNumID: 1
|
||||||
NumRefType: NMRC
|
NumRefType: NMRC
|
||||||
@ -119,16 +239,26 @@ TestDefinition:
|
|||||||
AgeEnd: 99
|
AgeEnd: 99
|
||||||
Flag: N
|
Flag: N
|
||||||
Interpretation: Normal
|
Interpretation: Normal
|
||||||
TEST_numeric_thold:
|
TEST_threshold:
|
||||||
summary: Technical test - threshold reference (THOLD)
|
summary: Technical test with threshold reference (panic)
|
||||||
value:
|
value:
|
||||||
id: 1
|
TestSiteID: 2
|
||||||
TestCode: GLU
|
SiteID: 1
|
||||||
TestName: Glucose
|
TestSiteCode: GLU
|
||||||
|
TestSiteName: Glucose
|
||||||
TestType: TEST
|
TestType: TEST
|
||||||
DisciplineID: 1
|
DisciplineID: 2
|
||||||
DepartmentID: 1
|
DepartmentID: 2
|
||||||
Unit: mg/dL
|
ResultType: NMRIC
|
||||||
|
RefType: THOLD
|
||||||
|
Unit1: mg/dL
|
||||||
|
Decimal: 0
|
||||||
|
Method: Hexokinase
|
||||||
|
SeqScr: 11
|
||||||
|
SeqRpt: 11
|
||||||
|
VisibleScr: 1
|
||||||
|
VisibleRpt: 1
|
||||||
|
CountStat: 1
|
||||||
refnum:
|
refnum:
|
||||||
- RefNumID: 2
|
- RefNumID: 2
|
||||||
NumRefType: THOLD
|
NumRefType: THOLD
|
||||||
@ -144,8 +274,23 @@ TestDefinition:
|
|||||||
AgeEnd: 120
|
AgeEnd: 120
|
||||||
Flag: L
|
Flag: L
|
||||||
Interpretation: Critical Low
|
Interpretation: Critical Low
|
||||||
$2:
|
TEST_text:
|
||||||
Unit: null
|
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:
|
reftxt:
|
||||||
- RefTxtID: 1
|
- RefTxtID: 1
|
||||||
TxtRefType: TEXT
|
TxtRefType: TEXT
|
||||||
@ -156,39 +301,48 @@ TestDefinition:
|
|||||||
AgeEnd: 99
|
AgeEnd: 99
|
||||||
RefTxt: 'NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic'
|
RefTxt: 'NORM=Normal;HYPO=Hypochromic;MACRO=Macrocytic'
|
||||||
Flag: N
|
Flag: N
|
||||||
TEST_text_vset:
|
|
||||||
summary: Technical test - text reference (VSET)
|
|
||||||
value:
|
|
||||||
id: 1
|
|
||||||
TestCode: STAGE
|
|
||||||
TestName: Disease Stage
|
|
||||||
TestType: TEST
|
|
||||||
DisciplineID: 1
|
|
||||||
DepartmentID: 1
|
|
||||||
Unit: null
|
|
||||||
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'
|
|
||||||
Flag: N
|
|
||||||
PARAM:
|
PARAM:
|
||||||
summary: Parameter - no reference range allowed
|
summary: Parameter test
|
||||||
value:
|
value:
|
||||||
id: 2
|
TestSiteID: 4
|
||||||
TestCode: GLU_FAST
|
SiteID: 1
|
||||||
TestName: Fasting Glucose
|
TestSiteCode: HEIGHT
|
||||||
|
TestSiteName: Height
|
||||||
TestType: PARAM
|
TestType: PARAM
|
||||||
DisciplineID: 1
|
DisciplineID: 10
|
||||||
DepartmentID: 1
|
ResultType: NMRIC
|
||||||
Unit: mg/dL
|
Unit1: cm
|
||||||
$3:
|
Decimal: 0
|
||||||
Unit: null
|
SeqScr: 40
|
||||||
Formula: "BUN / Creatinine"
|
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:
|
refnum:
|
||||||
- RefNumID: 5
|
- RefNumID: 5
|
||||||
NumRefType: NMRC
|
NumRefType: NMRC
|
||||||
@ -207,72 +361,90 @@ TestDefinition:
|
|||||||
AgeEnd: 120
|
AgeEnd: 120
|
||||||
Flag: N
|
Flag: N
|
||||||
Interpretation: Normal
|
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
|
|
||||||
|
|
||||||
GROUP:
|
GROUP:
|
||||||
summary: Panel/Profile - no reference range allowed
|
summary: Panel/Profile test
|
||||||
value:
|
value:
|
||||||
id: 4
|
TestSiteID: 6
|
||||||
TestCode: LIPID
|
SiteID: 1
|
||||||
TestName: Lipid Panel
|
TestSiteCode: LIPID
|
||||||
|
TestSiteName: Lipid Panel
|
||||||
TestType: GROUP
|
TestType: GROUP
|
||||||
DisciplineID: 1
|
DisciplineID: 2
|
||||||
DepartmentID: 1
|
DepartmentID: 2
|
||||||
Unit: null
|
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:
|
TITLE:
|
||||||
summary: Section header - no reference range allowed
|
summary: Section header
|
||||||
value:
|
value:
|
||||||
id: 5
|
TestSiteID: 7
|
||||||
TestCode: CHEM_HEADER
|
SiteID: 1
|
||||||
TestName: '--- CHEMISTRY ---'
|
TestSiteCode: CHEM_HEADER
|
||||||
|
TestSiteName: '--- CHEMISTRY ---'
|
||||||
TestType: TITLE
|
TestType: TITLE
|
||||||
DisciplineID: 1
|
DisciplineID: 2
|
||||||
DepartmentID: 1
|
DepartmentID: 2
|
||||||
Unit: null
|
SeqScr: 100
|
||||||
|
SeqRpt: 100
|
||||||
|
VisibleScr: 1
|
||||||
|
VisibleRpt: 1
|
||||||
|
CountStat: 0
|
||||||
|
|
||||||
TestMap:
|
TestMap:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
id:
|
|
||||||
type: integer
|
|
||||||
TestMapID:
|
TestMapID:
|
||||||
type: integer
|
type: integer
|
||||||
TestCode:
|
TestSiteID:
|
||||||
type: string
|
type: integer
|
||||||
HostCode:
|
|
||||||
type: string
|
|
||||||
HostName:
|
|
||||||
type: string
|
|
||||||
ClientCode:
|
|
||||||
type: string
|
|
||||||
ClientName:
|
|
||||||
type: string
|
|
||||||
HostType:
|
HostType:
|
||||||
type: string
|
type: string
|
||||||
description: Host type code
|
description: Host type code
|
||||||
HostTypeLabel:
|
HostID:
|
||||||
type: string
|
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:
|
ClientType:
|
||||||
type: string
|
type: string
|
||||||
description: Client type code
|
description: Client type code
|
||||||
ClientTypeLabel:
|
ClientID:
|
||||||
type: string
|
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:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
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:
|
responses:
|
||||||
'201':
|
'201':
|
||||||
description: Test definition created
|
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:
|
patch:
|
||||||
tags: [Tests]
|
tags: [Tests]
|
||||||
@ -91,10 +188,101 @@
|
|||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
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:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Test definition updated
|
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}:
|
/api/tests/{id}:
|
||||||
get:
|
get:
|
||||||
@ -108,6 +296,67 @@
|
|||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: integer
|
type: integer
|
||||||
|
description: Test Site ID
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Test definition details
|
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 CodeIgniter\Test\CIUnitTestCase;
|
||||||
use App\Models\Test\TestDefSiteModel;
|
use App\Models\Test\TestDefSiteModel;
|
||||||
use App\Models\Test\TestDefTechModel;
|
|
||||||
use App\Models\Test\TestDefCalModel;
|
use App\Models\Test\TestDefCalModel;
|
||||||
use App\Models\Test\TestDefGrpModel;
|
use App\Models\Test\TestDefGrpModel;
|
||||||
use App\Models\Test\TestMapModel;
|
use App\Models\Test\TestMapModel;
|
||||||
@ -12,7 +12,7 @@ use App\Models\Test\TestMapModel;
|
|||||||
class TestDefModelsTest extends CIUnitTestCase
|
class TestDefModelsTest extends CIUnitTestCase
|
||||||
{
|
{
|
||||||
protected $testDefSiteModel;
|
protected $testDefSiteModel;
|
||||||
protected $testDefTechModel;
|
|
||||||
protected $testDefCalModel;
|
protected $testDefCalModel;
|
||||||
protected $testDefGrpModel;
|
protected $testDefGrpModel;
|
||||||
protected $testMapModel;
|
protected $testMapModel;
|
||||||
@ -21,7 +21,7 @@ class TestDefModelsTest extends CIUnitTestCase
|
|||||||
{
|
{
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
$this->testDefSiteModel = new TestDefSiteModel();
|
$this->testDefSiteModel = new TestDefSiteModel();
|
||||||
$this->testDefTechModel = new TestDefTechModel();
|
|
||||||
$this->testDefCalModel = new TestDefCalModel();
|
$this->testDefCalModel = new TestDefCalModel();
|
||||||
$this->testDefGrpModel = new TestDefGrpModel();
|
$this->testDefGrpModel = new TestDefGrpModel();
|
||||||
$this->testMapModel = new TestMapModel();
|
$this->testMapModel = new TestMapModel();
|
||||||
@ -76,43 +76,6 @@ class TestDefModelsTest extends CIUnitTestCase
|
|||||||
$this->assertEquals('EndDate', $this->testDefSiteModel->deletedField);
|
$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
|
* Test TestDefCalModel has correct table name
|
||||||
*/
|
*/
|
||||||
@ -218,7 +181,6 @@ class TestDefModelsTest extends CIUnitTestCase
|
|||||||
*/
|
*/
|
||||||
public function testAllModelsUseSoftDeletes()
|
public function testAllModelsUseSoftDeletes()
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->testDefTechModel->useSoftDeletes);
|
|
||||||
$this->assertTrue($this->testDefCalModel->useSoftDeletes);
|
$this->assertTrue($this->testDefCalModel->useSoftDeletes);
|
||||||
$this->assertTrue($this->testDefGrpModel->useSoftDeletes);
|
$this->assertTrue($this->testDefGrpModel->useSoftDeletes);
|
||||||
$this->assertTrue($this->testMapModel->useSoftDeletes);
|
$this->assertTrue($this->testMapModel->useSoftDeletes);
|
||||||
@ -229,7 +191,6 @@ class TestDefModelsTest extends CIUnitTestCase
|
|||||||
*/
|
*/
|
||||||
public function testAllModelsUseEndDateAsDeletedField()
|
public function testAllModelsUseEndDateAsDeletedField()
|
||||||
{
|
{
|
||||||
$this->assertEquals('EndDate', $this->testDefTechModel->deletedField);
|
|
||||||
$this->assertEquals('EndDate', $this->testDefCalModel->deletedField);
|
$this->assertEquals('EndDate', $this->testDefCalModel->deletedField);
|
||||||
$this->assertEquals('EndDate', $this->testDefGrpModel->deletedField);
|
$this->assertEquals('EndDate', $this->testDefGrpModel->deletedField);
|
||||||
$this->assertEquals('EndDate', $this->testMapModel->deletedField);
|
$this->assertEquals('EndDate', $this->testMapModel->deletedField);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user