206 lines
6.9 KiB
SQL
206 lines
6.9 KiB
SQL
-- Enhanced quote database structure
|
|
-- This script creates tables to store detailed quote information for better reporting
|
|
|
|
-- Create project_types table for standardized project types
|
|
CREATE TABLE IF NOT EXISTS project_types (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
type_name VARCHAR(100) NOT NULL UNIQUE,
|
|
type_icon VARCHAR(10) DEFAULT NULL,
|
|
description TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Insert standard project types
|
|
INSERT IGNORE INTO project_types (type_name, type_icon, description) VALUES
|
|
('tagrenovering', '🏠', 'Komplet renovering af eksisterende tag'),
|
|
('tagskifte', '🔧', 'Udskiftning af tagmaterialer'),
|
|
('tagudskiftning', '🔨', 'Fuldstændig udskiftning af tag'),
|
|
('tagreparation', '⚒️', 'Reparation af eksisterende tag'),
|
|
('tagterasse', '🏗️', 'Installation eller renovering af tagterasse'),
|
|
('tageftersyn', '🔍', 'Inspektion og mindre reparationer');
|
|
|
|
-- Create roof_types table for standardized roof types
|
|
CREATE TABLE IF NOT EXISTS roof_types (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
roof_name VARCHAR(100) NOT NULL UNIQUE,
|
|
roof_icon VARCHAR(10) DEFAULT NULL,
|
|
description TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Insert standard roof types
|
|
INSERT IGNORE INTO roof_types (roof_name, roof_icon, description) VALUES
|
|
('skrå tag', '📐', 'Traditionelt skrå tag med hældning'),
|
|
('fladt tag', '📏', 'Fladt tag eller tagterasse'),
|
|
('tagterasse', '🏗️', 'Bebygget tagterasse'),
|
|
('mansardtag', '🏛️', 'Tag med knækket profil'),
|
|
('saddeltag', '⛺', 'Klassisk saddeltag');
|
|
|
|
-- Add project_type_id to customer_projects table
|
|
ALTER TABLE customer_projects
|
|
ADD COLUMN project_type_id INT DEFAULT NULL,
|
|
ADD FOREIGN KEY (project_type_id) REFERENCES project_types(id);
|
|
|
|
-- Add roof_type_id to roof_geometry table
|
|
ALTER TABLE roof_geometry
|
|
ADD COLUMN roof_type_id INT DEFAULT NULL,
|
|
ADD FOREIGN KEY (roof_type_id) REFERENCES roof_types(id);
|
|
|
|
-- Create enhanced_quote_details table to store additional quote information
|
|
CREATE TABLE IF NOT EXISTS enhanced_quote_details (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
quote_id INT NOT NULL,
|
|
project_type_id INT,
|
|
roof_type_id INT,
|
|
total_area DECIMAL(10,2),
|
|
roof_pitch DECIMAL(5,2),
|
|
work_hours DECIMAL(8,2),
|
|
worker_count INT,
|
|
hourly_rate DECIMAL(8,2),
|
|
material_count INT DEFAULT 0,
|
|
material_categories JSON,
|
|
labor_breakdown JSON,
|
|
material_breakdown JSON,
|
|
pricing_details JSON,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (quote_id) REFERENCES generated_quotes(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (project_type_id) REFERENCES project_types(id),
|
|
FOREIGN KEY (roof_type_id) REFERENCES roof_types(id)
|
|
);
|
|
|
|
-- Create index for faster lookups
|
|
CREATE INDEX idx_enhanced_quote_details_quote_id ON enhanced_quote_details(quote_id);
|
|
CREATE INDEX idx_customer_projects_type ON customer_projects(project_type_id);
|
|
CREATE INDEX idx_roof_geometry_type ON roof_geometry(roof_type_id);
|
|
|
|
-- Create view for easy quote retrieval with all details
|
|
CREATE OR REPLACE VIEW v_enhanced_quotes AS
|
|
SELECT
|
|
gq.id,
|
|
gq.quote_text,
|
|
gq.quote_format,
|
|
gq.ai_tokens_used,
|
|
gq.ai_cost,
|
|
gq.ai_model,
|
|
gq.created_at,
|
|
gq.updated_at,
|
|
-- Project information
|
|
cp.project_name,
|
|
cp.customer_name,
|
|
cp.customer_email,
|
|
cp.customer_phone,
|
|
cp.customer_address,
|
|
cp.project_description,
|
|
cp.project_status,
|
|
pt.type_name as project_type,
|
|
pt.type_icon as project_icon,
|
|
-- Calculation details
|
|
pc.total_incl_vat,
|
|
pc.total_labor_cost,
|
|
pc.total_material_cost,
|
|
pc.subtotal,
|
|
pc.vat_amount,
|
|
pc.vat_percentage,
|
|
pc.overhead_percentage,
|
|
pc.profit_percentage,
|
|
-- Geometry details
|
|
rg.total_area,
|
|
rt.roof_name as roof_type,
|
|
rt.roof_icon as roof_icon,
|
|
rg.roof_pitch,
|
|
rg.length,
|
|
rg.width,
|
|
-- Labor details
|
|
pl.total_work_hours,
|
|
pl.carpenter_count,
|
|
pl.hourly_rate,
|
|
-- Enhanced details
|
|
eqd.material_count,
|
|
eqd.material_categories,
|
|
eqd.labor_breakdown,
|
|
eqd.material_breakdown,
|
|
eqd.pricing_details
|
|
FROM generated_quotes gq
|
|
LEFT JOIN project_calculations pc ON gq.calculation_id = pc.id
|
|
LEFT JOIN customer_projects cp ON gq.project_id = cp.id
|
|
LEFT JOIN project_types pt ON cp.project_type_id = pt.id
|
|
LEFT JOIN roof_geometry rg ON cp.id = rg.project_id
|
|
LEFT JOIN roof_types rt ON rg.roof_type_id = rt.id
|
|
LEFT JOIN project_labor pl ON cp.id = pl.project_id
|
|
LEFT JOIN enhanced_quote_details eqd ON gq.id = eqd.quote_id;
|
|
|
|
-- Create trigger to automatically populate enhanced_quote_details when a quote is created
|
|
DELIMITER //
|
|
CREATE OR REPLACE TRIGGER tr_populate_enhanced_quote_details
|
|
AFTER INSERT ON generated_quotes
|
|
FOR EACH ROW
|
|
BEGIN
|
|
DECLARE project_type_id_val INT DEFAULT NULL;
|
|
DECLARE roof_type_id_val INT DEFAULT NULL;
|
|
DECLARE area_val DECIMAL(10,2) DEFAULT NULL;
|
|
DECLARE pitch_val DECIMAL(5,2) DEFAULT NULL;
|
|
DECLARE hours_val DECIMAL(8,2) DEFAULT NULL;
|
|
DECLARE workers_val INT DEFAULT NULL;
|
|
DECLARE rate_val DECIMAL(8,2) DEFAULT NULL;
|
|
DECLARE material_cnt INT DEFAULT 0;
|
|
DECLARE material_cats JSON DEFAULT NULL;
|
|
|
|
-- Get project type
|
|
SELECT cp.project_type_id INTO project_type_id_val
|
|
FROM customer_projects cp
|
|
WHERE cp.id = NEW.project_id;
|
|
|
|
-- Get roof information
|
|
SELECT rg.roof_type_id, rg.total_area, rg.roof_pitch
|
|
INTO roof_type_id_val, area_val, pitch_val
|
|
FROM roof_geometry rg
|
|
WHERE rg.project_id = NEW.project_id;
|
|
|
|
-- Get labor information
|
|
SELECT pl.total_work_hours, pl.carpenter_count, pl.hourly_rate
|
|
INTO hours_val, workers_val, rate_val
|
|
FROM project_labor pl
|
|
WHERE pl.project_id = NEW.project_id;
|
|
|
|
-- Get material information
|
|
SELECT COUNT(*), JSON_ARRAYAGG(DISTINCT material_category)
|
|
INTO material_cnt, material_cats
|
|
FROM project_materials pm
|
|
WHERE pm.project_id = NEW.project_id;
|
|
|
|
-- Insert enhanced details
|
|
INSERT INTO enhanced_quote_details (
|
|
quote_id, project_type_id, roof_type_id, total_area, roof_pitch,
|
|
work_hours, worker_count, hourly_rate, material_count, material_categories
|
|
) VALUES (
|
|
NEW.id, project_type_id_val, roof_type_id_val, area_val, pitch_val,
|
|
hours_val, workers_val, rate_val, material_cnt, material_cats
|
|
);
|
|
END//
|
|
DELIMITER ;
|
|
|
|
-- Update existing quotes to have enhanced details
|
|
INSERT INTO enhanced_quote_details (
|
|
quote_id, project_type_id, roof_type_id, total_area, roof_pitch,
|
|
work_hours, worker_count, hourly_rate, material_count, material_categories
|
|
)
|
|
SELECT
|
|
gq.id,
|
|
cp.project_type_id,
|
|
rg.roof_type_id,
|
|
rg.total_area,
|
|
rg.roof_pitch,
|
|
pl.total_work_hours,
|
|
pl.carpenter_count,
|
|
pl.hourly_rate,
|
|
COALESCE((SELECT COUNT(*) FROM project_materials pm WHERE pm.project_id = cp.id), 0),
|
|
COALESCE((SELECT JSON_ARRAYAGG(DISTINCT material_category) FROM project_materials pm WHERE pm.project_id = cp.id), JSON_ARRAY())
|
|
FROM generated_quotes gq
|
|
LEFT JOIN customer_projects cp ON gq.project_id = cp.id
|
|
LEFT JOIN roof_geometry rg ON cp.id = rg.project_id
|
|
LEFT JOIN project_labor pl ON cp.id = pl.project_id
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM enhanced_quote_details eqd WHERE eqd.quote_id = gq.id
|
|
);
|