// prissammanstallning.js
// EN gemensam prissammanställning för ALLA kalkyler
// Läser skattesatser från globala taxSettings (laddas från DB vid app-start)
// Global: alla kategoriers prisdata i kalkylen
var _kalkylItems = {};
function getKalkylEntries(category) {
var item = _kalkylItems[category];
if(!item) return [];
if(Array.isArray(item.entries)) return item.entries.slice();
return [item];
}
function rebuildKalkylCategory(category, entries) {
var validEntries = (entries || []).filter(function(entry) {
return entry && (parseFloat(entry.total) || 0) > 0;
});
if(!validEntries.length) {
delete _kalkylItems[category];
return;
}
_kalkylItems[category] = {
description: validEntries[0].description || validEntries[0].product_name || category,
total: validEntries.reduce(function(sum, entry){ return sum + (parseFloat(entry.total) || 0); }, 0),
entries: validEntries
};
}
function appendKalkylEntry(category, entry) {
if(!category || !entry) return;
var entries = getKalkylEntries(category);
if(!entry.entry_id) entry.entry_id = category + '_' + Date.now() + '_' + Math.floor(Math.random() * 10000);
entries.push(entry);
rebuildKalkylCategory(category, entries);
}
function removeKalkylEntry(category, entryId) {
var entries = getKalkylEntries(category).filter(function(entry){ return entry.entry_id !== entryId; });
rebuildKalkylCategory(category, entries);
}
function getTax() {
return typeof taxSettings !== 'undefined' ? taxSettings : {gt20:20, gt50:50, rot:30, rotMax:50000, moms:25};
}
// Registrera en kategoris prisdata (anropas av varje konfigurators updateCalc)
function registerCfgItem(category, itemData) {
if(!category) return;
_kalkylItems[category] = {
description: itemData.description || '',
total: itemData.total || 0,
product_name: itemData.product_name || '',
lines: itemData.lines || [],
windows: itemData.windows || [],
entries: itemData.entries || []
};
}
function renderPrisSidebar(containerId, data) {
// data = {
// lines: [{label, detail, value}],
// subtotal: number,
// taxType: 'GT20'|'GT50'|'ROT'|'NONE' (from product),
// deductType: 'green'|'rot'|'none' (user choice, legacy support),
// deductLabel: string,
// deductAmount: number,
// deductDetail: string,
// owners: 1|2,
// maxDeduction: number,
// sliderInteractive: boolean,
// sliderValue: number,
// onSliderChange: string,
// total: number,
// finYears: number,
// monthly: number,
// saving: number (optional),
// payback: number (optional),
// margin: {pct, amount, onSliderChange} (optional),
// category: string,
// onDeductChange: string,
// onOwnerChange: string,
// onFinChange: string,
// onSave: string,
// onOrder: string,
// purposeOptions: [{value, label}] (optional, e.g. batteri egen lagring/lagringstjänst),
// selectedPurpose: string,
// onPurposeChange: string
// }
var el = document.getElementById(containerId);
if (!el) return;
var d = data || {};
var tax = getTax();
var cartOnly = !!d.cartOnly;
var lines = d.lines || [];
var activeLines = lines.filter(function(line){
return line && (parseFloat(line.value) || 0) > 0;
});
var owners = d.owners || 1;
var finYears = d.finYears !== undefined ? d.finYears : 15;
var onDeduct = d.onDeductChange || 'setPrisDeduction';
var onOwner = d.onOwnerChange || 'setPrisOwners';
var onFin = d.onFinChange || 'setPrisFinYears';
var onSave = d.onSave || 'saveCfgQuote()';
var onOrder = d.onOrder || "showAddToKalkyl('" + (d.category || '') + "')";
var saveLabel = d.saveLabel || (((typeof currentQuoteId !== 'undefined' && currentQuoteId) ? 'Spara kalkyl' : 'Skapa ny kalkyl'));
var orderLabel = d.orderLabel || 'Lägg till i kalkyl';
var hideOrderButton = true;
var cat = d.category || '';
var categoryViewAction = d.categoryViewAction || '';
var canReturnToSummary = !cartOnly && cat && cat !== '_summary' && Object.keys(_kalkylItems || {}).filter(function(key){
return _kalkylItems[key] && (_kalkylItems[key].total || 0) > 0;
}).length > 1;
function renderSidebarLine(line) {
var detail = line.detail ? ' <span style="font-size:10px;color:#94a3b8">' + line.detail + '</span>' : '';
var valueHtml = '<span class="price-line-value">' + fmt(line.value || 0) + '</span>';
if(line.editAction) {
valueHtml = '<span style="display:flex;align-items:center;gap:6px">'
+ '<button onclick="' + line.editAction + '" style="background:none;border:none;padding:0;cursor:pointer;opacity:.65" title="Redigera"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg></button>'
+ valueHtml
+ '</span>';
}
return '<div class="price-line"><span class="price-line-label">' + line.label + detail + '</span>' + valueHtml + '</div>';
}
function renderCategoryHeading(label, action) {
var html = '<div style="font-size:10px;font-weight:600;color:#024550;text-transform:uppercase;letter-spacing:.5px;padding:8px 0 4px;border-top:1px solid #e5e7eb;display:flex;justify-content:space-between;align-items:center">';
html += '<span>' + label + '</span>';
if(action) {
html += '<button onclick="' + action + '" style="background:none;border:none;padding:0;cursor:pointer;opacity:.65" title="Visa detaljer"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>';
}
html += '</div>';
return html;
}
function renderCategoryEntries(categoryKey, entries, fallbackItem) {
var html = '';
var windowRows = [];
if(fallbackItem && Array.isArray(fallbackItem.windows) && fallbackItem.windows.length) {
windowRows = windowRows.concat(fallbackItem.windows);
}
(entries || []).forEach(function(entry) {
if(entry && Array.isArray(entry.windows) && entry.windows.length) {
windowRows = windowRows.concat(entry.windows);
}
});
if(categoryKey === 'fonster' && windowRows.length) {
windowRows.forEach(function(w) {
html += renderSidebarLine({
label: (w.productName || (catLabels[categoryKey] || categoryKey)) + ' ' + (w.modelLabel || ''),
detail: '',
value: (w.pris || 0) * (w.antal || 1),
editAction: "fkEditWindowById(" + (w.id || 0) + ")"
});
});
return html;
}
(entries || []).forEach(function(entry) {
html += renderSidebarLine({
label: entry.description || entry.product_name || (fallbackItem && fallbackItem.description) || (catLabels[categoryKey] || categoryKey),
detail: entry.detail || '',
value: entry.total || 0,
editAction: entry.entry_id ? ("editSummaryEntry('" + categoryKey + "','" + entry.entry_id + "')") : ("editFromSummary('" + categoryKey + "')")
});
});
if(!html && fallbackItem && fallbackItem.total) {
html += renderSidebarLine({
label: fallbackItem.description || (catLabels[categoryKey] || categoryKey),
value: fallbackItem.total || 0,
editAction: "editFromSummary('" + categoryKey + "')"
});
}
return html;
}
// Kategori-labels
var catLabels = typeof _catLabels !== 'undefined' ? _catLabels : {solceller:'Solpaneler',batteri:'Batteri',laddbox:'Laddbox',taktvatt:'Taktv\u00e4tt',varmepump:'V\u00e4rmepump',tak:'Tak',fonster:'F\u00f6nster',isolering:'Isolering'};
var currentItem = (typeof _kalkylItems !== "undefined" && cat && cat !== "_summary") ? _kalkylItems[cat] : null;
var currentItemEntries = currentItem ? (Array.isArray(currentItem.entries) ? currentItem.entries : [currentItem]) : [];
// Övriga kategorier i samma kalkyl (från _kalkylItems, fylls av openQuoteFromList/saveCfgQuote)
var otherItemsHtml = '';
var otherTotal = 0;
if(typeof _kalkylItems !== "undefined" && cat !== "_summary") {
Object.keys(_kalkylItems).forEach(function(k) {
if(k === cat) return;
var item = _kalkylItems[k];
if(!item || !item.total) return;
otherTotal += item.total;
otherItemsHtml += renderCategoryHeading((catLabels[k] || k), "showSummaryCategory('" + k + "')");
otherItemsHtml += renderCategoryEntries(k, Array.isArray(item.entries) ? item.entries : [item], item);
});
}
// Prisrader — aktuell kategori
var linesHtml = '';
if(cartOnly) {
var cartItemsHtml = '';
var cartTotal = 0;
var cartSubtotal = 0;
var cartDeductionTotal = 0;
var cartDeductionRows = [];
if(typeof _kalkylItems !== 'undefined') {
Object.keys(_kalkylItems).forEach(function(k) {
var item = _kalkylItems[k];
if(!item || !item.total) return;
cartTotal += item.total || 0;
var entries = Array.isArray(item.entries) ? item.entries : [item];
var windowRows = [];
if(item && Array.isArray(item.windows) && item.windows.length) {
windowRows = windowRows.concat(item.windows);
}
entries.forEach(function(entry) {
if(entry && Array.isArray(entry.windows) && entry.windows.length) {
windowRows = windowRows.concat(entry.windows);
}
});
cartItemsHtml += '<div style="font-size:10px;font-weight:600;color:#94a3b8;text-transform:uppercase;letter-spacing:.5px;padding:8px 0 4px;border-top:1px solid #e5e7eb;display:flex;justify-content:space-between;align-items:center">';
cartItemsHtml += '<span>' + (catLabels[k] || k) + '</span>';
cartItemsHtml += '<span style="display:flex;align-items:center;gap:8px">';
cartItemsHtml += '<button onclick="showSummaryCategory(\'' + k + '\')" style="background:none;border:none;padding:0;cursor:pointer;opacity:.65" title="Visa detaljer"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg></button>';
cartItemsHtml += '</span></div>';
if(k === 'fonster' && windowRows.length) {
windowRows.forEach(function(w) {
cartSubtotal += parseFloat(w.pris * w.antal || 0);
cartItemsHtml += '<div class="price-line"><span class="price-line-label">' + (w.productName + ' ' + w.modelLabel) + '</span><span style="display:flex;align-items:center;gap:6px"><button onclick="fkEditWindowById(' + (w.id || 0) + ')" style="background:none;border:none;padding:0;cursor:pointer;opacity:.65" title="Redigera"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg></button><span class="price-line-value">' + fmt((w.pris || 0) * (w.antal || 1)) + '</span></span></div>';
});
} else {
entries.forEach(function(entry) {
cartSubtotal += parseFloat(entry.subtotal || entry.total || 0);
cartDeductionTotal += parseFloat(entry.deduction_amount || 0);
if(parseFloat(entry.deduction_amount || 0) > 0) {
cartDeductionRows.push({
label: (catLabels[k] || k),
amount: parseFloat(entry.deduction_amount || 0)
});
}
cartItemsHtml += '<div class="price-line"><span class="price-line-label">' + (entry.description || item.description || '') + '</span><span style="display:flex;align-items:center;gap:6px"><button onclick="' + (entry.entry_id ? ("editSummaryEntry('" + k + "','" + entry.entry_id + "')") : ("editFromSummary('" + k + "')")) + '" style="background:none;border:none;padding:0;cursor:pointer;opacity:.65" title="Redigera"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#64748b" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z"/></svg></button><span class="price-line-value">' + fmt(entry.total || 0) + '</span></span></div>';
});
}
});
}
if(!cartItemsHtml) {
cartItemsHtml = '<div style="font-size:13px;color:#94a3b8;padding:6px 0">Inga produkter tillagda ännu</div>';
}
linesHtml = cartItemsHtml;
linesHtml += '<div class="price-line subtotal"><span class="price-line-label">Totalt i kalkylen</span><span class="price-line-value">' + fmt(cartSubtotal || cartTotal) + '</span></div>';
} else if(otherItemsHtml) {
linesHtml += '<div style="font-size:10px;font-weight:600;color:#94a3b8;text-transform:uppercase;letter-spacing:.5px;padding:4px 0">\u00d6vriga i kalkylen</div>';
linesHtml += otherItemsHtml;
if(activeLines.length) {
linesHtml += renderCategoryHeading((catLabels[cat] || cat), categoryViewAction);
linesHtml += activeLines.map(renderSidebarLine).join('');
} else if(currentItem && currentItem.total) {
linesHtml += renderCategoryHeading((catLabels[cat] || cat), categoryViewAction);
linesHtml += renderCategoryEntries(cat, currentItemEntries, currentItem);
}
var grandSubtotal = (d.subtotal || 0) + otherTotal;
linesHtml += '<div class="price-line subtotal"><span class="price-line-label">Totalt före avdrag</span><span class="price-line-value">' + fmt(grandSubtotal) + '</span></div>';
} else {
if(cat && cat !== '_summary') {
linesHtml += renderCategoryHeading((catLabels[cat] || cat), categoryViewAction);
}
if(activeLines.length) {
linesHtml += activeLines.map(renderSidebarLine).join('');
} else if(currentItem && currentItem.total) {
linesHtml += renderCategoryEntries(cat, currentItemEntries, currentItem);
} else {
linesHtml += lines.map(renderSidebarLine).join('');
}
var grandSubtotal = (d.subtotal || 0) + otherTotal;
linesHtml += '<div class="price-line subtotal"><span class="price-line-label">Totalt före avdrag</span><span class="price-line-value">' + fmt(grandSubtotal) + '</span></div>';
}
// Skatteavdrag — bestäms av taxType från produkten
var taxType = d.taxType || 'NONE';
var deductType = d.deductType || 'none';
var deductHtml = '';
if (cartOnly) {
var allEntries = [];
if(typeof _kalkylItems !== 'undefined') {
Object.keys(_kalkylItems).forEach(function(k) {
var item = _kalkylItems[k];
if(!item) return;
var entries = Array.isArray(item.entries) ? item.entries : [item];
entries.forEach(function(entry){ allEntries.push({category:k, entry:entry}); });
});
}
var dedRows = allEntries.filter(function(row){ return parseFloat(row.entry.deduction_amount || 0) > 0; });
if(dedRows.length) {
deductHtml = '<div style="margin-bottom:10px"><div style="font-size:11px;color:#6b7280;margin-bottom:6px;font-weight:600">SKATTEAVDRAG</div>';
dedRows.forEach(function(row) {
deductHtml += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px"><span style="font-size:12px;color:#059669;font-weight:600">' + (row.entry.deduction_label || (catLabels[row.category] || row.category)) + '</span><span style="font-size:14px;font-weight:700;color:#059669">-' + fmt(row.entry.deduction_amount || 0) + '</span></div>';
});
var dedTotal = dedRows.reduce(function(sum, row){ return sum + parseFloat(row.entry.deduction_amount || 0); }, 0);
deductHtml += '<div style="display:flex;justify-content:space-between;align-items:center;padding-top:8px;border-top:1px solid #bbf7d0"><span style="font-size:12px;color:#059669;font-weight:700">Totalt avdrag</span><span style="font-size:16px;font-weight:700;color:#059669">-' + fmt(dedTotal) + '</span></div></div>';
} else {
deductHtml = '<div style="margin-bottom:10px"><div style="font-size:11px;color:#6b7280;margin-bottom:6px;font-weight:600">PRISSAMMANSTÄLLNING</div><div style="font-size:13px;color:#94a3b8">Här visas produkter som redan lagts till i kalkylen.</div></div>';
}
} else if (taxType === 'NONE' && deductType === 'none') {
// Inget avdrag alls
deductHtml = '<div style="margin-bottom:10px">'
+ '<div style="font-size:11px;color:#6b7280;margin-bottom:6px;font-weight:600">GRÖNT TEKNIK-AVDRAG</div>'
+ '<div style="font-size:13px;color:#94a3b8">Inget skatteavdrag för denna produkt</div>'
+ '</div>';
} else {
// Visa avdragsinfo
var deductLabel = d.deductLabel || '';
var deductPct = 0;
var deductBase = '';
if (taxType === 'GT20' || deductType === 'green' && taxType !== 'GT50') {
deductPct = tax.gt20;
deductLabel = deductLabel || 'GRÖNT TEKNIK-AVDRAG (GT20)';
deductBase = 'material + arbete';
} else if (taxType === 'GT50') {
deductPct = tax.gt50;
deductLabel = deductLabel || 'SKATTEREDUKTION (GT50)';
deductBase = 'material + arbete';
} else if (taxType === 'ROT' || deductType === 'rot') {
deductPct = tax.rot;
deductLabel = deductLabel || 'ROT-AVDRAG';
deductBase = 'enbart arbete';
}
// Avdragsknappar — visa bara relevanta val
function deductBtn(type, label, sub, active) {
var style = active
? 'flex:1;padding:7px 4px;border:1.5px solid #059669;border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;background:#059669;color:#fff;font-family:inherit;line-height:1.2'
: 'flex:1;padding:7px 4px;border:1.5px solid #bbf7d0;border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;background:#fff;color:#059669;font-family:inherit;line-height:1.2';
return '<button onclick="' + onDeduct + '(\'' + type + '\')" style="' + style + '">' + label + '<br><span style="font-size:9px;font-weight:400;opacity:.8">' + sub + '</span></button>';
}
deductHtml = '<div style="margin-bottom:10px">'
+ '<div style="font-size:11px;color:#6b7280;margin-bottom:6px;font-weight:600">GRÖNT TEKNIK-AVDRAG</div>'
+ '<div style="display:flex;gap:4px">';
if (taxType === 'GT20') {
deductHtml += deductBtn('green', 'Grönt teknik', tax.gt20 + '% av allt', deductType === 'green');
deductHtml += deductBtn('rot', 'ROT-avdrag', tax.rot + '% av arbete', deductType === 'rot');
deductHtml += deductBtn('both', 'Båda', 'GT + ROT', deductType === 'both');
} else if (taxType === 'GT50') {
deductHtml += deductBtn('green', 'GT50', tax.gt50 + '% av allt', deductType === 'green');
} else if (taxType === 'ROT') {
deductHtml += deductBtn('rot', 'ROT-avdrag', tax.rot + '% av arbete', deductType === 'rot');
}
deductHtml += deductBtn('none', 'Inget', ' ', deductType === 'none');
deductHtml += '</div></div>';
// Avdragssumma
deductHtml += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px">'
+ '<span style="font-size:12px;font-weight:700;color:#059669">' + deductLabel + '</span>'
+ '<span style="font-size:16px;font-weight:700;color:#059669">' + (d.deductAmount ? '-' + fmt(d.deductAmount) : '0 kr') + '</span></div>';
if (d.deductDetail) deductHtml += '<div style="font-size:11px;color:#6b7280;margin-bottom:8px">' + d.deductDetail + '</div>';
}
// Antal ägare (bara om avdrag är aktivt)
if (deductType !== 'none') {
deductHtml += '<div style="margin-bottom:10px"><div style="font-size:11px;color:#6b7280;margin-bottom:4px">Antal ägare</div>'
+ '<div style="display:flex;gap:6px">'
+ '<button onclick="' + onOwner + '(1)" style="flex:1;padding:6px;border:1.5px solid ' + (owners === 1 ? '#059669' : '#bbf7d0') + ';border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;background:' + (owners === 1 ? '#059669' : '#fff') + ';color:' + (owners === 1 ? '#fff' : '#059669') + ';font-family:inherit">1 person</button>'
+ '<button onclick="' + onOwner + '(2)" style="flex:1;padding:6px;border:1.5px solid ' + (owners === 2 ? '#059669' : '#bbf7d0') + ';border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;background:' + (owners === 2 ? '#059669' : '#fff') + ';color:' + (owners === 2 ? '#fff' : '#059669') + ';font-family:inherit">2 personer</button>'
+ '</div></div>';
// Kvarvarande avdrag slider
var maxDed = d.maxDeduction || (owners * (taxType === 'ROT' ? tax.rotMax : 50000));
var sliderVal = d.sliderValue !== undefined ? d.sliderValue : maxDed;
var sliderDisabled = d.sliderInteractive ? '' : ' disabled';
var sliderOnInput = d.onSliderChange ? ' oninput="' + d.onSliderChange + '(this.value)"' : '';
deductHtml += '<div><div style="display:flex;justify-content:space-between;font-size:11px;color:#6b7280;margin-bottom:4px">'
+ '<span>Kvarvarande avdrag</span><span style="font-weight:600;color:#059669">' + sliderVal.toLocaleString('sv-SE') + ' kr</span></div>'
+ '<input type="range" min="0" max="' + maxDed + '" step="5000" value="' + sliderVal + '" style="width:100%;accent-color:#059669"' + sliderDisabled + sliderOnInput + '>'
+ '<div style="display:flex;justify-content:space-between;font-size:10px;color:#94a3b8"><span>0 kr</span><span>' + maxDed.toLocaleString('sv-SE') + ' kr</span></div></div>';
}
// Finansiering
function finBtn(yr, active) {
var style = active
? 'padding:4px 10px;border:1.5px solid #3b82f6;border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;background:#3b82f6;color:#fff;font-family:inherit'
: 'padding:4px 10px;border:1.5px solid #bfdbfe;border-radius:6px;font-size:11px;font-weight:600;cursor:pointer;background:#fff;color:#3b82f6;font-family:inherit';
var label = yr === 0 ? 'Ej finans' : yr + ' år';
return '<button onclick="' + onFin + '(' + yr + ')" style="' + style + '">' + label + '</button>';
}
var finHtml = '<div style="background:#f0f9ff;border-radius:10px;padding:14px;margin-bottom:12px">'
+ '<div style="font-size:11px;color:#3b82f6;font-weight:600;margin-bottom:8px">FINANSIERING</div>'
+ '<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
+ finBtn(0, finYears === 0) + finBtn(5, finYears === 5) + finBtn(10, finYears === 10) + finBtn(15, finYears === 15) + finBtn(20, finYears === 20) + finBtn(25, finYears === 25)
+ '</div>';
if (finYears > 0) {
finHtml += '<div style="display:flex;justify-content:space-between;align-items:baseline">'
+ '<span style="font-size:13px;color:#334155">Månadskostnad <span style="font-size:10px;color:#64748b">(' + finYears + ' år, 4.9%)</span></span>'
+ '<span style="font-size:20px;font-weight:700;color:#1e40af">' + fmt(d.monthly || 0) + '/mån</span></div>';
} else {
finHtml += '<div style="font-size:13px;color:#64748b">Ingen finansiering vald</div>';
}
finHtml += '</div>';
// Marginal (valfritt, för fönster)
var marginHtml = '';
if (d.margin) {
var m = d.margin;
marginHtml = '<div style="background:#fefce8;border-radius:10px;padding:14px;margin-bottom:12px">'
+ '<div style="font-size:11px;color:#92400e;font-weight:600;margin-bottom:8px">MARGINAL</div>'
+ '<div style="display:flex;align-items:center;gap:12px">'
+ '<input type="range" min="0" max="50" step="1" value="' + (m.pct || 0) + '" style="flex:1;accent-color:#f59e0b" oninput="' + (m.onSliderChange || '') + '(this.value)">'
+ '<span style="font-size:14px;font-weight:700;color:#92400e;min-width:40px;text-align:right">' + (m.pct || 0) + '%</span>'
+ '</div>'
+ '<div style="display:flex;justify-content:space-between;margin-top:6px"><span style="font-size:12px;color:#92400e">Marginal</span><span style="font-size:14px;font-weight:700;color:#92400e">' + fmt(m.amount || 0) + '</span></div>'
+ '</div>';
}
// Besparing (valfritt)
var savingHtml = '';
if (d.saving) {
savingHtml = '<div style="background:#ecfdf5;border-radius:10px;padding:14px;margin-bottom:16px">'
+ '<div style="font-size:11px;color:#059669;font-weight:600;margin-bottom:4px">UPPSKATTAD BESPARING</div>'
+ '<div style="display:flex;justify-content:space-between;align-items:baseline"><span style="font-size:13px;color:#334155">Per år</span><span style="font-size:20px;font-weight:700;color:#166534">' + d.saving.toLocaleString('sv-SE') + ' kr/år</span></div>'
+ (d.payback ? '<div style="display:flex;justify-content:space-between;align-items:baseline;margin-top:4px"><span style="font-size:13px;color:#334155">Återbetalningstid</span><span style="font-size:16px;font-weight:700;color:#166534">' + d.payback + ' år</span></div>' : '')
+ '</div>';
}
// Moms-info
var momsHtml = '<div style="display:flex;justify-content:space-between;font-size:11px;color:#94a3b8;margin-bottom:12px">'
+ '<span>Moms (' + tax.moms + '%)</span><span>Inkl. i priserna</span></div>';
// Knappar
var saveIcon = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>';
var addIcon = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><line x1="9" y1="15" x2="15" y2="15"/></svg>';
var btnsHtml = '';
if(canReturnToSummary) {
btnsHtml += '<button onclick="showKalkylSummary()" style="width:100%;padding:12px;background:#fff;color:#024550;border:1.5px solid #bfdbfe;border-radius:10px;font-size:13px;font-weight:700;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:8px;margin-bottom:8px">'
+ '<svg viewBox="0 0 24 24" style="width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M7 8h10M7 12h10M7 16h6"/></svg>'
+ 'Kalkylsammanställning</button>';
}
btnsHtml += '<button onclick="' + onSave + '" style="width:100%;padding:12px;background:#f59e0b;color:#fff;border:none;border-radius:10px;font-size:14px;font-weight:700;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:8px' + (hideOrderButton ? '' : ';margin-bottom:8px') + '">'
+ saveIcon + saveLabel + '</button>';
if(!hideOrderButton) {
btnsHtml += '<button onclick="' + onOrder + '" style="width:100%;padding:14px;background:linear-gradient(135deg,#024550,#035e6b);color:#fff;border:none;border-radius:10px;font-size:15px;font-weight:700;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:8px">'
+ addIcon + orderLabel + '</button>';
}
// Hela prissammanställningen
el.innerHTML = '<div style="position:sticky;top:20px"><div class="price-card">'
+ '<div class="price-header">Prissammanställning</div>'
+ '<div class="price-rows">' + linesHtml + '</div>'
+ '<div class="rot-section" style="background:#ecfdf5;padding:14px 16px">' + deductHtml + '</div>'
+ '<div class="total-section"><div class="total-line"><span class="total-label">Att betala</span><span class="total-value">' + fmt(cartOnly ? Object.keys(_kalkylItems || {}).reduce(function(sum, key){ return sum + ((_kalkylItems[key] && _kalkylItems[key].total) || 0); }, 0) : ((d.total || 0) + otherTotal)) + '</span></div><div class="total-vat">' + momsHtml + '</div></div>'
+ '<div style="padding:0 16px 16px">' + finHtml + marginHtml + savingHtml + btnsHtml + '</div>'
+ '</div></div>';
}
// Hjälpfunktion: beräkna avdrag baserat på taxType och taxSettings
function calcTaxDeduction(subtotal, laborCost, taxType, deductType, owners) {
var tax = getTax();
var maxPerPerson = taxType === 'ROT' ? tax.rotMax : 50000;
var maxTotal = owners * maxPerPerson;
if (deductType === 'none') return {amount: 0, label: 'INGET AVDRAG', detail: ''};
if (taxType === 'GT50' && deductType === 'green') {
var calc = Math.round(subtotal * tax.gt50 / 100);
var amt = Math.min(calc, maxTotal);
return {
amount: amt,
label: 'SKATTEREDUKTION (GT50)',
detail: tax.gt50 + '% av ' + fmt(subtotal) + ' = ' + fmt(calc) + (calc > maxTotal ? ' (max ' + fmt(maxTotal) + ')' : '')
};
}
if (taxType === 'GT20' && deductType === 'green') {
var calc = Math.round(subtotal * tax.gt20 / 100);
var amt = Math.min(calc, maxTotal);
return {
amount: amt,
label: 'GRÖNT TEKNIK-AVDRAG (GT20)',
detail: tax.gt20 + '% av ' + fmt(subtotal) + ' = ' + fmt(calc) + (calc > maxTotal ? ' (max ' + fmt(maxTotal) + ')' : '')
};
}
if (deductType === 'rot') {
var calc = Math.round(laborCost * tax.rot / 100);
var amt = Math.min(calc, maxTotal);
return {
amount: amt,
label: 'ROT-AVDRAG',
detail: tax.rot + '% av arbete ' + fmt(laborCost) + ' = ' + fmt(calc) + (calc > maxTotal ? ' (max ' + fmt(maxTotal) + ')' : '')
};
}
if (deductType === 'both') {
// GT20 på material + ROT på arbete (bara för solceller)
var materialCost = subtotal - laborCost;
var greenCalc = Math.round(materialCost * tax.gt20 / 100);
var rotCalc = Math.round(laborCost * tax.rot / 100);
var bothTotal = greenCalc + rotCalc;
var amt = Math.min(bothTotal, maxTotal);
return {
amount: amt,
label: 'GRÖNT TEKNIK + ROT',
detail: 'GT20: ' + fmt(greenCalc) + ' + ROT: ' + fmt(rotCalc) + ' = ' + fmt(bothTotal) + (bothTotal > maxTotal ? ' (max ' + fmt(maxTotal) + ')' : '')
};
}
return {amount: 0, label: 'INGET AVDRAG', detail: ''};
}