v0.5.3: elektra-buizen min. 50 mm uit elkaar (gebundeld alleen naar de meterkast), vloer-wcd met leiding door de vloer, elektra op de PDF-bladen per wand/vloer/dakvlak, kosten elektra (buis + draad per meter, boorgaten 90 s geteld op stijlen/regels/balken, dozen, groepenkast, keuring), dakbeschot OSB 18 mm bovenop de sporen, felsplaten als dakbedekking
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e1a688728c
commit
b5510d56c7
@@ -122,6 +122,10 @@ window.COST_DEFAULTS = {
|
||||
dakleerMontage: { label: 'Montage dakleer', unit: 's/m²', value: 600 },
|
||||
rietM2: { label: 'Riet', unit: '€/m²', value: 90 },
|
||||
rietMontage: { label: 'Montage riet', unit: 's/m²', value: 3600 },
|
||||
beschotM2: { label: 'Dakbeschot OSB 18 mm (bovenop de sporen)', unit: '€/m²', value: 14 },
|
||||
beschotMontage: { label: 'Montage dakbeschot', unit: 's/m²', value: 150 },
|
||||
felsM2: { label: 'Felsplaten staande naad (zink/staal, klangen, scheidingslaag)', unit: '€/m²', value: 65 },
|
||||
felsMontage: { label: 'Montage felsplaten', unit: 's/m²', value: 1800 },
|
||||
boeideelM: { label: 'Boeideel', unit: '€/m', value: 25 },
|
||||
boeideelMontage: { label: 'Montage boeideel', unit: 's/m', value: 600 },
|
||||
onderplaatM2: { label: 'Onderplaat boeideel', unit: '€/m²', value: 30 },
|
||||
@@ -157,7 +161,55 @@ window.COST_DEFAULTS = {
|
||||
gevellamp: { label: 'Gevellamp', unit: '€/st.', value: 45 },
|
||||
boeideelSpot: { label: 'Boeideel-spot', unit: '€/st.', value: 25 },
|
||||
binnenspot: { label: 'Binnenspot', unit: '€/st.', value: 20 },
|
||||
montage: { label: 'Montage per lamp/spot (incl. bekabeling)', unit: 's', value: 900 }
|
||||
montage: { label: 'Montage per lamp/spot (armatuur plaatsen en aansluiten; leidingen en dozen onder Elektra)', unit: 's', value: 300 }
|
||||
}
|
||||
},
|
||||
|
||||
// Indicatieve groothandelsprijzen (excl. btw) en tijden; zie ElektraModel
|
||||
// voor de hoeveelheden (strekkende meters per leidingtype, boorgaten, dozen).
|
||||
elektra: {
|
||||
label: 'Elektra',
|
||||
items: {
|
||||
personeel: { label: 'Personeel bij elektra (i.p.v. de bezetting)', unit: 'man', value: 1 },
|
||||
boorgat: { label: 'Boorgat door stijl, regel of balk (aftekenen, boren, ontbramen)', unit: 's', value: 90 },
|
||||
buisLeggen: { label: 'Installatiebuis leggen en bevestigen', unit: 's/m', value: 60 },
|
||||
draadTrekken: { label: 'Draad trekken (per meter buis, alle aders)', unit: 's/m', value: 20 },
|
||||
kabelLeggen: { label: 'XMvK-kabel leggen en bevestigen (buiten)', unit: 's/m', value: 40 },
|
||||
doosPlaatsen: { label: 'Inbouwdoos plaatsen (luchtdicht, hollewand)', unit: 's', value: 240 },
|
||||
verdeeldoos: { label: 'Verdeeldoos plaatsen en verbinden', unit: 's', value: 600 },
|
||||
spotdoos: { label: 'Spotdoos plaatsen (luchtdicht plafond)', unit: 's', value: 300 },
|
||||
vloerdoos: { label: 'Vloerdoos plaatsen (gat in vloer, aansluiten)', unit: 's', value: 1800 },
|
||||
afmonteren: { label: 'Afmonteren schakelaar/wcd/apparaataansluiting', unit: 's', value: 300 },
|
||||
steekverbinderMontage: { label: 'Steekverbinder module-naad monteren (set m/v)', unit: 's', value: 300 },
|
||||
kastMontage: { label: 'Groepenkast plaatsen (kast, hoofdschakelaar, aardlek)', unit: 's', value: 3600 },
|
||||
groepMontage: { label: 'Per groep: automaat plaatsen, bedraden, labelen', unit: 's', value: 900 },
|
||||
keuring: { label: 'Meten, testen en opleveren (NEN 1010 / NEN 3140)', unit: 's', value: 10800 },
|
||||
buis16M: { label: 'Installatiebuis flexibel Ø16', unit: '€/m', value: 0.35 },
|
||||
buis19M: { label: 'Installatiebuis flexibel Ø19', unit: '€/m', value: 0.45 },
|
||||
buis25M: { label: 'Installatiebuis flexibel Ø25', unit: '€/m', value: 0.8 },
|
||||
draad15M: { label: 'VD-draad 1,5 mm² (per ader)', unit: '€/m', value: 0.28 },
|
||||
draad25M: { label: 'VD-draad 2,5 mm² (per ader)', unit: '€/m', value: 0.45 },
|
||||
xmvkM: { label: 'XMvK 3×1,5 mm²', unit: '€/m', value: 1.25 },
|
||||
inbouwdoos: { label: 'Luchtdichte hollewanddoos', unit: '€/st.', value: 1.6 },
|
||||
verdeeldoosSt: { label: 'Luchtdichte verdeeldoos', unit: '€/st.', value: 4.5 },
|
||||
spotdoosSt: { label: 'Luchtdichte spotdoos', unit: '€/st.', value: 7.5 },
|
||||
vloerdoosSt: { label: 'Vloerdoos met dubbele wcd', unit: '€/st.', value: 95 },
|
||||
schakelaar: { label: 'Schakelaar enkelpolig (inbouw)', unit: '€/st.', value: 9 },
|
||||
afdekraam1: { label: 'Afdekraam 1-voudig', unit: '€/st.', value: 3 },
|
||||
afdekraam2: { label: 'Afdekraam 2-voudig', unit: '€/st.', value: 5 },
|
||||
wcdDubbel: { label: 'Wandcontactdoos dubbel met randaarde', unit: '€/st.', value: 10 },
|
||||
wcdEnkel: { label: 'Wandcontactdoos enkel met randaarde', unit: '€/st.', value: 6 },
|
||||
perilex: { label: 'Perilex-wandcontactdoos (kookgroep)', unit: '€/st.', value: 18 },
|
||||
werkschakelaar: { label: 'Werkschakelaar (warmtepomp)', unit: '€/st.', value: 28 },
|
||||
lasklem: { label: 'Lasklem 3-voudig', unit: '€/st.', value: 0.35 },
|
||||
steekverbinder3: { label: 'Steekverbinder 3-polig (set m/v)', unit: '€/set', value: 9 },
|
||||
steekverbinder5: { label: 'Steekverbinder 5-polig (set m/v)', unit: '€/set', value: 14 },
|
||||
doorvoer: { label: 'Luchtdichte kabeldoorvoer naar buiten', unit: '€/st.', value: 3.5 },
|
||||
kast: { label: 'Groepenkast 3-fase leeg (behuizing, kammen, aansluitmateriaal)', unit: '€/st.', value: 180 },
|
||||
hoofdschakelaar: { label: 'Hoofdschakelaar 4-polig 40 A', unit: '€/st.', value: 55 },
|
||||
aardlek: { label: 'Aardlekschakelaar 2-polig 40 A / 30 mA', unit: '€/st.', value: 40 },
|
||||
automaat: { label: 'Installatieautomaat 1P+N (B10/B16)', unit: '€/st.', value: 14 },
|
||||
automaat2f: { label: 'Installatieautomaat 2-fase (kookgroep)', unit: '€/st.', value: 30 }
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
+71
-2
@@ -77,8 +77,8 @@ window.CostModel = (() => {
|
||||
// ------------------------------------------------------------
|
||||
// Berekening
|
||||
// ------------------------------------------------------------
|
||||
const CAT_ORDER = ['Hout', 'Schroeven', 'Plaatwerk', 'Isolatie', 'Gevel', 'Dak', 'Vloer', 'Kozijnen', 'Verlichting'];
|
||||
const ACT_ORDER = ['Zagen', 'Regelwerk monteren', 'Wanden plaatsen', 'Plaatwerk', 'Isoleren', 'Gevel', 'Latwerk', 'Dak', 'Vloer', 'Kozijnen', 'Verlichting'];
|
||||
const CAT_ORDER = ['Hout', 'Schroeven', 'Plaatwerk', 'Isolatie', 'Gevel', 'Dak', 'Vloer', 'Kozijnen', 'Verlichting', 'Elektra'];
|
||||
const ACT_ORDER = ['Zagen', 'Regelwerk monteren', 'Wanden plaatsen', 'Plaatwerk', 'Isoleren', 'Gevel', 'Latwerk', 'Dak', 'Vloer', 'Kozijnen', 'Verlichting', 'Elektra'];
|
||||
const VERTICAL_KINDS = ['verticale balk', 'kreupele stijl'];
|
||||
const DORPEL_KINDS = ['bovendorpel', 'onderdorpel'];
|
||||
|
||||
@@ -233,9 +233,11 @@ window.CostModel = (() => {
|
||||
addJoints(rf, n * V.verbindingenPerVloerbalk, 'wolfseindbalken', true);
|
||||
}
|
||||
addSheet(rf, 'Plaatwerk', 'OSB plafond', rs.osbAreaM2, P.osbM2, P.osbMontage);
|
||||
addSheet(rf, 'Plaatwerk', `Dakbeschot OSB ${RoofModel.BESCHOT_MM} mm`, rs.beschotM2 || 0, D.beschotM2, D.beschotMontage);
|
||||
add(rf, 'Isolatie', 'Isoleren', 'Glaswol dak', rs.voidM3, 'm³', rs.voidM3 * S.isolatie.glaswolM3, rs.voidM3 * S.isolatie.glaswolMontage);
|
||||
add(rf, 'Dak', 'Dak', 'Dakleer (EPDM)', rs.dakleerM2 || 0, 'm²', (rs.dakleerM2 || 0) * D.dakleerM2, (rs.dakleerM2 || 0) * D.dakleerMontage);
|
||||
add(rf, 'Dak', 'Dak', 'Riet', rs.rietM2 || 0, 'm²', (rs.rietM2 || 0) * D.rietM2, (rs.rietM2 || 0) * D.rietMontage);
|
||||
add(rf, 'Dak', 'Dak', 'Felsplaten (staande naad)', rs.felsM2 || 0, 'm²', (rs.felsM2 || 0) * D.felsM2, (rs.felsM2 || 0) * D.felsMontage);
|
||||
});
|
||||
|
||||
// --- Woning-breed: dakrand, sandwichpanelen, verlichting ---
|
||||
@@ -257,6 +259,73 @@ window.CostModel = (() => {
|
||||
add(wo, 'Verlichting', 'Verlichting', 'Boeideel-spots', spots, 'st.', spots * L.boeideelSpot, spots * L.montage);
|
||||
add(wo, 'Verlichting', 'Verlichting', 'Binnenspots', lm.indoor, 'st.', lm.indoor * L.binnenspot, lm.indoor * L.montage);
|
||||
|
||||
// --- Elektra (ElektraModel): per unit de leidingen (strekkende meters
|
||||
// per type: buis + draad per ader, of XMvK), boorgaten, steekverbinders,
|
||||
// dozen en aansluitingen; meterkast, groepen en keuring bij de unit waar
|
||||
// de meterkast hangt. Arbeid met E.personeel man.
|
||||
const elk = parts.elektra, E = S.elektra;
|
||||
if (elk && elk.enabled) {
|
||||
const unitIds = new Set(parts.units.map(u => u.id)), elOf = {};
|
||||
const elFor = (uid) => {
|
||||
const id = unitIds.has(uid) ? uid : null, k = id || '-';
|
||||
return elOf[k] || (elOf[k] = newEl(id ? `${id}-EL` : 'EL', id ? `Unit ${id} elektra` : 'Elektra', id));
|
||||
};
|
||||
const ea = (uid, label, qty, unit, mat, sec) => add(elFor(uid), 'Elektra', 'Elektra', label, qty, unit, mat, sec, E.personeel);
|
||||
const mkUnit = elk.meterkast ? elk.meterkast.unitId : null;
|
||||
const groupUnit = (nr) => (elk.groups.find(g => g.nr === nr) || {}).unitId || mkUnit;
|
||||
const buisPrijs = (d) => d >= 25 ? E.buis25M : d >= 19 ? E.buis19M : E.buis16M;
|
||||
const agg = {};
|
||||
elk.runs.forEach(r => {
|
||||
const uid = groupUnit(r.group), a = agg[uid] = agg[uid] || { types: {}, holes: 0, cross: {} };
|
||||
a.types[r.type] = (a.types[r.type] || 0) + r.lengthMM / 1000;
|
||||
a.holes += r.holes || 0;
|
||||
if (r.crossings) { const n = ElektraModel.cableInfo(r.type).cores.length; a.cross[n] = (a.cross[n] || 0) + r.crossings; }
|
||||
});
|
||||
Object.keys(agg).forEach(uid => {
|
||||
const a = agg[uid];
|
||||
Object.keys(a.types).sort().forEach(type => {
|
||||
const c = ElektraModel.cableInfo(type), m = a.types[type];
|
||||
if (c.conduit) {
|
||||
const draad = c.mm2 >= 2.5 ? E.draad25M : E.draad15M;
|
||||
ea(uid, `${c.label}: ${c.use.toLowerCase()} (buis + ${c.cores.length} aders)`, m, 'm', m * (buisPrijs(c.conduit) + c.cores.length * draad), m * (E.buisLeggen + E.draadTrekken));
|
||||
} else ea(uid, `${c.label}: ${c.use.toLowerCase()}`, m, 'm', m * E.xmvkM, m * E.kabelLeggen);
|
||||
});
|
||||
ea(uid, `Boorgaten stijlen/regels/balken (${E.boorgat} s per gat)`, a.holes, 'st.', 0, a.holes * E.boorgat);
|
||||
Object.keys(a.cross).forEach(n => {
|
||||
const k = a.cross[n];
|
||||
ea(uid, `Steekverbinder module-naad ${n}-polig`, k, 'set', k * (Number(n) >= 5 ? E.steekverbinder5 : E.steekverbinder3), k * E.steekverbinderMontage);
|
||||
});
|
||||
});
|
||||
const count = (list, uid) => list.filter(x => x.unitId === uid).length;
|
||||
parts.units.forEach(u => {
|
||||
const uid = u.id;
|
||||
const nSw = count(elk.switches, uid), combos = elk.combos.filter(c => c.unitId === uid);
|
||||
const raam1 = combos.filter(c => c.switches.length === 1).length, raam2 = combos.length - raam1;
|
||||
ea(uid, `Schakelaars (${raam1}× 1-voudig, ${raam2}× 2-voudig raam)`, nSw, 'st.',
|
||||
nSw * (E.schakelaar + E.inbouwdoos) + raam1 * E.afdekraam1 + raam2 * E.afdekraam2, nSw * (E.doosPlaatsen + E.afmonteren));
|
||||
const nW = count(elk.wcds, uid);
|
||||
ea(uid, 'Wandcontactdozen dubbel (2 inbouwdozen)', nW, 'st.', nW * (E.wcdDubbel + 2 * E.inbouwdoos), nW * (2 * E.doosPlaatsen + E.afmonteren));
|
||||
elk.apps.filter(a => a.unitId === uid).forEach(a => {
|
||||
const price = a.app === 'koken' ? E.perilex : a.app === 'warmtepomp' ? E.werkschakelaar : E.wcdEnkel;
|
||||
ea(uid, `Aansluitpunt ${a.label.toLowerCase()}`, 1, 'st.', price + E.inbouwdoos, E.doosPlaatsen + E.afmonteren);
|
||||
});
|
||||
const nV = count(elk.floorWcds, uid);
|
||||
ea(uid, 'Vloerdoos met dubbele wcd', nV, 'st.', nV * E.vloerdoosSt, nV * (E.vloerdoos + E.afmonteren));
|
||||
const nB = count(elk.boxes, uid), nKl = nB * 3 + nSw + nW;
|
||||
ea(uid, `Verdeeldozen plafond (+ ${nKl} lasklemmen)`, nB, 'st.', nB * E.verdeeldoosSt + nKl * E.lasklem, nB * E.verdeeldoos);
|
||||
const nSpot = elk.switches.filter(sw => sw.unitId === uid).reduce((t, sw) => t + sw.lamps.filter(l => l.kind === 'binnenspot').length, 0);
|
||||
ea(uid, 'Spotdozen plafond (luchtdicht)', nSpot, 'st.', nSpot * E.spotdoosSt, nSpot * E.spotdoos);
|
||||
const nDv = elk.runs.filter(r => r.type === 'buiten' && r.from.startsWith('VD') && groupUnit(r.group) === uid).length;
|
||||
ea(uid, 'Kabeldoorvoer naar buiten', nDv, 'st.', nDv * E.doorvoer, 0);
|
||||
});
|
||||
if (elk.meterkast) {
|
||||
const g1 = elk.groups.filter(g => (g.poles || 1) === 1).length, g2 = elk.groups.length - g1;
|
||||
ea(mkUnit, `Groepenkast 3×25 A: kast, hoofdschakelaar, ${elk.rcdCount} aardlek`, 1, 'st.', E.kast + E.hoofdschakelaar + elk.rcdCount * E.aardlek, E.kastMontage);
|
||||
ea(mkUnit, `Groepen: ${g1}× automaat 1P+N${g2 ? `, ${g2}× 2-fase` : ''}`, elk.groups.length, 'groep', g1 * E.automaat + g2 * E.automaat2f, elk.groups.length * E.groepMontage);
|
||||
ea(mkUnit, 'Meten, testen en opleveren', 1, 'woning', 0, E.keuring);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Optellen ---
|
||||
const sumLines = (lines) => lines.reduce((a, l) => ({ mat: a.mat + l.mat, sec: a.sec + l.sec, clock: a.clock + l.clock }), { mat: 0, sec: 0, clock: 0 });
|
||||
elements.forEach(el => Object.assign(el, sumLines(el.lines)));
|
||||
|
||||
Reference in New Issue
Block a user