Files
tilbudgivern/backend/create-special-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

260 lines
9.4 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 createSpecialPackage(conn, allMaterials, packageData) {
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`);
return;
}
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 || 'mellem',
packageData.hours,
packageData.hourlyRate || 580,
packageData.notes,
'System',
0,
1, 1, 1,
packageData.timePerSqm,
1
]
);
const packageId = result.insertId;
console.log(`${packageData.name} (ID ${packageId})`);
// Tilføj materialer
for (const matDef of packageData.materials) {
const material = await getMaterialByName(allMaterials, matDef.searchTerms);
if (material) {
await conn.execute(
`INSERT INTO package_materials
(package_id, material_name, material_category, quantity, unit, unit_price,
total_price, supplier, notes, base_quantity)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
packageId,
material.name,
material.category || 'Tag',
matDef.quantity,
material.enhed || 'stk',
parseFloat(material.price),
matDef.quantity * parseFloat(material.price),
material.leverandoer || 'Bygma',
matDef.notes || '',
matDef.baseQty || matDef.quantity
]
);
}
}
// 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]
);
}
}
(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
});
const response = await axios.get('http://localhost:4031/api/materials');
const allMaterials = response.data.materials || [];
console.log('🏗️ OPRETTER SPECIALISEREDE TAGPAKKER\n');
// TAGSKIFT - HURTIG (kun plader)
await createSpecialPackage(conn, allMaterials, {
name: 'Tagskift B7 - Kun plader (express)',
description: `Hurtig udskiftning af B7 tagplader - eksisterende lægter bibeholdes.
⚡ EXPRESS LØSNING:
• Kun udskiftning af slidte/beskadigede plader
• Eksisterende lægter genbruges (hvis OK)
• Hurtig løsning til presserende behov
⏱ TID: 2 timer per 10m²
💰 TIMEPRIS: 580 kr/time
⚠️ KRAV:
- Eksisterende lægter skal være i god stand
- Kun egnet til nyere konstruktioner
- Spær skal være OK`,
hours: 2.0,
timePerSqm: 0.2,
difficulty: 'let',
notes: 'Hurtig løsning hvor kun plader skiftes. Kræver OK lægter.',
materials: [
{ searchTerms: ['B7 tagplader'], quantity: 11, baseQty: 11, notes: 'Med 10% reserve' },
{ searchTerms: ['Skruer til tagplader', 'tagskrue'], quantity: 160, baseQty: 16, notes: 'Rustfri skruer' }
],
tasks: [
{ name: 'Inspektion', desc: 'Kontrollere lægter og konstruktion', hours: 0.3, phase: 'forberedelse', order: 1 },
{ name: 'Nedtagning af gamle plader', desc: 'Fjerne slidte B7 plader', hours: 0.5, phase: 'hovedarbejde', order: 1 },
{ name: 'Montering af nye plader', desc: 'Montere nye B7 plader', hours: 1.0, phase: 'hovedarbejde', order: 2 },
{ name: 'Kontrol', desc: 'Kvalitetskontrol', hours: 0.2, phase: 'inspektion', order: 1 }
]
});
// TAG REPARATION - MINDRE SKADER
await createSpecialPackage(conn, allMaterials, {
name: 'Tag Reparation - Mindre skader',
description: `Reparation af mindre tagskader uden komplet udskiftning.
🔧 INKLUDERER:
• Udskiftning af enkelte beskadigede elementer
• Reparation af lækager
• Fornyelse af tætninger
• Mindre spærreparationer
⏱ TID: 3-4 timer typisk
💰 TIMEPRIS: 580 kr/time
✓ EGNET TIL:
- Enkelte utætte steder
- Revnede/ødelagte enkelte plader
- Mindre lækager`,
hours: 3.5,
timePerSqm: 0,
difficulty: 'let',
notes: 'Reparation uden komplet udskiftning. Pris per job, ikke per m².',
materials: [
{ searchTerms: ['B7 tagplader'], quantity: 3, baseQty: 3, notes: 'Reserve plader' },
{ searchTerms: ['Skruer til tagplader'], quantity: 50, baseQty: 50, notes: 'Diverse skruer' },
{ searchTerms: ['Tagpap underlag', 'pap'], quantity: 2, baseQty: 2, notes: 'Til tætning' },
{ searchTerms: ['Lægter 38x63'], quantity: 5, baseQty: 5, notes: 'Til mindre reparationer' }
],
tasks: [
{ name: 'Fejlfinding', desc: 'Lokalisere skader og lækager', hours: 0.5, phase: 'forberedelse', order: 1 },
{ name: 'Reparation af skader', desc: 'Udbedre identificerede skader', hours: 2.5, phase: 'hovedarbejde', order: 1 },
{ name: 'Tætning', desc: 'Tætne alle samlinger', hours: 0.5, phase: 'afslutning', order: 1 }
]
});
// GRØNT TAG / SEDUM
await createSpecialPackage(conn, allMaterials, {
name: 'Grønt Tag - Sedum (fladtag)',
description: `Etablering af grønt sedum-tag på fladtag. Miljøvenlig og moderne løsning.
🌱 INKLUDERER:
• Tagisolering 200mm
• Vandtæt membran
• Dræneringslag
• Substrat til sedum
• Sedum planter/måtter
⏱ TID: 10 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✨ FORDELE:
- Isolerende effekt
- Nedsætter regnvand-afstrømning
- Forbedrer bymiljø
- Moderne look`,
hours: 10.0,
timePerSqm: 1.0,
difficulty: 'svær',
notes: 'Grønt tag kræver speciel konstruktion. Kun fladtag/lav hældning.',
materials: [
{ searchTerms: ['Tagisolering 200mm', 'isolering'], quantity: 10, baseQty: 10, notes: 'Isolering' },
{ searchTerms: ['Tagpap'], quantity: 12, baseQty: 12, notes: 'Vandtæt membran' },
{ searchTerms: ['Lægter'], quantity: 15, baseQty: 15, notes: 'Til dræneringslag' }
],
tasks: [
{ name: 'Forberedelse af underlag', desc: 'Klargøre og kontrollere fladtag', hours: 1.5, phase: 'forberedelse', order: 1 },
{ name: 'Isolering', desc: 'Montere tagisolering', hours: 2.0, phase: 'hovedarbejde', order: 1 },
{ name: 'Membran og tætning', desc: 'Lægge vandtæt membran', hours: 2.5, phase: 'hovedarbejde', order: 2 },
{ name: 'Dræneringslag', desc: 'Etablere drænering', hours: 1.5, phase: 'hovedarbejde', order: 3 },
{ name: 'Substrat', desc: 'Udlægge substrat til planter', hours: 1.5, phase: 'hovedarbejde', order: 4 },
{ name: 'Beplantning', desc: 'Etablere sedum', hours: 1.0, phase: 'afslutning', order: 1 }
]
});
// TAGTERRASSE
await createSpecialPackage(conn, allMaterials, {
name: 'Tagterrasse - Komplet anlæg',
description: `Etablering af tagterrasse på fladtag med trægulv.
🏡 INKLUDERER:
• Tagisolering
• Vandtæt membran
• Underlagskonstruktion
• Trægulv (trykimprægneret)
• Gelænder (efter behov)
⏱ TID: 12 timer per 10m²
💰 TIMEPRIS: 580 kr/time
✓ PERFEKT TIL:
- Byboliger
- Penthouse
- Udnyttelse af fladtag`,
hours: 12.0,
timePerSqm: 1.2,
difficulty: 'svær',
notes: 'Tagterrasse kræver solid konstruktion og vandtætning.',
materials: [
{ searchTerms: ['Tagisolering 200mm'], quantity: 10, baseQty: 10, notes: 'Isolering' },
{ searchTerms: ['Tagpap'], quantity: 12, baseQty: 12, notes: 'Vandtæt membran' },
{ searchTerms: ['Lægter 38x63 trykimprægneret', 'lægte trykim'], quantity: 30, baseQty: 30, notes: 'Underlagskonstruktion' },
{ searchTerms: ['SPÅNSKRUE', 'skrue'], quantity: 2, baseQty: 2, notes: 'Beslag og skruer' }
],
tasks: [
{ name: 'Forberedelse og planlægning', desc: 'Opmåle og planlægge terrasse', hours: 1.5, phase: 'forberedelse', order: 1 },
{ name: 'Isolering', desc: 'Montere isolering', hours: 2.0, phase: 'hovedarbejde', order: 1 },
{ name: 'Membran', desc: 'Lægge vandtæt membran', hours: 2.5, phase: 'hovedarbejde', order: 2 },
{ name: 'Underlagskonstruktion', desc: 'Bygge bærende konstruktion', hours: 3.0, phase: 'hovedarbejde', order: 3 },
{ name: 'Gulvlægning', desc: 'Montere trægulv', hours: 2.5, phase: 'hovedarbejde', order: 4 },
{ name: 'Afslutning', desc: 'Montere afslutninger og finish', hours: 0.5, phase: 'afslutning', order: 1 }
]
});
console.log('\n✅ FÆRDIG! Specialpakker oprettet\n');
// Vis samlet oversigt
const [allPackages] = await conn.execute(
'SELECT id, name, category FROM material_packages WHERE id >= 126 ORDER BY id'
);
console.log('📊 ALLE NYE TAGPAKKER:\n');
allPackages.forEach(p => console.log(' • ' + p.name + ' (ID ' + p.id + ')'));
await conn.end();
})();