Update site controller, organization & test models, migrations, and API docs

This commit is contained in:
mahdahar 2026-03-10 16:40:37 +07:00
parent 011a2456c2
commit ad8e1cc977
23 changed files with 698 additions and 774 deletions

View File

@ -0,0 +1,97 @@
# CLQMS Code Conventions
## PHP Standards
- **Version**: PHP 8.1+
- **Autoloading**: PSR-4
- **Coding Style**: PSR-12 (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` |
| Database Tables | snake_case | `patient_visits` |
| Database Columns | PascalCase (legacy) | `PatientID`, `NameFirst` |
| JSON Fields | PascalCase | `"PatientID": "123"` |
## Imports & Namespaces
- Fully qualified namespaces at top of file
- Group imports: Framework first, then App, then external
- 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 Pattern
Controllers handle HTTP requests, delegate business logic to Models (no DB queries in controllers).
```php
class ExampleController extends Controller
{
use ResponseTrait;
protected $model;
public function __construct()
{
$this->model = new \App\Models\ExampleModel();
}
}
```
## Response Format
All API responses use standardized format:
```php
// Success
return $this->respond([
'status' => 'success',
'message' => 'Operation completed',
'data' => $data
], 200);
// Error
return $this->respond([
'status' => 'failed',
'message' => 'Error description',
'data' => []
], 400);
```
## Database Operations
- Use CodeIgniter Query Builder or Model methods
- Use `helper('utc')` for UTC date conversion
- Wrap multi-table operations in transactions
```php
$this->db->transStart();
// ... operations
$this->db->transComplete();
if ($this->db->transStatus() === false) {
return $this->respond(['status' => 'error', ...], 500);
}
```
## Test Naming Convention
Format: `test<Action><Scenario><ExpectedResult>`
Examples: `testCreatePatientValidationFail`, `testUpdatePatientSuccess`
## HTTP Status Codes
- 200: GET/PATCH success
- 201: POST success
- 400: Validation error
- 401: Unauthorized
- 404: Not found
- 500: Server error
## Legacy Field Naming
Database uses PascalCase: `PatientID`, `NameFirst`, `Birthdate`, `CreatedAt`

View File

@ -1,55 +1,54 @@
# CLQMS Project Overview # CLQMS Project Overview
## Project Purpose ## Project Purpose
CLQMS (Clinical Laboratory Quality Management System) is a headless REST API backend for clinical laboratory workflows. It provides comprehensive JSON endpoints for:
- Patient management
- Order/test management
- Specimen tracking
- Result management and verification
- Reference ranges
- Laboratory instrument integration (Edge API)
CLQMS (Clinical Laboratory Quality Management System) is a **headless REST API backend** designed for modern clinical laboratory workflows. This API-only system provides comprehensive JSON endpoints for laboratory operations without any view layer. Frontend applications (web, mobile, desktop) consume these REST endpoints to build laboratory information systems. ## Tech Stack
- **Language**: PHP 8.1+
- **Framework**: CodeIgniter 4 (API-only mode)
- **Database**: MySQL with MySQLi driver
- **Authentication**: JWT (JSON Web Tokens)
- **Testing**: PHPUnit 10.5+
- **Documentation**: OpenAPI/Swagger YAML
### Core Features ## Architecture
- Patient registration and management - **API-First**: No view layer, headless REST API only
- Laboratory test ordering and tracking - **Stateless**: JWT-based authentication per request
- Specimen lifecycle management (collection → transport → reception → prep → analysis) - **UTC Dates**: All dates stored in UTC, converted for display
- Result entry with reference range validation - **PSR-4 Autoloading**: `App\``app/`, `Config\``app/Config/`
- Multi-level result verification (Technical → Clinical → Reporting)
- Instrument integration via Edge API (tiny-edge middleware)
- Master data management (value sets, test definitions, reference ranges)
- Quality control and calibration tracking
### Product Vision ## Key Directories
To provide a headless, API-first laboratory information system serving as the backend for any frontend client while streamlining laboratory operations, ensuring regulatory compliance, and integrating seamlessly with laboratory instruments. ```
app/
Controllers/ # API endpoint handlers
Models/ # Database models
Libraries/ # Helper classes (Lookups, ValueSet)
Database/
Migrations/ # Schema migrations
Seeds/ # Test data seeders
Helpers/ # json_helper.php, utc_helper.php
Traits/ # ResponseTrait
Config/ # Configuration files
Filters/ # AuthFilter, CORS
## Technology Stack public/ # Web root
paths/ # OpenAPI path definitions
components/schemas/ # OpenAPI schemas
| Component | Specification | tests/
|-----------|---------------| feature/ # Feature/integration tests
| **Language** | PHP 8.1+ (PSR-compliant) | unit/ # Unit tests
| **Framework** | CodeIgniter 4 (API-only mode) | _support/ # Test support files
| **Database** | MySQL 8.0+ | ```
| **Security** | JWT (JSON Web Tokens) via firebase/php-jwt |
| **Testing** | PHPUnit 10.5+ |
| **API Format** | RESTful JSON |
| **Architecture** | Clean architecture, API-first design |
### Key Dependencies ## Key Dependencies
- `codeigniter4/framework` - Main framework - `codeigniter4/framework` - Core framework
- `firebase/php-jwt` - JWT authentication - `firebase/php-jwt` - JWT authentication
- `fakerphp/faker` - Test data generation - `fakerphp/faker` - Test data generation (dev)
- `phpunit/phpunit` - Unit/feature testing - `phpunit/phpunit` - Testing (dev)
## Strategic Pillars
- **Precision & Accuracy**: Strict validation for all laboratory parameters and reference ranges
- **Scalability**: Optimized for high-volume diagnostic environments
- **Compliance**: Built-in audit trails and status history for full traceability
- **Interoperability**: Modular architecture designed for LIS, HIS, and analyzer integrations
## Key Characteristics
- **API-Only**: No view layer, no server-side rendering
- **Frontend Agnostic**: Any client can consume these APIs
- **JSON-First**: All requests/responses use JSON format
- **Stateless**: Each API request is independent with JWT authentication
- **UTC Normalization**: Automatic UTC timestamp handling via BaseModel
## Current Architecture Status
The system is undergoing an **Architectural Redesign** to consolidate legacy structures into a high-performance, maintainable schema focusing on:
- Unified Test Definitions (consolidating technical, calculated, and site-specific test data)
- Reference Range Centralization (unified engine for numeric, threshold, text, and coded results)
- Ordered Workflow Management (precise tracking of orders from collection to verification)

View File

@ -1,393 +1,100 @@
# CLQMS Suggested Commands # CLQMS Suggested Commands
## Database Commands ## Testing
### Migrations
```bash
# Run all pending migrations
php spark migrate
# Run specific migration
php spark migrate [migration_file]
# Rollback last batch of migrations
php spark migrate:rollback
# Rollback and re-run migrations
php spark migrate:refresh
# Refresh and seed database
php spark migrate:refresh --seed
# Check migration status
php spark migrate:status
```
### Database Seeding
```bash
# Run all seeders
php spark db:seed
# Run specific seeder
php spark db:seed DBSeeder
# Create new database
php spark db:create
```
### Database Query
```bash
# Get table information
php spark db:table [table_name]
```
## Testing Commands
### PHPUnit Tests
```bash ```bash
# Run all tests # Run all tests
vendor/bin/phpunit ./vendor/bin/phpunit
# Run specific test file (IMPORTANT for debugging) # Run specific test file
vendor/bin/phpunit tests/feature/UniformShowTest.php ./vendor/bin/phpunit tests/feature/Patients/PatientCreateTest.php
vendor/bin/phpunit tests/feature/Patient/PatientCreateTest.php
# Run tests in specific directory
vendor/bin/phpunit tests/feature/Patient/
# Run tests with coverage (text output)
vendor/bin/phpunit --coverage-text=tests/coverage.txt -d memory_limit=1024m
# Run tests with coverage (HTML report)
vendor/bin/phpunit --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m
# Run with verbose output
vendor/bin/phpunit --verbose
# Run specific test method # Run specific test method
vendor/bin/phpunit --filter testCanCreatePatient ./vendor/bin/phpunit --filter testCreatePatientSuccess tests/feature/Patients/PatientCreateTest.php
```
## Code Generation Commands # Run tests with coverage
./vendor/bin/phpunit --coverage-html build/logs/html
### Generate Code Files # Run tests by suite
```bash ./vendor/bin/phpunit --testsuite App
# Generate new model
php spark make:model ModelName
# Generate new controller # Run via composer
php spark make:controller ControllerName composer test
# Generate new migration
php spark make:migration MigrationName
# Generate new seeder
php spark make:seeder SeederName
# Generate new test
php spark make:test TestName
# Generate scaffold (complete set)
php spark make:scaffold ModelName
``` ```
## Development Server ## Development Server
### Start Development Server
```bash ```bash
# Start CodeIgniter dev server (default port 8080) # Start PHP development server
php spark serve php spark serve
# Start on specific port # Or specify port
php spark serve --port=8080 php spark serve --port 8080
# Start with specific host
php spark serve --host=0.0.0.0
``` ```
## Cache Management ## Database
### Clear Caches
```bash ```bash
# Clear application cache # Run migrations
php spark cache:clear php spark migrate
# Show cache information # Rollback migrations
php spark cache:info php spark migrate:rollback
# Clear debug bar JSON files # Create new migration
php spark debugbar:clear php spark make:migration CreateUsersTable
# Clear log files # Run database seeds
php spark logs:clear php spark db:seed DBSeeder
php spark db:seed PatientSeeder
``` ```
## System Utilities ## Code Generation (Scaffolding)
### Configuration & Environment
```bash ```bash
# Get current environment # Create controller
php spark env php spark make:controller Users
# Set environment # Create model
php spark env development php spark make:model UserModel
# Check configuration values # Create migration
php spark config:check php spark make:migration CreateUsersTable
# Check php.ini values (for production) # Create seeder
php spark phpini:check php spark make:seeder UserSeeder
# Verify namespaces
php spark namespaces
``` ```
### Routes ## API Documentation
```bash ```bash
# Display all routes # After updating YAML files, regenerate bundled docs
php spark routes node public/bundle-api-docs.js
# Check filters for a route # Produces: public/api-docs.bundled.yaml
php spark filter:check
``` ```
### Optimization ## Utilities (Windows)
```bash ```bash
# Optimize for production # List files
php spark optimize
```
## Utility Commands
### Encryption
```bash
# Generate new encryption key (writes to .env)
php spark key:generate
```
### Publish
```bash
# Publish predefined resources
php spark publish
```
## General Utility Commands (Windows)
### File & Directory Operations
```bash
# List files in current directory
dir dir
# List files with details # Search in files (PowerShell)
dir /a Select-String -Path "app\*.php" -Pattern "PatientModel"
# Change directory # Or using git bash (if available)
cd path\to\directory grep -r "PatientModel" app/
# Go to parent directory # Clear writable cache
cd .. del /q writable\cache\*
# Create directory
mkdir directory_name
# Remove directory (empty)
rmdir directory_name
# Remove directory with contents
rmdir /s /q directory_name
# Copy file
copy source_file destination
# Move/Rename file
move source destination
# Delete file
del filename
# Search for file
dir /s filename
``` ```
### File Content Operations ## Git Commands
```bash ```bash
# Display file content # Check status
type filename
# Display file content page by page
more filename
# Search for text in file
findstr "pattern" filename
# Search recursively
findstr /s /i "pattern" *.php
```
### Git Commands
```bash
# Check git status
git status git status
# View changes # Add files
git diff
# View staged changes
git diff --staged
# Add files to staging
git add . git add .
# Add specific file # Commit (only when explicitly asked)
git add path/to/file git commit -m "message"
# Commit changes # View recent commits
git commit -m "commit message" git log --oneline -10
# Push to remote
git push
# Pull from remote
git pull
# View commit history
git log
# View commit history with graph
git log --graph --oneline
# Create new branch
git checkout -b branch_name
# Switch branch
git checkout branch_name
# Merge branch
git merge branch_name
# View branches
git branch
``` ```
### Process Management
```bash
# List running processes
tasklist
# Kill process by PID
taskkill /PID pid_number
# Kill process by name
taskkill /IM process_name.exe
# Kill process forcefully
taskkill /F /PID pid_number
```
### Network Operations
```bash
# Check port usage
netstat -an | findstr :port
# Test network connectivity
ping hostname
# View active connections
netstat -an
```
## After Task Completion Checklist
When completing a task, run the following commands to ensure code quality:
### 1. Run Tests
```bash
# Run all tests
vendor/bin/phpunit
# If tests fail, run specific test file for debugging
vendor/bin/phpunit tests/feature/[SpecificTestFile].php
```
### 2. Check for Linting Issues (if configured)
```bash
# Check for PHP syntax errors
php -l app/Controllers/YourController.php
php -l app/Models/YourModel.php
# Run any custom linting tools if configured in composer.json
composer test # if 'test' script includes linting
```
### 3. Type Checking (if configured)
```bash
# Run static analysis tools if configured
vendor/bin/phpstan analyse # if phpstan is installed
vendor/bin/psalm # if psalm is installed
```
### 4. Database Verification
```bash
# Check migration status
php spark migrate:status
# If you created a migration, run it
php spark migrate
```
### 5. API Documentation Update (CRITICAL)
```bash
# After modifying ANY controller, MUST update api-docs.yaml
# This is a manual process - edit public/api-docs.yaml
# Verify YAML syntax (optional, if yamllint is available)
yamllint public/api-docs.yaml
```
### 6. Code Review Checklist
- [ ] All tests passing
- [ ] No PHP syntax errors
- [ ] Database migrations applied (if any)
- [ ] API documentation updated (`public/api-docs.yaml`)
- [ ] Code follows style conventions (see `code_style_conventions.md`)
- [ ] Proper error handling in place
- [ ] Input validation implemented
- [ ] JWT authentication required where needed
- [ ] UTC date handling via BaseModel
- [ ] Soft delete using `DelDate` where applicable
- [ ] ValueSet lookups properly used and cached cleared if modified
### 7. Verify API Endpoints (if applicable)
```bash
# If you have curl or a REST client, test the endpoints
# Example using curl:
curl -X GET http://localhost:8080/api/patient -H "Cookie: token=your_jwt_token"
```
## Common Workflows
### Creating a New API Endpoint
1. Create controller: `php spark make:controller ControllerName`
2. Create model: `php spark make:model ModelName`
3. Create migration (if new table): `php spark make:migration MigrationName`
4. Run migration: `php spark migrate`
5. Add routes in `app/Config/Routes.php`
6. Implement controller methods following pattern
7. Create tests: `php spark make:test Feature/EndpointNameTest`
8. Run tests: `vendor/bin/phpunit tests/feature/EndpointNameTest.php`
9. Update `public/api-docs.yaml`
10. Verify with test client
### Debugging a Failing Test
1. Run specific test file: `vendor/bin/phpunit tests/feature/SpecificTest.php`
2. Add debug output: `var_dump($result); die();` temporarily
3. Check database state: View with database client
4. Check logs: `writable/logs/` directory
5. Run with verbose: `vendor/bin/phpunit --verbose`
6. Isolate specific test: `vendor/bin/phpunit --filter testMethodName`
### Working with ValueSets
1. Create/edit JSON file: `app/Libraries/Data/valuesets/{name}.json`
2. Clear cache: `ValueSet::clearCache();` (in code) or via code
3. Verify via API: GET `/api/valueset/{name}`
4. Test lookup: `ValueSet::get('name')` in controller/model

View File

@ -1,129 +1,67 @@
# CLQMS Task Completion Guidelines # CLQMS Task Completion Checklist
## When a Task is Completed When completing a task, ensure:
### 1. Run Tests
Always run relevant tests after making changes:
## 1. Tests Pass
```bash ```bash
# Run all tests
./vendor/bin/phpunit ./vendor/bin/phpunit
# Run specific test file
./vendor/bin/phpunit tests/feature/Patients/PatientCreateTest.php
# Run specific test method
./vendor/bin/phpunit --filter testCreatePatientSuccess tests/feature/Patients/PatientCreateTest.php
``` ```
- All existing tests must pass
- Add new tests for new features
- Test naming: `test<Action><Scenario><Result>`
### 2. Verify Code Quality ## 2. API Documentation Updated (CRITICAL)
When updating ANY controller, update corresponding OpenAPI YAML:
#### Check for Syntax Errors | Controller | YAML Path File | YAML Schema File |
|-----------|----------------|------------------|
| `PatientController` | `paths/patients.yaml` | `components/schemas/patient.yaml` |
| `PatVisitController` | `paths/patient-visits.yaml` | `components/schemas/patient-visit.yaml` |
| `OrderTestController` | `paths/orders.yaml` | `components/schemas/orders.yaml` |
| `SpecimenController` | `paths/specimen.yaml` | `components/schemas/specimen.yaml` |
| `TestsController` | `paths/tests.yaml` | `components/schemas/tests.yaml` |
| `AuthController` | `paths/authentication.yaml` | `components/schemas/authentication.yaml` |
| `ResultController` | `paths/results.yaml` | `components/schemas/*.yaml` |
| `EdgeController` | `paths/edge-api.yaml` | `components/schemas/edge-api.yaml` |
| `LocationController` | `paths/locations.yaml` | `components/schemas/master-data.yaml` |
| `ValueSetController` | `paths/valuesets.yaml` | `components/schemas/valuesets.yaml` |
| `ContactController` | `paths/contact.yaml` | (inline schemas) |
After updating YAML files:
```bash ```bash
php -l app/Controllers/Patient/PatientController.php node public/bundle-api-docs.js
``` ```
#### Check Test Results ## 3. Code Quality Checks
Ensure: - PSR-12 compliance where applicable
- All existing tests still pass - No database queries in controllers
- New tests (if any) pass
- No unexpected warnings or errors
### 3. Code Review Checklist
#### Controller Changes
- [ ] Validation rules are properly defined
- [ ] Error handling uses try-catch blocks
- [ ] Responses use standardized format with `ResponseTrait`
- [ ] Authentication filter applied where needed
- [ ] Input sanitization via validation rules
- [ ] Database operations wrapped in transactions (if multi-table)
#### Model Changes
- [ ] Extends `BaseModel` for UTC handling
- [ ] Table name, primary key, allowed fields defined
- [ ] Uses `checkDbError()` for error detection
- [ ] Audit logging via `AuditService::logData()` for data changes
- [ ] Soft delete fields configured if using soft deletes
- [ ] Nested data properly handled (extracted before filtering)
#### New Routes
- [ ] Added to `app/Config/Routes.php`
- [ ] Follows REST conventions (GET, POST, PATCH, DELETE)
- [ ] Grouped appropriately under `/api/`
- [ ] Auth filter applied if needed
#### New Tests
- [ ] Test name follows `test<Action><Scenario><ExpectedResult>` pattern
- [ ] Uses `FeatureTestTrait`
- [ ] Uses `Factory::create('id_ID')` for Indonesian test data
- [ ] Asserts correct status codes (200, 201, 400, 401, 404, 500)
- [ ] Tests both success and failure scenarios
### 4. Common Issues to Check
#### Database Operations
- Multi-table operations should use transactions
- Use parameterized queries (Query Builder handles this)
- Check for empty/null arrays before processing
#### Nested Data
- Extract nested arrays before filtering/processing
- Handle empty/null nested data appropriately
- Use transactions for multi-table operations - Use transactions for multi-table operations
- Proper error handling with try-catch for JWT/external calls
- Log errors: `log_message('error', $message)`
#### Date Handling ## 4. Response Format Verification
- All dates stored in UTC Ensure all responses follow the standard format:
- Use `helper('utc')` for conversions ```php
- BaseModel extends with automatic UTC conversion return $this->respond([
'status' => 'success|failed',
#### Security 'message' => 'Description',
- Input validation rules defined 'data' => $data
- SQL injection prevention via parameterized queries ], $httpStatus);
- JWT validation on protected endpoints
- No sensitive data logged or exposed
### 5. What NOT to Do
- **Do NOT commit** unless explicitly asked by the user
- **Do NOT push** to remote repository unless asked
- **Do NOT** skip running tests
- **Do NOT** add comments unless specifically requested
- **Do NOT** modify `.env` (database credentials, secrets)
- **Do NOT** include hardcoded secrets in code
### 6. Common Test Status Codes Reference
| Code | Usage | Example |
|------|-------|---------|
| 200 | GET/PATCH success | `->assertStatus(200)` |
| 201 | POST success (created) | `->assertStatus(201)` |
| 400 | Validation error | `->assertStatus(400)` |
| 401 | Unauthorized | `->assertStatus(401)` |
| 404 | Not found | `->assertStatus(404)` |
| 500 | Server error | `->assertStatus(500)` |
### 7. After Completing Tasks
Simply inform the user the task is complete. For example:
```
Task completed. The patient create endpoint now validates the identifier type dynamically.
``` ```
Or if tests were run: ## 5. Security Checklist
``` - Use `auth` filter for protected routes
Task completed. All tests passing: - Sanitize user inputs
- testCreatePatientSuccess ✓ - Use parameterized queries
- testCreatePatientValidationFail ✓ - No secrets committed to repo (use .env)
```
### 8. When Something Goes Wrong ## 6. Naming Conventions
- Classes: PascalCase
- Methods: camelCase
- Properties: snake_case (legacy) / camelCase (new)
- Database columns: PascalCase (legacy convention)
If tests fail or errors occur: ## 7. Do NOT Commit Unless Explicitly Asked
1. Check the error message carefully - Check status: `git status`
2. Review the code against the patterns in this guide - Never commit .env files
3. Check database connection and configuration - Never commit secrets
4. Verify all required dependencies are installed
5. Review log files in `writable/logs/`
If unable to resolve, inform the user with details of the issue.

View File

@ -125,3 +125,8 @@ language_backend:
# list of regex patterns which, when matched, mark a memory entry as readonly. # list of regex patterns which, when matched, mark a memory entry as readonly.
# Extends the list from the global configuration, merging the two lists. # Extends the list from the global configuration, merging the two lists.
read_only_memory_patterns: [] read_only_memory_patterns: []
# line ending convention to use when writing source files.
# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default)
# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings.
line_ending:

View File

@ -56,6 +56,17 @@ class SiteController extends BaseController {
public function create() { public function create() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
$validation = service('validation');
$validation->setRules([
'SiteCode' => 'required|regex_match[/^[A-Z0-9]{2}$/]',
'SiteName' => 'required',
]);
if (!$validation->run($input)) {
return $this->failValidationErrors($validation->getErrors());
}
try { try {
$id = $this->model->insert($input,true); $id = $this->model->insert($input,true);
return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $id ], 201); return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $id ], 201);
@ -66,9 +77,22 @@ class SiteController extends BaseController {
public function update() { public function update() {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);
try {
$id = $input['SiteID']; $id = $input['SiteID'];
if (!$id) { return $this->failValidationErrors('ID is required.'); } if (!$id) { return $this->failValidationErrors('ID is required.'); }
if (!empty($input['SiteCode'])) {
$validation = service('validation');
$validation->setRules([
'SiteCode' => 'regex_match[/^[A-Z0-9]{2}$/]',
]);
if (!$validation->run($input)) {
return $this->failValidationErrors($validation->getErrors());
}
}
try {
$this->model->update($id, $input); $this->model->update($id, $input);
return $this->respondCreated([ 'status' => 'success', 'message' => 'data updated successfully', 'data' => $id ], 201); return $this->respondCreated([ 'status' => 'success', 'message' => 'data updated successfully', 'data' => $id ], 201);
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -11,7 +11,6 @@ class TestsController extends BaseController
{ {
use ResponseTrait; use ResponseTrait;
protected $db;
protected $model; protected $model;
protected $modelCal; protected $modelCal;
protected $modelGrp; protected $modelGrp;
@ -23,7 +22,6 @@ class TestsController extends BaseController
public function __construct() public function __construct()
{ {
$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->modelGrp = new \App\Models\Test\TestDefGrpModel; $this->modelGrp = new \App\Models\Test\TestDefGrpModel;
@ -81,9 +79,7 @@ class TestsController extends BaseController
return $this->failValidationErrors('TestSiteID is required'); return $this->failValidationErrors('TestSiteID is required');
} }
$row = $this->model->select('testdefsite.*') $row = $this->model->getTestById($id);
->where('testdefsite.TestSiteID', $id)
->find($id);
if (!$row) { if (!$row) {
return $this->respond([ return $this->respond([
@ -93,25 +89,14 @@ class TestsController extends BaseController
], 200); ], 200);
} }
$row = ValueSet::transformLabels([$row], [
'TestType' => 'test_type',
])[0];
$typeCode = $row['TestType'] ?? ''; $typeCode = $row['TestType'] ?? '';
if ($typeCode === 'CALC') { if ($typeCode === 'CALC') {
$row['testdefcal'] = $this->modelCal->getByTestSiteID($id); $row['testdefcal'] = $this->modelCal->getByTestSiteID($id);
} elseif ($typeCode === 'GROUP') { } elseif ($typeCode === 'GROUP') {
$row['testdefgrp'] = $this->modelGrp->getGroupMembers($id); $row['testdefgrp'] = $this->modelGrp->getGroupMembers($id);
} elseif ($typeCode === 'TITLE') { } elseif ($typeCode !== 'TITLE') {
} else { $row['testdeftech'] = $this->model->getTestTechWithRelations($id);
$row['testdeftech'] = $this->db->table('testdefsite')
->select('testdefsite.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID=testdefsite.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID=testdefsite.DepartmentID', 'left')
->where('testdefsite.TestSiteID', $id)
->where('testdefsite.EndDate IS NULL')
->get()->getResultArray();
if (!empty($row['testdeftech'])) { if (!empty($row['testdeftech'])) {
$techData = $row['testdeftech'][0]; $techData = $row['testdeftech'][0];
@ -119,47 +104,11 @@ class TestsController extends BaseController
$resultType = $techData['ResultType'] ?? ''; $resultType = $techData['ResultType'] ?? '';
if (TestValidationService::usesRefNum($resultType, $refType)) { if (TestValidationService::usesRefNum($resultType, $refType)) {
$refnumData = $this->modelRefNum->getActiveByTestSiteID($id); $row['refnum'] = $this->modelRefNum->getFormattedByTestSiteID($id);
$row['refnum'] = array_map(function ($r) {
return [
'RefNumID' => $r['RefNumID'],
'NumRefType' => $r['NumRefType'],
'NumRefTypeLabel' => $r['NumRefType'] ? ValueSet::getLabel('numeric_ref_type', $r['NumRefType']) : '',
'RangeType' => $r['RangeType'],
'RangeTypeLabel' => $r['RangeType'] ? ValueSet::getLabel('range_type', $r['RangeType']) : '',
'Sex' => $r['Sex'],
'SexLabel' => $r['Sex'] ? ValueSet::getLabel('gender', $r['Sex']) : '',
'LowSign' => $r['LowSign'],
'LowSignLabel' => $r['LowSign'] ? ValueSet::getLabel('math_sign', $r['LowSign']) : '',
'HighSign' => $r['HighSign'],
'HighSignLabel' => $r['HighSign'] ? ValueSet::getLabel('math_sign', $r['HighSign']) : '',
'High' => $r['High'] !== null ? (float) $r['High'] : null,
'Low' => $r['Low'] !== null ? (float) $r['Low'] : null,
'AgeStart' => (int) $r['AgeStart'],
'AgeEnd' => (int) $r['AgeEnd'],
'Flag' => $r['Flag'],
'Interpretation' => $r['Interpretation'],
];
}, $refnumData ?? []);
} }
if (TestValidationService::usesRefTxt($resultType, $refType)) { if (TestValidationService::usesRefTxt($resultType, $refType)) {
$reftxtData = $this->modelRefTxt->getActiveByTestSiteID($id); $row['reftxt'] = $this->modelRefTxt->getFormattedByTestSiteID($id);
$row['reftxt'] = array_map(function ($r) {
return [
'RefTxtID' => $r['RefTxtID'],
'TxtRefType' => $r['TxtRefType'],
'TxtRefTypeLabel'=> $r['TxtRefType'] ? ValueSet::getLabel('text_ref_type', $r['TxtRefType']) : '',
'Sex' => $r['Sex'],
'SexLabel' => $r['Sex'] ? ValueSet::getLabel('gender', $r['Sex']) : '',
'AgeStart' => (int) $r['AgeStart'],
'AgeEnd' => (int) $r['AgeEnd'],
'RefTxt' => $r['RefTxt'],
'Flag' => $r['Flag'],
];
}, $reftxtData ?? []);
} }
} }
} }
@ -199,7 +148,8 @@ class TestsController extends BaseController
} }
} }
$this->db->transStart(); $db = \Config\Database::connect();
$db->transStart();
try { try {
$testSiteData = [ $testSiteData = [
@ -225,9 +175,9 @@ class TestsController extends BaseController
$this->handleDetails($id, $input, 'insert'); $this->handleDetails($id, $input, 'insert');
$this->db->transComplete(); $db->transComplete();
if ($this->db->transStatus() === false) { if ($db->transStatus() === false) {
return $this->failServerError('Transaction failed'); return $this->failServerError('Transaction failed');
} }
@ -237,7 +187,7 @@ class TestsController extends BaseController
'data' => ['TestSiteId' => $id], 'data' => ['TestSiteId' => $id],
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->db->transRollback(); $db->transRollback();
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
@ -279,7 +229,8 @@ class TestsController extends BaseController
} }
} }
$this->db->transStart(); $db = \Config\Database::connect();
$db->transStart();
try { try {
$testSiteData = []; $testSiteData = [];
@ -310,9 +261,9 @@ class TestsController extends BaseController
$this->handleDetails($id, $input, 'update'); $this->handleDetails($id, $input, 'update');
$this->db->transComplete(); $db->transComplete();
if ($this->db->transStatus() === false) { if ($db->transStatus() === false) {
return $this->failServerError('Transaction failed'); return $this->failServerError('Transaction failed');
} }
@ -322,7 +273,7 @@ class TestsController extends BaseController
'data' => ['TestSiteId' => $id], 'data' => ['TestSiteId' => $id],
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->db->transRollback(); $db->transRollback();
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
@ -348,7 +299,8 @@ class TestsController extends BaseController
return $this->failValidationErrors('Test is already disabled'); return $this->failValidationErrors('Test is already disabled');
} }
$this->db->transStart(); $db = \Config\Database::connect();
$db->transStart();
try { try {
$now = date('Y-m-d H:i:s'); $now = date('Y-m-d H:i:s');
@ -363,8 +315,8 @@ class TestsController extends BaseController
} elseif (TestValidationService::isGroup($typeCode)) { } elseif (TestValidationService::isGroup($typeCode)) {
$this->modelGrp->disableByTestSiteID($id); $this->modelGrp->disableByTestSiteID($id);
} elseif (TestValidationService::isTechnicalTest($typeCode)) { } elseif (TestValidationService::isTechnicalTest($typeCode)) {
$this->modelRefNum->where('TestSiteID', $id)->set('EndDate', $now)->update(); $this->modelRefNum->disableByTestSiteID($id);
$this->modelRefTxt->where('TestSiteID', $id)->set('EndDate', $now)->update(); $this->modelRefTxt->disableByTestSiteID($id);
} }
// Disable testmap by test code // Disable testmap by test code
@ -372,17 +324,14 @@ class TestsController extends BaseController
if ($testSiteCode) { if ($testSiteCode) {
$existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode); $existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode);
foreach ($existingMaps as $existingMap) { foreach ($existingMaps as $existingMap) {
$this->modelMapDetail->where('TestMapID', $existingMap['TestMapID']) $this->modelMapDetail->disableByTestMapID($existingMap['TestMapID']);
->where('EndDate', null)
->set('EndDate', $now)
->update();
$this->modelMap->update($existingMap['TestMapID'], ['EndDate' => $now]); $this->modelMap->update($existingMap['TestMapID'], ['EndDate' => $now]);
} }
} }
$this->db->transComplete(); $db->transComplete();
if ($this->db->transStatus() === false) { if ($db->transStatus() === false) {
return $this->failServerError('Transaction failed'); return $this->failServerError('Transaction failed');
} }
@ -392,7 +341,7 @@ class TestsController extends BaseController
'data' => ['TestSiteId' => $id, 'EndDate' => $now], 'data' => ['TestSiteId' => $id, 'EndDate' => $now],
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
$this->db->transRollback(); $db->transRollback();
return $this->failServerError('Something went wrong: ' . $e->getMessage()); return $this->failServerError('Something went wrong: ' . $e->getMessage());
} }
@ -488,53 +437,19 @@ class TestsController extends BaseController
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID) private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
{ {
if ($action === 'update') { if ($action === 'update') {
$this->modelRefNum->where('TestSiteID', $testSiteID) $this->modelRefNum->disableByTestSiteID($testSiteID);
->set('EndDate', date('Y-m-d H:i:s'))
->update();
} }
foreach ($ranges as $index => $range) { $this->modelRefNum->batchInsert($testSiteID, $siteID, $ranges);
$this->modelRefNum->insert([
'TestSiteID' => $testSiteID,
'SiteID' => $siteID,
'NumRefType' => $range['NumRefType'],
'RangeType' => $range['RangeType'],
'Sex' => $range['Sex'],
'AgeStart' => (int) ($range['AgeStart'] ?? 0),
'AgeEnd' => (int) ($range['AgeEnd'] ?? 150),
'LowSign' => !empty($range['LowSign']) ? $range['LowSign'] : null,
'Low' => !empty($range['Low']) ? (float) $range['Low'] : null,
'HighSign' => !empty($range['HighSign']) ? $range['HighSign'] : null,
'High' => !empty($range['High']) ? (float) $range['High'] : null,
'Flag' => $range['Flag'] ?? null,
'Interpretation'=> $range['Interpretation'] ?? null,
'Display' => $index,
'CreateDate' => date('Y-m-d H:i:s'),
]);
}
} }
private function saveRefTxtRanges($testSiteID, $ranges, $action, $siteID) private function saveRefTxtRanges($testSiteID, $ranges, $action, $siteID)
{ {
if ($action === 'update') { if ($action === 'update') {
$this->modelRefTxt->where('TestSiteID', $testSiteID) $this->modelRefTxt->disableByTestSiteID($testSiteID);
->set('EndDate', date('Y-m-d H:i:s'))
->update();
} }
foreach ($ranges as $range) { $this->modelRefTxt->batchInsert($testSiteID, $siteID, $ranges);
$this->modelRefTxt->insert([
'TestSiteID' => $testSiteID,
'SiteID' => $siteID,
'TxtRefType' => $range['TxtRefType'],
'Sex' => $range['Sex'],
'AgeStart' => (int) ($range['AgeStart'] ?? 0),
'AgeEnd' => (int) ($range['AgeEnd'] ?? 150),
'RefTxt' => $range['RefTxt'] ?? '',
'Flag' => $range['Flag'] ?? null,
'CreateDate' => date('Y-m-d H:i:s'),
]);
}
} }
private function saveCalcDetails($testSiteID, $data, $action) private function saveCalcDetails($testSiteID, $data, $action)
@ -595,10 +510,7 @@ class TestsController extends BaseController
$existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode); $existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode);
foreach ($existingMaps as $existingMap) { foreach ($existingMaps as $existingMap) {
$this->modelMapDetail->where('TestMapID', $existingMap['TestMapID']) $this->modelMapDetail->disableByTestMapID($existingMap['TestMapID']);
->where('EndDate', null)
->set('EndDate', date('Y-m-d H:i:s'))
->update();
} }
// Soft delete the testmap headers // Soft delete the testmap headers

View File

@ -36,6 +36,7 @@ class CreateLookups extends Migration {
'CounterValue' => ['type' => 'INT', 'null' => false], 'CounterValue' => ['type' => 'INT', 'null' => false],
'CounterStart' => ['type' => 'INT', 'null' => false], 'CounterStart' => ['type' => 'INT', 'null' => false],
'CounterEnd' => ['type' => 'INT', 'null' => false], 'CounterEnd' => ['type' => 'INT', 'null' => false],
'CounterName' => [ 'type' => 'VARCHAR', 'constraint' => 50, 'null' => true, 'after' => 'CounterID' ],
'CounterDesc' => ['type' => 'varchar', 'constraint' => 255, 'null' => true], 'CounterDesc' => ['type' => 'varchar', 'constraint' => 255, 'null' => true],
'CounterReset' => ['type' => 'varchar', 'constraint' => 1, 'null' => true], 'CounterReset' => ['type' => 'varchar', 'constraint' => 1, 'null' => true],
'CreateDate' => ['type' => 'Datetime', 'null' => true], 'CreateDate' => ['type' => 'Datetime', 'null' => true],

View File

@ -31,12 +31,13 @@ class CreateOrganization extends Migration {
$this->forge->addField([ $this->forge->addField([
'SiteID' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true], 'SiteID' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
'SiteCode' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => false], 'ExtSiteID' => ['type' => 'int', 'null' => true],
'SiteCode' => ['type' => 'VARCHAR', 'constraint' => 2, 'null' => false],
'SiteName' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => false], 'SiteName' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => false],
'AccountID' => ['type' => 'int', 'null' => true], 'AccountID' => ['type' => 'int', 'null' => true],
'SiteTypeID' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true], 'SiteType' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
'Parent' => ['type' => 'int', 'null' => true], 'Parent' => ['type' => 'int', 'null' => true],
'SiteClassID' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true], 'SiteClass' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
'ME' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true], 'ME' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
'CreateDate' => ['type' => 'datetime', 'null'=> true], 'CreateDate' => ['type' => 'datetime', 'null'=> true],
'EndDate' => ['type' => 'datetime', 'null'=> true] 'EndDate' => ['type' => 'datetime', 'null'=> true]
@ -81,6 +82,8 @@ class CreateOrganization extends Migration {
'DisciplineCode' => ['type' => 'varchar', 'constraint'=> 10, 'null'=> false], 'DisciplineCode' => ['type' => 'varchar', 'constraint'=> 10, 'null'=> false],
'DisciplineName' => ['type' => 'varchar', 'constraint'=> 150, 'null'=> true], 'DisciplineName' => ['type' => 'varchar', 'constraint'=> 150, 'null'=> true],
'Parent' => ['type' => 'int', 'null'=> true], 'Parent' => ['type' => 'int', 'null'=> true],
'SeqScr' => ['type' => 'int', 'null' => true],
'SeqRpt' => ['type' => 'int', 'null' => true],
'CreateDate' => ['type'=>'DATETIME', 'null' => true], 'CreateDate' => ['type'=>'DATETIME', 'null' => true],
'EndDate' => ['type'=>'DATETIME', 'null' => true] 'EndDate' => ['type'=>'DATETIME', 'null' => true]
]); ]);

View File

@ -20,25 +20,25 @@ class OrganizationSeeder extends Seeder
$this->db->table('account')->insertBatch($data); $this->db->table('account')->insertBatch($data);
$data = [ $data = [
[ 'SiteID' => 1, 'SiteCode' => 'QSIT', 'SiteName' => 'Dummy Site', 'AccountID' => 1, 'Parent' => null, 'CreateDate' => "$now" ], [ 'SiteID' => 1, 'SiteCode' => 'Q1', 'SiteName' => 'Dummy Site', 'AccountID' => 1, 'Parent' => null, 'CreateDate' => "$now" ],
[ 'SiteID' => 2, 'SiteCode' => 'XSIT', 'SiteName' => 'Dummy Child Site', 'AccountID' => 1, 'Parent' => 1, 'CreateDate' => "$now" ], [ 'SiteID' => 2, 'SiteCode' => 'X1', 'SiteName' => 'Dummy Child Site', 'AccountID' => 1, 'Parent' => 1, 'CreateDate' => "$now" ],
]; ];
$this->db->table('site')->insertBatch($data); $this->db->table('site')->insertBatch($data);
$data = [ $data = [
['DisciplineID' => '1', 'DisciplineCode' => 'HEMA', 'DisciplineName' => 'Hematology', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '1', 'DisciplineCode' => 'HEMA', 'DisciplineName' => 'Hematology', 'Parent' => null, 'SeqScr' => 10, 'SeqRpt' => 10, 'CreateDate' => "$now"],
['DisciplineID' => '2', 'DisciplineCode' => 'CHEM', 'DisciplineName' => 'Clinical Chemistry', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '2', 'DisciplineCode' => 'CHEM', 'DisciplineName' => 'Clinical Chemistry', 'Parent' => null, 'SeqScr' => 20, 'SeqRpt' => 20, 'CreateDate' => "$now"],
['DisciplineID' => '3', 'DisciplineCode' => 'IMSR', 'DisciplineName' => 'Immunology/Serology', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '3', 'DisciplineCode' => 'IMSR', 'DisciplineName' => 'Immunology/Serology', 'Parent' => null, 'SeqScr' => 30, 'SeqRpt' => 30, 'CreateDate' => "$now"],
['DisciplineID' => '4', 'DisciplineCode' => 'URIN', 'DisciplineName' => 'Urinalysis', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '4', 'DisciplineCode' => 'URIN', 'DisciplineName' => 'Urinalysis', 'Parent' => null, 'SeqScr' => 40, 'SeqRpt' => 40, 'CreateDate' => "$now"],
['DisciplineID' => '5', 'DisciplineCode' => 'FECAL', 'DisciplineName' => 'Fecal Analysis', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '5', 'DisciplineCode' => 'FECAL', 'DisciplineName' => 'Fecal Analysis', 'Parent' => null, 'SeqScr' => 50, 'SeqRpt' => 50, 'CreateDate' => "$now"],
['DisciplineID' => '6', 'DisciplineCode' => 'HC', 'DisciplineName' => 'Pathology/Cytology', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '6', 'DisciplineCode' => 'HC', 'DisciplineName' => 'Pathology/Cytology', 'Parent' => null, 'SeqScr' => 60, 'SeqRpt' => 60, 'CreateDate' => "$now"],
['DisciplineID' => '7', 'DisciplineCode' => 'MICRO', 'DisciplineName' => 'Microbiology', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '7', 'DisciplineCode' => 'MICRO', 'DisciplineName' => 'Microbiology', 'Parent' => null, 'SeqScr' => 70, 'SeqRpt' => 70, 'CreateDate' => "$now"],
['DisciplineID' => '8', 'DisciplineCode' => 'TXC', 'DisciplineName' => 'Toxicology', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '8', 'DisciplineCode' => 'TXC', 'DisciplineName' => 'Toxicology', 'Parent' => null, 'SeqScr' => 80, 'SeqRpt' => 80, 'CreateDate' => "$now"],
['DisciplineID' => '9', 'DisciplineCode' => 'LF', 'DisciplineName' => 'Life Sciences', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '9', 'DisciplineCode' => 'LF', 'DisciplineName' => 'Life Sciences', 'Parent' => null, 'SeqScr' => 90, 'SeqRpt' => 90, 'CreateDate' => "$now"],
['DisciplineID' => '10', 'DisciplineCode' => 'ND', 'DisciplineName' => 'Non-discipline', 'Parent' => null, 'CreateDate' => "$now"], ['DisciplineID' => '10', 'DisciplineCode' => 'ND', 'DisciplineName' => 'Non-discipline', 'Parent' => null, 'SeqScr' => 100, 'SeqRpt' => 100, 'CreateDate' => "$now"],
['DisciplineID' => '11', 'DisciplineCode' => 'HEMO', 'DisciplineName' => 'Hemostasis', 'Parent' => '1', 'CreateDate' => "$now"], ['DisciplineID' => '11', 'DisciplineCode' => 'HEMO', 'DisciplineName' => 'Hemostasis', 'Parent' => '1', 'SeqScr' => 15, 'SeqRpt' => 15, 'CreateDate' => "$now"],
['DisciplineID' => '12', 'DisciplineCode' => 'BLGLU', 'DisciplineName' => 'Blood Glucose', 'Parent' => '2', 'CreateDate' => "$now"], ['DisciplineID' => '12', 'DisciplineCode' => 'BLGLU', 'DisciplineName' => 'Blood Glucose', 'Parent' => '2', 'SeqScr' => 25, 'SeqRpt' => 25, 'CreateDate' => "$now"],
['DisciplineID' => '13', 'DisciplineCode' => 'KIDF', 'DisciplineName' => 'Kidney Function', 'Parent' => '2', 'CreateDate' => "$now"], ['DisciplineID' => '13', 'DisciplineCode' => 'KIDF', 'DisciplineName' => 'Kidney Function', 'Parent' => '2', 'SeqScr' => 26, 'SeqRpt' => 26, 'CreateDate' => "$now"],
]; ];
$this->db->table('discipline')->insertBatch($data); $this->db->table('discipline')->insertBatch($data);

View File

@ -65,128 +65,51 @@ class TestSeeder extends Seeder
}; };
// ======================================== // ========================================
// TEST TYPE - Actual Laboratory Tests // DEPARTMENT 1 - HEMATOLOGY (Discipline 1)
// Order: GROUP (<100) → PARAM (<100) → TEST (100+) → CALC (100+)
// ======================================== // ========================================
// Hematology Tests - Technical details merged into testdefsite
$data = ['SiteID' => '1', 'TestSiteCode' => 'HB', 'TestSiteName' => 'Hemoglobin', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '2', 'SeqRpt' => '2', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'g/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; // GROUP: CBC (Complete Blood Count)
$data = ['SiteID' => '1', 'TestSiteCode' => 'CBC', 'TestSiteName' => 'Complete Blood Count', 'TestType' => 'GROUP', 'Description' => 'Darah Lengkap', 'SeqScr' => '10', 'SeqRpt' => '10', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['CBC'] = $this->db->insertID();
// PARAM: (none for Hematology)
// TEST: Hematology Tests
$data = ['SiteID' => '1', 'TestSiteCode' => 'HB', 'TestSiteName' => 'Hemoglobin', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '100', 'SeqRpt' => '100', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => '%', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'HCT', 'TestSiteName' => 'Hematocrit', 'TestType' => 'TEST', 'Description' => '', 'SeqScr' => '110', 'SeqRpt' => '110', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^6/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '2', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'RBC', 'TestSiteName' => 'Red Blood Cell', 'TestType' => 'TEST', 'Description' => 'Eritrosit', 'SeqScr' => '120', 'SeqRpt' => '120', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^3/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '2', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'WBC', 'TestSiteName' => 'White Blood Cell', 'TestType' => 'TEST', 'Description' => 'Leukosit', 'SeqScr' => '130', 'SeqRpt' => '130', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'x10^3/uL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'PLT', 'TestSiteName' => 'Platelet', 'TestType' => 'TEST', 'Description' => 'Trombosit', 'SeqScr' => '140', 'SeqRpt' => '140', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'fL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'MCV', 'TestSiteName' => 'MCV', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Volume', 'SeqScr' => '150', 'SeqRpt' => '150', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'pg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'MCH', 'TestSiteName' => 'MCH', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Hemoglobin', 'SeqScr' => '160', 'SeqRpt' => '160', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '500', 'ReqQtyUnit' => 'uL', 'Unit1' => 'g/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'CBC Analyzer', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'MCHC', 'TestSiteName' => 'MCHC', 'TestType' => 'TEST', 'Description' => 'Mean Corpuscular Hemoglobin Concentration', 'SeqScr' => '170', 'SeqRpt' => '170', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '1', 'DepartmentID' => '1', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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();
// Chemistry Tests // Add CBC members now that tests are defined
$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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '0.0555', 'Unit2' => 'mmol/L', 'Decimal' => '0', 'Method' => 'Hexokinase', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['GLU'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '88.4', 'Unit2' => 'umol/L', 'Decimal' => '2', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['CREA'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Urease-GLDH', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['UREA'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['SGOT'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['SGPT'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['CHOL'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'GPO-PAP', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['TG'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['HDL'] = $this->db->insertID();
$data = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['LDL'] = $this->db->insertID();
// ========================================
// 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', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'cm', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['HEIGHT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'WEIGHT', 'TestSiteName' => 'Weight', 'TestType' => 'PARAM', 'Description' => 'Berat Badan', 'SeqScr' => '41', 'SeqRpt' => '41', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'kg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['WEIGHT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'AGE', 'TestSiteName' => 'Age', 'TestType' => 'PARAM', 'Description' => 'Usia', 'SeqScr' => '42', 'SeqRpt' => '42', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'years', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['AGE'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'SYSTL', 'TestSiteName' => 'Systolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Sistolik', 'SeqScr' => '43', 'SeqRpt' => '43', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['SYSTL'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'DIASTL', 'TestSiteName' => 'Diastolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Diastolik', 'SeqScr' => '44', 'SeqRpt' => '44', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['DIASTL'] = $this->db->insertID();
// ========================================
// CALC TYPE - Calculated Tests
// ========================================
$data = ['SiteID' => '1', 'TestSiteCode' => 'BMI', 'TestSiteName' => 'Body Mass Index', 'TestType' => 'CALC', 'Description' => 'Indeks Massa Tubuh - weight/(height^2)', 'SeqScr' => '45', 'SeqRpt' => '45', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['BMI'] = $this->db->insertID();
$data = ['TestSiteID' => $tIDs['BMI'], 'DisciplineID' => '10', 'DepartmentID' => '', 'FormulaInput' => 'WEIGHT,HEIGHT', 'FormulaCode' => 'WEIGHT / ((HEIGHT/100) * (HEIGHT/100))', 'RefType' => 'RANGE', 'Unit1' => 'kg/m2', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'CreateDate' => "$now"];
$this->db->table('testdefcal')->insert($data);
$data = ['SiteID' => '1', 'TestSiteCode' => 'EGFR', 'TestSiteName' => 'eGFR (CKD-EPI)', 'TestType' => 'CALC', 'Description' => 'Estimated Glomerular Filtration Rate', 'SeqScr' => '20', 'SeqRpt' => '20', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['EGFR'] = $this->db->insertID();
$data = ['TestSiteID' => $tIDs['EGFR'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'FormulaInput' => 'CREA,AGE,GENDER', 'FormulaCode' => 'CKD_EPI(CREA,AGE,GENDER)', 'RefType' => 'RANGE', 'Unit1' => 'mL/min/1.73m2', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefcal')->insert($data);
$data = ['SiteID' => '1', 'TestSiteCode' => 'LDLCALC', 'TestSiteName' => 'LDL Cholesterol (Calculated)', 'TestType' => 'CALC', 'Description' => 'Friedewald formula: TC - HDL - (TG/5)', 'SeqScr' => '21', 'SeqRpt' => '21', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['LDLCALC'] = $this->db->insertID();
$data = ['TestSiteID' => $tIDs['LDLCALC'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'FormulaInput' => 'CHOL,HDL,TG', 'FormulaCode' => 'CHOL - HDL - (TG/5)', 'RefType' => 'RANGE', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefcal')->insert($data);
// ========================================
// GROUP TYPE - Panel/Profile Tests
// ========================================
$data = ['SiteID' => '1', 'TestSiteCode' => 'CBC', 'TestSiteName' => 'Complete Blood Count', 'TestType' => 'GROUP', 'Description' => 'Darah Lengkap', 'SeqScr' => '50', 'SeqRpt' => '50', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['CBC'] = $this->db->insertID();
$this->db->table('testdefgrp')->insertBatch([ $this->db->table('testdefgrp')->insertBatch([
['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['HB'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['HB'], 'CreateDate' => "$now"],
['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['HCT'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['HCT'], 'CreateDate' => "$now"],
@ -198,9 +121,79 @@ class TestSeeder extends Seeder
['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['MCHC'], 'CreateDate' => "$now"] ['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['MCHC'], 'CreateDate' => "$now"]
]); ]);
$data = ['SiteID' => '1', 'TestSiteCode' => 'LIPID', 'TestSiteName' => 'Lipid Profile', 'TestType' => 'GROUP', 'Description' => 'Profil Lipid', 'SeqScr' => '51', 'SeqRpt' => '51', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"]; // CALC: (none for Hematology)
// ========================================
// DEPARTMENT 2 - CHEMISTRY (Discipline 2)
// Order: GROUP (<100) → PARAM (<100) → TEST (100+) → CALC (100+)
// ========================================
// GROUP: LIPID, LFT, RFT
$data = ['SiteID' => '1', 'TestSiteCode' => 'LIPID', 'TestSiteName' => 'Lipid Profile', 'TestType' => 'GROUP', 'Description' => 'Profil Lipid', 'SeqScr' => '10', 'SeqRpt' => '10', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data); $this->db->table('testdefsite')->insert($data);
$tIDs['LIPID'] = $this->db->insertID(); $tIDs['LIPID'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'LFT', 'TestSiteName' => 'Liver Function Test', 'TestType' => 'GROUP', 'Description' => 'Fungsi Hati', 'SeqScr' => '20', 'SeqRpt' => '20', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['LFT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'RFT', 'TestSiteName' => 'Renal Function Test', 'TestType' => 'GROUP', 'Description' => 'Fungsi Ginjal', 'SeqScr' => '30', 'SeqRpt' => '30', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['RFT'] = $this->db->insertID();
// PARAM: (none for Chemistry)
// TEST: Chemistry Tests
$data = ['SiteID' => '1', 'TestSiteCode' => 'GLU', 'TestSiteName' => 'Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Sewaktu', 'SeqScr' => '100', 'SeqRpt' => '100', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '0.0555', 'Unit2' => 'mmol/L', 'Decimal' => '0', 'Method' => 'Hexokinase', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['GLU'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'CREA', 'TestSiteName' => 'Creatinine', 'TestType' => 'TEST', 'Description' => 'Kreatinin', 'SeqScr' => '110', 'SeqRpt' => '110', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '88.4', 'Unit2' => 'umol/L', 'Decimal' => '2', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['CREA'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'UREA', 'TestSiteName' => 'Blood Urea Nitrogen', 'TestType' => 'TEST', 'Description' => 'BUN', 'SeqScr' => '120', 'SeqRpt' => '120', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Urease-GLDH', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['UREA'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'SGOT', 'TestSiteName' => 'AST (SGOT)', 'TestType' => 'TEST', 'Description' => 'Aspartate Aminotransferase', 'SeqScr' => '130', 'SeqRpt' => '130', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['SGOT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'SGPT', 'TestSiteName' => 'ALT (SGPT)', 'TestType' => 'TEST', 'Description' => 'Alanine Aminotransferase', 'SeqScr' => '140', 'SeqRpt' => '140', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'U/L', 'Factor' => '0.017', 'Unit2' => 'ukat/L', 'Decimal' => '0', 'Method' => 'IFCC', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['SGPT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'CHOL', 'TestSiteName' => 'Total Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol Total', 'SeqScr' => '150', 'SeqRpt' => '150', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Enzymatic', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['CHOL'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'TG', 'TestSiteName' => 'Triglycerides', 'TestType' => 'TEST', 'Description' => 'Trigliserida', 'SeqScr' => '160', 'SeqRpt' => '160', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'GPO-PAP', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['TG'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'HDL', 'TestSiteName' => 'HDL Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol HDL', 'SeqScr' => '170', 'SeqRpt' => '170', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['HDL'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'LDL', 'TestSiteName' => 'LDL Cholesterol', 'TestType' => 'TEST', 'Description' => 'Kolesterol LDL', 'SeqScr' => '180', 'SeqRpt' => '180', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '2', 'DepartmentID' => '2', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', 'VSet' => '', 'ReqQty' => '300', 'ReqQtyUnit' => 'uL', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => 'Direct', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['LDL'] = $this->db->insertID();
// CALC: Chemistry Calculated Tests
$data = ['SiteID' => '1', 'TestSiteCode' => 'EGFR', 'TestSiteName' => 'eGFR (CKD-EPI)', 'TestType' => 'CALC', 'Description' => 'Estimated Glomerular Filtration Rate', 'SeqScr' => '190', 'SeqRpt' => '190', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['EGFR'] = $this->db->insertID();
$data = ['TestSiteID' => $tIDs['EGFR'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'FormulaInput' => 'CREA,AGE,GENDER', 'FormulaCode' => 'CKD_EPI(CREA,AGE,GENDER)', 'RefType' => 'RANGE', 'Unit1' => 'mL/min/1.73m2', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefcal')->insert($data);
$data = ['SiteID' => '1', 'TestSiteCode' => 'LDLCALC', 'TestSiteName' => 'LDL Cholesterol (Calculated)', 'TestType' => 'CALC', 'Description' => 'Friedewald formula: TC - HDL - (TG/5)', 'SeqScr' => '200', 'SeqRpt' => '200', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['LDLCALC'] = $this->db->insertID();
$data = ['TestSiteID' => $tIDs['LDLCALC'], 'DisciplineID' => '2', 'DepartmentID' => '2', 'FormulaInput' => 'CHOL,HDL,TG', 'FormulaCode' => 'CHOL - HDL - (TG/5)', 'RefType' => 'RANGE', 'Unit1' => 'mg/dL', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefcal')->insert($data);
// Add Chemistry Group members now that tests are defined
$this->db->table('testdefgrp')->insertBatch([ $this->db->table('testdefgrp')->insertBatch([
['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['CHOL'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['CHOL'], 'CreateDate' => "$now"],
['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['TG'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['TG'], 'CreateDate' => "$now"],
@ -209,48 +202,87 @@ class TestSeeder extends Seeder
['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['LDLCALC'], 'CreateDate' => "$now"] ['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['LDLCALC'], 'CreateDate' => "$now"]
]); ]);
$data = ['SiteID' => '1', 'TestSiteCode' => 'LFT', 'TestSiteName' => 'Liver Function Test', 'TestType' => 'GROUP', 'Description' => 'Fungsi Hati', 'SeqScr' => '52', 'SeqRpt' => '52', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['LFT'] = $this->db->insertID();
$this->db->table('testdefgrp')->insertBatch([ $this->db->table('testdefgrp')->insertBatch([
['TestSiteID' => $tIDs['LFT'], 'Member' => $tIDs['SGOT'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['LFT'], 'Member' => $tIDs['SGOT'], 'CreateDate' => "$now"],
['TestSiteID' => $tIDs['LFT'], 'Member' => $tIDs['SGPT'], 'CreateDate' => "$now"] ['TestSiteID' => $tIDs['LFT'], 'Member' => $tIDs['SGPT'], 'CreateDate' => "$now"]
]); ]);
$data = ['SiteID' => '1', 'TestSiteCode' => 'RFT', 'TestSiteName' => 'Renal Function Test', 'TestType' => 'GROUP', 'Description' => 'Fungsi Ginjal', 'SeqScr' => '53', 'SeqRpt' => '53', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'ResultType' => 'NORES', 'RefType' => 'NOREF', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['RFT'] = $this->db->insertID();
$this->db->table('testdefgrp')->insertBatch([ $this->db->table('testdefgrp')->insertBatch([
['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['UREA'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['UREA'], 'CreateDate' => "$now"],
['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['CREA'], 'CreateDate' => "$now"], ['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['CREA'], 'CreateDate' => "$now"],
['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['EGFR'], 'CreateDate' => "$now"] ['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['EGFR'], 'CreateDate' => "$now"]
]); ]);
// 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', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'VSET', 'VSet' => '1001', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Visual', 'CreateDate' => "$now"]; // DEPARTMENT 4 - URINALYSIS (Discipline 4)
// Order: GROUP (<100) → PARAM (<100) → TEST (100+) → CALC (100+)
// ========================================
// GROUP: (none for Urinalysis in current setup)
// PARAM: (none for Urinalysis)
// TEST: Urinalysis Tests
$data = ['SiteID' => '1', 'TestSiteCode' => 'UCOLOR', 'TestSiteName' => 'Urine Color', 'TestType' => 'TEST', 'Description' => 'Warna Urine', 'SeqScr' => '100', 'SeqRpt' => '100', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'VSET', '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 = ['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' => 'VSET', 'VSet' => '1002', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Dipstick', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'UGLUC', 'TestSiteName' => 'Urine Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Urine', 'SeqScr' => '110', 'SeqRpt' => '110', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'VSET', '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 = ['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' => 'VSET', 'VSet' => '1003', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '', 'Method' => 'Dipstick', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'UPROT', 'TestSiteName' => 'Urine Protein', 'TestType' => 'TEST', 'Description' => 'Protein Urine', 'SeqScr' => '120', 'SeqRpt' => '120', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'VSET', 'RefType' => 'VSET', '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 = ['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' => 'RANGE', 'VSet' => '', 'ReqQty' => '10', 'ReqQtyUnit' => 'mL', 'Unit1' => '', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => 'Dipstick', 'CreateDate' => "$now"]; $data = ['SiteID' => '1', 'TestSiteCode' => 'PH', 'TestSiteName' => 'Urine pH', 'TestType' => 'TEST', 'Description' => 'pH Urine', 'SeqScr' => '130', 'SeqRpt' => '130', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', 'DisciplineID' => '4', 'DepartmentID' => '4', 'ResultType' => 'NMRIC', 'RefType' => 'RANGE', '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();
// CALC: (none for Urinalysis)
// ========================================
// DEPARTMENT 10 - GENERAL (Discipline 10)
// Order: GROUP (<100) → PARAM (<100) → TEST (100+) → CALC (100+)
// ========================================
// GROUP: (none for General)
// PARAM: General Parameters (< 100)
$data = ['SiteID' => '1', 'TestSiteCode' => 'HEIGHT', 'TestSiteName' => 'Height', 'TestType' => 'PARAM', 'Description' => 'Tinggi Badan', 'SeqScr' => '10', 'SeqRpt' => '10', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'cm', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['HEIGHT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'WEIGHT', 'TestSiteName' => 'Weight', 'TestType' => 'PARAM', 'Description' => 'Berat Badan', 'SeqScr' => '20', 'SeqRpt' => '20', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'kg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['WEIGHT'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'AGE', 'TestSiteName' => 'Age', 'TestType' => 'PARAM', 'Description' => 'Usia', 'SeqScr' => '30', 'SeqRpt' => '30', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'years', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['AGE'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'SYSTL', 'TestSiteName' => 'Systolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Sistolik', 'SeqScr' => '40', 'SeqRpt' => '40', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['SYSTL'] = $this->db->insertID();
$data = ['SiteID' => '1', 'TestSiteCode' => 'DIASTL', 'TestSiteName' => 'Diastolic BP', 'TestType' => 'PARAM', 'Description' => 'Tekanan Darah Diastolik', 'SeqScr' => '50', 'SeqRpt' => '50', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '0', 'CountStat' => '0', 'DisciplineID' => '10', 'DepartmentID' => '', 'ResultType' => 'NMRIC', 'RefType' => '', 'VSet' => '', 'ReqQty' => '', 'ReqQtyUnit' => '', 'Unit1' => 'mmHg', 'Factor' => '', 'Unit2' => '', 'Decimal' => '0', 'Method' => '', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['DIASTL'] = $this->db->insertID();
// TEST: (none for General)
// CALC: BMI (>= 100)
$data = ['SiteID' => '1', 'TestSiteCode' => 'BMI', 'TestSiteName' => 'Body Mass Index', 'TestType' => 'CALC', 'Description' => 'Indeks Massa Tubuh - weight/(height^2)', 'SeqScr' => '100', 'SeqRpt' => '100', 'IndentLeft' => '0', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '0', 'CreateDate' => "$now"];
$this->db->table('testdefsite')->insert($data);
$tIDs['BMI'] = $this->db->insertID();
$data = ['TestSiteID' => $tIDs['BMI'], 'DisciplineID' => '10', 'DepartmentID' => '', 'FormulaInput' => 'WEIGHT,HEIGHT', 'FormulaCode' => 'WEIGHT / ((HEIGHT/100) * (HEIGHT/100))', 'RefType' => 'RANGE', 'Unit1' => 'kg/m2', 'Factor' => '', 'Unit2' => '', 'Decimal' => '1', 'CreateDate' => "$now"];
$this->db->table('testdefcal')->insert($data);
// ======================================== // ========================================
// TEST MAP - Specimen Mapping // TEST MAP - Specimen Mapping
// Maps tests to workstations and containers
// New structure: testmap (header) + testmapdetail (details)
// ======================================== // ========================================
// Get container IDs (inserted by SpecimenSeeder in order) // Get container IDs (inserted by SpecimenSeeder in order)
// ConCode order: 1, 11, 12, 13, 14, 15, 16, 20, 101, 150, 200, 290, 295, 900
$conSST = 1; // SST (Serum Separator Tube) $conSST = 1; // SST (Serum Separator Tube)
$conEDTA = 9; // EDTA - Hematology $conEDTA = 9; // EDTA - Hematology
$conCitrate = 10; // Citrate - Koagulasi $conCitrate = 10; // Citrate - Koagulasi
@ -299,10 +331,7 @@ class TestSeeder extends Seeder
]; ];
}; };
// ============================================ // Test mappings configuration
// TEST MAP CONFIGURATION
// Grouped by discipline for maintainability
// ============================================
$testMappings = [ $testMappings = [
// Hematology: Site → HAUTO → Sysmex (EDTA) // Hematology: Site → HAUTO → Sysmex (EDTA)
[ [
@ -347,7 +376,7 @@ class TestSeeder extends Seeder
$entityInst = $this->getEntityType('INST') ?? 'INST'; $entityInst = $this->getEntityType('INST') ?? 'INST';
foreach ($testMappings as $mapping) { foreach ($testMappings as $mapping) {
// Site → Workstation mapping (one header per workstation) // Site → Workstation mapping
$testMapSiteWsID = $getTestMapID($entitySite, '1', $entityWst, (string)$mapping['siteToWs']['ws']); $testMapSiteWsID = $getTestMapID($entitySite, '1', $entityWst, (string)$mapping['siteToWs']['ws']);
foreach ($mapping['tests'] as $testCode) { foreach ($mapping['tests'] as $testCode) {
$addDetail($testMapSiteWsID, $testCode, $testCode, $mapping['siteToWs']['con'], $testCode, $testCode); $addDetail($testMapSiteWsID, $testCode, $testCode, $mapping['siteToWs']['con'], $testCode, $testCode);
@ -356,7 +385,7 @@ class TestSeeder extends Seeder
$addDetail($testMapSiteWsID, $panelCode, $panelCode, $mapping['siteToWs']['con'], $panelCode, $panelCode); $addDetail($testMapSiteWsID, $panelCode, $panelCode, $mapping['siteToWs']['con'], $panelCode, $panelCode);
} }
// Workstation → Instrument mapping (one header per instrument) // Workstation → Instrument mapping
if ($mapping['wsToInst'] !== null) { if ($mapping['wsToInst'] !== null) {
$testMapWsInstID = $getTestMapID($entityWst, (string)$mapping['wsToInst']['ws'], $entityInst, (string)$mapping['wsToInst']['inst']); $testMapWsInstID = $getTestMapID($entityWst, (string)$mapping['wsToInst']['ws'], $entityInst, (string)$mapping['wsToInst']['inst']);
foreach ($mapping['tests'] as $testCode) { foreach ($mapping['tests'] as $testCode) {

View File

@ -5,7 +5,7 @@ use App\Models\BaseModel;
class CounterModel extends BaseModel { class CounterModel extends BaseModel {
protected $table = 'counter'; protected $table = 'counter';
protected $primaryKey = 'CounterID'; protected $primaryKey = 'CounterID';
protected $allowedFields = ['CounterValue', 'CounterStart', 'CounterEnd', 'CounterReset', 'CreateDate', 'EndDate']; protected $allowedFields = ['CounterValue', 'CounterStart', 'CounterEnd', 'CounterReset', 'CounterName', 'CreateDate', 'EndDate'];
protected $useTimestamps = true; protected $useTimestamps = true;
protected $createdField = "CreateDate"; protected $createdField = "CreateDate";

View File

@ -60,7 +60,7 @@ class OrderTestModel extends BaseModel {
$this->db->transStart(); $this->db->transStart();
try { try {
$orderID = $data['OrderID'] ?? $this->generateOrderID($data['SiteCode'] ?? '00'); $orderID = !empty($data['OrderID']) ? $data['OrderID'] : $this->generateOrderID($data['SiteCode'] ?? '00');
$orderData = [ $orderData = [
'OrderID' => $orderID, 'OrderID' => $orderID,

View File

@ -5,7 +5,7 @@ use App\Models\BaseModel;
class DisciplineModel extends BaseModel { class DisciplineModel extends BaseModel {
protected $table = 'discipline'; protected $table = 'discipline';
protected $primaryKey = 'DisciplineID'; protected $primaryKey = 'DisciplineID';
protected $allowedFields = ['DisciplineCode', 'DisciplineName', 'SiteID', 'Parent', 'CreateDate', 'EndDate']; protected $allowedFields = ['DisciplineCode', 'DisciplineName', 'SiteID', 'Parent', 'SeqScr', 'SeqRpt', 'CreateDate', 'EndDate'];
protected $useTimestamps = true; protected $useTimestamps = true;
protected $createdField = 'CreateDate'; protected $createdField = 'CreateDate';
@ -15,7 +15,7 @@ class DisciplineModel extends BaseModel {
public function getDisciplines($filter) { public function getDisciplines($filter) {
$builder = $this->select('discipline.DisciplineID, discipline.DisciplineCode, discipline.DisciplineName, discipline.SiteID, $builder = $this->select('discipline.DisciplineID, discipline.DisciplineCode, discipline.DisciplineName, discipline.SiteID,
discipline.Parent, d.DisciplineCode as ParentCode,d.DisciplineName as ParentName') discipline.Parent, discipline.SeqScr, discipline.SeqRpt, d.DisciplineCode as ParentCode,d.DisciplineName as ParentName')
->join('discipline as d', 'd.DisciplineID = discipline.Parent', 'left'); ->join('discipline as d', 'd.DisciplineID = discipline.Parent', 'left');
if (!empty($filter['DisciplineCode'])) { if (!empty($filter['DisciplineCode'])) {

View File

@ -6,7 +6,7 @@ use App\Libraries\ValueSet;
class SiteModel extends BaseModel { class SiteModel extends BaseModel {
protected $table = 'site'; protected $table = 'site';
protected $primaryKey = 'SiteID'; protected $primaryKey = 'SiteID';
protected $allowedFields = ['SiteCode', 'SiteName', 'AccountID', 'SiteTypeID', 'Parent', 'SiteClassID', 'ME', protected $allowedFields = ['SiteCode', 'ExtSiteID', 'SiteName', 'AccountID', 'SiteType', 'Parent', 'SiteClass', 'ME',
'CreateDate', 'EndDate']; 'CreateDate', 'EndDate'];
protected $useTimestamps = true; protected $useTimestamps = true;

View File

@ -46,4 +46,82 @@ class RefNumModel extends BaseModel
->orderBy('Display', 'ASC') ->orderBy('Display', 'ASC')
->findAll(); ->findAll();
} }
/**
* Get formatted numeric reference ranges with labels
*
* @param int $testSiteID
* @return array
*/
public function getFormattedByTestSiteID($testSiteID)
{
$rows = $this->getActiveByTestSiteID($testSiteID);
return array_map(function ($r) {
return [
'RefNumID' => $r['RefNumID'],
'NumRefType' => $r['NumRefType'],
'NumRefTypeLabel' => $r['NumRefType'] ? \App\Libraries\ValueSet::getLabel('numeric_ref_type', $r['NumRefType']) : '',
'RangeType' => $r['RangeType'],
'RangeTypeLabel' => $r['RangeType'] ? \App\Libraries\ValueSet::getLabel('range_type', $r['RangeType']) : '',
'Sex' => $r['Sex'],
'SexLabel' => $r['Sex'] ? \App\Libraries\ValueSet::getLabel('gender', $r['Sex']) : '',
'LowSign' => $r['LowSign'],
'LowSignLabel' => $r['LowSign'] ? \App\Libraries\ValueSet::getLabel('math_sign', $r['LowSign']) : '',
'HighSign' => $r['HighSign'],
'HighSignLabel' => $r['HighSign'] ? \App\Libraries\ValueSet::getLabel('math_sign', $r['HighSign']) : '',
'High' => $r['High'] !== null ? (float) $r['High'] : null,
'Low' => $r['Low'] !== null ? (float) $r['Low'] : null,
'AgeStart' => (int) $r['AgeStart'],
'AgeEnd' => (int) $r['AgeEnd'],
'Flag' => $r['Flag'],
'Interpretation' => $r['Interpretation'],
];
}, $rows ?? []);
}
/**
* Disable all numeric reference ranges for a test
*
* @param int $testSiteID
* @return void
*/
public function disableByTestSiteID($testSiteID)
{
$this->where('TestSiteID', $testSiteID)
->set('EndDate', date('Y-m-d H:i:s'))
->update();
}
/**
* Batch insert numeric reference ranges
*
* @param int $testSiteID
* @param int $siteID
* @param array $ranges
* @return void
*/
public function batchInsert($testSiteID, $siteID, $ranges)
{
foreach ($ranges as $index => $range) {
$this->insert([
'TestSiteID' => $testSiteID,
'SiteID' => $siteID,
'NumRefType' => $range['NumRefType'],
'RangeType' => $range['RangeType'],
'Sex' => $range['Sex'],
'AgeStart' => (int) ($range['AgeStart'] ?? 0),
'AgeEnd' => (int) ($range['AgeEnd'] ?? 150),
'LowSign' => !empty($range['LowSign']) ? $range['LowSign'] : null,
'Low' => !empty($range['Low']) ? (float) $range['Low'] : null,
'HighSign' => !empty($range['HighSign']) ? $range['HighSign'] : null,
'High' => !empty($range['High']) ? (float) $range['High'] : null,
'Flag' => $range['Flag'] ?? null,
'Interpretation'=> $range['Interpretation'] ?? null,
'Display' => $index,
'CreateDate' => date('Y-m-d H:i:s'),
]);
}
}
} }

View File

@ -40,4 +40,68 @@ class RefTxtModel extends BaseModel
->orderBy('RefTxtID', 'ASC') ->orderBy('RefTxtID', 'ASC')
->findAll(); ->findAll();
} }
/**
* Get formatted text reference ranges with labels
*
* @param int $testSiteID
* @return array
*/
public function getFormattedByTestSiteID($testSiteID)
{
$rows = $this->getActiveByTestSiteID($testSiteID);
return array_map(function ($r) {
return [
'RefTxtID' => $r['RefTxtID'],
'TxtRefType' => $r['TxtRefType'],
'TxtRefTypeLabel'=> $r['TxtRefType'] ? \App\Libraries\ValueSet::getLabel('text_ref_type', $r['TxtRefType']) : '',
'Sex' => $r['Sex'],
'SexLabel' => $r['Sex'] ? \App\Libraries\ValueSet::getLabel('gender', $r['Sex']) : '',
'AgeStart' => (int) $r['AgeStart'],
'AgeEnd' => (int) $r['AgeEnd'],
'RefTxt' => $r['RefTxt'],
'Flag' => $r['Flag'],
];
}, $rows ?? []);
}
/**
* Disable all text reference ranges for a test
*
* @param int $testSiteID
* @return void
*/
public function disableByTestSiteID($testSiteID)
{
$this->where('TestSiteID', $testSiteID)
->set('EndDate', date('Y-m-d H:i:s'))
->update();
}
/**
* Batch insert text reference ranges
*
* @param int $testSiteID
* @param int $siteID
* @param array $ranges
* @return void
*/
public function batchInsert($testSiteID, $siteID, $ranges)
{
foreach ($ranges as $range) {
$this->insert([
'TestSiteID' => $testSiteID,
'SiteID' => $siteID,
'TxtRefType' => $range['TxtRefType'],
'Sex' => $range['Sex'],
'AgeStart' => (int) ($range['AgeStart'] ?? 0),
'AgeEnd' => (int) ($range['AgeEnd'] ?? 150),
'RefTxt' => $range['RefTxt'] ?? '',
'Flag' => $range['Flag'] ?? null,
'CreateDate' => date('Y-m-d H:i:s'),
]);
}
}
} }

View File

@ -11,6 +11,8 @@ class TestDefGrpModel extends BaseModel {
protected $allowedFields = [ protected $allowedFields = [
'TestSiteID', 'TestSiteID',
'Member', 'Member',
'SeqScr',
'SeqRpt',
'CreateDate', 'CreateDate',
'EndDate' 'EndDate'
]; ];
@ -25,10 +27,12 @@ class TestDefGrpModel extends BaseModel {
$db = \Config\Database::connect(); $db = \Config\Database::connect();
$rows = $db->table('testdefgrp') $rows = $db->table('testdefgrp')
->select('testdefgrp.*, t.TestSiteID as MemberTestSiteID, t.TestSiteCode, t.TestSiteName, t.TestType') ->select('t.TestSiteID as TestSiteID, t.TestSiteCode, t.TestSiteName, t.TestType, t.SeqScr, t. SeqRpt')
->join('testdefsite t', 't.TestSiteID=testdefgrp.Member', 'left') ->join('testdefsite t', 't.TestSiteID=testdefgrp.Member', 'left')
->where('testdefgrp.TestSiteID', $testSiteID) ->where('testdefgrp.TestSiteID', $testSiteID)
->where('testdefgrp.EndDate IS NULL') ->where('testdefgrp.EndDate IS NULL')
->orderBy('t.SeqScr', 'ASC')
->orderBy('t.SeqRpt', 'ASC')
->orderBy('testdefgrp.TestGrpID', 'ASC') ->orderBy('testdefgrp.TestGrpID', 'ASC')
->get()->getResultArray(); ->get()->getResultArray();

View File

@ -158,17 +158,8 @@ class TestDefSiteModel extends BaseModel {
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']); $row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
} elseif (TestValidationService::isGroup($typeCode)) { } elseif (TestValidationService::isGroup($typeCode)) {
$row['testdefgrp'] = $db->table('testdefgrp') $testDefGrpModel = new \App\Models\Test\TestDefGrpModel();
->select('testdefgrp.*, t.TestSiteID as MemberTestSiteID, t.TestSiteCode, t.TestSiteName, t.TestType') $row['testdefgrp'] = $testDefGrpModel->getGroupMembers($TestSiteID);
->join('testdefsite t', 't.TestSiteID=testdefgrp.Member', 'left')
->where('testdefgrp.TestSiteID', $TestSiteID)
->where('testdefgrp.EndDate IS NULL')
->orderBy('testdefgrp.TestGrpID', 'ASC')
->get()->getResultArray();
$row['testdefgrp'] = ValueSet::transformLabels($row['testdefgrp'], [
'TestType' => 'test_type',
]);
$testMapModel = new \App\Models\Test\TestMapModel(); $testMapModel = new \App\Models\Test\TestMapModel();
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']); $row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
@ -230,4 +221,45 @@ class TestDefSiteModel extends BaseModel {
{ {
return TestValidationService::getReferenceTable($resultType, $refType); return TestValidationService::getReferenceTable($resultType, $refType);
} }
/**
* Get test by ID with ValueSet transformation
*
* @param int $id
* @return array|null
*/
public function getTestById($id)
{
$row = $this->select('testdefsite.*')
->where('testdefsite.TestSiteID', $id)
->find($id);
if (!$row) {
return null;
}
$rows = ValueSet::transformLabels([$row], [
'TestType' => 'test_type',
]);
return $rows[0];
}
/**
* Get technical test with discipline and department relations
*
* @param int $testSiteID
* @return array
*/
public function getTestTechWithRelations($testSiteID)
{
return $this->db->table('testdefsite')
->select('testdefsite.*, d.DisciplineName, dept.DepartmentName')
->join('discipline d', 'd.DisciplineID=testdefsite.DisciplineID', 'left')
->join('department dept', 'dept.DepartmentID=testdefsite.DepartmentID', 'left')
->where('testdefsite.TestSiteID', $testSiteID)
->where('testdefsite.EndDate IS NULL')
->get()
->getResultArray();
}
} }

View File

@ -50,4 +50,19 @@ class TestMapDetailModel extends BaseModel {
->where('EndDate IS NULL') ->where('EndDate IS NULL')
->findAll(); ->findAll();
} }
/**
* Disable all details for a test map
*
* @param int $testMapID
* @return void
*/
public function disableByTestMapID($testMapID)
{
$this->where('TestMapID', $testMapID)
->where('EndDate', null)
->set('EndDate', date('Y-m-d H:i:s'))
->update();
}
} }

View File

@ -5519,6 +5519,8 @@ components:
type: string type: string
SiteCode: SiteCode:
type: string type: string
maxLength: 2
pattern: ^[A-Z0-9]{2}$
AccountID: AccountID:
type: integer type: integer
Discipline: Discipline:

View File

@ -19,6 +19,8 @@ Site:
type: string type: string
SiteCode: SiteCode:
type: string type: string
maxLength: 2
pattern: '^[A-Z0-9]{2}$'
AccountID: AccountID:
type: integer type: integer
@ -31,6 +33,12 @@ Discipline:
type: string type: string
DisciplineCode: DisciplineCode:
type: string type: string
SeqScr:
type: integer
description: Display order on screen
SeqRpt:
type: integer
description: Display order in reports
Department: Department:
type: object type: object

View File

@ -150,6 +150,12 @@
type: string type: string
DisciplineCode: DisciplineCode:
type: string type: string
SeqScr:
type: integer
description: Display order on screen
SeqRpt:
type: integer
description: Display order in reports
responses: responses:
'200': '200':
description: Discipline updated description: Discipline updated