From 182d4ca4b38fb3a24032d6695eaf9c1074e1b78a Mon Sep 17 00:00:00 2001 From: BOHA Date: Fri, 5 Jun 2026 11:44:08 +0200 Subject: [PATCH] feat(plan): add work_plan_entries, work_plan_overrides, plan_category enum --- .../migration.sql | 61 +++++++++++++++++++ prisma/schema.prisma | 57 +++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 prisma/migrations/20260605120000_add_work_plan/migration.sql diff --git a/prisma/migrations/20260605120000_add_work_plan/migration.sql b/prisma/migrations/20260605120000_add_work_plan/migration.sql new file mode 100644 index 0000000..a0395a2 --- /dev/null +++ b/prisma/migrations/20260605120000_add_work_plan/migration.sql @@ -0,0 +1,61 @@ +-- Add work_plan_entries and work_plan_overrides tables plus the plan_category +-- enum. Both tables are owned by users (Cascade on delete) and reference +-- projects (SetNull). `created_by` uses Restrict so we never silently lose +-- the audit trail of who created the entry. + +-- CreateTable +CREATE TABLE `work_plan_entries` ( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `user_id` INTEGER NOT NULL, + `date_from` DATE NOT NULL, + `date_to` DATE NOT NULL, + `project_id` INTEGER NULL, + `category` ENUM('work', 'preparation', 'travel', 'leave', 'sick', 'training', 'other') NOT NULL DEFAULT 'work', + `note` VARCHAR(500) NOT NULL, + `created_by` INTEGER NOT NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `is_deleted` BOOLEAN NULL DEFAULT false, + + INDEX `idx_wpe_user_from`(`user_id`, `date_from`), + INDEX `idx_wpe_user_to`(`user_id`, `date_to`), + INDEX `idx_wpe_project`(`project_id`), + INDEX `idx_wpe_dates`(`date_from`, `date_to`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `work_plan_overrides` ( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `user_id` INTEGER NOT NULL, + `shift_date` DATE NOT NULL, + `project_id` INTEGER NULL, + `category` ENUM('work', 'preparation', 'travel', 'leave', 'sick', 'training', 'other') NOT NULL, + `note` VARCHAR(500) NOT NULL, + `created_by` INTEGER NOT NULL, + `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `updated_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), + `is_deleted` BOOLEAN NULL DEFAULT false, + + INDEX `idx_wpo_date`(`shift_date`), + UNIQUE INDEX `uniq_wpo_user_date`(`user_id`, `shift_date`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `work_plan_entries` ADD CONSTRAINT `work_plan_entries_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE `work_plan_entries` ADD CONSTRAINT `work_plan_entries_project_id_fkey` FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE `work_plan_entries` ADD CONSTRAINT `work_plan_entries_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE `work_plan_overrides` ADD CONSTRAINT `work_plan_overrides_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE `work_plan_overrides` ADD CONSTRAINT `work_plan_overrides_project_id_fkey` FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON DELETE SET NULL ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE `work_plan_overrides` ADD CONSTRAINT `work_plan_overrides_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE NO ACTION; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index fb355d0..dcc7538 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -365,6 +365,8 @@ model projects { project_notes project_notes[] sklad_issues sklad_issues[] sklad_reservations sklad_reservations[] + work_plan_entries work_plan_entries[] + work_plan_overrides work_plan_overrides[] users users? @relation(fields: [responsible_user_id], references: [id], onUpdate: NoAction, map: "fk_projects_responsible_user") customers customers? @relation(fields: [customer_id], references: [id], onUpdate: NoAction, map: "projects_ibfk_1") quotations quotations? @relation(fields: [quotation_id], references: [id], onUpdate: NoAction, map: "projects_ibfk_2") @@ -591,6 +593,10 @@ model users { sklad_receipts_received sklad_receipts[] @relation("SkladReceivedBy") sklad_issues_issued sklad_issues[] @relation("SkladIssuedBy") sklad_reservations sklad_reservations[] @relation("SkladReservedBy") + work_plan_entries work_plan_entries[] @relation("work_plan_entries_creator") + work_plan_entries_owned work_plan_entries[] + work_plan_overrides work_plan_overrides[] @relation("work_plan_overrides_creator") + work_plan_overrides_owned work_plan_overrides[] roles roles? @relation(fields: [role_id], references: [id], onUpdate: NoAction, map: "users_ibfk_1") @@index([is_active], map: "idx_users_is_active") @@ -672,6 +678,16 @@ enum sklad_inventory_status { CONFIRMED } +enum plan_category { + work + preparation + travel + leave + sick + training + other +} + model sklad_categories { id Int @id @default(autoincrement()) name String @db.VarChar(100) @@ -917,3 +933,44 @@ model sklad_inventory_lines { @@index([session_id], map: "sklad_inventory_lines_session_id") @@map("sklad_inventory_lines") } + +model work_plan_entries { + id Int @id @default(autoincrement()) + user_id Int + date_from DateTime @db.Date + date_to DateTime @db.Date + project_id Int? + category plan_category @default(work) + note String @db.VarChar(500) + created_by Int + created_at DateTime? @default(now()) @db.Timestamp(0) + updated_at DateTime? @default(now()) @db.Timestamp(0) + is_deleted Boolean? @default(false) + users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction) + projects projects? @relation(fields: [project_id], references: [id], onDelete: SetNull, onUpdate: NoAction) + creator users @relation("work_plan_entries_creator", fields: [created_by], references: [id], onDelete: Restrict, onUpdate: NoAction) + + @@index([user_id, date_from], map: "idx_wpe_user_from") + @@index([user_id, date_to], map: "idx_wpe_user_to") + @@index([project_id], map: "idx_wpe_project") + @@index([date_from, date_to], map: "idx_wpe_dates") +} + +model work_plan_overrides { + id Int @id @default(autoincrement()) + user_id Int + shift_date DateTime @db.Date + project_id Int? + category plan_category + note String @db.VarChar(500) + created_by Int + created_at DateTime? @default(now()) @db.Timestamp(0) + updated_at DateTime? @default(now()) @db.Timestamp(0) + is_deleted Boolean? @default(false) + users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction) + projects projects? @relation(fields: [project_id], references: [id], onDelete: SetNull, onUpdate: NoAction) + creator users @relation("work_plan_overrides_creator", fields: [created_by], references: [id], onDelete: Restrict, onUpdate: NoAction) + + @@unique([user_id, shift_date], map: "uniq_wpo_user_date") + @@index([shift_date], map: "idx_wpo_date") +}