// konfigurator-solar.js - Solar configurator
// === SOLAR CONFIGURATOR ===
// Pricing from SimCRM: full price 116,250 for 8 panels (before green tech deduction)
// Green tech = 20% → customer pays 93,000 (=116,250 × 0.80)
const SOL_FULL_BASE_PRICE = 116250; // Full price before deduction for 8 panels
const SOL_BASE_PANELS = 8;
const SOL_FULL_PRICE_PER_PANEL = 3688; // Full price per extra panel
const SOL_MATERIAL_RATIO = 0.65; // 65% material, 35% installation
const SOL_LABOR_RATIO = 0.35;
const SOL_PANEL_AREA = 1.87; // m² per panel
const SOL_ELECTRICITY_PRICE = 1.50; // kr/kWh
const SOL_SELF_USE = 0.70;
const SOL_SELL_PRICE = 0.50; // kr/kWh for surplus
const SOL_FINANCE_RATE = 0.049; // 4.9% annual
let SOL_FINANCE_YEARS = 15;
const GREEN_TECH_RATE = 0.20; // 20% of total (material+labor+battery+charger)
const ROT_RATE = 0.30; // 30% of labor only
let solSelectedPanel = null;
let solSelectedBattery = 0;
let solSelectedBatteryPrice = 0;
let solSelectedCharger = null;
let solSelectedChargerPrice = 0;
let solOwnerCount = 1;
let solGreenTechMax = 50000;
let solDeductionType = 'green'; // 'green', 'rot', 'both', 'none'
// Current calc state for Affär
let currentCalcState = {};
let kalkylOrigin = 'konfigurator';
// EV chargers from SimCRM
const evChargers = [
{brand:'Garo',model:'22kW',price:26000,desc:'Inkl. lastbalans'},
{brand:'Zaptec',model:'GO',price:26000,desc:'Inkl. lastbalans'},
{brand:'Zaptec',model:'PRO 22kW',price:33000,desc:'Inkl. lastbalans'},
{brand:'Charge Amps',model:'Aura 22kW (2 uttag)',price:40000,desc:'Inkl. lastbalans'}
];
// Battery options from SimCRM
const batteryOptions = [
{kwh:5,price:35000,label:'5 kWh'},
{kwh:10,price:50000,label:'10 kWh'},
{kwh:15,price:65000,label:'15 kWh'},
{kwh:20,price:85000,label:'20 kWh'}
];
function initSolarConfig(){ var _lbl=document.getElementById('cfgFileLabel');if(_lbl)_lbl.textContent='konfigurator-solar.js';
// Get solar panels from catalog
const panels = catalogProducts.filter(p => p.watt && p.watt > 0 && p.cat === 'solceller');
const container = document.getElementById('solarPanelCards');
if(!panels.length){
// Retry after catalog loads
container.innerHTML='<div style="padding:20px;color:#94a3b8;text-align:center"><div class="spinner" style="display:inline-block;width:20px;height:20px;border:2px solid #e5e7eb;border-top-color:#024550;border-radius:50%;animation:bgspin .6s linear infinite"></div><p style="margin-top:6px;font-size:12px">Laddar paneler...</p></div>';
if(!window._solarRetryCount) window._solarRetryCount = 0;
if(window._solarRetryCount < 10){
window._solarRetryCount++;
setTimeout(initSolarConfig, 500);
} else {
container.innerHTML='<div style="padding:20px;color:#94a3b8;text-align:center">Inga solpaneler i katalogen. Lägg till via Produkter.</div>';
}
// Still run updateSolarCalc with defaults so price shows
updateSolarCalc();
return;
}
window._solarRetryCount = 0;
// Calculate per-panel system cost (inkl. arbete/installation)
const avgSystemPricePerPanel = Math.round(SOL_FULL_BASE_PRICE / SOL_BASE_PANELS);
container.innerHTML = panels.map((p,i) => {
const sel = i===0 ? 'border-color:#3b82f6;background:#f0f9ff' : 'border-color:#e5e7eb;background:#fff';
const dot = i===0 ? '<div style="width:10px;height:10px;background:#3b82f6;border-radius:50%"></div>' : '';
const greenTag = p.greenTechEligible ? '<span style="background:#dcfce7;color:#166534;font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;margin-left:6px">Grönt avdrag</span>' : '';
return '<div class="sol-panel-card" data-panel-id="'+p.id+'" onclick="selectPanel(this,\''+p.id+'\')" style="padding:14px 16px;border:2px solid;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:12px;'+sel+'">'
+'<div style="width:20px;height:20px;border:2px solid '+(i===0?'#3b82f6':'#cbd5e1')+';border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0">'+dot+'</div>'
+(p.img?'<img src="'+p.img+'" style="width:48px;height:48px;object-fit:cover;border-radius:6px;flex-shrink:0">':'<div style="width:48px;height:48px;background:#f1f5f9;border-radius:6px;flex-shrink:0"></div>')
+'<div style="flex:1"><div style="font-weight:600;font-size:14px">'+p.name+greenTag+'</div><div style="font-size:12px;color:#64748b">'+p.watt+'W per panel'+(p.desc?' — '+p.desc:'')+'</div></div>'
+'<div style="text-align:right"><div style="font-weight:700;font-size:14px;color:#1a1a1a">'+avgSystemPricePerPanel.toLocaleString('sv-SE')+' kr/st</div><div style="font-size:10px;color:#94a3b8">inkl. installation</div></div>'
+'</div>';
}).join('');
if(panels.length) solSelectedPanel = panels[0];
// Render battery options
const batContainer = document.getElementById('solarBatteryCards');
batContainer.innerHTML = '<div class="sol-addon-card" data-battery="0" onclick="selectBattery(this)" style="padding:14px 16px;border:2px solid #3b82f6;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:12px;background:#f0f9ff">'
+'<div style="width:20px;height:20px;border:2px solid #3b82f6;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0"><div style="width:10px;height:10px;background:#3b82f6;border-radius:50%"></div></div>'
+'<div style="flex:1"><div style="font-weight:600;font-size:14px">Inget batteri</div></div>'
+'<div style="font-weight:700;font-size:14px;color:#1a1a1a">0 kr</div></div>'
+ batteryOptions.map(b => '<div class="sol-addon-card" data-battery="'+b.kwh+'" data-price="'+b.price+'" onclick="selectBattery(this)" style="padding:14px 16px;border:2px solid #e5e7eb;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:12px">'
+'<div style="width:20px;height:20px;border:2px solid #cbd5e1;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0"></div>'
+'<div style="flex:1"><div style="font-weight:600;font-size:14px">'+b.label+' batteri</div><div style="font-size:12px;color:#64748b">Lagra överskottsel'+
'<span style="background:#dcfce7;color:#166534;font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;margin-left:6px">Grönt avdrag</span></div></div>'
+'<div style="font-weight:700;font-size:14px;color:#1a1a1a">'+b.price.toLocaleString('sv-SE')+' kr</div></div>').join('');
// Render EV charger options
const chgContainer = document.getElementById('solarChargerCards');
chgContainer.innerHTML = '<div class="sol-addon-card" data-charger="0" onclick="selectCharger(this)" style="padding:14px 16px;border:2px solid #3b82f6;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:12px;background:#f0f9ff">'
+'<div style="width:20px;height:20px;border:2px solid #3b82f6;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0"><div style="width:10px;height:10px;background:#3b82f6;border-radius:50%"></div></div>'
+'<div style="flex:1"><div style="font-weight:600;font-size:14px">Ingen laddare</div></div>'
+'<div style="font-weight:700;font-size:14px;color:#1a1a1a">0 kr</div></div>'
+ evChargers.map(c => '<div class="sol-addon-card" data-charger="'+c.brand+'-'+c.model+'" data-price="'+c.price+'" onclick="selectCharger(this)" style="padding:14px 16px;border:2px solid #e5e7eb;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:12px">'
+'<div style="width:20px;height:20px;border:2px solid #cbd5e1;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0"></div>'
+'<div style="flex:1"><div style="font-weight:600;font-size:14px">'+c.brand+' '+c.model+'</div><div style="font-size:12px;color:#64748b">'+c.desc+
'<span style="background:#dcfce7;color:#166534;font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;margin-left:6px">Grönt avdrag</span></div></div>'
+'<div style="font-weight:700;font-size:14px;color:#1a1a1a">'+c.price.toLocaleString('sv-SE')+' kr</div></div>').join('');
// Sync owner count from customer data if available
if(pendingKalkylCustomer){
const ot = pendingKalkylCustomer.ownerType;
if(ot === '2' || ot === 2) setOwnerCount(2);
else if(ot === 'brf') { setOwnerCount(1); document.getElementById('solGreenSlider').value = 0; updateGreenSlider(); }
}
updateSolarCalc();
}
function selectPanel(el, id){
const p = catalogProducts.find(x => x.id === id);
if(!p) return;
solSelectedPanel = p;
document.querySelectorAll('.sol-panel-card').forEach(c => {
const isSel = c.dataset.panelId === id;
c.style.borderColor = isSel ? '#3b82f6' : '#e5e7eb';
c.style.background = isSel ? '#f0f9ff' : '#fff';
const dot = c.querySelector('div > div');
dot.style.borderColor = isSel ? '#3b82f6' : '#cbd5e1';
dot.innerHTML = isSel ? '<div style="width:10px;height:10px;background:#3b82f6;border-radius:50%"></div>' : '';
});
updateSolarCalc();
}
function selectBattery(el){
const kwh = parseInt(el.dataset.battery)||0;
solSelectedBattery = kwh;
solSelectedBatteryPrice = parseInt(el.dataset.price)||0;
document.querySelectorAll('#solarBatteryCards .sol-addon-card').forEach(c => {
const isSel = c === el;
c.style.borderColor = isSel ? '#3b82f6' : '#e5e7eb';
c.style.background = isSel ? '#f0f9ff' : '#fff';
const dot = c.firstElementChild;
dot.style.borderColor = isSel ? '#3b82f6' : '#cbd5e1';
dot.innerHTML = isSel ? '<div style="width:10px;height:10px;background:#3b82f6;border-radius:50%"></div>' : '';
});
updateSolarCalc();
}
function selectCharger(el){
const val = el.dataset.charger;
solSelectedCharger = val === '0' ? null : val;
solSelectedChargerPrice = parseInt(el.dataset.price)||0;
document.querySelectorAll('#solarChargerCards .sol-addon-card').forEach(c => {
const isSel = c === el;
c.style.borderColor = isSel ? '#3b82f6' : '#e5e7eb';
c.style.background = isSel ? '#f0f9ff' : '#fff';
const dot = c.firstElementChild;
dot.style.borderColor = isSel ? '#3b82f6' : '#cbd5e1';
dot.innerHTML = isSel ? '<div style="width:10px;height:10px;background:#3b82f6;border-radius:50%"></div>' : '';
});
updateSolarCalc();
}
function updateSolarCalc(){
const count = parseInt(document.getElementById('solPanelCount').value)||14;
document.getElementById('solPanelCountVal').textContent = count;
const watt = solSelectedPanel ? solSelectedPanel.watt : 430;
const kwp = (count * watt / 1000).toFixed(1);
const roofArea = Math.round(count * SOL_PANEL_AREA);
const yearlyKwh = Math.round(parseFloat(kwp) * 900);
document.getElementById('solKwpVal').textContent = kwp + ' kWp';
document.getElementById('solRoofVal').textContent = roofArea + ' m²';
document.getElementById('solProdVal').textContent = '~' + yearlyKwh.toLocaleString('sv-SE') + ' kWh';
// Full system price (before green tech deduction)
let systemFullPrice;
if(count <= SOL_BASE_PANELS){
systemFullPrice = SOL_FULL_BASE_PRICE;
} else {
systemFullPrice = SOL_FULL_BASE_PRICE + (count - SOL_BASE_PANELS) * SOL_FULL_PRICE_PER_PANEL;
}
// Split into material and labor
const materialCost = Math.round(systemFullPrice * SOL_MATERIAL_RATIO);
const laborCost = systemFullPrice - materialCost;
const batteryPrice = solSelectedBatteryPrice;
const chargerPrice = solSelectedChargerPrice;
const subtotal = systemFullPrice + batteryPrice + chargerPrice;
// Deduction calculation based on type
let sliderMax = parseInt(document.getElementById('solGreenSlider')?.value);
if(isNaN(sliderMax)) sliderMax = solGreenTechMax;
let totalDeduction = 0;
let deductDetail = '';
const totalLabor = laborCost; // Labor portion of system price
if(solDeductionType === 'green'){
const greenCalc = Math.round(subtotal * GREEN_TECH_RATE);
totalDeduction = Math.min(greenCalc, sliderMax);
deductDetail = '20% av ' + fmt(subtotal) + ' = ' + fmt(greenCalc) + (greenCalc > sliderMax ? ' (begränsat till ' + fmt(sliderMax) + ')' : '');
} else if(solDeductionType === 'rot'){
const rotCalc = Math.round(totalLabor * ROT_RATE);
totalDeduction = Math.min(rotCalc, sliderMax);
deductDetail = '30% av arbete ' + fmt(totalLabor) + ' = ' + fmt(rotCalc) + (rotCalc > sliderMax ? ' (begränsat till ' + fmt(sliderMax) + ')' : '');
} else if(solDeductionType === 'both'){
// Green tech on material+battery+charger, ROT on labor
const greenBase = materialCost + batteryPrice + chargerPrice;
const greenCalc = Math.round(greenBase * GREEN_TECH_RATE);
const rotCalc = Math.round(totalLabor * ROT_RATE);
const bothTotal = greenCalc + rotCalc;
totalDeduction = Math.min(bothTotal, sliderMax);
deductDetail = 'Grönt: ' + fmt(greenCalc) + ' + ROT: ' + fmt(rotCalc) + ' = ' + fmt(bothTotal);
} else {
totalDeduction = 0;
deductDetail = 'Inget avdrag valt';
}
const total = subtotal - totalDeduction;
document.getElementById('solPrMaterial').textContent = fmt(materialCost);
document.getElementById('solPrLabor').textContent = fmt(laborCost);
document.getElementById('solPrBattery').textContent = batteryPrice > 0 ? fmt(batteryPrice) : '0 kr';
document.getElementById('solPrCharger').textContent = chargerPrice > 0 ? fmt(chargerPrice) : '0 kr';
document.getElementById('solPrSubtotal').textContent = fmt(subtotal);
document.getElementById('solPrGreenTech').textContent = totalDeduction > 0 ? '-' + fmt(totalDeduction) : '0 kr';
const detailEl = document.getElementById('solDeductDetail');
if(detailEl) detailEl.textContent = deductDetail;
const el = document.getElementById('solPrTotal');
if(el) el.textContent = fmt(total);
// Monthly financing
const r = SOL_FINANCE_RATE / 12;
const n = SOL_FINANCE_YEARS * 12;
const monthly = total > 0 ? Math.round(total * r * Math.pow(1+r,n) / (Math.pow(1+r,n)-1)) : 0;
document.getElementById('solPrMonthly').textContent = monthly.toLocaleString('sv-SE') + ' kr/mån';
// Yearly savings
const selfUseKwh = yearlyKwh * SOL_SELF_USE;
const surplusKwh = yearlyKwh * (1 - SOL_SELF_USE);
const yearlySaving = Math.round(selfUseKwh * SOL_ELECTRICITY_PRICE + surplusKwh * SOL_SELL_PRICE);
const payback = total > 0 ? (total / yearlySaving).toFixed(1) : 0;
document.getElementById('solPrSaving').textContent = yearlySaving.toLocaleString('sv-SE') + ' kr/år';
document.getElementById('solPrPayback').textContent = payback + ' år';
// Store state for Affär
currentCalcState = {
panelId: solSelectedPanel?.id,
panelName: solSelectedPanel?.name || 'Okänd',
panelWatt: watt,
panelCount: count,
kwp: parseFloat(kwp),
roofArea,
yearlyKwh,
materialCost,
laborCost,
systemFullPrice,
batteryKwh: solSelectedBattery,
batteryPrice,
chargerName: solSelectedCharger,
chargerPrice,
subtotal,
greenTechDeduction: totalDeduction,
deductionType: solDeductionType,
total,
monthly,
yearlySaving,
payback: parseFloat(payback),
financeYears: SOL_FINANCE_YEARS,
financeRate: SOL_FINANCE_RATE,
ownerCount: solOwnerCount
};
// Update shared summary
if(typeof cfgAddItem==='function') {
cfgAddItem('solceller', 'Solceller (' + count + ' paneler, ' + kwp + ' kWp)', subtotal, solDeductionType === 'green' ? 'green' : 'none', laborCost/Math.max(subtotal,1));
}
}
function setDeductionType(type){
solDeductionType = type;
const label = document.getElementById('solDeductLabel');
const ownerSection = document.getElementById('solOwnerSection');
const sliderSection = document.getElementById('solSliderSection');
const colors = {green:'#059669', rot:'#2563eb', both:'#7c3aed', none:'#94a3b8'};
const labels = {green:'GRÖNT TEKNIK-AVDRAG', rot:'ROT-AVDRAG', both:'GRÖNT TEKNIK + ROT', none:'INGET AVDRAG'};
const col = colors[type] || '#059669';
if(label){ label.textContent = labels[type] || ''; label.style.color = col; }
document.getElementById('solPrGreenTech').style.color = col;
// Show/hide owner + slider for all except 'none'
if(ownerSection) ownerSection.style.display = type === 'none' ? 'none' : '';
if(sliderSection) sliderSection.style.display = type === 'none' ? 'none' : '';
// Update slider accent color
const slider = document.getElementById('solGreenSlider');
if(slider) slider.style.accentColor = col;
// Update button styles
document.querySelectorAll('.deduct-btn').forEach(b => {
const dt = b.dataset.dt;
if(dt === type){
b.style.background = col; b.style.color = '#fff'; b.style.borderColor = col;
} else {
b.style.background = '#fff'; b.style.color = col; b.style.borderColor = '#e5e7eb';
}
});
updateSolarCalc();
}
function setOwnerCount(count){
solOwnerCount = count;
const maxPerPerson = 50000;
const newMax = count * maxPerPerson;
const slider = document.getElementById('solGreenSlider');
if(slider){
slider.max = newMax;
// If current value exceeds new max, or was at old max, set to new max
if(parseInt(slider.value) > newMax || parseInt(slider.value) === solGreenTechMax){
slider.value = newMax;
}
}
solGreenTechMax = newMax;
document.getElementById('solGreenSliderMax').textContent = newMax.toLocaleString('sv-SE') + ' kr';
document.querySelectorAll('.owner-btn').forEach(b => {
const oc = parseInt(b.dataset.oc);
if(oc === count){
b.style.background = '#059669'; b.style.color = '#fff'; b.style.borderColor = '#059669';
} else {
b.style.background = '#fff'; b.style.color = '#059669'; b.style.borderColor = '#bbf7d0';
}
});
updateGreenSlider();
}
function updateGreenSlider(){
const val = parseInt(document.getElementById('solGreenSlider').value)||0;
document.getElementById('solGreenSliderVal').textContent = val.toLocaleString('sv-SE') + ' kr';
updateSolarCalc();
}
function setFinanceYears(yrs){
SOL_FINANCE_YEARS = yrs;
document.querySelectorAll('.fin-yr-btn').forEach(b => {
const y = parseInt(b.dataset.yr);
if(y === yrs){
b.style.background = '#3b82f6';
b.style.color = '#fff';
b.style.borderColor = '#3b82f6';
} else {
b.style.background = '#fff';
b.style.color = '#3b82f6';
b.style.borderColor = '#bfdbfe';
}
});
const info = document.getElementById('solFinanceInfo');
if(info) info.textContent = '('+yrs+' år, 4.9%)';
updateSolarCalc();
}