Files
tilbudgivern/backend/create-roof-packages.js
alexpolo1 bdb9e524db Implement manual and automated tests for auto-save countdown feature
- Added a comprehensive manual testing guide for the countdown functionality in `test_countdown_manual.md`.
- Developed a detailed Selenium test suite in `test_countdown_selenium.py` to verify countdown behavior, including server accessibility, login, countdown progression, and UI elements.
- Created a minimal Selenium test version in `test_countdown_selenium_minimal.py` for quick checks without complex setup.
- Introduced a verification script in `test_countdown_verification.py` to analyze code correctness, including server checks, build file existence, and countdown logic.
2025-11-14 11:28:58 +00:00

345 lines
15 KiB
JavaScript

require('dotenv').config();
const mysql = require('mysql2/promise');
const axios = require('axios');
async function getMaterialByName(allMaterials, searchTerms) {
for (const term of searchTerms) {
const found = allMaterials.find(m =>
m.name && m.name.toLowerCase().includes(term.toLowerCase()) &&
m.price && parseFloat(m.price) > 0
);
if (found) return found;
}
return null;
}
async function createRoofPackage(conn, allMaterials, packageData) {
// Tjek om pakken allerede findes
const [existing] = await conn.execute(
'SELECT id FROM material_packages WHERE name = ? AND is_active = 1',
[packageData.name]
);
if (existing.length > 0) {
console.log(` ⏭️ Pakke "${packageData.name}" findes allerede (ID ${existing[0].id})`);
return existing[0].id;
}
// Opret pakke
const [result] = await conn.execute(
`INSERT INTO material_packages
(name, description, category, difficulty_level, estimated_hours, hourly_rate,
installation_notes, created_by, total_estimated_price, is_active, is_template,
area_based, time_per_sqm, auto_calculated)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
packageData.name,
packageData.description,
'Tag',
packageData.difficulty || 'svær',
packageData.hours,
packageData.hourlyRate || 580,
packageData.notes,
'System',
0, // Will be calculated from materials
1, // is_active
1, // is_template
1, // area_based
packageData.timePerSqm,
1 // auto_calculated
]
);
const packageId = result.insertId;
console.log(` ✓ Oprettet pakke: ${packageData.name} (ID ${packageId})`);
// Tilføj materialer
let totalPrice = 0;
for (const matDef of packageData.materials) {
const material = await getMaterialByName(allMaterials, matDef.searchTerms);
if (material) {
const quantity = matDef.quantity;
const price = parseFloat(material.price);
const total = quantity * price;
totalPrice += total;
await conn.execute(
`INSERT INTO package_materials
(package_id, material_name, material_category, quantity, unit, unit_price,
total_price, supplier, notes, base_quantity, geometry_multiplier, waste_factor)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
packageId,
material.name,
material.category || 'Tag',
quantity,
material.enhed || 'stk',
price,
total,
material.leverandoer || 'Bygma',
matDef.notes || '',
matDef.baseQty || quantity,
matDef.multiplier || null,
matDef.wasteFactor || 1.05
]
);
console.log(` + Material: ${material.name} (${quantity} ${material.enhed || 'stk'})`);
} else {
console.log(` ⚠️ Kunne ikke finde: ${matDef.searchTerms[0]}`);
}
}
// Opdater total pris
await conn.execute(
'UPDATE material_packages SET total_estimated_price = ? WHERE id = ?',
[totalPrice, packageId]
);
// Tilføj opgaver
for (const task of packageData.tasks) {
await conn.execute(
`INSERT INTO package_tasks
(package_id, task_name, task_description, estimated_hours, task_order, task_phase)
VALUES (?, ?, ?, ?, ?, ?)`,
[packageId, task.name, task.desc, task.hours, task.order, task.phase]
);
}
console.log(` + ${packageData.tasks.length} opgaver tilføjet\n`);
return packageId;
}
(async () => {
const conn = await mysql.createConnection({
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
// Hent alle materialer
const response = await axios.get('http://localhost:4031/api/materials');
const allMaterials = response.data.materials || [];
console.log('🏗️ OPRETTER SMARTPAKKER FOR FORSKELLIGE TAGTYPER\n');
// 1. BETONTEGL TAG
await createRoofPackage(conn, allMaterials, {
name: 'Betontegl - Komplet tagudskiftning',
description: `Komplet tagudskiftning med betontegl. Professionel løsning til traditionelle danske huse.
🏠 INKLUDERER:
• Nedrivning af gammelt tag
• Nye bærelægter og kontralægter
• Undertag med membran
• NIBRA H10 betontegl i naturrød
• Vindskeder og afslutninger
• Tagrende og nedløb
⏱ TID: 8 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✨ BETONTEGL FORDELE:
- Klassisk dansk udtryk
- Lang levetid (50+ år)
- God lydisolering
- Vejrbestandig`,
hours: 8.0,
timePerSqm: 0.8,
hourlyRate: 580,
difficulty: 'svær',
notes: 'Betontegl kræver solid bærekonstruktion. 8 timer/10m² inkl. nedrivning og opsætning.',
materials: [
{ searchTerms: ['NIBRA H10 Teglsten', 'tegl'], quantity: 12, baseQty: 12, notes: 'Ca 12 stk pr m²' },
{ searchTerms: ['Bærelægte', 'lægte 38x73'], quantity: 20, baseQty: 2, multiplier: 'areal', notes: 'Bærelægter' },
{ searchTerms: ['undertag', 'tagpap'], quantity: 11, baseQty: 11, notes: 'Undertag med 10% overlap' },
{ searchTerms: ['Tagisolering 200mm', 'isolering'], quantity: 10, baseQty: 10, notes: 'Isolering' }
],
tasks: [
{ name: 'Sikkerhedsforanstaltninger', desc: 'Opsætte stillads og sikkerhedsudstyr', hours: 1.0, phase: 'forberedelse', order: 1 },
{ name: 'Nedrivning af gammelt tag', desc: 'Nedtage gamle tagsten og undertag', hours: 2.5, phase: 'hovedarbejde', order: 1 },
{ name: 'Kontrol af spærkonstruktion', desc: 'Kontrollere og reparere spær ved behov', hours: 1.0, phase: 'hovedarbejde', order: 2 },
{ name: 'Montering af lægter', desc: 'Montere kontra- og bærelægter med korrekt afstand', hours: 2.0, phase: 'hovedarbejde', order: 3 },
{ name: 'Undertag og membran', desc: 'Lægge undertag med korrekt overlæg', hours: 1.5, phase: 'hovedarbejde', order: 4 },
{ name: 'Lægning af betontegl', desc: 'Lægge betontagsten med korrekt overlæg og fastgørelse', hours: 4.0, phase: 'hovedarbejde', order: 5 },
{ name: 'Montering af vindskeder', desc: 'Montere vindskeder og afslutninger', hours: 1.5, phase: 'afslutning', order: 1 },
{ name: 'Slutkontrol', desc: 'Gennemgå taget for kvalitet og tæthed', hours: 0.5, phase: 'inspektion', order: 1 }
]
});
// 2. ETERNIT B6 TAG
await createRoofPackage(conn, allMaterials, {
name: 'Eternit B6 - Komplet tagudskiftning',
description: `Komplet tagudskiftning med Eternit B6 tagsten. Moderne og vedligeholdelsesfri løsning.
🏠 INKLUDERER:
• Nedrivning af gammelt tag
• Kontralægter for optimal ventilation
• Bærelægter med præcis afstand
• Eternit B6 tagsten i rød
• Eternit rygningsten
• Eternit vindskeder
⏱ TID: 6 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✨ ETERNIT B6 FORDELE:
- Vedligeholdelsesfri
- Nem og hurtig montering
- Perfekt ventilation
- Moderne look`,
hours: 6.0,
timePerSqm: 0.6,
hourlyRate: 580,
difficulty: 'mellem',
notes: 'Eternit B6 er lettere end betontegl. 6 timer/10m² inkl. nedrivning.',
materials: [
{ searchTerms: ['Eternit tagsten B6', 'eternit'], quantity: 11, baseQty: 11, notes: 'Ca 11 stk pr m²' },
{ searchTerms: ['Eternit rygningsten', 'rygning'], quantity: 1, baseQty: 0.1, multiplier: 'rygning', notes: 'Rygningsten pr løbemeter' },
{ searchTerms: ['Eternit vindskeder', 'vindskede'], quantity: 2, baseQty: 0.2, multiplier: 'facade', notes: 'Vindskeder' },
{ searchTerms: ['Bærelægte', 'lægte'], quantity: 20, baseQty: 2, multiplier: 'areal', notes: 'Lægter' }
],
tasks: [
{ name: 'Forberedelse og stillads', desc: 'Opsætte stillads og sikkerhedsudstyr', hours: 0.8, phase: 'forberedelse', order: 1 },
{ name: 'Nedrivning', desc: 'Nedtage gammelt tag', hours: 2.0, phase: 'hovedarbejde', order: 1 },
{ name: 'Montering af lægter', desc: 'Montere lægter med korrekt afstand til Eternit B6', hours: 1.5, phase: 'hovedarbejde', order: 2 },
{ name: 'Lægning af Eternit tagsten', desc: 'Lægge Eternit B6 tagsten', hours: 3.5, phase: 'hovedarbejde', order: 3 },
{ name: 'Montering af rygning', desc: 'Montere Eternit rygningsten', hours: 1.0, phase: 'hovedarbejde', order: 4 },
{ name: 'Vindskeder og afslutning', desc: 'Montere Eternit vindskeder', hours: 1.0, phase: 'afslutning', order: 1 },
{ name: 'Kvalitetskontrol', desc: 'Kontrollere montering og tæthed', hours: 0.5, phase: 'inspektion', order: 1 }
]
});
// 3. B7 BØLGEPLADE TAG (forbedret version)
await createRoofPackage(conn, allMaterials, {
name: 'B7 Bølgeplade - Komplet tagudskiftning',
description: `Komplet tagudskiftning med B7 bølgeplader. Økonomisk og pålidelig løsning.
🏠 INKLUDERER:
• Nedrivning af gammelt tag
• Kontralægter for ventilation (VIGTIGT!)
• Bærelægter med korrekt afstand
• B7 bølgeplader med overlap
• Rustfri tagskruer med gummipakninger
• Underlægspap T400
⏱ TID: 5 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✨ B7 BØLGEPLADE FORDELE:
- Økonomisk løsning
- Hurtig montering
- God ventilation med kontralægter
- Robust og vejrbestandig`,
hours: 5.0,
timePerSqm: 0.5,
hourlyRate: 580,
difficulty: 'mellem',
notes: 'B7 er hurtigere at montere. Kontralægter er kritisk vigtige for ventilation!',
materials: [
{ searchTerms: ['B7 tagplader', 'bølgeplade'], quantity: 10.5, baseQty: 10.5, wasteFactor: 1.05, notes: 'Med 5% spild' },
{ searchTerms: ['Skruer til tagplader', 'tagskrue'], quantity: 150, baseQty: 15, multiplier: 'areal', notes: 'Rustfri skruer' },
{ searchTerms: ['Tagpap underlag', 'undertag'], quantity: 11, baseQty: 11, notes: 'T400 underlægspap' },
{ searchTerms: ['Bærelægte', 'lægte'], quantity: 22, baseQty: 2.2, multiplier: 'areal', notes: 'Bære- og kontralægter' }
],
tasks: [
{ name: 'Forberedelse', desc: 'Opsætte arbejdsområde og sikkerhed', hours: 0.5, phase: 'forberedelse', order: 1 },
{ name: 'Nedrivning', desc: 'Nedtage gammelt tagmateriale', hours: 1.5, phase: 'hovedarbejde', order: 1 },
{ name: 'Kontralægter (VIGTIGT)', desc: 'Montere kontralægter for ventilation - essentielt!', hours: 1.0, phase: 'hovedarbejde', order: 2 },
{ name: 'Bærelægter', desc: 'Montere bærelægter med præcis afstand', hours: 0.8, phase: 'hovedarbejde', order: 3 },
{ name: 'Underlægspap', desc: 'Lægge T400 underlægspap', hours: 0.5, phase: 'hovedarbejde', order: 4 },
{ name: 'Montering af B7 plader', desc: 'Lægge B7 bølgeplader med korrekt overlap', hours: 2.0, phase: 'hovedarbejde', order: 5 },
{ name: 'Skruning', desc: 'Skrue plader fast med rustfri skruer', hours: 0.8, phase: 'hovedarbejde', order: 6 },
{ name: 'Slutkontrol', desc: 'Kontrollere tæthed og finish', hours: 0.4, phase: 'inspektion', order: 1 }
]
});
// 4. B9 BØLGEPLADE TAG (dyb bølge)
await createRoofPackage(conn, allMaterials, {
name: 'B9 Bølgeplade - Komplet tagudskiftning',
description: `Komplet tagudskiftning med B9 bølgeplader (dyb bølge). Ekstra styrke til større spænd.
🏠 INKLUDERER:
• Nedrivning af gammelt tag
• Forstærket lægter til B9
• B9 bølgeplader (dyb bølge)
• Specialskruer til B9
• Underlægspap
⏱ TID: 5.5 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✨ B9 BØLGEPLADE FORDELE:
- Dybere bølge = større styrke
- Kan dække længere spænd
- Bedre selvrensning (vand)
- Professionelt look`,
hours: 5.5,
timePerSqm: 0.55,
hourlyRate: 580,
difficulty: 'mellem',
notes: 'B9 kræver lidt længere monteringstid end B7 pga. størrelse.',
materials: [
{ searchTerms: ['B9', 'bølgeplade dyb', 'trapez'], quantity: 10.3, baseQty: 10.3, wasteFactor: 1.03, notes: 'B9 eller tilsvarende dyb bølge' },
{ searchTerms: ['Skruer til tagplader', 'tagskrue'], quantity: 140, baseQty: 14, multiplier: 'areal', notes: 'Færre skruer pga. større plader' },
{ searchTerms: ['Tagpap underlag', 'undertag'], quantity: 11, baseQty: 11, notes: 'Underlægspap' },
{ searchTerms: ['Bærelægte', 'lægte'], quantity: 20, baseQty: 2, multiplier: 'areal', notes: 'Forstærkede lægter' }
],
tasks: [
{ name: 'Forberedelse', desc: 'Klargøre arbejdsområde', hours: 0.5, phase: 'forberedelse', order: 1 },
{ name: 'Nedrivning', desc: 'Nedtage gammelt tag', hours: 1.5, phase: 'hovedarbejde', order: 1 },
{ name: 'Forstærket lægter', desc: 'Montere forstærkede lægter til B9', hours: 1.2, phase: 'hovedarbejde', order: 2 },
{ name: 'Underlægspap', desc: 'Lægge underlægspap', hours: 0.5, phase: 'hovedarbejde', order: 3 },
{ name: 'Montering af B9 plader', desc: 'Lægge B9 dyb bølgeplader', hours: 2.2, phase: 'hovedarbejde', order: 4 },
{ name: 'Fastgørelse', desc: 'Skrue plader fast korrekt', hours: 0.8, phase: 'hovedarbejde', order: 5 },
{ name: 'Kvalitetskontrol', desc: 'Kontrollere tæthed og stabilitet', hours: 0.5, phase: 'inspektion', order: 1 }
]
});
// 5. TRAPEZPLADE TAG (industri/moderne)
await createRoofPackage(conn, allMaterials, {
name: 'Trapezplade - Komplet tagudskiftning',
description: `Komplet tagudskiftning med trapezplader. Moderne og robust løsning til erhverv og carporte.
🏠 INKLUDERER:
• Nedrivning af gammelt tag
• Forstærkede lægter
• Trapezplader i stål
• Specialskruer med tætning
• Afslutningslister
⏱ TID: 4.5 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✨ TRAPEZPLADE FORDELE:
- Meget robust
- Hurtig montering
- Moderne industrilook
- Perfekt til carporte/udhuse`,
hours: 4.5,
timePerSqm: 0.45,
hourlyRate: 580,
difficulty: 'mellem',
notes: 'Trapezplader er hurtige at montere. Perfekt til erhverv og carporte.',
materials: [
{ searchTerms: ['trapez', 'stålplade', 'tagplade'], quantity: 10.2, baseQty: 10.2, notes: 'Trapezplader' },
{ searchTerms: ['Skruer til tagplader', 'tagskrue'], quantity: 120, baseQty: 12, multiplier: 'areal', notes: 'Specialskruer' },
{ searchTerms: ['Bærelægte', 'lægte'], quantity: 18, baseQty: 1.8, multiplier: 'areal', notes: 'Lægter' }
],
tasks: [
{ name: 'Forberedelse', desc: 'Klargøre område og materiale', hours: 0.4, phase: 'forberedelse', order: 1 },
{ name: 'Nedrivning', desc: 'Nedtage eksisterende tag', hours: 1.3, phase: 'hovedarbejde', order: 1 },
{ name: 'Montering af lægter', desc: 'Montere lægter med korrekt afstand til trapezplader', hours: 1.0, phase: 'hovedarbejde', order: 2 },
{ name: 'Montering af trapezplader', desc: 'Lægge trapezplader med overlap', hours: 2.0, phase: 'hovedarbejde', order: 3 },
{ name: 'Fastgørelse og tætning', desc: 'Skrue fast og tætne samlinger', hours: 1.0, phase: 'hovedarbejde', order: 4 },
{ name: 'Afslutning', desc: 'Montere afslutningslister', hours: 0.5, phase: 'afslutning', order: 1 },
{ name: 'Inspektion', desc: 'Kontrollere kvalitet', hours: 0.3, phase: 'inspektion', order: 1 }
]
});
console.log('\n✅ FÆRDIG! Alle tagtype-pakker er oprettet\n');
await conn.end();
})();