diff --git a/app/Database/Seeds/InvestigationMasterSeeder.php b/app/Database/Seeds/InvestigationMasterSeeder.php new file mode 100644 index 0000000..a762f08 --- /dev/null +++ b/app/Database/Seeds/InvestigationMasterSeeder.php @@ -0,0 +1,325 @@ + 'CBC (Complete Blood Count)', 'short' => 'CBC', 'fav' => 1], + ['name' => 'Haemoglobin (Hb)', 'short' => 'Hb', 'fav' => 1], + ['name' => 'ESR (Erythrocyte Sedimentation Rate)', 'short' => 'ESR', 'fav' => 0], + ['name' => 'Peripheral Blood Smear', 'short' => 'PBS', 'fav' => 0], + ['name' => 'Platelet Count', 'short' => 'PLT', 'fav' => 0], + ['name' => 'Reticulocyte Count', 'short' => 'Retic', 'fav' => 0], + ['name' => 'PT/INR', 'short' => 'PT-INR', 'fav' => 0], + ['name' => 'APTT', 'short' => 'APTT', 'fav' => 0], + ['name' => 'D-Dimer', 'short' => 'D-Dimer', 'fav' => 0], + + // Biochemistry + ['name' => 'Blood Sugar Fasting (FBS)', 'short' => 'FBS', 'fav' => 1], + ['name' => 'Blood Sugar Post Prandial (PPBS)', 'short' => 'PPBS', 'fav' => 1], + ['name' => 'Random Blood Sugar (RBS)', 'short' => 'RBS', 'fav' => 1], + ['name' => 'HbA1c (Glycated Haemoglobin)', 'short' => 'HbA1c', 'fav' => 1], + ['name' => 'Renal Function Test (RFT)', 'short' => 'RFT', 'fav' => 1], + ['name' => 'Blood Urea', 'short' => 'Urea', 'fav' => 0], + ['name' => 'Serum Creatinine', 'short' => 'Creat', 'fav' => 1], + ['name' => 'Serum Uric Acid', 'short' => 'Uric Acid', 'fav' => 0], + ['name' => 'Liver Function Test (LFT)', 'short' => 'LFT', 'fav' => 1], + ['name' => 'SGOT (AST)', 'short' => 'SGOT', 'fav' => 0], + ['name' => 'SGPT (ALT)', 'short' => 'SGPT', 'fav' => 0], + ['name' => 'Serum Bilirubin (Total/Direct)', 'short' => 'Bili', 'fav' => 0], + ['name' => 'Serum Alkaline Phosphatase (ALP)', 'short' => 'ALP', 'fav' => 0], + ['name' => 'Serum Albumin', 'short' => 'Albumin', 'fav' => 0], + ['name' => 'Serum Electrolytes (Na/K/Cl)', 'short' => 'Electro', 'fav' => 1], + ['name' => 'Serum Sodium', 'short' => 'Na', 'fav' => 0], + ['name' => 'Serum Potassium', 'short' => 'K', 'fav' => 0], + ['name' => 'Serum Calcium', 'short' => 'Ca', 'fav' => 0], + ['name' => 'Serum Phosphorus', 'short' => 'Phos', 'fav' => 0], + ['name' => 'Serum Magnesium', 'short' => 'Mg', 'fav' => 0], + + // Lipid Profile + ['name' => 'Lipid Profile', 'short' => 'Lipid', 'fav' => 1], + ['name' => 'Total Cholesterol', 'short' => 'Chol', 'fav' => 0], + ['name' => 'HDL Cholesterol', 'short' => 'HDL', 'fav' => 0], + ['name' => 'LDL Cholesterol', 'short' => 'LDL', 'fav' => 0], + ['name' => 'Triglycerides', 'short' => 'TG', 'fav' => 0], + + // Thyroid + ['name' => 'Thyroid Function Test (TFT)', 'short' => 'TFT', 'fav' => 1], + ['name' => 'TSH (Thyroid Stimulating Hormone)', 'short' => 'TSH', 'fav' => 1], + ['name' => 'T3 (Triiodothyronine)', 'short' => 'T3', 'fav' => 0], + ['name' => 'T4 (Thyroxine)', 'short' => 'T4', 'fav' => 0], + + // Cardiac + ['name' => 'Troponin I (cTnI)', 'short' => 'Troponin', 'fav' => 1], + ['name' => 'CK-MB', 'short' => 'CKMB', 'fav' => 0], + ['name' => 'BNP / NT-proBNP', 'short' => 'BNP', 'fav' => 0], + ['name' => 'CRP (C-Reactive Protein)', 'short' => 'CRP', 'fav' => 1], + + // Infectious / Serology + ['name' => 'Widal Test', 'short' => 'Widal', 'fav' => 0], + ['name' => 'Dengue NS1 Antigen', 'short' => 'Dengue NS1','fav' => 1], + ['name' => 'Dengue IgG/IgM', 'short' => 'Dengue Ab', 'fav' => 0], + ['name' => 'Malaria Card Test', 'short' => 'Malaria', 'fav' => 1], + ['name' => 'HIV I & II (Elisa)', 'short' => 'HIV', 'fav' => 0], + ['name' => 'HBsAg', 'short' => 'HBsAg', 'fav' => 0], + ['name' => 'Anti-HCV', 'short' => 'HCV', 'fav' => 0], + ['name' => 'VDRL / RPR', 'short' => 'VDRL', 'fav' => 0], + ['name' => 'COVID-19 Antigen', 'short' => 'COVID Ag', 'fav' => 0], + ['name' => 'Typhoid IgM (Typhidot)', 'short' => 'Typhidot', 'fav' => 0], + + // Urine + ['name' => 'Urine Routine & Microscopy', 'short' => 'Urine R/M', 'fav' => 1], + ['name' => 'Urine Culture & Sensitivity', 'short' => 'Urine C/S', 'fav' => 0], + ['name' => 'Urine Protein (24hr)', 'short' => '24h Prot', 'fav' => 0], + ['name' => 'Urine Creatinine Ratio', 'short' => 'UCR', 'fav' => 0], + ['name' => 'Urine Pregnancy Test (UPT)', 'short' => 'UPT', 'fav' => 0], + + // Radiology + ['name' => 'X-Ray Chest (PA View)', 'short' => 'CXR', 'fav' => 1], + ['name' => 'X-Ray Spine (L-S)', 'short' => 'X-Ray LS', 'fav' => 0], + ['name' => 'X-Ray KUB', 'short' => 'KUB X-Ray', 'fav' => 0], + ['name' => 'USG Abdomen & Pelvis', 'short' => 'USG Abd', 'fav' => 1], + ['name' => 'USG KUB', 'short' => 'USG KUB', 'fav' => 0], + ['name' => 'ECHO (Echocardiography)', 'short' => 'ECHO', 'fav' => 0], + ['name' => 'CT Scan Head Plain', 'short' => 'CT Head', 'fav' => 0], + ['name' => 'MRI Brain with Contrast', 'short' => 'MRI Brain', 'fav' => 0], + + // Cardiac Procedures + ['name' => 'ECG (Electrocardiogram)', 'short' => 'ECG', 'fav' => 1], + ['name' => 'Holter Monitoring (24hr)', 'short' => 'Holter', 'fav' => 0], + ['name' => 'Stress Test (TMT)', 'short' => 'TMT', 'fav' => 0], + + // Hormones / Vitamins + ['name' => 'Serum Vitamin D (25-OH)', 'short' => 'Vit D', 'fav' => 1], + ['name' => 'Serum Vitamin B12', 'short' => 'Vit B12', 'fav' => 1], + ['name' => 'Serum Ferritin', 'short' => 'Ferritin', 'fav' => 0], + ['name' => 'Serum Iron / TIBC', 'short' => 'Iron/TIBC', 'fav' => 0], + ['name' => 'FSH / LH', 'short' => 'FSH/LH', 'fav' => 0], + ['name' => 'Prolactin', 'short' => 'PRL', 'fav' => 0], + ['name' => 'Testosterone (Total)', 'short' => 'Testo', 'fav' => 0], + ['name' => 'PSA (Prostate-Specific Antigen)', 'short' => 'PSA', 'fav' => 0], + + // Stool + ['name' => 'Stool Routine & Microscopy', 'short' => 'Stool R/M', 'fav' => 0], + ['name' => 'Stool Culture & Sensitivity', 'short' => 'Stool C/S', 'fav' => 0], + ['name' => 'H. Pylori Antigen (Stool)', 'short' => 'H.Pylori', 'fav' => 0], + + // Sputum / Microbiology + ['name' => 'Sputum AFB (for TB)', 'short' => 'Sputum AFB','fav' => 0], + ['name' => 'Sputum Culture & Sensitivity', 'short' => 'Sputum C/S','fav' => 0], + ['name' => 'Blood Culture & Sensitivity', 'short' => 'Blood C/S', 'fav' => 0], + + // Paediatric-specific + ['name' => 'Neonatal Bilirubin', 'short' => 'Bili Neo', 'fav' => 0], + ['name' => 'G6PD Assay', 'short' => 'G6PD', 'fav' => 0], + ]; + + // --------------------------------------------------------------- + // Profile definitions: [profile name => [test short names...]] + // --------------------------------------------------------------- + private const PROFILES = [ + 'Fever Panel' => ['CBC', 'ESR', 'CRP', 'Widal', 'Dengue NS1', 'Malaria', 'Typhidot', 'Urine R/M'], + 'Diabetic Monitoring' => ['FBS', 'PPBS', 'HbA1c', 'RFT', 'Creat', 'Urine R/M', 'Lipid', 'Electro'], + 'Hypertension Panel' => ['RFT', 'Electro', 'Lipid', 'Creat', 'Urine R/M', 'ECG', 'CXR'], + 'Renal Panel' => ['RFT', 'Urea', 'Creat', 'Uric Acid', 'Electro', 'Urine R/M', 'Urine C/S', '24h Prot'], + 'Liver Panel' => ['LFT', 'SGOT', 'SGPT', 'Bili', 'ALP', 'Albumin', 'HBsAg', 'HCV'], + 'Cardiac Risk Profile' => ['CBC', 'Lipid', 'FBS', 'CRP', 'Troponin', 'ECG', 'ECHO'], + 'Thyroid Panel' => ['TSH', 'T3', 'T4'], + 'Anaemia Panel' => ['CBC', 'Hb', 'PBS', 'Retic', 'Ferritin', 'Iron/TIBC', 'Vit B12', 'Vit D'], + 'Pre-Operative Panel' => ['CBC', 'RFT', 'LFT', 'PT-INR', 'APTT', 'Blood C/S', 'Urine R/M', 'ECG', 'CXR'], + 'Annual Health Check' => ['CBC', 'FBS', 'HbA1c', 'Lipid', 'RFT', 'LFT', 'TFT', 'Urine R/M', 'CXR', 'ECG', 'Vit D', 'Vit B12'], + 'Vitamin Deficiency' => ['Vit D', 'Vit B12', 'Ferritin', 'Iron/TIBC', 'Ca'], + 'Paediatric Fever' => ['CBC', 'CRP', 'Dengue NS1', 'Malaria', 'Widal', 'Urine R/M'], + 'STI / Infectious Screen' => ['HIV', 'HBsAg', 'HCV', 'VDRL'], + 'Pregnancy Panel' => ['CBC', 'FBS', 'TSH', 'HBsAg', 'HIV', 'VDRL', 'Urine R/M', 'UPT', 'Bili'], + 'Urinary Tract Infection' => ['Urine R/M', 'Urine C/S', 'Creat', 'RFT', 'USG KUB'], + ]; + + // --------------------------------------------------------------- + // run() + // --------------------------------------------------------------- + public function run(): void + { + $this->ensureSeedLogTable(); + + $insertedCodes = $this->seedInvestigations(); + $this->seedProfiles($insertedCodes); + } + + // --------------------------------------------------------------- + // Seed investigation master + // Returns map: short_name => Code + // --------------------------------------------------------------- + private function seedInvestigations(): array + { + if (! $this->db->tableExists('investigation')) { + return []; + } + + $fields = $this->db->getFieldNames('investigation'); + $codeField = $this->resolveFirstField($fields, ['Code', 'code', 'id']); + $nameField = $this->resolveFirstField($fields, ['Name', 'name']); + + if ($codeField === null || $nameField === null) { + return []; + } + + $hasShort = in_array('short_name', $fields, true); + $hasFav = in_array('is_favourite', $fields, true); + + // Build short→Code map from existing rows so we can skip duplicates + $existingRows = $this->db->table('investigation') + ->select($codeField . ' as code, ' . $nameField . ' as name') + ->get()->getResultArray(); + + $existingByName = []; + foreach ($existingRows as $row) { + $existingByName[strtolower(trim((string) $row['name']))] = (int) $row['code']; + } + + $shortToCode = []; + + foreach (self::TESTS as $test) { + $normalised = strtolower(trim($test['name'])); + + if (array_key_exists($normalised, $existingByName)) { + // Already in DB — just record the code + $shortToCode[$test['short']] = $existingByName[$normalised]; + continue; + } + + $insert = [$nameField => $test['name']]; + if ($hasShort) { + $insert['short_name'] = $test['short']; + } + if ($hasFav) { + $insert['is_favourite'] = $test['fav']; + } + + $this->db->table('investigation')->insert($insert); + $newCode = (int) $this->db->insertID(); + $this->logInsertedRow('investigation', $newCode); + $shortToCode[$test['short']] = $newCode; + } + + return $shortToCode; + } + + // --------------------------------------------------------------- + // Seed invprofiles + invtprofiles + // --------------------------------------------------------------- + private function seedProfiles(array $shortToCode): void + { + if (! $this->db->tableExists('invprofiles') || ! $this->db->tableExists('invtprofiles')) { + return; + } + + $pFields = $this->db->getFieldNames('invprofiles'); + $pCodeField = $this->resolveFirstField($pFields, ['Code', 'code', 'id']); + $pNameField = $this->resolveFirstField($pFields, ['Name', 'name']); + + $tFields = $this->db->getFieldNames('invtprofiles'); + $tProfField = $this->resolveFirstField($tFields, ['ProfileCode', 'profile_code']); + $tInvField = $this->resolveFirstField($tFields, ['InvestigationCode', 'investigation_code']); + $tOrderField = $this->resolveFirstField($tFields, ['printOrder', 'print_order', 'order']); + + if ($pCodeField === null || $pNameField === null || $tProfField === null || $tInvField === null) { + return; + } + + foreach (self::PROFILES as $profileName => $testShorts) { + // Check if profile already exists + $existingProfile = $this->db->table('invprofiles') + ->where($pNameField, $profileName) + ->get(1)->getRowArray(); + + if (! empty($existingProfile)) { + continue; // Skip — already seeded + } + + // Insert profile + $this->db->table('invprofiles')->insert([$pNameField => $profileName]); + $profileCode = (int) $this->db->insertID(); + $this->logInsertedRow('invprofiles', $profileCode); + + // Insert test links + $order = 1; + foreach ($testShorts as $short) { + if (! isset($shortToCode[$short])) { + continue; // test not found — skip gracefully + } + + $tInsert = [ + $tProfField => $profileCode, + $tInvField => $shortToCode[$short], + ]; + if ($tOrderField !== null) { + $tInsert[$tOrderField] = $order; + } + $this->db->table('invtprofiles')->insert($tInsert); + $this->logInsertedRow('invtprofiles', (int) $this->db->insertID()); + $order++; + } + } + } + + // --------------------------------------------------------------- + // Helpers (mirrors OpdDemoMasterSeeder pattern) + // --------------------------------------------------------------- + private function ensureSeedLogTable(): void + { + if ($this->db->tableExists('ai_demo_seed_log')) { + return; + } + + $this->db->query("CREATE TABLE IF NOT EXISTS ai_demo_seed_log ( + id INT AUTO_INCREMENT PRIMARY KEY, + seed_name VARCHAR(120) NOT NULL, + table_name VARCHAR(120) NOT NULL, + row_id INT NOT NULL, + created_at DATETIME NULL, + INDEX idx_seed_name (seed_name), + INDEX idx_table_row (table_name, row_id) + )"); + } + + private function logInsertedRow(string $tableName, int $rowId): void + { + if ($rowId <= 0 || ! $this->db->tableExists('ai_demo_seed_log')) { + return; + } + + $this->db->table('ai_demo_seed_log')->insert([ + 'seed_name' => static::class, + 'table_name' => $tableName, + 'row_id' => $rowId, + 'created_at' => date('Y-m-d H:i:s'), + ]); + } + + private function resolveFirstField(array $fields, array $candidates): ?string + { + foreach ($candidates as $candidate) { + if (in_array($candidate, $fields, true)) { + return $candidate; + } + } + + return null; + } +} diff --git a/app/Database/Seeds/OpdDemoMasterSeeder.php b/app/Database/Seeds/OpdDemoMasterSeeder.php index 28e07b4..76328ae 100644 --- a/app/Database/Seeds/OpdDemoMasterSeeder.php +++ b/app/Database/Seeds/OpdDemoMasterSeeder.php @@ -13,6 +13,7 @@ class OpdDemoMasterSeeder extends Seeder $this->seedOpdMedicineMaster(); $this->seedRxGroupTemplate(); $this->call(ClinicalTemplateWorkspaceSeeder::class); + $this->call(InvestigationMasterSeeder::class); } private function seedMedCompany(): void