- 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
245 lines
8.4 KiB
SQL
245 lines
8.4 KiB
SQL
-- Database struktur til månedlige Bygma prisbøger
|
|
-- Dette skema håndterer løbende prisimport fra Bygma's månedlige prislister
|
|
|
|
-- Hovedtabel for Bygma produkter (master data)
|
|
CREATE TABLE IF NOT EXISTS bygma_products (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
-- Produkt identifikation
|
|
product_code VARCHAR(255) NOT NULL UNIQUE, -- VareNr fra CSV
|
|
product_group VARCHAR(100) NOT NULL, -- Varegrp fra CSV
|
|
product_name TEXT NOT NULL, -- Tekst fra CSV
|
|
unit VARCHAR(50) NOT NULL, -- Enhed fra CSV
|
|
|
|
-- Tekniske felter
|
|
db_number VARCHAR(100), -- DB-nr fra CSV
|
|
ean_number VARCHAR(100), -- EAN-nr fra CSV
|
|
standard_field VARCHAR(100), -- Std fra CSV
|
|
|
|
-- Metadata
|
|
first_seen DATE NOT NULL,
|
|
last_seen DATE NOT NULL,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
|
-- Indices for performance
|
|
INDEX idx_product_code (product_code),
|
|
INDEX idx_product_group (product_group),
|
|
INDEX idx_product_name (product_name(100)),
|
|
INDEX idx_active (is_active),
|
|
INDEX idx_last_seen (last_seen)
|
|
);
|
|
|
|
-- Varegrupper/kategorier fra Bygma
|
|
CREATE TABLE IF NOT EXISTS bygma_product_groups (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
group_code VARCHAR(100) NOT NULL UNIQUE, -- Varegrp fra CSV
|
|
group_name VARCHAR(255), -- Kan tilføjes manuelt eller mapping
|
|
parent_group VARCHAR(100), -- For hierarkisk struktur
|
|
description TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
INDEX idx_group_code (group_code),
|
|
INDEX idx_group_name (group_name)
|
|
);
|
|
|
|
-- Prishistorik fra månedlige imports
|
|
CREATE TABLE IF NOT EXISTS bygma_price_history (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
product_id INT NOT NULL,
|
|
|
|
-- Priser fra CSV
|
|
gross_price DECIMAL(15,2) NOT NULL, -- BruttoPris fra CSV
|
|
net_price DECIMAL(15,2) NOT NULL, -- Nettopris fra CSV (vores indkøbspris)
|
|
update_flag TINYINT NOT NULL DEFAULT 1, -- Opdat fra CSV
|
|
|
|
-- Import metadata
|
|
import_date DATE NOT NULL, -- Dato for denne import
|
|
import_file VARCHAR(255) NOT NULL, -- Filnavn på importeret CSV
|
|
import_batch_id VARCHAR(100) NOT NULL, -- Unik ID for denne import batch
|
|
file_hash VARCHAR(64), -- SHA256 hash af CSV fil for duplikat check
|
|
|
|
-- Validering
|
|
is_current BOOLEAN DEFAULT TRUE, -- Er dette den aktuelle pris?
|
|
price_change_pct DECIMAL(8,4), -- Procentvis ændring fra forrige pris
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
FOREIGN KEY (product_id) REFERENCES bygma_products(id) ON DELETE CASCADE,
|
|
|
|
-- Indices for performance
|
|
INDEX idx_product_date (product_id, import_date),
|
|
INDEX idx_import_batch (import_batch_id),
|
|
INDEX idx_import_date (import_date),
|
|
INDEX idx_current (is_current),
|
|
INDEX idx_file_hash (file_hash),
|
|
|
|
-- Unik constraint: kun én pris per produkt per import
|
|
UNIQUE KEY unique_product_import (product_id, import_batch_id)
|
|
);
|
|
|
|
-- Log over imports for sporing
|
|
CREATE TABLE IF NOT EXISTS bygma_import_log (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
-- Import detaljer
|
|
import_batch_id VARCHAR(100) NOT NULL UNIQUE,
|
|
filename VARCHAR(255) NOT NULL,
|
|
filepath VARCHAR(500) NOT NULL,
|
|
file_size BIGINT NOT NULL,
|
|
file_hash VARCHAR(64) NOT NULL,
|
|
|
|
-- Import statistik
|
|
total_rows INT NOT NULL DEFAULT 0,
|
|
processed_rows INT NOT NULL DEFAULT 0,
|
|
successful_rows INT NOT NULL DEFAULT 0,
|
|
failed_rows INT NOT NULL DEFAULT 0,
|
|
new_products INT NOT NULL DEFAULT 0,
|
|
updated_prices INT NOT NULL DEFAULT 0,
|
|
|
|
-- Fejl og advarsler
|
|
error_summary JSON, -- Samling af fejl der opstod
|
|
warnings JSON, -- Advarsler (fx store prisændringer)
|
|
|
|
-- Import tider
|
|
started_at TIMESTAMP NOT NULL,
|
|
completed_at TIMESTAMP,
|
|
duration_seconds INT,
|
|
|
|
-- Status
|
|
status ENUM('running', 'completed', 'failed', 'cancelled') DEFAULT 'running',
|
|
imported_by VARCHAR(100), -- Hvem startede importen
|
|
|
|
INDEX idx_batch_id (import_batch_id),
|
|
INDEX idx_filename (filename),
|
|
INDEX idx_status (status),
|
|
INDEX idx_started_at (started_at),
|
|
INDEX idx_file_hash (file_hash)
|
|
);
|
|
|
|
-- Aktuelle priser view for nem adgang
|
|
CREATE OR REPLACE VIEW bygma_current_prices AS
|
|
SELECT
|
|
p.id as product_id,
|
|
p.product_code,
|
|
p.product_group,
|
|
p.product_name,
|
|
p.unit,
|
|
p.db_number,
|
|
p.ean_number,
|
|
ph.gross_price,
|
|
ph.net_price,
|
|
ph.import_date,
|
|
ph.import_file,
|
|
p.is_active as product_active
|
|
FROM bygma_products p
|
|
JOIN bygma_price_history ph ON p.id = ph.product_id
|
|
WHERE ph.is_current = TRUE
|
|
AND p.is_active = TRUE;
|
|
|
|
-- Integration med eksisterende materials system
|
|
-- Denne tabel mapper Bygma produkter til vores materials tabel
|
|
CREATE TABLE IF NOT EXISTS bygma_materials_mapping (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
-- Links
|
|
bygma_product_id INT NOT NULL,
|
|
material_id INT, -- Kan være NULL hvis ikke mapped endnu
|
|
|
|
-- Mapping detaljer
|
|
mapping_type ENUM('automatic', 'manual', 'verified') DEFAULT 'automatic',
|
|
mapping_confidence DECIMAL(3,2), -- 0.00-1.00 confidence score
|
|
mapping_notes TEXT,
|
|
|
|
-- Auto-sync indstillinger
|
|
auto_update_price BOOLEAN DEFAULT TRUE, -- Skal priser auto-opdateres i materials?
|
|
price_markup_pct DECIMAL(8,4) DEFAULT 0, -- Markup på Bygma priser
|
|
|
|
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)
|
|
);
|
|
|
|
-- Triggers til at opdatere timestamps og vedligeholde data integritet
|
|
|
|
-- Trigger: Opdater last_seen når der kommer ny pris
|
|
DELIMITER //
|
|
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,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = NEW.product_id;
|
|
END//
|
|
|
|
-- Trigger: Deaktiver gamle priser når nye kommer
|
|
CREATE TRIGGER tr_bygma_price_history_deactivate_old
|
|
AFTER INSERT ON bygma_price_history
|
|
FOR EACH ROW
|
|
BEGIN
|
|
-- Deaktiver alle andre priser for dette produkt
|
|
UPDATE bygma_price_history
|
|
SET is_current = FALSE
|
|
WHERE product_id = NEW.product_id
|
|
AND id != NEW.id;
|
|
END//
|
|
|
|
-- Trigger: Beregn prisændring procentvis
|
|
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 forrige pris
|
|
SELECT net_price INTO prev_price
|
|
FROM bygma_price_history
|
|
WHERE product_id = NEW.product_id
|
|
AND is_current = TRUE
|
|
LIMIT 1;
|
|
|
|
-- Beregn ændring hvis der er en forrige pris
|
|
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;
|
|
END//
|
|
|
|
DELIMITER ;
|
|
|
|
-- Indsæt Bygma som leverandør hvis ikke allerede eksisterer
|
|
INSERT IGNORE INTO bygma_product_groups (group_code, group_name) VALUES
|
|
('1000', 'Træ og byggeplader'),
|
|
('2000', 'Tagmaterialer'),
|
|
('3000', 'Isolering'),
|
|
('4000', 'Vinduer og døre'),
|
|
('5000', 'Beslag og skruer'),
|
|
('6000', 'Maling og behandling'),
|
|
('7000', 'VVS og el'),
|
|
('8000', 'Værktøj'),
|
|
('9000', 'Øvrige materialer');
|
|
|
|
-- Eksempel på indeks optimering for store datasets
|
|
-- Partition på import_date hvis vi får mange måneders data
|
|
-- ALTER TABLE bygma_price_history
|
|
-- PARTITION BY RANGE (YEAR(import_date) * 100 + MONTH(import_date))
|
|
-- (PARTITION p202501 VALUES LESS THAN (202502),
|
|
-- PARTITION p202502 VALUES LESS THAN (202503),
|
|
-- PARTITION p_future VALUES LESS THAN MAXVALUE);
|
|
|
|
-- Grants til applikation bruger (tilpas brugernavne efter behov)
|
|
-- GRANT SELECT, INSERT, UPDATE ON tilbudgivern.bygma_* TO 'tilbudgivern_user'@'localhost';
|
|
-- GRANT SELECT ON tilbudgivern.bygma_current_prices TO 'tilbudgivern_user'@'localhost';
|