Files
tilbudgivern/migrations/feature_3_smart_packages.sql
alexpolo1 0a2c02b51b feat: Implement task categorization service with fuzzy matching and caching
- Added TaskCategorizationService to categorize tasks based on keywords in descriptions.
- Implemented fuzzy matching using Levenshtein distance for better keyword matching.
- Introduced caching for categories and keywords to optimize database queries.
- Added methods for categorizing individual tasks and batch processing for project tasks.
- Created SQL migration scripts for task_categories and category_keywords tables.
- Included default categories and keywords for initial setup.
- Enhanced project_tasks table with new columns for categorization data.
- Added statistics export functionality for category performance analysis.
2025-10-20 09:05:59 +00:00

151 lines
7.2 KiB
SQL

-- Feature 3: Smart Packages with Task Ordering
-- Date: 2025-01-XX
-- Description: Tilføjer task ordering, dependencies og geometry-baseret material beregning
-- Opret package_tasks tabel til at linke tasks til packages
CREATE TABLE IF NOT EXISTS package_tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
package_id INT NOT NULL,
task_name VARCHAR(255) NOT NULL,
task_description TEXT,
estimated_hours DECIMAL(8,2) DEFAULT 0,
task_order INT DEFAULT 0 COMMENT 'Rækkefølge inden for fase',
task_phase ENUM('forberedelse', 'hovedarbejde', 'afslutning', 'inspektion') DEFAULT 'hovedarbejde',
depends_on_task_id INT DEFAULT NULL COMMENT 'ID af task der skal udføres først',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (package_id) REFERENCES material_packages(id) ON DELETE CASCADE,
FOREIGN KEY (depends_on_task_id) REFERENCES package_tasks(id) ON DELETE SET NULL,
INDEX idx_package_id (package_id),
INDEX idx_task_phase (task_phase),
INDEX idx_task_order (task_order),
INDEX idx_depends_on (depends_on_task_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Tilføj geometry multiplier kolonner til package_materials (skip hvis eksisterer)
SET @dbname = 'tilbudgivern';
SET @tablename = 'package_materials';
SET @columnname = 'geometry_multiplier';
SET @preparedStatement = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @dbname AND TABLE_NAME = @tablename AND COLUMN_NAME = @columnname) > 0,
'SELECT "Column geometry_multiplier already exists";',
'ALTER TABLE package_materials ADD COLUMN geometry_multiplier VARCHAR(50) DEFAULT NULL COMMENT "area, length, width, spaer_count, perimeter, none";'
));
PREPARE alterStatement FROM @preparedStatement;
EXECUTE alterStatement;
DEALLOCATE PREPARE alterStatement;
SET @columnname = 'base_quantity';
SET @preparedStatement = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @dbname AND TABLE_NAME = @tablename AND COLUMN_NAME = @columnname) > 0,
'SELECT "Column base_quantity already exists";',
'ALTER TABLE package_materials ADD COLUMN base_quantity DECIMAL(10,3) DEFAULT NULL COMMENT "Basis mængde før geometri multiplikation";'
));
PREPARE alterStatement FROM @preparedStatement;
EXECUTE alterStatement;
DEALLOCATE PREPARE alterStatement;
SET @columnname = 'waste_factor';
SET @preparedStatement = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @dbname AND TABLE_NAME = @tablename AND COLUMN_NAME = @columnname) > 0,
'SELECT "Column waste_factor already exists";',
'ALTER TABLE package_materials ADD COLUMN waste_factor DECIMAL(5,3) DEFAULT 1.10 COMMENT "Spildfaktor (1.10 = 10% spild)";'
));
PREPARE alterStatement FROM @preparedStatement;
EXECUTE alterStatement;
DEALLOCATE PREPARE alterStatement;
-- Opdater eksisterende records med default værdier
UPDATE package_materials
SET
base_quantity = quantity,
waste_factor = 1.10,
geometry_multiplier = 'none'
WHERE base_quantity IS NULL;
-- Opret smart_packages tabel (hvis ikke eksisterer) til færdige packages
CREATE TABLE IF NOT EXISTS smart_packages (
id INT AUTO_INCREMENT PRIMARY KEY,
package_code VARCHAR(50) UNIQUE NOT NULL COMMENT 'B7, S12, etc',
package_name VARCHAR(255) NOT NULL,
package_description TEXT,
default_geometry_type ENUM('fladt_tag', 'skraat_tag', 'mansard', 'komplekst') DEFAULT 'skraat_tag',
estimated_total_hours DECIMAL(8,2) DEFAULT 0,
estimated_material_cost DECIMAL(12,2) DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_package_code (package_code),
INDEX idx_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Opret customer_project_packages junction tabel
CREATE TABLE IF NOT EXISTS customer_project_packages (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
smart_package_id INT NOT NULL,
quantity INT DEFAULT 1,
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE CASCADE,
FOREIGN KEY (smart_package_id) REFERENCES smart_packages(id) ON DELETE CASCADE,
INDEX idx_project_id (project_id),
INDEX idx_smart_package_id (smart_package_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Indsæt eksempel B7 package i material_packages tabel først
INSERT INTO material_packages (name, description, category, created_by, total_estimated_price, is_active)
VALUES ('B7 - Tag Renovation Komplet', 'Komplet tagrenovation med nedtagning, spær, undertag, tagplader og isolering', 'Tagmaterialer', 'system', 85000, 1)
ON DUPLICATE KEY UPDATE name = VALUES(name);
-- Hent B7 package ID
SET @b7_id = (SELECT id FROM material_packages WHERE name = 'B7 - Tag Renovation Komplet' LIMIT 1);
-- Indsæt også i smart_packages (reference tabel)
INSERT INTO smart_packages (package_code, package_name, package_description, estimated_total_hours, estimated_material_cost)
SELECT 'B7', name, description, 120, total_estimated_price
FROM material_packages
WHERE id = @b7_id
ON DUPLICATE KEY UPDATE package_name = VALUES(package_name);
-- Indsæt tasks for B7 package med rækkefølge
INSERT INTO package_tasks (package_id, task_name, task_description, estimated_hours, task_order, task_phase, depends_on_task_id)
VALUES
-- Fase 1: Forberedelse
(@b7_id, 'Stillads opsætning', 'Opsætte stillads rundt om hele bygningen', 8, 1, 'forberedelse', NULL),
(@b7_id, 'Sik kerhedsforanstaltninger', 'Opsætte sikkerhedsnet og advarselsskiltning', 2, 2, 'forberedelse', NULL),
-- Fase 2: Hovedarbejde (nedrivning først)
(@b7_id, 'Nedtagning af gamle tagplader', 'Fjerne og bortskaffe gamle tagplader', 12, 1, 'hovedarbejde', NULL),
(@b7_id, 'Fjernelse af gamle lægter', 'Fjerne gamle lægter og genbrugsmaterialer', 8, 2, 'hovedarbejde', NULL),
(@b7_id, 'Inspektion og reparation af spær', 'Inspicere spær og reparere/udskifte skadede dele', 12, 3, 'hovedarbejde', NULL),
(@b7_id, 'Montering af nyt undertag', 'Montere undertag med overlæg og tape', 16, 4, 'hovedarbejde', NULL),
(@b7_id, 'Montering af lægter', 'Montere nye lægter med korrekt afstand (0.6m eller 1.0m)', 14, 5, 'hovedarbejde', NULL),
(@b7_id, 'Montering af tagplader', 'Montere nye tagplader med overlæg og skruer', 20, 6, 'hovedarbejde', NULL),
(@b7_id, 'Montering af vindskeder', 'Montere vindskeder langs gavle', 10, 7, 'hovedarbejde', NULL),
-- Fase 3: Afslutning
(@b7_id, 'Montering af tagrende og nedløb', 'Montere tagrende og nedløb med korrekt fald', 12, 1, 'afslutning', NULL),
(@b7_id, 'Tætning og fuger', 'Tætne gennemføringer og fuger', 6, 2, 'afslutning', NULL),
(@b7_id, 'Oprydning', 'Fjerne affald og rengøre arbejdsområdet', 4, 3, 'afslutning', NULL),
-- Fase 4: Inspektion
(@b7_id, 'Endelig inspektion', 'Gennemgå hele taget for kvalitetskontrol', 4, 1, 'inspektion', NULL);
SELECT 'Feature 3 Migration Complete!' as Status;
SELECT
COUNT(*) as total_tasks,
task_phase,
SUM(estimated_hours) as phase_hours
FROM package_tasks
WHERE package_id = @b7_id
GROUP BY task_phase
ORDER BY FIELD(task_phase, 'forberedelse', 'hovedarbejde', 'afslutning', 'inspektion');