- Implement test script for Bygma ESG data import (test_bygma_import.js) - Create test script for Bygma Prisbog import functionality (test_bygma_prisbog_import.js) - Develop full integration test for Bygma materials system (test_full_bygma_integration.js) - Add materials synchronization test script (test_materials_sync.js) - Ensure database connection and import statistics are logged - Validate API visibility and price updates in integration tests - Include sample data checks and cleanup procedures in tests
260 lines
7.5 KiB
SQL
260 lines
7.5 KiB
SQL
-- 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;
|