clqms-be/app/Libraries/Lookups.php

650 lines
19 KiB
PHP
Raw Normal View History

<?php
namespace App\Libraries;
/**
* Static Lookup Values
* All predefined lookup values stored as constants for easy access.
* No database queries - all data is hardcoded.
* Based on valuesetdef and valueset tables.
*/
class Lookups {
// VSetID 1: Workstation Type
const WS_TYPE = [
'0' => 'Primary',
'1' => 'Secondary'
];
// VSetID 2: Enable/Disable
const ENABLE_DISABLE = [
'0' => 'Disabled',
'1' => 'Enabled'
];
// VSetID 3: Gender
const GENDER = [
'1' => 'Female',
'2' => 'Male',
'3' => 'Unknown'
];
// VSetID 4: Marital Status
const MARITAL_STATUS = [
'A' => 'Separated',
'D' => 'Divorced',
'M' => 'Married',
'S' => 'Single',
'W' => 'Widowed',
'B' => 'Unmarried',
'U' => 'Unknown',
'O' => 'Other'
];
// VSetID 5: Death Indicator
const DEATH_INDICATOR = [
'Y' => 'Death',
'N' => 'Life'
];
// VSetID 6: Identifier Type
const IDENTIFIER_TYPE = [
'KTP' => 'Kartu Tanda Penduduk',
'PASS' => 'Passport',
'SSN' => 'Social Security Number',
'SIM' => 'Surat Izin Mengemudi',
'KTAS' => 'Kartu Izin Tinggal Terbatas'
];
// VSetID 7: Operation (CRUD)
const OPERATION = [
'Create' => 'Create record',
'Read' => 'Read record/field',
'Update' => 'Update record/field',
'Delete' => 'Delete record/field'
];
// VSetID 8: DID Type
const DID_TYPE = [
'WDID' => 'Windows Device ID',
'AAID' => 'Android AAID',
'IDFA' => 'iOS IDFA'
];
// VSetID 9: Requested Entity
const REQUESTED_ENTITY = [
'PAT' => 'Patient',
'ISN' => 'Insurance',
'ACC' => 'Account',
'DOC' => 'Doctor'
];
// VSetID 10: Order Priority
const ORDER_PRIORITY = [
'S' => 'Stat',
'A' => 'ASAP',
'R' => 'Routine',
'P' => 'Preop',
'C' => 'Callback',
'T' => 'Timing critical',
'PRN' => 'As needed'
];
// VSetID 11: Order Status
const ORDER_STATUS = [
'A' => 'Some, not all results available',
'CA' => 'Order is cancelled',
'CM' => 'Order is completed',
'DC' => 'Order was discontinued',
'ER' => 'Error, order not found',
'HD' => 'Order on hold',
'IP' => 'In process, unspecified',
'RP' => 'Order has been replaced',
'SC' => 'In process, scheduled',
'CL' => 'Closed',
'AC' => 'Archived',
'DL' => 'Deleted'
];
// VSetID 12: Location Type
const LOCATION_TYPE = [
'FCLT' => 'Facility',
'BLDG' => 'Building',
'FLOR' => 'Floor',
'POC' => 'Point of Care',
'ROOM' => 'Room',
'BED' => 'Bed',
'MOBL' => 'Mobile',
'REMT' => 'Remote'
];
// VSetID 13: Additive
const ADDITIVE = [
'Hep' => 'Heparin ammonium',
'Apro' => 'Aprotinin',
'HepCa' => 'Heparin calcium',
'H3BO3' => 'Boric acid',
'CaOxa' => 'Calcium oxalate',
'EDTA' => 'EDTA',
'Ede' => 'Edetate',
'HCl' => 'Hydrochloric acid',
'Hrdn' => 'Hirudin',
'EdeK' => 'Edetate dipotassium',
'EdeTri' => 'Tripotassium edetate',
'LiHep' => 'Heparin lithium',
'EdeNa' => 'Edetate disodium',
'NaCtrt' => 'Sodium citrate',
'NaHep' => 'Heparin sodium',
'NaF' => 'Sodium fluoride',
'Borax' => 'Sodium tetraborate',
'Mntl' => 'Mannitol',
'NaFrm' => 'Sodium formate'
];
// VSetID 14: Container Class
const CONTAINER_CLASS = [
'Pri' => 'Primary',
'Sec' => 'Secondary',
'Ter' => 'Tertiary'
];
// VSetID 15: Specimen Type
const SPECIMEN_TYPE = [
'BLD' => 'Whole blood',
'BLDA' => 'Blood arterial',
'BLDCO' => 'Cord blood',
'FBLOOD' => 'Blood, Fetal',
'CSF' => 'Cerebral spinal fluid',
'WB' => 'Blood, Whole',
'BBL' => 'Blood bag',
'SER' => 'Serum',
'PLAS' => 'Plasma',
'PLB' => 'Plasma bag',
'MUCOS' => 'Mucosa',
'MUCUS' => 'Mucus',
'UR' => 'Urine',
'RANDU' => 'Urine, Random',
'URINM' => 'Urine, Midstream'
];
// VSetID 16: Unit
const UNIT = [
'L' => 'Liter',
'mL' => 'Mili Liter',
'Pcs' => 'Pieces'
];
// VSetID 17: Generate By
const GENERATE_BY = [
'order' => 'Generate by order',
'user' => 'Generate by user'
];
// VSetID 18: Specimen Activity
const SPECIMEN_ACTIVITY = [
'SColl' => 'Collection',
'STran' => 'Transport',
'SRec' => 'Reception',
'SPrep' => 'Preparation',
'SAlqt' => 'Aliquot',
'SDisp' => 'Dispatching',
'SDest' => 'Destruction'
];
// VSetID 19: Activity Result
const ACTIVITY_RESULT = [
'0' => 'Failed',
'1' => 'Success with note',
'2' => 'Success'
];
// VSetID 20: Specimen Status
const SPECIMEN_STATUS = [
'STC' => 'To be collected',
'SCFld' => 'Collection failed',
'SCtd' => 'Collected',
'STran' => 'In-transport',
'STFld' => 'Transport failed',
'SArrv' => 'Arrived',
'SRejc' => 'Rejected',
'SRcvd' => 'Received',
'SPAna' => 'Pre-analytical',
'SPAF' => 'Pre-analytical failed',
'STA' => 'To be analyze',
'SAFld' => 'Analytical failed',
'SAna' => 'Analytical',
'STS' => 'To be stored',
'SSFld' => 'Store failed',
'SStrd' => 'Stored',
'SExp' => 'Expired',
'STD' => 'To be destroyed',
'SDFld' => 'Failed to destroy',
'SDstd' => 'Destroyed'
];
// VSetID 21: Specimen Condition
const SPECIMEN_CONDITION = [
'HEM' => 'Hemolyzed',
'ITC' => 'Icteric',
'LIP' => 'Lipemic',
'CFU' => 'Centrifuged',
'ROOM' => 'Room temperature',
'COOL' => 'Cool',
'FROZ' => 'Frozen',
'CLOT' => 'Clotted',
'AUT' => 'Autolyzed',
'CON' => 'Contaminated',
'LIVE' => 'Live'
];
// VSetID 22: Specimen Role
const SPECIMEN_ROLE = [
'P' => 'Patient',
'B' => 'Blind Sample',
'Q' => 'Control specimen',
'E' => 'Electronic QC',
'F' => 'Filler Organization Proficiency',
'O' => 'Operator Proficiency',
'C' => 'Calibrator',
'R' => 'Replicate',
'V' => 'Verifying Calibrator'
];
// VSetID 23: Collection Method
const COLLECTION_METHOD = [
'pcntr' => 'Puncture',
'fprk' => 'Finger-prick sampling',
'ucct' => 'Urine specimen collection, clean catch',
'utcl' => 'Timed urine collection',
'ucth' => 'Urine specimen collection, catheterized',
'scgh' => 'Collection of coughed sputum',
'bpsy' => 'Biopsy',
'aspn' => 'Aspiration',
'excs' => 'Excision',
'scrp' => 'Scraping'
];
// VSetID 24: Body Site
const BODY_SITE = [
'LA' => 'Left Arm',
'RA' => 'Right Arm',
'LF' => 'Left Foot',
'RF' => 'Right Foot'
];
// VSetID 25: Container Size
const CONTAINER_SIZE = [
'5ml' => '5 mL',
'7ml' => '7 mL',
'10ml' => '10 mL',
'1l' => '1 L'
];
// VSetID 26: Fasting Status
const FASTING_STATUS = [
'F' => 'Fasting',
'NF' => 'Not Fasting',
'NG' => 'Not Given'
];
// VSetID 27: Test Type
const TEST_TYPE = [
'TEST' => 'Test',
'PARAM' => 'Parameter',
'CALC' => 'Calculated Test',
'GROUP' => 'Group Test',
'TITLE' => 'Title'
];
// VSetID 28: Result Unit
const RESULT_UNIT = [
'g/dL' => 'g/dL',
'g/L' => 'g/L',
'mg/dL' => 'mg/dL',
'mg/L' => 'mg/L',
'L/L' => 'L/L',
'x106/mL' => 'x106/mL',
'x1012/L' => 'x1012/L',
'fL' => 'fL',
'pg' => 'pg',
'x109/L' => 'x109/L'
];
// VSetID 29: Formula Language
const FORMULA_LANGUAGE = [
'Phyton' => 'Phyton',
'CQL' => 'Clinical Quality Language',
'FHIRP' => 'FHIRPath',
'SQL' => 'SQL'
];
// VSetID 30: Race (Ethnicity)
const RACE = [
'JAWA' => 'Jawa',
'SUNDA' => 'Sunda',
'BATAK' => 'Batak',
'SULOR' => 'Suku asal Sulawesi lainnya',
'MDRA' => 'Madura',
'BTWI' => 'Betawi',
'MNG' => 'Minangkabau',
'BUGIS' => 'Bugis',
'MLYU' => 'Melayu',
'SUMSL' => 'Suku asal Sumatera Selatan',
'BTNOR' => 'Suku asal Banten',
'NTTOR' => 'Suku asal Nusa Tenggara Timur',
'BNJAR' => 'Banjar',
'ACEH' => 'Aceh',
'BALI' => 'Bali',
'SASAK' => 'Sasak',
'DAYAK' => 'Dayak',
'TNGHA' => 'Tionghoa',
'PPAOR' => 'Suku asal Papua',
'MKSSR' => 'Makassar',
'SUMOR' => 'Suku asal Sumatera lainnya',
'MLKOR' => 'Suku asal Maluku',
'KLMOR' => 'Suku asal Kalimantan lainnya',
'CRBON' => 'Cirebon',
'JBIOR' => 'Suku asal Jambi',
'LPGOR' => 'Suku Lampung',
'NTBOR' => 'Suku asal Nusa Tenggara Barat lainnya',
'GRTLO' => 'Gorontalo',
'MNHSA' => 'Minahasa',
'NIAS' => 'Nias',
'FORGN' => 'Asing/luar negeri'
];
// VSetID 31: Religion
const RELIGION = [
'ISLAM' => 'Islam',
'KRSTN' => 'Kristen',
'KTLIK' => 'Katolik',
'HINDU' => 'Hindu',
'BUDHA' => 'Budha',
'KHCU' => 'Khong Hu Cu',
'OTHER' => 'Lainnya'
];
// VSetID 32: Ethnic
const ETHNIC = [
'PPMLN' => 'Papua Melanezoid',
'NGRID' => 'Negroid',
'WDOID' => 'Weddoid',
'MMPM' => 'Melayu Mongoloid_Proto Melayu',
'MMDM' => 'Melayu Mongoloid_Deutro Melayu',
'TNGHA' => 'Tionghoa',
'INDIA' => 'India',
'ARAB' => 'Arab'
];
// VSetID 33: Country (ISO 2-letter codes - ISO 3166-1 alpha-2)
const COUNTRY = null; // Loaded from external file
/**
* Get COUNTRY data from external file (lazy load)
*/
private static function loadCountryData(): array {
$file = APPPATH . 'Libraries/Data/Countries.php';
if (is_file($file)) {
return require $file;
}
return [];
}
/**
* Get formatted country list
*/
public static function getCountry(): array {
return self::format(self::loadCountryData());
}
// VSetID 34: Container Cap Color
const CONTAINER_CAP_COLOR = [
'PRPL' => 'Purple',
'RED' => 'Red',
'YLLW' => 'Yellow',
'GRN' => 'Green',
'PINK' => 'Pink',
'LBLU' => 'Light Blue',
'RBLU' => 'Royal Blue',
'GRAY' => 'Gray'
];
// VSetID 35: Test Activity
const TEST_ACTIVITY = [
'ORD' => 'Order',
'ANA' => 'Analyse',
'VER' => 'Result Verification/Technical Validation',
'REV' => 'Clinical Review/Clinical Validation',
'REP' => 'Reporting'
];
// VSetID 36: ADT Event
const ADT_EVENT = [
'A01' => 'Admit',
'A02' => 'Transfer',
'A03' => 'Discharge',
'A04' => 'Register',
'A08' => 'Update patient information',
'A11' => 'Cancel admit',
'A12' => 'Cancel transfer',
'A13' => 'Cancel discharge',
'A23' => 'Delete patient record',
'A24' => 'Link patient information',
'A37' => 'Unlink patient information',
'A54' => 'Change attending doctor',
'A61' => 'Change consulting doctor'
];
// VSetID 37: Site Type
const SITE_TYPE = [
'GH' => 'Government Hospital',
'PH' => 'Private Hospital',
'GHL' => 'Government Hospital Lab',
'PHL' => 'Private Hospital Lab',
'GL' => 'Government Lab',
'PL' => 'Private Lab'
];
// VSetID 38: Site Class
const SITE_CLASS = [
'A' => 'Kelas A',
'B' => 'Kelas B',
'C' => 'Kelas C',
'D' => 'Kelas D',
'Utm' => 'Utama',
'Ptm' => 'Pratama'
];
// VSetID 39: Entity Type
const ENTITY_TYPE = [
'HIS' => 'HIS',
'SITE' => 'Site',
'WST' => 'Workstation',
'INST' => 'Equipment/Instrument'
];
// VSetID 40: Area Class
const AREA_CLASS = [
'PROP' => 'Propinsi',
'KAB' => 'Kabupaten',
'KOTA' => 'Kota'
];
// VSetID 41: Math Sign
const MATH_SIGN = [
'=' => 'Equal',
'<' => 'Less than',
'>' => 'Greater than',
'<=' => 'Less than or equal to',
'>=' => 'Greater than or equal to'
];
// VSetID 42: VCategory
const V_CATEGORY = [
'0' => 'System',
'1' => 'User-defined'
];
// VSetID 43: Result Type
const RESULT_TYPE = [
'NMRIC' => 'Numeric',
'RANGE' => 'Range',
'TEXT' => 'Text',
'VSET' => 'Value set'
];
// VSetID 44: Reference Type
const REFERENCE_TYPE = [
'NMRC' => 'Numeric',
'TEXT' => 'Text'
];
// VSetID 45: Range Type
const RANGE_TYPE = [
'REF' => 'Reference Range',
'CRTC' => 'Critical Range',
'VAL' => 'Validation Range',
'RERUN' => 'Rerun Range'
];
// VSetID 46: Numeric Reference Type
const NUMERIC_REF_TYPE = [
'RANGE' => 'Range',
'THOLD' => 'Threshold'
];
// VSetID 47: Text Reference Type
const TEXT_REF_TYPE = [
'VSET' => 'Value Set',
'TEXT' => 'Text'
];
// Convenience constants (aliases for common use cases)
const PRIORITY = self::ORDER_PRIORITY;
const TEST_STATUS = [
'PENDING' => 'Waiting for Results',
'IN_PROCESS' => 'Analyzing',
'VERIFIED' => 'Verified & Signed',
'REJECTED' => 'Sample Rejected'
];
const REQUEST_STATUS = self::SPECIMEN_STATUS;
const RESULT_STATUS = [
'PRELIMINARY' => 'Preliminary',
'FINAL' => 'Final',
'CORRECTED' => 'Corrected',
'CANCELLED' => 'Cancelled'
];
/**
* Get all lookups formatted for frontend
* @return array
*/
public static function getAll(): array {
return [
'ws_type' => self::format(self::WS_TYPE),
'enable_disable' => self::format(self::ENABLE_DISABLE),
'gender' => self::format(self::GENDER),
'marital_status' => self::format(self::MARITAL_STATUS),
'death_indicator' => self::format(self::DEATH_INDICATOR),
'identifier_type' => self::format(self::IDENTIFIER_TYPE),
'operation' => self::format(self::OPERATION),
'did_type' => self::format(self::DID_TYPE),
'requested_entity' => self::format(self::REQUESTED_ENTITY),
'order_priority' => self::format(self::ORDER_PRIORITY),
'order_status' => self::format(self::ORDER_STATUS),
'location_type' => self::format(self::LOCATION_TYPE),
'additive' => self::format(self::ADDITIVE),
'container_class' => self::format(self::CONTAINER_CLASS),
'specimen_type' => self::format(self::SPECIMEN_TYPE),
'unit' => self::format(self::UNIT),
'generate_by' => self::format(self::GENERATE_BY),
'specimen_activity' => self::format(self::SPECIMEN_ACTIVITY),
'activity_result' => self::format(self::ACTIVITY_RESULT),
'specimen_status' => self::format(self::SPECIMEN_STATUS),
'specimen_condition' => self::format(self::SPECIMEN_CONDITION),
'specimen_role' => self::format(self::SPECIMEN_ROLE),
'collection_method' => self::format(self::COLLECTION_METHOD),
'body_site' => self::format(self::BODY_SITE),
'container_size' => self::format(self::CONTAINER_SIZE),
'fasting_status' => self::format(self::FASTING_STATUS),
'test_type' => self::format(self::TEST_TYPE),
'result_unit' => self::format(self::RESULT_UNIT),
'formula_language' => self::format(self::FORMULA_LANGUAGE),
'race' => self::format(self::RACE),
'religion' => self::format(self::RELIGION),
'ethnic' => self::format(self::ETHNIC),
'country' => self::getCountry(),
'container_cap_color' => self::format(self::CONTAINER_CAP_COLOR),
'test_activity' => self::format(self::TEST_ACTIVITY),
'adt_event' => self::format(self::ADT_EVENT),
'site_type' => self::format(self::SITE_TYPE),
'site_class' => self::format(self::SITE_CLASS),
'entity_type' => self::format(self::ENTITY_TYPE),
'area_class' => self::format(self::AREA_CLASS),
'math_sign' => self::format(self::MATH_SIGN),
'v_category' => self::format(self::V_CATEGORY),
'result_type' => self::format(self::RESULT_TYPE),
'reference_type' => self::format(self::REFERENCE_TYPE),
'range_type' => self::format(self::RANGE_TYPE),
'numeric_ref_type' => self::format(self::NUMERIC_REF_TYPE),
'text_ref_type' => self::format(self::TEXT_REF_TYPE)
];
}
/**
* Format associative array as [{value: 'KEY', label: 'Label'}, ...]
*/
private static function format(array $array): array {
$result = [];
foreach ($array as $key => $label) {
$result[] = ['value' => (string) $key, 'label' => (string) $label];
}
return $result;
}
/**
* Get single lookup by constant name (case-insensitive)
* @param string $name Constant name (e.g., 'gender', 'PRIORITY')
* @return array|null
*/
public static function get(string $name): ?array {
$const = strtoupper($name);
// Special case for COUNTRY (loaded from external file)
if ($const === 'COUNTRY') {
return self::getCountry();
}
if (defined("self::$const")) {
return self::format(constant("self::$const"));
}
return null;
}
/**
* Get raw constant array (not formatted)
* @param string $name
* @return array|null
*/
public static function getRaw(string $name): ?array {
$const = strtoupper($name);
// Special case for COUNTRY (loaded from external file)
if ($const === 'COUNTRY') {
return self::loadCountryData();
}
if (defined("self::$const")) {
return constant("self::$const");
}
return null;
}
/**
* Get label by key from a lookup
* @param string $lookup Lookup name
* @param string $key Key to find
* @return string|null
*/
public static function getLabel(string $lookup, string $key): ?string {
$raw = self::getRaw($lookup);
return $raw[$key] ?? null;
}
}