Files
tilbudgivern/archive/analysis/create-experience-based-packages.js

518 lines
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Script til at oprette erfaringsbaserede SmartPackages
* Baseret på kundens faktiske priser og erfaringer
*/
const axios = require('axios');
const mysql = require('mysql2/promise');
const LOCAL_API = 'http://localhost:4031';
// Database connection
const dbConfig = {
host: 'localhost',
user: 'tilbudgivern_service',
password: process.env.DB_PASSWORD,
database: 'tilbudgivern'
};
/**
* Hent pris fra database med 20% avance
*/
async function getPriceWithMarkup(varenr) {
const connection = await mysql.createConnection(dbConfig);
try {
const [rows] = await connection.execute(
`SELECT mp.price, mp.unit, m.name
FROM materials m
LEFT JOIN material_prices mp ON m.id = mp.material_id
WHERE m.sku = ? AND mp.is_active = 1
ORDER BY mp.valid_from DESC LIMIT 1`,
[varenr]
);
if (rows.length > 0) {
const basePrice = parseFloat(rows[0].price);
const priceWithMarkup = basePrice * 1.20; // 20% avance
return {
price: priceWithMarkup,
unit: rows[0].unit,
name: rows[0].name
};
}
// Returner placeholder hvis ikke fundet - tilføjes senere
return null;
} finally {
await connection.end();
}
}
/**
* Opret materiale entry (bruges til at oprette pakkerne nu, priser tilføjes senere)
*/
function createMaterialEntry(name, productNumber, quantity, unit, description = '') {
return {
name,
productNumber,
quantity: typeof quantity === 'string' ? 1 : quantity,
quantityFormula: typeof quantity === 'string' ? quantity : null,
unit,
unitPrice: 0, // Placeholder - opdateres når priser tilføjes
description,
needsPriceUpdate: true
};
}
/**
* Opret SmartPackage via API
*/
async function createSmartPackage(packageData) {
try {
const response = await axios.post(`${LOCAL_API}/api/smart-packages`, packageData);
console.log(`✅ Oprettet pakke: ${packageData.name} (ID: ${response.data.id})`);
return response.data;
} catch (error) {
console.error(`❌ Fejl ved oprettelse af ${packageData.name}:`, error.response?.data || error.message);
throw error;
}
}
/**
* PAKKE 1: Tagrende med Konsoljern i stål (Lindab materialer)
*/
async function createTagrendePakke() {
console.log('\n📦 Opretter Tagrende pakke...');
// Materialeliste med formler for beregning
const materials = [
createMaterialEntry(
'Tagrende 3 meter',
'077424',
'FORMULA:facadelængde/3',
'stk',
'Antal beregnes automatisk: facadelængde / 3 meter'
),
createMaterialEntry(
'Ende bund',
'107744',
4,
'stk',
'1 i hver ende - 4 stk generisk'
),
createMaterialEntry(
'Samle stykke',
'077419',
'FORMULA:(facadelængde/3)-1',
'stk',
'1 samle beslag pr 3 meter tagrende'
),
createMaterialEntry(
'Konsol jern',
'077407',
'FORMULA:facadelængde/0.6',
'stk',
'Beregnes automatisk: maks 60cm afstand'
),
createMaterialEntry(
'Hjørne indvendig',
'077426',
1,
'stk',
'Huskeliste - tilpas efter behov'
),
createMaterialEntry(
'Hjørne udvendig',
'077431',
1,
'stk',
'Huskeliste - tilpas efter behov'
)
];
const packageData = {
name: 'Tagrende med Konsoljern (Lindab)',
description: 'Komplet tagrende system med konsoljern i stål. Materialer fra Lindab.\n\nArbeidsberegning: 10 meter tager 5 timer (0,5 time pr meter)',
category: 'Tag - Tagrende',
estimatedHours: 'FORMULA:facadelængde*0.5', // 10m = 5 timer
materials,
requiresGeometry: true,
geometryFields: ['facadelængde']
};
return await createSmartPackage(packageData);
}
/**
* PAKKE 2: Nedløb
*/
async function createNedløbPakke() {
console.log('\n📦 Opretter Nedløb pakke...');
const materials = [
{
name: 'Nedløb 3 meter',
productNumber: '077438',
quantity: 'FORMULA:nedløb_antal', // Sættes af bruger
unit: 'stk'
},
{
name: 'Rørholder',
productNumber: '184937',
quantity: 'FORMULA:nedløb_antal*2', // 2 pr nedløb
unit: 'stk'
},
{
name: 'Tudstykke',
productNumber: '122214',
quantity: 'FORMULA:nedløb_antal', // 1 pr nedløb
unit: 'stk'
},
{
name: 'Silikone',
productNumber: '050043',
quantity: 'FORMULA:nedløb_antal', // 1 pr nedløb
unit: 'stk'
},
{
name: 'Brøndkrave',
productNumber: '061637',
quantity: 'FORMULA:nedløb_antal', // 1 pr nedløb
unit: 'stk'
},
{
name: 'Bøjning',
productNumber: '076623',
quantity: 'FORMULA:nedløb_antal*2', // 2 pr nedløb
unit: 'stk',
description: 'Bøjninger varierer - tilpas efter behov'
}
];
const materialsWithPrices = [];
for (const m of materials) {
const priceData = await getPriceWithMarkup(m.productNumber);
if (priceData) {
materialsWithPrices.push({
name: priceData.name || m.name,
quantity: 1, // Placeholder
quantityFormula: m.quantity,
unit: priceData.unit,
unitPrice: priceData.price,
description: m.description
});
} else {
console.warn(`⚠️ Kunne ikke finde pris for ${m.productNumber} - ${m.name}`);
}
}
const packageData = {
name: 'Nedløb komplet',
description: 'Komplet nedløbssystem med tilbehør.\n\nVælg antal nedløb - systemet beregner automatisk tilbehør.\n\nArbeidsberegning: 1 nedløb = 1 time',
category: 'Tag - Nedløb',
estimatedHours: 'FORMULA:nedløb_antal*1', // 1 stk = 1 time
materials: materialsWithPrices,
requiresGeometry: true,
geometryFields: ['nedløb_antal']
};
return await createSmartPackage(packageData);
}
/**
* PAKKE 3: Opretning af spær
*/
async function createSpærPakke() {
console.log('\n📦 Opretter Opretning af spær pakke...');
const materials = [
{
name: 'Spær træ 200mm',
productNumber: '146304720010450',
quantity: 'FORMULA:(huslængde+1)*husbredde', // LBM beregning
unit: 'løbende meter'
},
{
name: 'Spånskruer 5,0x100',
productNumber: '310615',
quantity: 'FORMULA:((huslængde+1)*husbredde)*5', // 5 skruer pr LBM
unit: 'stk'
},
{
name: 'Muresnor',
productNumber: '195408',
quantity: 1,
unit: 'stk'
},
{
name: 'Bits TX 20',
productNumber: '224770',
quantity: 1,
unit: 'stk'
},
{
name: 'Snorvatterpas',
productNumber: '064736',
quantity: 2,
unit: 'stk'
},
{
name: 'Rundsavsklinge',
productNumber: '182788',
quantity: 1,
unit: 'stk'
},
{
name: 'Stiksavsklinger',
productNumber: '147761',
quantity: 1,
unit: 'stk'
}
];
const materialsWithPrices = [];
for (const m of materials) {
const priceData = await getPriceWithMarkup(m.productNumber);
if (priceData) {
materialsWithPrices.push({
name: priceData.name || m.name,
quantity: typeof m.quantity === 'string' ? 1 : m.quantity,
quantityFormula: typeof m.quantity === 'string' ? m.quantity : null,
unit: priceData.unit,
unitPrice: priceData.price
});
} else {
console.warn(`⚠️ Kunne ikke finde pris for ${m.productNumber} - ${m.name}`);
}
}
const packageData = {
name: 'Opretning af spær',
description: 'Komplet opretning af tagspær med materialer og værktøj.\n\nLBM beregnes automatisk: (huslængde + 1) × husbredde\n\nArbeidsberegning: 5 meter = 0,5 time',
category: 'Tag - Spær',
estimatedHours: 'FORMULA:((huslængde+1)*husbredde)*0.1', // 5m = 0.5t => 1m = 0.1t
materials: materialsWithPrices,
requiresGeometry: true,
geometryFields: ['huslængde', 'husbredde']
};
return await createSmartPackage(packageData);
}
/**
* PAKKE 4: Montering af B7 inkl. lægter
*/
async function createB7Pakke() {
console.log('\n📦 Opretter B7 montering pakke...');
const materials = [
{
name: 'B7 Plade',
productNumber: '147072',
quantity: 'FORMULA:tagflade_m2*2.13', // 2,13 plade pr m²
unit: 'm²'
},
{
name: 'Lægter',
productNumber: '1632038073',
quantity: 'FORMULA:tagflade_m2*2.17', // 2,17 m pr m²
unit: 'løbende meter',
description: 'Lægteafstand 46 cm'
},
{
name: 'Tagskruer',
productNumber: '119229',
quantity: 'FORMULA:tagflade_m2*4.25', // 4,25 skrue pr m²
unit: 'stk'
},
{
name: 'Ringsøm',
productNumber: '101933',
quantity: 'FORMULA:tagflade_m2*15', // 15 søm pr m²
unit: 'stk',
description: 'Pakke med 2880 stk'
},
{
name: 'EPDM bånd 30 meter',
productNumber: '029218',
quantity: 'FORMULA:tagflade_m2*2.17', // 2,17 m pr m²
unit: 'løbende meter'
}
];
const materialsWithPrices = [];
for (const m of materials) {
const priceData = await getPriceWithMarkup(m.productNumber);
if (priceData) {
materialsWithPrices.push({
name: priceData.name || m.name,
quantity: typeof m.quantity === 'string' ? 1 : m.quantity,
quantityFormula: typeof m.quantity === 'string' ? m.quantity : null,
unit: priceData.unit,
unitPrice: priceData.price,
description: m.description
});
} else {
console.warn(`⚠️ Kunne ikke finde pris for ${m.productNumber} - ${m.name}`);
}
}
const packageData = {
name: 'B7 montering inkl. lægter',
description: 'Komplet B7 tagbeklædning med lægter og fastgørelse.\n\nArbeidsberegning: 0,5 time pr m²',
category: 'Tag - B7',
estimatedHours: 'FORMULA:tagflade_m2*0.5', // 0,5 time pr m²
materials: materialsWithPrices,
requiresGeometry: true,
geometryFields: ['tagflade_m2']
};
return await createSmartPackage(packageData);
}
/**
* PAKKE 5: Montering af rygning B7
*/
async function createRygningB7Pakke() {
console.log('\n📦 Opretter Rygning B7 pakke...');
const materials = [
{
name: 'Rygning',
productNumber: '057437',
quantity: 'FORMULA:rygning_længde', // 1 stk pr meter
unit: 'løbende meter'
},
{
name: 'Rygningselement',
productNumber: '038218',
quantity: 'FORMULA:rygning_længde', // 1 stk pr meter
unit: 'løbende meter'
},
{
name: 'Tagskruer 100 stk',
productNumber: '144855',
quantity: 'FORMULA:rygning_længde*4', // 4 skrue pr meter
unit: 'stk'
},
{
name: 'EPDM bånd 30 meter',
productNumber: '029218',
quantity: 'FORMULA:rygning_længde*0.4', // 0,4 meter pr meter
unit: 'løbende meter'
}
];
const materialsWithPrices = [];
for (const m of materials) {
const priceData = await getPriceWithMarkup(m.productNumber);
if (priceData) {
materialsWithPrices.push({
name: priceData.name || m.name,
quantity: typeof m.quantity === 'string' ? 1 : m.quantity,
quantityFormula: typeof m.quantity === 'string' ? m.quantity : null,
unit: priceData.unit,
unitPrice: priceData.price
});
} else {
console.warn(`⚠️ Kunne ikke finde pris for ${m.productNumber} - ${m.name}`);
}
}
const packageData = {
name: 'Rygning B7',
description: 'Komplet rygningsløsning til B7 tag.\n\nArbeidsberegning: Tilføjes senere',
category: 'Tag - Rygning',
estimatedHours: 'FORMULA:rygning_længde*0.25', // Estimeret 15 min pr meter
materials: materialsWithPrices,
requiresGeometry: true,
geometryFields: ['rygning_længde']
};
return await createSmartPackage(packageData);
}
/**
* PAKKE 6: Montering af taghætte B7
*/
async function createTaghætteB7Pakke() {
console.log('\n📦 Opretter Taghætte B7 pakke...');
const materials = [
{
name: 'Taghætte',
productNumber: '126813',
quantity: 1,
unit: 'stk'
}
];
const materialsWithPrices = [];
for (const m of materials) {
const priceData = await getPriceWithMarkup(m.productNumber);
if (priceData) {
materialsWithPrices.push({
name: priceData.name || m.name,
quantity: m.quantity,
unit: priceData.unit,
unitPrice: priceData.price
});
} else {
console.warn(`⚠️ Kunne ikke finde pris for ${m.productNumber} - ${m.name}`);
}
}
const packageData = {
name: 'Taghætte B7',
description: 'Montering af taghætte til B7 tag.\n\nArbeidsberegning: Tilføjes senere',
category: 'Tag - Taghætte',
estimatedHours: 1, // Estimeret
materials: materialsWithPrices,
requiresGeometry: false
};
return await createSmartPackage(packageData);
}
/**
* Hovedfunktion
*/
async function main() {
console.log('🚀 Starter oprettelse af erfaringsbaserede SmartPackages...\n');
console.log('📌 Alle priser hentes fra database med 20% avance\n');
try {
// Opret alle pakker
await createTagrendePakke();
await createNedløbPakke();
await createSpærPakke();
await createB7Pakke();
await createRygningB7Pakke();
await createTaghætteB7Pakke();
console.log('\n✅ Alle pakker oprettet succesfuldt!');
console.log('\n📝 Næste skridt:');
console.log(' 1. Sikr at geometri gemmes i database (facadelængde, husbredde, m² osv.)');
console.log(' 2. Implementer beregningslogik for formler (FORMULA:...)');
console.log(' 3. Test pakkerne i frontend');
console.log(' 4. Få manglende pakker fra kunde (B6, Betontegl, Velux osv.)');
} catch (error) {
console.error('\n❌ Fejl under oprettelse:', error);
process.exit(1);
}
}
// Kør scriptet
if (require.main === module) {
main();
}
module.exports = {
createTagrendePakke,
createNedløbPakke,
createSpærPakke,
createB7Pakke,
createRygningB7Pakke,
createTaghætteB7Pakke
};