Laser is six to eight sessions; the previous design only knew single appointments, which is the exception rather than the rule. - CourseProtocol per service: session count and three distinct spacings — min is the earliest that is clinically allowed, ideal is best, max is where the course starts losing its effect - Starting a course creates every session up front as `planned` and copies the protocol's numbers and per-session params, so changing the protocol tomorrow leaves a running course alone - Suggestions anchor on the last *completed* session, not the course start: when session 2 slips, session 3 moves with it - Slots are ranked by distance from ideal, not by earliest available — day 21 is worse than day 27 when 28 is the target - book-all is all-or-nothing inside one transaction, with a moving anchor and a 90-day horizon; sessions past the horizon stay planned and are reported, not treated as failures - The effective minimum is the stricter of the protocol and the task-09 spacing policy, so a clinic rule never fights the protocol - Cancelling one session returns only that session to planned; abandoning a course does not cancel its appointments, which stays an explicit decision One active course per (patient, service) via active_course_key, the same partial-uniqueness trick as Appointment::activeSlotKey. Admin: CourseProtocolsPage, TreatmentCoursePage and a courses tab on the patient record. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
56 lines
6.1 KiB
PHP
56 lines
6.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace DoctrineMigrations;
|
|
|
|
use Doctrine\DBAL\Schema\Schema;
|
|
use Doctrine\Migrations\AbstractMigration;
|
|
|
|
/**
|
|
* Auto-generated Migration: Please modify to your needs!
|
|
*/
|
|
final class Version20260731074710 extends AbstractMigration
|
|
{
|
|
public function getDescription(): string
|
|
{
|
|
return '';
|
|
}
|
|
|
|
public function up(Schema $schema): void
|
|
{
|
|
// this up() migration is auto-generated, please modify it to your needs
|
|
$this->addSql('CREATE TABLE course_protocol_steps (id INT AUTO_INCREMENT NOT NULL, session_number SMALLINT NOT NULL, params JSON DEFAULT NULL, override_duration_minutes SMALLINT DEFAULT NULL, protocol_id INT NOT NULL, INDEX IDX_58A0726CCD59258 (protocol_id), UNIQUE INDEX uniq_step (protocol_id, session_number), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
|
|
$this->addSql('CREATE TABLE course_protocols (id INT AUTO_INCREMENT NOT NULL, uuid VARCHAR(36) NOT NULL, session_count SMALLINT NOT NULL, min_days SMALLINT NOT NULL, ideal_days SMALLINT NOT NULL, max_days SMALLINT NOT NULL, prefer_same_resource TINYINT DEFAULT 1 NOT NULL, active TINYINT DEFAULT 1 NOT NULL, created_at INT NOT NULL, updated_at INT NOT NULL, entity_type VARCHAR(10) NOT NULL, entity_id INT NOT NULL, service_item_id INT NOT NULL, UNIQUE INDEX UNIQ_E60D42A0D17F50A6 (uuid), INDEX idx_protocols_tenant (entity_type, entity_id, active), UNIQUE INDEX uniq_protocol_service (service_item_id), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
|
|
$this->addSql('CREATE TABLE course_sessions (id INT AUTO_INCREMENT NOT NULL, uuid VARCHAR(36) NOT NULL, session_number SMALLINT NOT NULL, params JSON DEFAULT NULL, status VARCHAR(12) DEFAULT \'planned\' NOT NULL, completed_at INT DEFAULT NULL, created_at INT NOT NULL, updated_at INT NOT NULL, entity_type VARCHAR(10) NOT NULL, entity_id INT NOT NULL, course_id INT NOT NULL, appointment_id INT DEFAULT NULL, UNIQUE INDEX UNIQ_33D4F045D17F50A6 (uuid), INDEX IDX_33D4F045591CC992 (course_id), INDEX idx_sessions_tenant (entity_type, entity_id, status), UNIQUE INDEX uniq_course_session (course_id, session_number), UNIQUE INDEX uniq_session_appointment (appointment_id), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
|
|
$this->addSql('CREATE TABLE treatment_courses (id INT AUTO_INCREMENT NOT NULL, uuid VARCHAR(36) NOT NULL, session_count SMALLINT NOT NULL, min_days SMALLINT NOT NULL, ideal_days SMALLINT NOT NULL, max_days SMALLINT NOT NULL, status VARCHAR(12) DEFAULT \'active\' NOT NULL, active_course_key VARCHAR(64) DEFAULT NULL, abandon_reason VARCHAR(255) DEFAULT NULL, started_at INT NOT NULL, completed_at INT DEFAULT NULL, created_at INT NOT NULL, updated_at INT NOT NULL, entity_type VARCHAR(10) NOT NULL, entity_id INT NOT NULL, patient_record_id INT NOT NULL, service_item_id INT NOT NULL, protocol_id INT NOT NULL, patient_package_id INT DEFAULT NULL, preferred_resource_id INT DEFAULT NULL, UNIQUE INDEX UNIQ_D1639880D17F50A6 (uuid), UNIQUE INDEX UNIQ_D1639880DEBE4F6D (active_course_key), INDEX IDX_D1639880EB76A733 (patient_record_id), INDEX IDX_D1639880DDEB00C2 (service_item_id), INDEX IDX_D1639880CCD59258 (protocol_id), INDEX IDX_D1639880428C0D10 (patient_package_id), INDEX IDX_D1639880CB4D0F54 (preferred_resource_id), INDEX idx_courses_tenant (entity_type, entity_id, status, started_at), INDEX idx_courses_patient (patient_record_id, status), PRIMARY KEY (id)) DEFAULT CHARACTER SET utf8mb4');
|
|
$this->addSql('ALTER TABLE course_protocol_steps ADD CONSTRAINT FK_58A0726CCD59258 FOREIGN KEY (protocol_id) REFERENCES course_protocols (id) ON DELETE CASCADE');
|
|
$this->addSql('ALTER TABLE course_protocols ADD CONSTRAINT FK_E60D42A0DDEB00C2 FOREIGN KEY (service_item_id) REFERENCES service_items (id) ON DELETE CASCADE');
|
|
$this->addSql('ALTER TABLE course_sessions ADD CONSTRAINT FK_33D4F045591CC992 FOREIGN KEY (course_id) REFERENCES treatment_courses (id) ON DELETE CASCADE');
|
|
$this->addSql('ALTER TABLE course_sessions ADD CONSTRAINT FK_33D4F045E5B533F9 FOREIGN KEY (appointment_id) REFERENCES appointments (id) ON DELETE SET NULL');
|
|
$this->addSql('ALTER TABLE treatment_courses ADD CONSTRAINT FK_D1639880EB76A733 FOREIGN KEY (patient_record_id) REFERENCES patient_records (id) ON DELETE RESTRICT');
|
|
$this->addSql('ALTER TABLE treatment_courses ADD CONSTRAINT FK_D1639880DDEB00C2 FOREIGN KEY (service_item_id) REFERENCES service_items (id) ON DELETE RESTRICT');
|
|
$this->addSql('ALTER TABLE treatment_courses ADD CONSTRAINT FK_D1639880CCD59258 FOREIGN KEY (protocol_id) REFERENCES course_protocols (id) ON DELETE RESTRICT');
|
|
$this->addSql('ALTER TABLE treatment_courses ADD CONSTRAINT FK_D1639880428C0D10 FOREIGN KEY (patient_package_id) REFERENCES patient_packages (id) ON DELETE SET NULL');
|
|
$this->addSql('ALTER TABLE treatment_courses ADD CONSTRAINT FK_D1639880CB4D0F54 FOREIGN KEY (preferred_resource_id) REFERENCES clinic_resources (id) ON DELETE SET NULL');
|
|
}
|
|
|
|
public function down(Schema $schema): void
|
|
{
|
|
// this down() migration is auto-generated, please modify it to your needs
|
|
$this->addSql('ALTER TABLE course_protocol_steps DROP FOREIGN KEY FK_58A0726CCD59258');
|
|
$this->addSql('ALTER TABLE course_protocols DROP FOREIGN KEY FK_E60D42A0DDEB00C2');
|
|
$this->addSql('ALTER TABLE course_sessions DROP FOREIGN KEY FK_33D4F045591CC992');
|
|
$this->addSql('ALTER TABLE course_sessions DROP FOREIGN KEY FK_33D4F045E5B533F9');
|
|
$this->addSql('ALTER TABLE treatment_courses DROP FOREIGN KEY FK_D1639880EB76A733');
|
|
$this->addSql('ALTER TABLE treatment_courses DROP FOREIGN KEY FK_D1639880DDEB00C2');
|
|
$this->addSql('ALTER TABLE treatment_courses DROP FOREIGN KEY FK_D1639880CCD59258');
|
|
$this->addSql('ALTER TABLE treatment_courses DROP FOREIGN KEY FK_D1639880428C0D10');
|
|
$this->addSql('ALTER TABLE treatment_courses DROP FOREIGN KEY FK_D1639880CB4D0F54');
|
|
$this->addSql('DROP TABLE course_protocol_steps');
|
|
$this->addSql('DROP TABLE course_protocols');
|
|
$this->addSql('DROP TABLE course_sessions');
|
|
$this->addSql('DROP TABLE treatment_courses');
|
|
}
|
|
}
|