-- 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) );