Files
tilbudgivern/backend/sql/customer_project_system.sql
2026-07-05 08:10:59 +00:00

317 lines
11 KiB
SQL

-- Customer Project System Database Schema
-- Opretter tabeller for det nye strukturerede tilbuds-flow
-- Kunde projekter
CREATE TABLE IF NOT EXISTS customer_projects (
id INT AUTO_INCREMENT PRIMARY KEY,
project_name VARCHAR(255) NOT NULL,
customer_name VARCHAR(255) NOT NULL,
customer_number VARCHAR(50),
customer_email VARCHAR(255),
customer_phone VARCHAR(50),
customer_address TEXT,
project_description TEXT,
selected_packages JSON,
suggestion_snapshot JSON,
input_normalization_log JSON,
project_status ENUM(
'draft',
'geometry_complete',
'smart_package_complete',
'review_pending',
'ready_for_ordrestyring',
'sent_to_ordrestyring',
'accepted',
'rejected',
'geometry_pending',
'labor_pending',
'materials_pending',
'calculation_ready',
'quote_generated',
'sent'
) DEFAULT 'draft',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_status (project_status),
INDEX idx_customer (customer_name),
INDEX idx_customer_number (customer_number),
INDEX idx_created (created_at)
);
-- Tag geometri specifikt for tag arbejde
CREATE TABLE IF NOT EXISTS roof_geometry (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
roof_type ENUM('fladt_tag', 'skraat_tag', 'mansard', 'komplekst') NOT NULL,
total_area DECIMAL(10,2) NOT NULL COMMENT 'Samlet areal i m²',
roof_pitch DECIMAL(5,2) COMMENT 'Taghældning i grader',
roof_height DECIMAL(8,2) COMMENT 'Taghøjde i meter',
complexity_factor DECIMAL(3,2) DEFAULT 1.0 COMMENT 'Kompleksitetsfaktor 1.0-2.0',
-- Detaljerede målinger
length_main DECIMAL(8,2) COMMENT 'Hovedlængde i meter',
width_main DECIMAL(8,2) COMMENT 'Hovedbredde i meter',
-- Specielle forhold
has_dormers BOOLEAN DEFAULT FALSE COMMENT 'Har kviste',
has_chimneys BOOLEAN DEFAULT FALSE COMMENT 'Har skorstene',
has_skylights BOOLEAN DEFAULT FALSE COMMENT 'Har ovenlys',
access_difficulty ENUM('let', 'medium', 'svær') DEFAULT 'medium',
-- Beregnet data
estimated_work_hours DECIMAL(8,2) COMMENT 'Estimerede arbejdstimer',
estimated_carpenters INT COMMENT 'Anbefalede antal tømrere',
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE CASCADE,
INDEX idx_project (project_id),
INDEX idx_roof_type (roof_type)
);
-- Arbejdstimer og tømrere
CREATE TABLE IF NOT EXISTS project_labor (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
carpenter_count INT NOT NULL DEFAULT 1,
estimated_hours_per_carpenter DECIMAL(8,2) NOT NULL,
total_work_hours DECIMAL(8,2) NOT NULL,
hourly_rate DECIMAL(8,2) NOT NULL DEFAULT 580.00 COMMENT 'Fast pris 580 kr/time',
total_labor_cost DECIMAL(12,2) NOT NULL,
-- Detaljer om arbejdsopgaver
work_breakdown JSON COMMENT 'Detaljeret opdeling af arbejdsopgaver',
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE CASCADE,
INDEX idx_project (project_id)
);
-- Projekt materialer
CREATE TABLE IF NOT EXISTS project_materials (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
material_name VARCHAR(255) NOT NULL,
material_category VARCHAR(100),
quantity DECIMAL(10,3) NOT NULL,
unit VARCHAR(50) NOT NULL,
unit_price DECIMAL(10,2) NOT NULL,
total_price DECIMAL(12,2) NOT NULL,
supplier VARCHAR(255),
material_source ENUM('manual', 'database', 'bygma_api') DEFAULT 'manual',
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE CASCADE,
INDEX idx_project (project_id),
INDEX idx_category (material_category)
);
-- Projekt beregninger (råtilbud)
CREATE TABLE IF NOT EXISTS project_calculations (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
-- Geometri opsummering
total_area DECIMAL(10,2),
complexity_factor DECIMAL(3,2),
-- Arbejdstimer opsummering
total_work_hours DECIMAL(8,2),
carpenter_count INT,
total_labor_cost DECIMAL(12,2),
-- Materialer opsummering
total_material_cost DECIMAL(12,2),
material_count INT,
-- Totaler
subtotal DECIMAL(12,2),
overhead_percentage DECIMAL(5,2) DEFAULT 15.00,
overhead_amount DECIMAL(12,2),
profit_percentage DECIMAL(5,2) DEFAULT 20.00,
profit_amount DECIMAL(12,2),
total_excl_vat DECIMAL(12,2),
vat_percentage DECIMAL(5,2) DEFAULT 25.00,
vat_amount DECIMAL(12,2),
total_incl_vat DECIMAL(12,2),
-- Metadata
calculation_data JSON COMMENT 'Detaljerede beregningsdata',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE CASCADE,
INDEX idx_project (project_id)
);
-- Genererede tilbud
CREATE TABLE IF NOT EXISTS generated_quotes (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NOT NULL,
calculation_id INT NOT NULL,
quote_text TEXT NOT NULL COMMENT 'AI-genereret tilbudstekst',
quote_format ENUM('text', 'html', 'pdf') DEFAULT 'html',
-- AI usage tracking
ai_tokens_used INT,
ai_cost DECIMAL(8,4),
ai_model VARCHAR(50),
quote_status ENUM('draft', 'approved', 'sent', 'accepted', 'rejected') DEFAULT 'draft',
sent_at TIMESTAMP NULL,
valid_until DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE CASCADE,
FOREIGN KEY (calculation_id) REFERENCES project_calculations(id) ON DELETE CASCADE,
INDEX idx_project (project_id),
INDEX idx_status (quote_status)
);
CREATE TABLE IF NOT EXISTS ordrestyring_case_features (
case_number VARCHAR(64) PRIMARY KEY,
customer_number VARCHAR(64),
customer_name VARCHAR(255),
description TEXT,
remarks TEXT,
search_text MEDIUMTEXT,
inferred_roof_type VARCHAR(100),
inferred_package_id VARCHAR(100),
total_hours DECIMAL(10,2) DEFAULT 0,
hour_entries INT DEFAULT 0,
material_lines_count INT DEFAULT 0,
material_total DECIMAL(12,2) DEFAULT 0,
created_at_ordrestyring DATETIME NULL,
last_activity_at_ordrestyring DATETIME NULL,
synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_case_features_customer_number (customer_number),
INDEX idx_case_features_customer_name (customer_name),
INDEX idx_case_features_roof_type (inferred_roof_type),
INDEX idx_case_features_package (inferred_package_id),
INDEX idx_case_features_created_at (created_at_ordrestyring),
INDEX idx_case_features_last_activity (last_activity_at_ordrestyring)
);
CREATE TABLE IF NOT EXISTS ordrestyring_case_material_snapshots (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
case_number VARCHAR(64) NOT NULL,
line_id INT NOT NULL,
product_number VARCHAR(128),
product_text TEXT,
supplier VARCHAR(255),
quantity DECIMAL(12,3) DEFAULT 0,
cost_price DECIMAL(12,2) DEFAULT 0,
sales_price DECIMAL(12,2) DEFAULT 0,
created_at_ordrestyring DATETIME NULL,
synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uniq_ordrestyring_case_material_line (case_number, line_id),
INDEX idx_ordrestyring_case_material_case_number (case_number),
INDEX idx_ordrestyring_case_material_supplier (supplier)
);
CREATE TABLE IF NOT EXISTS ordrestyring_offer_snapshots (
offer_id INT PRIMARY KEY,
offer_number VARCHAR(64),
customer_name VARCHAR(255),
customer_email VARCHAR(255),
description TEXT,
status_text VARCHAR(255),
search_text MEDIUMTEXT,
total_sales_price DECIMAL(12,2) DEFAULT 0,
total_sales_price_with_vat DECIMAL(12,2) DEFAULT 0,
created_at_ordrestyring DATETIME NULL,
synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_offer_snapshots_customer_name (customer_name),
INDEX idx_offer_snapshots_status (status_text),
INDEX idx_offer_snapshots_created_at (created_at_ordrestyring)
);
CREATE TABLE IF NOT EXISTS ordrestyring_offer_line_snapshots (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
offer_id INT NOT NULL,
line_id INT NOT NULL,
description TEXT,
quantity DECIMAL(12,3) DEFAULT 0,
unit VARCHAR(50),
unit_price DECIMAL(12,2) DEFAULT 0,
line_total DECIMAL(12,2) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uniq_ordrestyring_offer_line (offer_id, line_id),
INDEX idx_ordrestyring_offer_line_offer_id (offer_id),
CONSTRAINT fk_ordrestyring_offer_line_offer
FOREIGN KEY (offer_id) REFERENCES ordrestyring_offer_snapshots(offer_id)
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS ordrestyring_sync_metadata (
id INT AUTO_INCREMENT PRIMARY KEY,
project_id INT NULL,
case_number VARCHAR(64) NULL,
offer_id INT NULL,
offer_number VARCHAR(64) NULL,
last_status VARCHAR(128) NULL,
last_status_at DATETIME NULL,
last_price_list_synced_at DATETIME NULL,
last_material_sync_at DATETIME NULL,
notes TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (project_id) REFERENCES customer_projects(id) ON DELETE SET NULL,
INDEX idx_ordrestyring_metadata_project (project_id),
INDEX idx_ordrestyring_metadata_case (case_number),
UNIQUE KEY uniq_ordrestyring_metadata_case (case_number),
UNIQUE KEY uniq_ordrestyring_metadata_offer (offer_id)
);
-- Bygma API cache (for version 2)
CREATE TABLE IF NOT EXISTS bygma_materials_cache (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id VARCHAR(100) UNIQUE,
product_name VARCHAR(255),
category VARCHAR(100),
subcategory VARCHAR(100),
unit VARCHAR(50),
price DECIMAL(10,2),
stock_status VARCHAR(50),
supplier_info JSON,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_category (category),
INDEX idx_name (product_name),
INDEX idx_updated (last_updated)
);
-- Stark API cache (samme struktur som Bygma)
CREATE TABLE IF NOT EXISTS stark_materials_cache (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id VARCHAR(100) UNIQUE,
product_name VARCHAR(255),
category VARCHAR(100),
subcategory VARCHAR(100),
unit VARCHAR(50),
price DECIMAL(10,2),
stock_status VARCHAR(50),
supplier_info JSON,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_category (category),
INDEX idx_name (product_name),
INDEX idx_updated (last_updated)
);