Update site controller, organization & test models, migrations, and API docs
This commit is contained in:
parent
011a2456c2
commit
ad8e1cc977
97
.serena/memories/code_conventions.md
Normal file
97
.serena/memories/code_conventions.md
Normal 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`
|
||||
@ -1,55 +1,54 @@
|
||||
# CLQMS Project Overview
|
||||
|
||||
## 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
|
||||
- Patient registration and management
|
||||
- Laboratory test ordering and tracking
|
||||
- Specimen lifecycle management (collection → transport → reception → prep → analysis)
|
||||
- Result entry with reference range validation
|
||||
- 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
|
||||
## Architecture
|
||||
- **API-First**: No view layer, headless REST API only
|
||||
- **Stateless**: JWT-based authentication per request
|
||||
- **UTC Dates**: All dates stored in UTC, converted for display
|
||||
- **PSR-4 Autoloading**: `App\` → `app/`, `Config\` → `app/Config/`
|
||||
|
||||
### Product Vision
|
||||
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.
|
||||
## Key Directories
|
||||
```
|
||||
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 |
|
||||
|-----------|---------------|
|
||||
| **Language** | PHP 8.1+ (PSR-compliant) |
|
||||
| **Framework** | CodeIgniter 4 (API-only mode) |
|
||||
| **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 |
|
||||
tests/
|
||||
feature/ # Feature/integration tests
|
||||
unit/ # Unit tests
|
||||
_support/ # Test support files
|
||||
```
|
||||
|
||||
### Key Dependencies
|
||||
- `codeigniter4/framework` - Main framework
|
||||
## Key Dependencies
|
||||
- `codeigniter4/framework` - Core framework
|
||||
- `firebase/php-jwt` - JWT authentication
|
||||
- `fakerphp/faker` - Test data generation
|
||||
- `phpunit/phpunit` - Unit/feature testing
|
||||
|
||||
## 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)
|
||||
- `fakerphp/faker` - Test data generation (dev)
|
||||
- `phpunit/phpunit` - Testing (dev)
|
||||
|
||||
@ -1,393 +1,100 @@
|
||||
# CLQMS Suggested Commands
|
||||
|
||||
## Database Commands
|
||||
|
||||
### 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
|
||||
## Testing
|
||||
```bash
|
||||
# Run all tests
|
||||
vendor/bin/phpunit
|
||||
./vendor/bin/phpunit
|
||||
|
||||
# Run specific test file (IMPORTANT for debugging)
|
||||
vendor/bin/phpunit tests/feature/UniformShowTest.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 file
|
||||
./vendor/bin/phpunit tests/feature/Patients/PatientCreateTest.php
|
||||
|
||||
# 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
|
||||
```bash
|
||||
# Generate new model
|
||||
php spark make:model ModelName
|
||||
# Run tests by suite
|
||||
./vendor/bin/phpunit --testsuite App
|
||||
|
||||
# Generate new controller
|
||||
php spark make:controller ControllerName
|
||||
|
||||
# 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
|
||||
# Run via composer
|
||||
composer test
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
### Start Development Server
|
||||
```bash
|
||||
# Start CodeIgniter dev server (default port 8080)
|
||||
# Start PHP development server
|
||||
php spark serve
|
||||
|
||||
# Start on specific port
|
||||
php spark serve --port=8080
|
||||
|
||||
# Start with specific host
|
||||
php spark serve --host=0.0.0.0
|
||||
# Or specify port
|
||||
php spark serve --port 8080
|
||||
```
|
||||
|
||||
## Cache Management
|
||||
|
||||
### Clear Caches
|
||||
## Database
|
||||
```bash
|
||||
# Clear application cache
|
||||
php spark cache:clear
|
||||
# Run migrations
|
||||
php spark migrate
|
||||
|
||||
# Show cache information
|
||||
php spark cache:info
|
||||
# Rollback migrations
|
||||
php spark migrate:rollback
|
||||
|
||||
# Clear debug bar JSON files
|
||||
php spark debugbar:clear
|
||||
# Create new migration
|
||||
php spark make:migration CreateUsersTable
|
||||
|
||||
# Clear log files
|
||||
php spark logs:clear
|
||||
# Run database seeds
|
||||
php spark db:seed DBSeeder
|
||||
php spark db:seed PatientSeeder
|
||||
```
|
||||
|
||||
## System Utilities
|
||||
|
||||
### Configuration & Environment
|
||||
## Code Generation (Scaffolding)
|
||||
```bash
|
||||
# Get current environment
|
||||
php spark env
|
||||
# Create controller
|
||||
php spark make:controller Users
|
||||
|
||||
# Set environment
|
||||
php spark env development
|
||||
# Create model
|
||||
php spark make:model UserModel
|
||||
|
||||
# Check configuration values
|
||||
php spark config:check
|
||||
# Create migration
|
||||
php spark make:migration CreateUsersTable
|
||||
|
||||
# Check php.ini values (for production)
|
||||
php spark phpini:check
|
||||
|
||||
# Verify namespaces
|
||||
php spark namespaces
|
||||
# Create seeder
|
||||
php spark make:seeder UserSeeder
|
||||
```
|
||||
|
||||
### Routes
|
||||
## API Documentation
|
||||
```bash
|
||||
# Display all routes
|
||||
php spark routes
|
||||
# After updating YAML files, regenerate bundled docs
|
||||
node public/bundle-api-docs.js
|
||||
|
||||
# Check filters for a route
|
||||
php spark filter:check
|
||||
# Produces: public/api-docs.bundled.yaml
|
||||
```
|
||||
|
||||
### Optimization
|
||||
## Utilities (Windows)
|
||||
```bash
|
||||
# Optimize for production
|
||||
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
|
||||
# List files
|
||||
dir
|
||||
|
||||
# List files with details
|
||||
dir /a
|
||||
# Search in files (PowerShell)
|
||||
Select-String -Path "app\*.php" -Pattern "PatientModel"
|
||||
|
||||
# Change directory
|
||||
cd path\to\directory
|
||||
# Or using git bash (if available)
|
||||
grep -r "PatientModel" app/
|
||||
|
||||
# Go to parent directory
|
||||
cd ..
|
||||
|
||||
# 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
|
||||
# Clear writable cache
|
||||
del /q writable\cache\*
|
||||
```
|
||||
|
||||
### File Content Operations
|
||||
## Git Commands
|
||||
```bash
|
||||
# Display file content
|
||||
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
|
||||
# Check status
|
||||
git status
|
||||
|
||||
# View changes
|
||||
git diff
|
||||
|
||||
# View staged changes
|
||||
git diff --staged
|
||||
|
||||
# Add files to staging
|
||||
# Add files
|
||||
git add .
|
||||
|
||||
# Add specific file
|
||||
git add path/to/file
|
||||
# Commit (only when explicitly asked)
|
||||
git commit -m "message"
|
||||
|
||||
# Commit changes
|
||||
git commit -m "commit message"
|
||||
|
||||
# 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
|
||||
# View recent commits
|
||||
git log --oneline -10
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
@ -1,129 +1,67 @@
|
||||
# CLQMS Task Completion Guidelines
|
||||
# CLQMS Task Completion Checklist
|
||||
|
||||
## When a Task is Completed
|
||||
|
||||
### 1. Run Tests
|
||||
Always run relevant tests after making changes:
|
||||
When completing a task, ensure:
|
||||
|
||||
## 1. Tests Pass
|
||||
```bash
|
||||
# Run all tests
|
||||
./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
|
||||
php -l app/Controllers/Patient/PatientController.php
|
||||
node public/bundle-api-docs.js
|
||||
```
|
||||
|
||||
#### Check Test Results
|
||||
Ensure:
|
||||
- All existing tests still pass
|
||||
- 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
|
||||
## 3. Code Quality Checks
|
||||
- PSR-12 compliance where applicable
|
||||
- No database queries in controllers
|
||||
- Use transactions for multi-table operations
|
||||
- Proper error handling with try-catch for JWT/external calls
|
||||
- Log errors: `log_message('error', $message)`
|
||||
|
||||
#### Date Handling
|
||||
- All dates stored in UTC
|
||||
- Use `helper('utc')` for conversions
|
||||
- BaseModel extends with automatic UTC conversion
|
||||
|
||||
#### Security
|
||||
- Input validation rules defined
|
||||
- SQL injection prevention via parameterized queries
|
||||
- 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.
|
||||
## 4. Response Format Verification
|
||||
Ensure all responses follow the standard format:
|
||||
```php
|
||||
return $this->respond([
|
||||
'status' => 'success|failed',
|
||||
'message' => 'Description',
|
||||
'data' => $data
|
||||
], $httpStatus);
|
||||
```
|
||||
|
||||
Or if tests were run:
|
||||
```
|
||||
Task completed. All tests passing:
|
||||
- testCreatePatientSuccess ✓
|
||||
- testCreatePatientValidationFail ✓
|
||||
```
|
||||
## 5. Security Checklist
|
||||
- Use `auth` filter for protected routes
|
||||
- Sanitize user inputs
|
||||
- Use parameterized queries
|
||||
- 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:
|
||||
1. Check the error message carefully
|
||||
2. Review the code against the patterns in this guide
|
||||
3. Check database connection and configuration
|
||||
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.
|
||||
## 7. Do NOT Commit Unless Explicitly Asked
|
||||
- Check status: `git status`
|
||||
- Never commit .env files
|
||||
- Never commit secrets
|
||||
|
||||
@ -125,3 +125,8 @@ language_backend:
|
||||
# list of regex patterns which, when matched, mark a memory entry as read‑only.
|
||||
# Extends the list from the global configuration, merging the two lists.
|
||||
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:
|
||||
|
||||
@ -56,6 +56,17 @@ class SiteController extends BaseController {
|
||||
|
||||
public function create() {
|
||||
$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 {
|
||||
$id = $this->model->insert($input,true);
|
||||
return $this->respondCreated([ 'status' => 'success', 'message' => 'data created successfully', 'data' => $id ], 201);
|
||||
@ -66,9 +77,22 @@ class SiteController extends BaseController {
|
||||
|
||||
public function update() {
|
||||
$input = $this->request->getJSON(true);
|
||||
try {
|
||||
|
||||
$id = $input['SiteID'];
|
||||
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);
|
||||
return $this->respondCreated([ 'status' => 'success', 'message' => 'data updated successfully', 'data' => $id ], 201);
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
@ -11,7 +11,6 @@ class TestsController extends BaseController
|
||||
{
|
||||
use ResponseTrait;
|
||||
|
||||
protected $db;
|
||||
protected $model;
|
||||
protected $modelCal;
|
||||
protected $modelGrp;
|
||||
@ -23,7 +22,6 @@ class TestsController extends BaseController
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = \Config\Database::connect();
|
||||
$this->model = new \App\Models\Test\TestDefSiteModel;
|
||||
$this->modelCal = new \App\Models\Test\TestDefCalModel;
|
||||
$this->modelGrp = new \App\Models\Test\TestDefGrpModel;
|
||||
@ -81,9 +79,7 @@ class TestsController extends BaseController
|
||||
return $this->failValidationErrors('TestSiteID is required');
|
||||
}
|
||||
|
||||
$row = $this->model->select('testdefsite.*')
|
||||
->where('testdefsite.TestSiteID', $id)
|
||||
->find($id);
|
||||
$row = $this->model->getTestById($id);
|
||||
|
||||
if (!$row) {
|
||||
return $this->respond([
|
||||
@ -93,25 +89,14 @@ class TestsController extends BaseController
|
||||
], 200);
|
||||
}
|
||||
|
||||
$row = ValueSet::transformLabels([$row], [
|
||||
'TestType' => 'test_type',
|
||||
])[0];
|
||||
|
||||
$typeCode = $row['TestType'] ?? '';
|
||||
|
||||
if ($typeCode === 'CALC') {
|
||||
$row['testdefcal'] = $this->modelCal->getByTestSiteID($id);
|
||||
} elseif ($typeCode === 'GROUP') {
|
||||
$row['testdefgrp'] = $this->modelGrp->getGroupMembers($id);
|
||||
} elseif ($typeCode === 'TITLE') {
|
||||
} else {
|
||||
$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();
|
||||
} elseif ($typeCode !== 'TITLE') {
|
||||
$row['testdeftech'] = $this->model->getTestTechWithRelations($id);
|
||||
|
||||
if (!empty($row['testdeftech'])) {
|
||||
$techData = $row['testdeftech'][0];
|
||||
@ -119,47 +104,11 @@ class TestsController extends BaseController
|
||||
$resultType = $techData['ResultType'] ?? '';
|
||||
|
||||
if (TestValidationService::usesRefNum($resultType, $refType)) {
|
||||
$refnumData = $this->modelRefNum->getActiveByTestSiteID($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 ?? []);
|
||||
$row['refnum'] = $this->modelRefNum->getFormattedByTestSiteID($id);
|
||||
}
|
||||
|
||||
if (TestValidationService::usesRefTxt($resultType, $refType)) {
|
||||
$reftxtData = $this->modelRefTxt->getActiveByTestSiteID($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 ?? []);
|
||||
$row['reftxt'] = $this->modelRefTxt->getFormattedByTestSiteID($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,7 +148,8 @@ class TestsController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->transStart();
|
||||
$db = \Config\Database::connect();
|
||||
$db->transStart();
|
||||
|
||||
try {
|
||||
$testSiteData = [
|
||||
@ -225,9 +175,9 @@ class TestsController extends BaseController
|
||||
|
||||
$this->handleDetails($id, $input, 'insert');
|
||||
|
||||
$this->db->transComplete();
|
||||
$db->transComplete();
|
||||
|
||||
if ($this->db->transStatus() === false) {
|
||||
if ($db->transStatus() === false) {
|
||||
return $this->failServerError('Transaction failed');
|
||||
}
|
||||
|
||||
@ -237,7 +187,7 @@ class TestsController extends BaseController
|
||||
'data' => ['TestSiteId' => $id],
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->db->transRollback();
|
||||
$db->transRollback();
|
||||
|
||||
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 {
|
||||
$testSiteData = [];
|
||||
@ -310,9 +261,9 @@ class TestsController extends BaseController
|
||||
|
||||
$this->handleDetails($id, $input, 'update');
|
||||
|
||||
$this->db->transComplete();
|
||||
$db->transComplete();
|
||||
|
||||
if ($this->db->transStatus() === false) {
|
||||
if ($db->transStatus() === false) {
|
||||
return $this->failServerError('Transaction failed');
|
||||
}
|
||||
|
||||
@ -322,7 +273,7 @@ class TestsController extends BaseController
|
||||
'data' => ['TestSiteId' => $id],
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->db->transRollback();
|
||||
$db->transRollback();
|
||||
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
@ -348,7 +299,8 @@ class TestsController extends BaseController
|
||||
return $this->failValidationErrors('Test is already disabled');
|
||||
}
|
||||
|
||||
$this->db->transStart();
|
||||
$db = \Config\Database::connect();
|
||||
$db->transStart();
|
||||
|
||||
try {
|
||||
$now = date('Y-m-d H:i:s');
|
||||
@ -363,8 +315,8 @@ class TestsController extends BaseController
|
||||
} elseif (TestValidationService::isGroup($typeCode)) {
|
||||
$this->modelGrp->disableByTestSiteID($id);
|
||||
} elseif (TestValidationService::isTechnicalTest($typeCode)) {
|
||||
$this->modelRefNum->where('TestSiteID', $id)->set('EndDate', $now)->update();
|
||||
$this->modelRefTxt->where('TestSiteID', $id)->set('EndDate', $now)->update();
|
||||
$this->modelRefNum->disableByTestSiteID($id);
|
||||
$this->modelRefTxt->disableByTestSiteID($id);
|
||||
}
|
||||
|
||||
// Disable testmap by test code
|
||||
@ -372,17 +324,14 @@ class TestsController extends BaseController
|
||||
if ($testSiteCode) {
|
||||
$existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode);
|
||||
foreach ($existingMaps as $existingMap) {
|
||||
$this->modelMapDetail->where('TestMapID', $existingMap['TestMapID'])
|
||||
->where('EndDate', null)
|
||||
->set('EndDate', $now)
|
||||
->update();
|
||||
$this->modelMapDetail->disableByTestMapID($existingMap['TestMapID']);
|
||||
$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');
|
||||
}
|
||||
|
||||
@ -392,7 +341,7 @@ class TestsController extends BaseController
|
||||
'data' => ['TestSiteId' => $id, 'EndDate' => $now],
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->db->transRollback();
|
||||
$db->transRollback();
|
||||
|
||||
return $this->failServerError('Something went wrong: ' . $e->getMessage());
|
||||
}
|
||||
@ -488,53 +437,19 @@ class TestsController extends BaseController
|
||||
private function saveRefNumRanges($testSiteID, $ranges, $action, $siteID)
|
||||
{
|
||||
if ($action === 'update') {
|
||||
$this->modelRefNum->where('TestSiteID', $testSiteID)
|
||||
->set('EndDate', date('Y-m-d H:i:s'))
|
||||
->update();
|
||||
$this->modelRefNum->disableByTestSiteID($testSiteID);
|
||||
}
|
||||
|
||||
foreach ($ranges as $index => $range) {
|
||||
$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'),
|
||||
]);
|
||||
}
|
||||
$this->modelRefNum->batchInsert($testSiteID, $siteID, $ranges);
|
||||
}
|
||||
|
||||
private function saveRefTxtRanges($testSiteID, $ranges, $action, $siteID)
|
||||
{
|
||||
if ($action === 'update') {
|
||||
$this->modelRefTxt->where('TestSiteID', $testSiteID)
|
||||
->set('EndDate', date('Y-m-d H:i:s'))
|
||||
->update();
|
||||
$this->modelRefTxt->disableByTestSiteID($testSiteID);
|
||||
}
|
||||
|
||||
foreach ($ranges as $range) {
|
||||
$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'),
|
||||
]);
|
||||
}
|
||||
$this->modelRefTxt->batchInsert($testSiteID, $siteID, $ranges);
|
||||
}
|
||||
|
||||
private function saveCalcDetails($testSiteID, $data, $action)
|
||||
@ -595,10 +510,7 @@ class TestsController extends BaseController
|
||||
$existingMaps = $this->modelMap->getMappingsByTestCode($testSiteCode);
|
||||
|
||||
foreach ($existingMaps as $existingMap) {
|
||||
$this->modelMapDetail->where('TestMapID', $existingMap['TestMapID'])
|
||||
->where('EndDate', null)
|
||||
->set('EndDate', date('Y-m-d H:i:s'))
|
||||
->update();
|
||||
$this->modelMapDetail->disableByTestMapID($existingMap['TestMapID']);
|
||||
}
|
||||
|
||||
// Soft delete the testmap headers
|
||||
|
||||
@ -36,6 +36,7 @@ class CreateLookups extends Migration {
|
||||
'CounterValue' => ['type' => 'INT', 'null' => false],
|
||||
'CounterStart' => ['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],
|
||||
'CounterReset' => ['type' => 'varchar', 'constraint' => 1, 'null' => true],
|
||||
'CreateDate' => ['type' => 'Datetime', 'null' => true],
|
||||
|
||||
@ -31,12 +31,13 @@ class CreateOrganization extends Migration {
|
||||
|
||||
$this->forge->addField([
|
||||
'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],
|
||||
'AccountID' => ['type' => 'int', 'null' => true],
|
||||
'SiteTypeID' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
|
||||
'SiteType' => ['type' => 'VARCHAR', 'constraint' => 10, '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],
|
||||
'CreateDate' => ['type' => 'datetime', 'null'=> true],
|
||||
'EndDate' => ['type' => 'datetime', 'null'=> true]
|
||||
@ -81,6 +82,8 @@ class CreateOrganization extends Migration {
|
||||
'DisciplineCode' => ['type' => 'varchar', 'constraint'=> 10, 'null'=> false],
|
||||
'DisciplineName' => ['type' => 'varchar', 'constraint'=> 150, 'null'=> true],
|
||||
'Parent' => ['type' => 'int', 'null'=> true],
|
||||
'SeqScr' => ['type' => 'int', 'null' => true],
|
||||
'SeqRpt' => ['type' => 'int', 'null' => true],
|
||||
'CreateDate' => ['type'=>'DATETIME', 'null' => true],
|
||||
'EndDate' => ['type'=>'DATETIME', 'null' => true]
|
||||
]);
|
||||
|
||||
@ -20,25 +20,25 @@ class OrganizationSeeder extends Seeder
|
||||
$this->db->table('account')->insertBatch($data);
|
||||
|
||||
$data = [
|
||||
[ 'SiteID' => 1, 'SiteCode' => 'QSIT', 'SiteName' => 'Dummy Site', 'AccountID' => 1, 'Parent' => null, 'CreateDate' => "$now" ],
|
||||
[ 'SiteID' => 2, 'SiteCode' => 'XSIT', 'SiteName' => 'Dummy Child Site', 'AccountID' => 1, 'Parent' => 1, 'CreateDate' => "$now" ],
|
||||
[ 'SiteID' => 1, 'SiteCode' => 'Q1', 'SiteName' => 'Dummy Site', 'AccountID' => 1, 'Parent' => null, 'CreateDate' => "$now" ],
|
||||
[ 'SiteID' => 2, 'SiteCode' => 'X1', 'SiteName' => 'Dummy Child Site', 'AccountID' => 1, 'Parent' => 1, 'CreateDate' => "$now" ],
|
||||
];
|
||||
$this->db->table('site')->insertBatch($data);
|
||||
|
||||
$data = [
|
||||
['DisciplineID' => '1', 'DisciplineCode' => 'HEMA', 'DisciplineName' => 'Hematology', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '2', 'DisciplineCode' => 'CHEM', 'DisciplineName' => 'Clinical Chemistry', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '3', 'DisciplineCode' => 'IMSR', 'DisciplineName' => 'Immunology/Serology', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '4', 'DisciplineCode' => 'URIN', 'DisciplineName' => 'Urinalysis', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '5', 'DisciplineCode' => 'FECAL', 'DisciplineName' => 'Fecal Analysis', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '6', 'DisciplineCode' => 'HC', 'DisciplineName' => 'Pathology/Cytology', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '7', 'DisciplineCode' => 'MICRO', 'DisciplineName' => 'Microbiology', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '8', 'DisciplineCode' => 'TXC', 'DisciplineName' => 'Toxicology', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '9', 'DisciplineCode' => 'LF', 'DisciplineName' => 'Life Sciences', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '10', 'DisciplineCode' => 'ND', 'DisciplineName' => 'Non-discipline', 'Parent' => null, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '11', 'DisciplineCode' => 'HEMO', 'DisciplineName' => 'Hemostasis', 'Parent' => '1', 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '12', 'DisciplineCode' => 'BLGLU', 'DisciplineName' => 'Blood Glucose', 'Parent' => '2', 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '13', 'DisciplineCode' => 'KIDF', 'DisciplineName' => 'Kidney Function', 'Parent' => '2', '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, 'SeqScr' => 20, 'SeqRpt' => 20, '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, 'SeqScr' => 40, 'SeqRpt' => 40, '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, 'SeqScr' => 60, 'SeqRpt' => 60, 'CreateDate' => "$now"],
|
||||
['DisciplineID' => '7', 'DisciplineCode' => 'MICRO', 'DisciplineName' => 'Microbiology', 'Parent' => null, 'SeqScr' => 70, 'SeqRpt' => 70, '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, 'SeqScr' => 90, 'SeqRpt' => 90, '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', 'SeqScr' => 15, 'SeqRpt' => 15, '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', 'SeqScr' => 26, 'SeqRpt' => 26, 'CreateDate' => "$now"],
|
||||
];
|
||||
$this->db->table('discipline')->insertBatch($data);
|
||||
|
||||
|
||||
@ -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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$tIDs['MCHC'] = $this->db->insertID();
|
||||
|
||||
// Chemistry Tests
|
||||
$data = ['SiteID' => '1', 'TestSiteCode' => 'GLU', 'TestSiteName' => 'Glucose', 'TestType' => 'TEST', 'Description' => 'Glukosa Sewaktu', 'SeqScr' => '11', 'SeqRpt' => '11', 'IndentLeft' => '1', 'VisibleScr' => '1', 'VisibleRpt' => '1', 'CountStat' => '1', '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();
|
||||
// Add CBC members now that tests are defined
|
||||
$this->db->table('testdefgrp')->insertBatch([
|
||||
['TestSiteID' => $tIDs['CBC'], 'Member' => $tIDs['HB'], '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"]
|
||||
]);
|
||||
|
||||
$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);
|
||||
$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([
|
||||
['TestSiteID' => $tIDs['LIPID'], 'Member' => $tIDs['CHOL'], '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"]
|
||||
]);
|
||||
|
||||
$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([
|
||||
['TestSiteID' => $tIDs['LFT'], 'Member' => $tIDs['SGOT'], '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([
|
||||
['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['UREA'], 'CreateDate' => "$now"],
|
||||
['TestSiteID' => $tIDs['RFT'], 'Member' => $tIDs['CREA'], '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);
|
||||
$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);
|
||||
$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);
|
||||
$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);
|
||||
$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
|
||||
// Maps tests to workstations and containers
|
||||
// New structure: testmap (header) + testmapdetail (details)
|
||||
// ========================================
|
||||
|
||||
// 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)
|
||||
$conEDTA = 9; // EDTA - Hematology
|
||||
$conCitrate = 10; // Citrate - Koagulasi
|
||||
@ -299,10 +331,7 @@ class TestSeeder extends Seeder
|
||||
];
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// TEST MAP CONFIGURATION
|
||||
// Grouped by discipline for maintainability
|
||||
// ============================================
|
||||
// Test mappings configuration
|
||||
$testMappings = [
|
||||
// Hematology: Site → HAUTO → Sysmex (EDTA)
|
||||
[
|
||||
@ -347,7 +376,7 @@ class TestSeeder extends Seeder
|
||||
$entityInst = $this->getEntityType('INST') ?? 'INST';
|
||||
|
||||
foreach ($testMappings as $mapping) {
|
||||
// Site → Workstation mapping (one header per workstation)
|
||||
// Site → Workstation mapping
|
||||
$testMapSiteWsID = $getTestMapID($entitySite, '1', $entityWst, (string)$mapping['siteToWs']['ws']);
|
||||
foreach ($mapping['tests'] as $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);
|
||||
}
|
||||
|
||||
// Workstation → Instrument mapping (one header per instrument)
|
||||
// Workstation → Instrument mapping
|
||||
if ($mapping['wsToInst'] !== null) {
|
||||
$testMapWsInstID = $getTestMapID($entityWst, (string)$mapping['wsToInst']['ws'], $entityInst, (string)$mapping['wsToInst']['inst']);
|
||||
foreach ($mapping['tests'] as $testCode) {
|
||||
|
||||
@ -5,7 +5,7 @@ use App\Models\BaseModel;
|
||||
class CounterModel extends BaseModel {
|
||||
protected $table = 'counter';
|
||||
protected $primaryKey = 'CounterID';
|
||||
protected $allowedFields = ['CounterValue', 'CounterStart', 'CounterEnd', 'CounterReset', 'CreateDate', 'EndDate'];
|
||||
protected $allowedFields = ['CounterValue', 'CounterStart', 'CounterEnd', 'CounterReset', 'CounterName', 'CreateDate', 'EndDate'];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = "CreateDate";
|
||||
|
||||
@ -60,7 +60,7 @@ class OrderTestModel extends BaseModel {
|
||||
$this->db->transStart();
|
||||
|
||||
try {
|
||||
$orderID = $data['OrderID'] ?? $this->generateOrderID($data['SiteCode'] ?? '00');
|
||||
$orderID = !empty($data['OrderID']) ? $data['OrderID'] : $this->generateOrderID($data['SiteCode'] ?? '00');
|
||||
|
||||
$orderData = [
|
||||
'OrderID' => $orderID,
|
||||
|
||||
@ -5,7 +5,7 @@ use App\Models\BaseModel;
|
||||
class DisciplineModel extends BaseModel {
|
||||
protected $table = 'discipline';
|
||||
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 $createdField = 'CreateDate';
|
||||
@ -15,7 +15,7 @@ class DisciplineModel extends BaseModel {
|
||||
|
||||
public function getDisciplines($filter) {
|
||||
$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');
|
||||
|
||||
if (!empty($filter['DisciplineCode'])) {
|
||||
|
||||
@ -6,7 +6,7 @@ use App\Libraries\ValueSet;
|
||||
class SiteModel extends BaseModel {
|
||||
protected $table = 'site';
|
||||
protected $primaryKey = 'SiteID';
|
||||
protected $allowedFields = ['SiteCode', 'SiteName', 'AccountID', 'SiteTypeID', 'Parent', 'SiteClassID', 'ME',
|
||||
protected $allowedFields = ['SiteCode', 'ExtSiteID', 'SiteName', 'AccountID', 'SiteType', 'Parent', 'SiteClass', 'ME',
|
||||
'CreateDate', 'EndDate'];
|
||||
|
||||
protected $useTimestamps = true;
|
||||
|
||||
@ -46,4 +46,82 @@ class RefNumModel extends BaseModel
|
||||
->orderBy('Display', 'ASC')
|
||||
->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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,4 +40,68 @@ class RefTxtModel extends BaseModel
|
||||
->orderBy('RefTxtID', 'ASC')
|
||||
->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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@ class TestDefGrpModel extends BaseModel {
|
||||
protected $allowedFields = [
|
||||
'TestSiteID',
|
||||
'Member',
|
||||
'SeqScr',
|
||||
'SeqRpt',
|
||||
'CreateDate',
|
||||
'EndDate'
|
||||
];
|
||||
@ -25,10 +27,12 @@ class TestDefGrpModel extends BaseModel {
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$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')
|
||||
->where('testdefgrp.TestSiteID', $testSiteID)
|
||||
->where('testdefgrp.EndDate IS NULL')
|
||||
->orderBy('t.SeqScr', 'ASC')
|
||||
->orderBy('t.SeqRpt', 'ASC')
|
||||
->orderBy('testdefgrp.TestGrpID', 'ASC')
|
||||
->get()->getResultArray();
|
||||
|
||||
|
||||
@ -158,17 +158,8 @@ class TestDefSiteModel extends BaseModel {
|
||||
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
|
||||
|
||||
} elseif (TestValidationService::isGroup($typeCode)) {
|
||||
$row['testdefgrp'] = $db->table('testdefgrp')
|
||||
->select('testdefgrp.*, t.TestSiteID as MemberTestSiteID, t.TestSiteCode, t.TestSiteName, t.TestType')
|
||||
->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',
|
||||
]);
|
||||
$testDefGrpModel = new \App\Models\Test\TestDefGrpModel();
|
||||
$row['testdefgrp'] = $testDefGrpModel->getGroupMembers($TestSiteID);
|
||||
|
||||
$testMapModel = new \App\Models\Test\TestMapModel();
|
||||
$row['testmap'] = $testMapModel->getMappingsByTestCode($row['TestSiteCode']);
|
||||
@ -230,4 +221,45 @@ class TestDefSiteModel extends BaseModel {
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,4 +50,19 @@ class TestMapDetailModel extends BaseModel {
|
||||
->where('EndDate IS NULL')
|
||||
->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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5519,6 +5519,8 @@ components:
|
||||
type: string
|
||||
SiteCode:
|
||||
type: string
|
||||
maxLength: 2
|
||||
pattern: ^[A-Z0-9]{2}$
|
||||
AccountID:
|
||||
type: integer
|
||||
Discipline:
|
||||
|
||||
@ -19,6 +19,8 @@ Site:
|
||||
type: string
|
||||
SiteCode:
|
||||
type: string
|
||||
maxLength: 2
|
||||
pattern: '^[A-Z0-9]{2}$'
|
||||
AccountID:
|
||||
type: integer
|
||||
|
||||
@ -31,6 +33,12 @@ Discipline:
|
||||
type: string
|
||||
DisciplineCode:
|
||||
type: string
|
||||
SeqScr:
|
||||
type: integer
|
||||
description: Display order on screen
|
||||
SeqRpt:
|
||||
type: integer
|
||||
description: Display order in reports
|
||||
|
||||
Department:
|
||||
type: object
|
||||
|
||||
@ -150,6 +150,12 @@
|
||||
type: string
|
||||
DisciplineCode:
|
||||
type: string
|
||||
SeqScr:
|
||||
type: integer
|
||||
description: Display order on screen
|
||||
SeqRpt:
|
||||
type: integer
|
||||
description: Display order in reports
|
||||
responses:
|
||||
'200':
|
||||
description: Discipline updated
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user