fix(seeds): ensure MedicalTemplatesLibrarySeeder preserves existing templates and inserts only missing ones
This commit is contained in:
parent
ad1df321c8
commit
8ad2a2923f
|
|
@ -23,19 +23,49 @@ use App\Database\Seeds\Data\OpdPrintTemplateSeedData;
|
|||
* 6. OPD Doctor Clinical Templates (opd_clinical_templates)
|
||||
* 7. OPD Prescription Print Templates (hospital_setting)
|
||||
*
|
||||
* Safe to re-run (idempotent — updates existing templates and inserts missing ones).
|
||||
* Safe to re-run (Insert-If-Not-Exists):
|
||||
* - Strictly checks if records already exist in the database.
|
||||
* - If a record exists, it is NEVER overwritten/updated by default, preserving all
|
||||
* doctor edits, customized normal ranges, and hospital modifications.
|
||||
* - If a record is missing (new template added to Data files), it is inserted seamlessly.
|
||||
* - Optional override: set SEED_FORCE_UPDATE=1 or call setForceUpdate(true).
|
||||
*
|
||||
* Usage:
|
||||
* php spark db:seed MedicalTemplatesLibrarySeeder
|
||||
*/
|
||||
class MedicalTemplatesLibrarySeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* When false (default), existing database records are preserved and never overwritten.
|
||||
*/
|
||||
protected bool $forceUpdate = false;
|
||||
|
||||
/**
|
||||
* Programmatically enable or disable force updating
|
||||
*/
|
||||
public function setForceUpdate(bool $force): self
|
||||
{
|
||||
$this->forceUpdate = $force;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$forceEnv = getenv('SEED_FORCE_UPDATE') ?: ($_ENV['SEED_FORCE_UPDATE'] ?? ($_SERVER['SEED_FORCE_UPDATE'] ?? null));
|
||||
if ($forceEnv === '1' || strtolower((string)$forceEnv) === 'true') {
|
||||
$this->forceUpdate = true;
|
||||
}
|
||||
|
||||
CLI::write("=======================================================", 'cyan');
|
||||
CLI::write(" SEEDING COMPREHENSIVE MEDICAL TEMPLATES LIBRARY ", 'yellow');
|
||||
CLI::write("=======================================================", 'cyan');
|
||||
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" [MODE] Force Update: ENABLED (Existing records will be updated)", 'yellow');
|
||||
} else {
|
||||
CLI::write(" [MODE] Safe Mode: Insert-If-Not-Exists (Existing records PRESERVED)", 'green');
|
||||
}
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
$this->seedPathology($now);
|
||||
|
|
@ -63,8 +93,10 @@ class MedicalTemplatesLibrarySeeder extends Seeder
|
|||
|
||||
$panels = PathologySeedData::getPanels();
|
||||
$panelInserted = 0;
|
||||
$panelSkipped = 0;
|
||||
$panelUpdated = 0;
|
||||
$testInserted = 0;
|
||||
$testSkipped = 0;
|
||||
$testUpdated = 0;
|
||||
|
||||
foreach ($panels as $p) {
|
||||
|
|
@ -127,7 +159,7 @@ class MedicalTemplatesLibrarySeeder extends Seeder
|
|||
</div>
|
||||
HTML;
|
||||
|
||||
// C. Insert or Update `lab_repo`
|
||||
// C. Insert or Skip `lab_repo`
|
||||
$existingPanel = $db->table('lab_repo')
|
||||
->where('Title', $p['title'])
|
||||
->get(1)
|
||||
|
|
@ -146,15 +178,19 @@ HTML;
|
|||
|
||||
if (! empty($existingPanel['mstRepoKey'])) {
|
||||
$repoKey = (int) $existingPanel['mstRepoKey'];
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('lab_repo')->where('mstRepoKey', $repoKey)->update($panelData);
|
||||
$panelUpdated++;
|
||||
} else {
|
||||
$panelSkipped++;
|
||||
}
|
||||
} else {
|
||||
$db->table('lab_repo')->insert($panelData);
|
||||
$repoKey = (int) $db->insertID();
|
||||
$panelInserted++;
|
||||
}
|
||||
|
||||
// D. Upsert individual tests in `lab_tests` and map in `lab_repotests`
|
||||
// D. Upsert or Skip individual tests in `lab_tests` and map in `lab_repotests`
|
||||
$eOrder = 10;
|
||||
foreach ($p['tests'] as $t) {
|
||||
$existingTest = $db->table('lab_tests')
|
||||
|
|
@ -175,8 +211,12 @@ HTML;
|
|||
|
||||
if (! empty($existingTest['mstTestKey'])) {
|
||||
$testKey = (int) $existingTest['mstTestKey'];
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('lab_tests')->where('mstTestKey', $testKey)->update($testData);
|
||||
$testUpdated++;
|
||||
} else {
|
||||
$testSkipped++;
|
||||
}
|
||||
} else {
|
||||
$db->table('lab_tests')->insert($testData);
|
||||
$testKey = (int) $db->insertID();
|
||||
|
|
@ -191,9 +231,11 @@ HTML;
|
|||
->getRowArray();
|
||||
|
||||
if (! empty($existingLink['id'])) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('lab_repotests')
|
||||
->where('id', $existingLink['id'])
|
||||
->update(['EOrder' => $eOrder]);
|
||||
}
|
||||
} else {
|
||||
$db->table('lab_repotests')->insert([
|
||||
'mstRepoKey' => $repoKey,
|
||||
|
|
@ -207,8 +249,13 @@ HTML;
|
|||
}
|
||||
|
||||
CLI::write(" [OK] Pathology Library Seeded:", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Panels: {$panelInserted} added, {$panelUpdated} updated (Total: " . count($panels) . ")");
|
||||
CLI::write(" - Test Parameters: {$testInserted} added, {$testUpdated} updated");
|
||||
} else {
|
||||
CLI::write(" - Panels: {$panelInserted} added, {$panelSkipped} preserved (already existing) (Total: " . count($panels) . ")");
|
||||
CLI::write(" - Test Parameters: {$testInserted} added, {$testSkipped} preserved (already existing)");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -249,9 +296,10 @@ HTML;
|
|||
}
|
||||
}
|
||||
|
||||
// B. Upsert Master Templates
|
||||
// B. Insert or Skip Master Templates
|
||||
$templates = RadiologySeedData::getTemplates();
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($templates as $tpl) {
|
||||
|
|
@ -278,10 +326,14 @@ HTML;
|
|||
];
|
||||
|
||||
if (! empty($existing['id'])) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('radiology_ultrasound_template')
|
||||
->where('id', $existing['id'])
|
||||
->update($data);
|
||||
$updated++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
} else {
|
||||
$db->table('radiology_ultrasound_template')->insert($data);
|
||||
$inserted++;
|
||||
|
|
@ -289,7 +341,11 @@ HTML;
|
|||
}
|
||||
|
||||
CLI::write(" [OK] Radiology Library Seeded (USG, ECHO, X-Ray, CT, MRI):", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Templates: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")");
|
||||
} else {
|
||||
CLI::write(" - Templates: {$inserted} added, {$skipped} preserved (already existing) (Total: " . count($templates) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -305,6 +361,7 @@ HTML;
|
|||
|
||||
$templates = IpdDischargeSeedData::getTemplates();
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($templates as $tpl) {
|
||||
|
|
@ -337,10 +394,14 @@ HTML;
|
|||
];
|
||||
|
||||
if (! empty($existing['id'])) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('ipd_discharge_templates')
|
||||
->where('id', $existing['id'])
|
||||
->update($data);
|
||||
$updated++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
} else {
|
||||
$data['created_at'] = $now;
|
||||
$db->table('ipd_discharge_templates')->insert($data);
|
||||
|
|
@ -348,7 +409,12 @@ HTML;
|
|||
}
|
||||
}
|
||||
|
||||
CLI::write(" [OK] IPD Discharge Templates Seeded: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")", 'green');
|
||||
CLI::write(" [OK] IPD Discharge Templates Seeded:", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Templates: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")");
|
||||
} else {
|
||||
CLI::write(" - Templates: {$inserted} added, {$skipped} preserved (already existing) (Total: " . count($templates) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -364,6 +430,7 @@ HTML;
|
|||
|
||||
$narratives = IpdDischargeSeedData::getNarratives();
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($narratives as $nar) {
|
||||
|
|
@ -384,10 +451,14 @@ HTML;
|
|||
];
|
||||
|
||||
if (! empty($existing['id'])) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('ipd_discharge_narrative_templates')
|
||||
->where('id', $existing['id'])
|
||||
->update($data);
|
||||
$updated++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
} else {
|
||||
$data['created_at'] = $now;
|
||||
$db->table('ipd_discharge_narrative_templates')->insert($data);
|
||||
|
|
@ -395,7 +466,12 @@ HTML;
|
|||
}
|
||||
}
|
||||
|
||||
CLI::write(" [OK] IPD Clinical Narratives Seeded: {$inserted} added, {$updated} updated (Total: " . count($narratives) . ")", 'green');
|
||||
CLI::write(" [OK] IPD Clinical Narratives Seeded:", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Narratives: {$inserted} added, {$updated} updated (Total: " . count($narratives) . ")");
|
||||
} else {
|
||||
CLI::write(" - Narratives: {$inserted} added, {$skipped} preserved (already existing) (Total: " . count($narratives) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -411,6 +487,7 @@ HTML;
|
|||
|
||||
$forms = IpdDocumentSeedData::getForms();
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($forms as $frm) {
|
||||
|
|
@ -438,10 +515,14 @@ HTML;
|
|||
];
|
||||
|
||||
if (! empty($existing['id'])) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('ipd_document_templates')
|
||||
->where('id', $existing['id'])
|
||||
->update($data);
|
||||
$updated++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
} else {
|
||||
$data['created_at'] = $now;
|
||||
$db->table('ipd_document_templates')->insert($data);
|
||||
|
|
@ -449,7 +530,12 @@ HTML;
|
|||
}
|
||||
}
|
||||
|
||||
CLI::write(" [OK] IPD Document Master Forms Seeded: {$inserted} added, {$updated} updated (Total: " . count($forms) . ")", 'green');
|
||||
CLI::write(" [OK] IPD Document Master Forms Seeded:", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Forms: {$inserted} added, {$updated} updated (Total: " . count($forms) . ")");
|
||||
} else {
|
||||
CLI::write(" - Forms: {$inserted} added, {$skipped} preserved (already existing) (Total: " . count($forms) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -459,22 +545,53 @@ HTML;
|
|||
{
|
||||
$db = $this->db;
|
||||
if (! $db->tableExists('opd_clinical_templates')) {
|
||||
$db->query("CREATE TABLE IF NOT EXISTS opd_clinical_templates (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
doc_id INT NOT NULL DEFAULT 0,
|
||||
section_key VARCHAR(80) NOT NULL,
|
||||
template_name VARCHAR(255) NOT NULL,
|
||||
template_text TEXT NOT NULL,
|
||||
is_active TINYINT NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NULL,
|
||||
updated_at DATETIME NULL,
|
||||
INDEX idx_doc_section (doc_id, section_key),
|
||||
INDEX idx_section_active (section_key, is_active)
|
||||
)");
|
||||
$forge = \Config\Database::forge($db);
|
||||
$forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'doc_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'default' => 0,
|
||||
],
|
||||
'section_key' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
],
|
||||
'template_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
],
|
||||
'template_text' => [
|
||||
'type' => 'TEXT',
|
||||
],
|
||||
'is_active' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 1,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$forge->addKey('id', true);
|
||||
$forge->addKey(['doc_id', 'section_key']);
|
||||
$forge->addKey(['section_key', 'is_active']);
|
||||
$forge->createTable('opd_clinical_templates', true);
|
||||
}
|
||||
|
||||
$templates = OpdClinicalSeedData::getTemplates();
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($templates as $t) {
|
||||
|
|
@ -495,10 +612,14 @@ HTML;
|
|||
];
|
||||
|
||||
if (! empty($existing['id'])) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('opd_clinical_templates')
|
||||
->where('id', $existing['id'])
|
||||
->update($data);
|
||||
$updated++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
} else {
|
||||
$data['created_at'] = $now;
|
||||
$db->table('opd_clinical_templates')->insert($data);
|
||||
|
|
@ -506,7 +627,12 @@ HTML;
|
|||
}
|
||||
}
|
||||
|
||||
CLI::write(" [OK] OPD Doctor Clinical Templates Seeded: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")", 'green');
|
||||
CLI::write(" [OK] OPD Doctor Clinical Templates Seeded:", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Templates: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")");
|
||||
} else {
|
||||
CLI::write(" - Templates: {$inserted} added, {$skipped} preserved (already existing) (Total: " . count($templates) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -522,6 +648,7 @@ HTML;
|
|||
|
||||
$templates = OpdPrintTemplateSeedData::getTemplates();
|
||||
$inserted = 0;
|
||||
$skipped = 0;
|
||||
$updated = 0;
|
||||
|
||||
foreach ($templates as $key => $t) {
|
||||
|
|
@ -532,10 +659,14 @@ HTML;
|
|||
->getRowArray();
|
||||
|
||||
if (! empty($existing)) {
|
||||
if ($this->forceUpdate) {
|
||||
$db->table('hospital_setting')
|
||||
->where('s_name', $storageKey)
|
||||
->update(['s_value' => $t['html']]);
|
||||
$updated++;
|
||||
} else {
|
||||
$skipped++;
|
||||
}
|
||||
} else {
|
||||
$db->table('hospital_setting')->insert([
|
||||
's_name' => $storageKey,
|
||||
|
|
@ -545,7 +676,12 @@ HTML;
|
|||
}
|
||||
}
|
||||
|
||||
CLI::write(" [OK] OPD Print Templates Seeded: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")", 'green');
|
||||
CLI::write(" [OK] OPD Print Templates Seeded:", 'green');
|
||||
if ($this->forceUpdate) {
|
||||
CLI::write(" - Templates: {$inserted} added, {$updated} updated (Total: " . count($templates) . ")");
|
||||
} else {
|
||||
CLI::write(" - Templates: {$inserted} added, {$skipped} preserved (already existing) (Total: " . count($templates) . ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,5 +118,60 @@ class MedicalTemplatesLibraryTest extends CIUnitTestCase
|
|||
$this->assertStringContainsString('{{PATIENT_NAME}}', $t['html']);
|
||||
}
|
||||
}
|
||||
|
||||
public function testSeederPreservesExistingCustomizations(): void
|
||||
{
|
||||
$db = \Config\Database::connect('default');
|
||||
if (! $db->tableExists('opd_clinical_templates')) {
|
||||
$this->markTestSkipped('opd_clinical_templates table not present');
|
||||
}
|
||||
|
||||
// 1. Pick or insert a custom clinical template simulating user edits
|
||||
$customName = 'TEST_CUSTOM_EXAM_TPL_' . uniqid();
|
||||
$customText = 'Patient exhibits custom examination notes that should never be overwritten.';
|
||||
|
||||
$db->table('opd_clinical_templates')->insert([
|
||||
'doc_id' => 0,
|
||||
'section_key' => 'finding_examinations',
|
||||
'template_name' => $customName,
|
||||
'template_text' => $customText,
|
||||
'is_active' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
$customId = $db->insertID();
|
||||
|
||||
// Also test an existing standard template from OpdClinicalSeedData
|
||||
$firstStandard = \App\Database\Seeds\Data\OpdClinicalSeedData::getTemplates()[0];
|
||||
$standardRowBefore = $db->table('opd_clinical_templates')
|
||||
->where('doc_id', 0)
|
||||
->where('section_key', $firstStandard['section_key'])
|
||||
->where('template_name', $firstStandard['template_name'])
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
// 2. Run Seeder in Safe Mode (default)
|
||||
$seeder = new \App\Database\Seeds\MedicalTemplatesLibrarySeeder(new \Config\Database());
|
||||
$seeder->setForceUpdate(false);
|
||||
$seeder->run();
|
||||
|
||||
// 3. Verify custom user record is 100% untouched
|
||||
$customRowAfter = $db->table('opd_clinical_templates')->where('id', $customId)->get(1)->getRowArray();
|
||||
$this->assertNotEmpty($customRowAfter);
|
||||
$this->assertEquals($customText, $customRowAfter['template_text']);
|
||||
|
||||
// 4. Verify standard existing template was not modified/overwritten
|
||||
if (! empty($standardRowBefore)) {
|
||||
$standardRowAfter = $db->table('opd_clinical_templates')
|
||||
->where('id', $standardRowBefore['id'])
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
$this->assertEquals($standardRowBefore['template_text'], $standardRowAfter['template_text']);
|
||||
$this->assertEquals($standardRowBefore['updated_at'], $standardRowAfter['updated_at']);
|
||||
}
|
||||
|
||||
// Clean up test custom record
|
||||
$db->table('opd_clinical_templates')->where('id', $customId)->delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user