-- Bygma Prisbog Database Schema (Fixed Version) -- This creates tables for monthly Bygma price imports -- Separate from the vendor history system USE tilbudgivern; -- Drop existing triggers first to avoid conflicts DROP TRIGGER IF EXISTS tr_bygma_products_update_last_seen; DROP TRIGGER IF EXISTS tr_bygma_price_history_deactivate_old; DROP TRIGGER IF EXISTS tr_bygma_price_history_calculate_change; -- Drop existing tables in correct order to avoid foreign key constraints DROP TABLE IF EXISTS bygma_materials_mapping; DROP TABLE IF EXISTS bygma_price_history; DROP TABLE IF EXISTS bygma_import_log; DROP TABLE IF EXISTS bygma_product_groups; DROP TABLE IF EXISTS bygma_products; -- Main table for Bygma products from monthly prisbog CREATE TABLE bygma_products ( id INT PRIMARY KEY AUTO_INCREMENT, vareNr VARCHAR(50) NOT NULL UNIQUE, tekst TEXT, enhed VARCHAR(20), varegrp VARCHAR(10), db_nr VARCHAR(50), ean_nr VARCHAR(50), std VARCHAR(50), -- Current pricing (for quick access) current_gross_price DECIMAL(15,2), current_net_price DECIMAL(15,2), -- Metadata first_seen DATE, last_seen DATE, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_vareNr (vareNr), INDEX idx_varegrp (varegrp), INDEX idx_tekst (tekst(100)), INDEX idx_current_prices (current_gross_price, current_net_price), INDEX idx_active (is_active), INDEX idx_last_seen (last_seen) ); -- Product groups for categorization CREATE TABLE bygma_product_groups ( id INT PRIMARY KEY AUTO_INCREMENT, varegrp VARCHAR(10) NOT NULL UNIQUE, group_name VARCHAR(255), description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_varegrp (varegrp) ); -- Price history to track all price changes over time CREATE TABLE bygma_price_history ( id INT PRIMARY KEY AUTO_INCREMENT, product_id INT NOT NULL, gross_price DECIMAL(15,2), net_price DECIMAL(15,2), -- Price change tracking price_change_pct DECIMAL(8,4) DEFAULT 0, is_current BOOLEAN DEFAULT TRUE, -- Import metadata update_flag TINYINT DEFAULT 0, import_date DATE, import_file VARCHAR(500), import_batch_id VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (product_id) REFERENCES bygma_products(id) ON DELETE CASCADE, INDEX idx_product (product_id), INDEX idx_import_batch (import_batch_id), INDEX idx_import_date (import_date), INDEX idx_current (is_current), INDEX idx_prices (gross_price, net_price) ); -- Import log to track all imports CREATE TABLE bygma_import_log ( id INT PRIMARY KEY AUTO_INCREMENT, batch_id VARCHAR(100) NOT NULL UNIQUE, filename VARCHAR(500), file_hash VARCHAR(64), -- Import statistics total_rows INT DEFAULT 0, processed_rows INT DEFAULT 0, new_products INT DEFAULT 0, updated_products INT DEFAULT 0, errors INT DEFAULT 0, -- Status tracking status ENUM('pending', 'processing', 'completed', 'failed') DEFAULT 'pending', error_message TEXT, -- Timing started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, completed_at TIMESTAMP NULL, processing_time INT, -- seconds INDEX idx_batch_id (batch_id), INDEX idx_status (status), INDEX idx_started_at (started_at), INDEX idx_filename (filename(100)) ); -- Mapping table to connect Bygma products with existing materials CREATE TABLE bygma_materials_mapping ( id INT PRIMARY KEY AUTO_INCREMENT, bygma_product_id INT NOT NULL, material_id INT, -- Kan være NULL hvis ikke mappet endnu -- Mapping metadata mapping_type ENUM('auto', 'manual', 'ai_suggested') DEFAULT 'auto', mapping_confidence DECIMAL(5,4), -- 0.0 til 1.0 auto_update_price BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, mapped_by VARCHAR(100), FOREIGN KEY (bygma_product_id) REFERENCES bygma_products(id) ON DELETE CASCADE, INDEX idx_bygma_product (bygma_product_id), INDEX idx_material (material_id), INDEX idx_mapping_type (mapping_type), INDEX idx_auto_update (auto_update_price), -- Sikr kun én mapping per Bygma produkt UNIQUE KEY unique_bygma_mapping (bygma_product_id) ); -- Simplified Triggers (without recursive calls) DELIMITER // -- Trigger: Update last_seen when new price comes in CREATE TRIGGER tr_bygma_products_update_last_seen AFTER INSERT ON bygma_price_history FOR EACH ROW BEGIN UPDATE bygma_products SET last_seen = NEW.import_date, current_gross_price = NEW.gross_price, current_net_price = NEW.net_price, updated_at = CURRENT_TIMESTAMP WHERE id = NEW.product_id; END// -- Trigger: Calculate price change percentage CREATE TRIGGER tr_bygma_price_history_calculate_change BEFORE INSERT ON bygma_price_history FOR EACH ROW BEGIN DECLARE prev_price DECIMAL(15,2); -- Find previous price SELECT net_price INTO prev_price FROM bygma_price_history WHERE product_id = NEW.product_id AND is_current = TRUE ORDER BY created_at DESC LIMIT 1; -- Calculate change if there's a previous price IF prev_price IS NOT NULL AND prev_price > 0 THEN SET NEW.price_change_pct = ((NEW.net_price - prev_price) / prev_price) * 100; END IF; -- Mark all other prices for this product as not current UPDATE bygma_price_history SET is_current = FALSE WHERE product_id = NEW.product_id; END// DELIMITER ; -- Useful views for reporting and analysis -- View: Current prices with product details CREATE VIEW v_bygma_current_prices AS SELECT p.id, p.vareNr, p.tekst, p.enhed, p.varegrp, p.current_gross_price, p.current_net_price, p.last_seen, pg.group_name, mm.material_id as mapped_material_id, mm.mapping_type, mm.auto_update_price FROM bygma_products p LEFT JOIN bygma_product_groups pg ON p.varegrp = pg.varegrp LEFT JOIN bygma_materials_mapping mm ON p.id = mm.bygma_product_id WHERE p.is_active = TRUE; -- View: Price history with changes CREATE VIEW v_bygma_price_changes AS SELECT ph.id, p.vareNr, p.tekst, ph.gross_price, ph.net_price, ph.price_change_pct, ph.import_date, ph.import_file, ph.is_current FROM bygma_price_history ph JOIN bygma_products p ON ph.product_id = p.id ORDER BY ph.import_date DESC, p.vareNr; -- View: Import statistics CREATE VIEW v_bygma_import_stats AS SELECT il.id, il.batch_id, il.filename, il.total_rows, il.processed_rows, il.new_products, il.updated_products, il.errors, il.status, il.started_at, il.completed_at, il.processing_time, ROUND((il.processed_rows / il.total_rows) * 100, 2) as success_rate_pct FROM bygma_import_log il ORDER BY il.started_at DESC; -- Add some basic product groups INSERT INTO bygma_product_groups (varegrp, group_name) VALUES ('3310', 'Porebeton og isolering'), ('3320', 'Leca og letbeton'), ('3330', 'Mursten og blokke') ON DUPLICATE KEY UPDATE group_name = VALUES(group_name); -- Grant necessary permissions to service user (run by admin separately if needed) -- GRANT ALL PRIVILEGES ON tilbudgivern.bygma_* TO 'tilbudgivern_service'@'localhost'; -- GRANT SELECT ON tilbudgivern.v_bygma_* TO 'tilbudgivern_service'@'localhost'; -- FLUSH PRIVILEGES;