Files
tilbudgivern/bygma_prisbog_database_final.sql
T
alex fe8d73e8d1 Add integration tests for Bygma import services
- 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
2025-09-18 13:24:50 +02:00

283 lines
8.5 KiB
SQL

-- Bygma Prisbog Database Schema - Final Version
-- Perfectly aligned with actual CSV structure
-- CSV columns: Varegrp;VareNr;Tekst;Enhed;BruttoPris;Opdat;Nettopris;DB-nr;EAN-nr;Std
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_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 - exactly matching CSV structure
CREATE TABLE bygma_products (
id INT PRIMARY KEY AUTO_INCREMENT,
-- Exact CSV columns
varegrp VARCHAR(10), -- CSV: Varegrp
vareNr VARCHAR(50) NOT NULL, -- CSV: VareNr (unique identifier)
tekst TEXT, -- CSV: Tekst
enhed VARCHAR(20), -- CSV: Enhed
db_nr VARCHAR(50), -- CSV: DB-nr
ean_nr VARCHAR(50), -- CSV: EAN-nr
std VARCHAR(50), -- CSV: Std
-- Current pricing (from most recent import)
current_brutto_pris DECIMAL(15,2), -- CSV: BruttoPris
current_netto_pris DECIMAL(15,2), -- CSV: Nettopris
current_opdat TINYINT, -- CSV: Opdat
-- 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,
-- Indexes for performance
UNIQUE KEY idx_vareNr (vareNr),
INDEX idx_varegrp (varegrp),
INDEX idx_tekst (tekst(100)),
INDEX idx_current_prices (current_brutto_pris, current_netto_pris),
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,
-- Exact price fields from CSV
brutto_pris DECIMAL(15,2), -- CSV: BruttoPris
netto_pris DECIMAL(15,2), -- CSV: Nettopris
opdat TINYINT, -- CSV: Opdat
-- Price change tracking
price_change_pct DECIMAL(8,4) DEFAULT 0,
is_current BOOLEAN DEFAULT TRUE,
-- Import metadata
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 (brutto_pris, netto_pris)
);
-- Import log to track all imports
CREATE TABLE bygma_import_log (
id INT PRIMARY KEY AUTO_INCREMENT,
import_batch_id VARCHAR(100) NOT NULL UNIQUE,
filename VARCHAR(500),
filepath VARCHAR(500),
file_hash VARCHAR(64),
file_size BIGINT,
-- Import statistics
total_rows INT DEFAULT 0,
processed_rows INT DEFAULT 0,
successful_rows INT DEFAULT 0,
failed_rows INT DEFAULT 0,
new_products INT DEFAULT 0,
updated_products INT DEFAULT 0,
updated_prices INT DEFAULT 0,
-- Status tracking
status ENUM('pending', 'processing', 'completed', 'failed') DEFAULT 'pending',
error_summary TEXT,
warnings TEXT,
-- Timing
started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP NULL,
duration_seconds INT,
-- User tracking
imported_by VARCHAR(100),
INDEX idx_batch_id (import_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, -- Can be NULL if not mapped yet
-- Mapping metadata
mapping_type ENUM('auto', 'manual', 'ai_suggested') DEFAULT 'auto',
mapping_confidence DECIMAL(5,4), -- 0.0 to 1.0
auto_update_price BOOLEAN DEFAULT FALSE,
price_markup_pct DECIMAL(8,4) DEFAULT 0, -- Markup percentage
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),
-- Ensure only one mapping per Bygma product
UNIQUE KEY unique_bygma_mapping (bygma_product_id)
);
-- Simplified Triggers (without recursive calls)
DELIMITER //
-- Trigger: Update last_seen and current prices 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_brutto_pris = NEW.brutto_pris,
current_netto_pris = NEW.netto_pris,
current_opdat = NEW.opdat,
updated_at = CURRENT_TIMESTAMP
WHERE id = NEW.product_id;
END//
-- Trigger: Calculate price change percentage and mark previous prices as not current
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 netto_pris 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.netto_pris - 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_brutto_pris,
p.current_netto_pris,
p.current_opdat,
p.last_seen,
pg.group_name,
mm.material_id as mapped_material_id,
mm.mapping_type,
mm.auto_update_price,
mm.price_markup_pct
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.brutto_pris,
ph.netto_pris,
ph.opdat,
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.import_batch_id,
il.filename,
il.total_rows,
il.processed_rows,
il.successful_rows,
il.failed_rows,
il.new_products,
il.updated_products,
il.updated_prices,
il.status,
il.started_at,
il.completed_at,
il.duration_seconds,
il.imported_by,
ROUND((il.successful_rows / NULLIF(il.total_rows, 0)) * 100, 2) as success_rate_pct
FROM bygma_import_log il
ORDER BY il.started_at DESC;
-- Add some basic product groups based on common Bygma categories
INSERT INTO bygma_product_groups (varegrp, group_name) VALUES
('1000', 'Tømmer og planker'),
('3310', 'Porebeton og isolering'),
('3320', 'Leca og letbeton'),
('3330', 'Mursten og blokke'),
('2000', 'Plader og isolering'),
('4000', 'Tagmaterialer'),
('5000', 'Vinduer og døre'),
('6000', 'Beton og cement'),
('7000', 'Værktøj'),
('8000', 'Beslag og fittings'),
('9000', 'Diverse byggematerialer')
ON DUPLICATE KEY UPDATE group_name = VALUES(group_name);