Changeset 3448482
- Timestamp:
- 01/28/2026 08:53:40 AM (3 weeks ago)
- Location:
- keiste-solar-report/trunk
- Files:
-
- 8 edited
-
assets/css/solar-analysis.css (modified) (1 diff)
-
assets/js/chart-initialization.js (modified) (8 diffs)
-
assets/js/maps-integration.js (modified) (14 diffs)
-
assets/js/modal-handler.js (modified) (13 diffs)
-
assets/js/solar-calculator-main.js (modified) (21 diffs)
-
includes/plugin-init.php (modified) (3 diffs)
-
keiste-solar-report.php (modified) (2 diffs)
-
readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
keiste-solar-report/trunk/assets/css/solar-analysis.css
r3447835 r3448482 1 1 /** 2 2 * Keiste Solar Analysis - Main Stylesheet 3 * Version: 1.1. 23 * Version: 1.1.3 4 4 */ 5 5 -
keiste-solar-report/trunk/assets/js/chart-initialization.js
r3415762 r3448482 91 91 function initializeChartsWhenReady() { 92 92 if (typeof Chart === 'undefined') { 93 console.log('Chart.js not yet loaded, waiting...');93 94 94 setTimeout(initializeChartsWhenReady, 50); 95 95 return; 96 96 } 97 console.log('Chart.js loaded! Version:', Chart.version);98 97 initializeCharts(); 99 98 } … … 103 102 */ 104 103 function initializeCharts() { 105 console.log('initializeCharts called', {106 alreadyInit: window.ksradChartsInitialized,107 hasBreakEvenChart: !!window.breakEvenChart,108 hasEnergyChart: !!window.energyChart109 });110 104 111 105 if (window.ksradChartsInitialized) { 112 console.log('Charts already initialized, skipping');113 106 return; 114 107 } … … 117 110 // Check if charts already exist (from external js files) 118 111 if (window.breakEvenChart || window.energyChart) { 119 console.log('Charts already exist externally, skipping');120 112 return; 121 113 } 122 123 console.log('Starting chart creation...');124 114 125 115 // --- Break Even Chart --- … … 127 117 const breakEvenCanvas = document.getElementById('breakEvenChart'); 128 118 if (!breakEvenCanvas) { 129 console.log('Break Even Chart canvas not found - charts will initialize when form loads');130 119 window.ksradChartsInitialized = false; // Reset so it can try again later 131 120 return; 132 121 } 133 console.log('Initializing Break Even Chart...', breakEvenCanvas);134 122 const breakEvenCtx = breakEvenCanvas.getContext('2d'); 135 123 136 124 // Initialize with zero data - actual data will populate on user interaction 137 125 const data = { cost: 0, savings: Array(25).fill(0), breakEvenYear: -1 }; 138 console.log('Creating Chart.js instance with data:', data);139 126 140 127 window.breakEvenChart = new Chart(breakEvenCtx, { … … 203 190 } 204 191 }); 205 console.log('Break Even Chart created successfully!', window.breakEvenChart);206 192 } catch (error) { 207 193 console.error('Error creating Break Even Chart:', error); … … 246 232 } 247 233 }); 248 console.log('Energy Chart created successfully!', window.energyChart);249 234 } catch (error) { 250 235 console.error('Error creating Energy Chart:', error); … … 253 238 // Don't trigger calculateROI automatically - let it be triggered by user interaction 254 239 // This prevents showing non-zero values on initial page load from cached data 255 console.log('Charts initialized and ready for user interaction');256 240 } 257 241 … … 271 255 // Listen for reinit event (triggered after AJAX content load) 272 256 document.addEventListener('ksrad-reinit-charts', () => { 273 console.log('Received ksrad-reinit-charts event');274 257 window.ksradChartsInitialized = false; 275 258 window.breakEvenChart = null; -
keiste-solar-report/trunk/assets/js/maps-integration.js
r3419453 r3448482 28 28 }; 29 29 30 // Removed API key logging for security 31 console.log('Map will center at:', DEFAULT_CENTER); 30 // Removed API key logging for security reasons 32 31 33 32 // Country restriction - check user selection first, then dashboard settings … … 147 146 REGION_CODE = COUNTRY_CODE_MAP[window.COUNTRY_SETTING] || 'us'; 148 147 pac.includedRegionCodes = [REGION_CODE]; 149 console.log('Country changed to:', window.COUNTRY_SETTING, 'Region code:', REGION_CODE);150 148 151 149 // Update currency symbol based on country … … 170 168 }); 171 169 172 console.log('Currency updated to:', window.CURRENCY_SYMBOL);173 174 170 // Force recalculation with new country settings (only if form elements exist) 175 171 if (typeof window.calculateROI === 'function' && document.getElementById('panelCount')) { 176 console.log('Recalculating with new country settings...');177 172 window.calculateROI(); 178 173 } … … 184 179 userBuildingTypeSelect.addEventListener('change', function() { 185 180 window.BUILDING_TYPE = this.value; 186 console.log('Building type changed to:', window.BUILDING_TYPE);187 181 188 182 // Update hidden field that persists through AJAX … … 201 195 // Add event listener for place selection 202 196 pac.addEventListener('gmp-select', async (e) => { 203 console.log('[DEBUG] Place selected - event fired');204 197 205 198 // Prevent form submission and event bubbling … … 209 202 if (e.stopImmediatePropagation) e.stopImmediatePropagation(); 210 203 } 211 212 console.log('[DEBUG] Event prevented, processing selection...');213 204 214 205 const { placePrediction } = e; … … 256 247 const savedCountry = window.COUNTRY_SETTING; 257 248 const savedBuildingType = window.BUILDING_TYPE; 258 console.log('[ajax] Saving user selections before AJAX:', savedCountry, savedBuildingType);259 249 260 250 const ll = new google.maps.LatLng(coords.lat, coords.lng); … … 279 269 // Fetch solar data via AJAX instead of page reload 280 270 const fetchUrl = `${window.location.pathname}?${params.toString()}`; 281 console.log('[DEBUG] Fetching solar data from:', fetchUrl);282 271 283 272 fetch(fetchUrl, { … … 287 276 }) 288 277 .then(response => { 289 console.log('[DEBUG] Response status:', response.status);290 278 if (!response.ok) { 291 279 // Try to parse error as JSON first … … 299 287 }) 300 288 .then(html => { 301 console.log('[DEBUG] HTML received, length:', html.length);302 289 // Parse the HTML response 303 290 const parser = new DOMParser(); … … 328 315 if (savedCountry) { 329 316 window.COUNTRY_SETTING = savedCountry; 330 console.log('[ajax] Restored COUNTRY_SETTING to:', savedCountry);331 317 } 332 318 if (savedBuildingType) { 333 319 window.BUILDING_TYPE = savedBuildingType; 334 console.log('[ajax] Restored BUILDING_TYPE to:', savedBuildingType);335 320 } 336 321 … … 347 332 window.KSRAD_CalcConfig.currencySymbol = window.CURRENCY_SYMBOL; 348 333 } 349 console.log('[ajax] Updated CURRENCY_SYMBOL to:', window.CURRENCY_SYMBOL);350 334 } 351 335 352 336 // NOW re-run initialization scripts with correct currency 353 337 if (window.KSRAD_initializeCalculator) { 354 console.log('[ajax] Running KSRAD_initializeCalculator with currency:', window.CURRENCY_SYMBOL);355 338 window.KSRAD_initializeCalculator(); 356 339 } … … 358 341 // Re-initialize calculator event handlers 359 342 if (typeof window.KSRAD_initCalculator === 'function') { 360 console.log('[ajax] Re-initializing calculator with currency:', window.CURRENCY_SYMBOL);361 343 window.KSRAD_initCalculator(); 362 344 } … … 370 352 setTimeout(() => { 371 353 const symbols = document.querySelectorAll('.currency-symbol'); 372 console.log('[ajax] Found', symbols.length, 'currency symbols to update');373 console.log('[ajax] COUNTRY_SETTING:', window.COUNTRY_SETTING, 'New currency:', window.CURRENCY_SYMBOL);374 354 symbols.forEach((el, idx) => { 375 355 const oldValue = el.textContent; 376 356 el.textContent = window.CURRENCY_SYMBOL; 377 console.log(`[ajax] Symbol ${idx}: "${oldValue}" → "${el.textContent}" (ID: ${el.id || 'none'})`);378 357 }); 379 console.log('[ajax] Currency update complete');380 358 }, 250); 381 359 382 360 // Recalculate with user's selected country/building type 383 361 if (typeof window.calculateROI === 'function') { 384 console.log('[ajax] Recalculating with selected settings...');385 362 setTimeout(() => window.calculateROI(), 200); 386 363 } -
keiste-solar-report/trunk/assets/js/modal-handler.js
r3415762 r3448482 97 97 // Email validation using emailchecker API (via WordPress proxy) 98 98 function validateEmail(email, callback) { 99 console.log('validateEmail called for:', email);100 console.log('jQuery available?', typeof jQuery !== 'undefined');101 console.log('ksradData available?', typeof ksradData !== 'undefined');102 99 103 100 // Skip validation if jQuery not available 104 101 if (typeof jQuery === 'undefined') { 105 console.log('jQuery not available, skipping email validation');106 102 callback(true, null); 107 103 return; … … 110 106 // If ksradData not available, assume valid (don't block user) 111 107 if (typeof ksradData === 'undefined') { 112 console.log('ksradData not available, skipping email validation');113 108 callback(true, null); 114 109 return; 115 110 } 116 117 console.log('Validating email:', email); 118 console.log('AJAX URL:', ksradData.ajaxUrl); 119 111 120 112 // Call WordPress AJAX endpoint (which proxies to emailchecker API) 121 113 jQuery.ajax({ … … 128 120 }, 129 121 success: function(response) { 130 console.log('Email validation response:', response);131 122 132 123 if (response.success) { … … 137 128 }, 138 129 error: function(xhr, status, error) { 139 console.log('Email validation API error:', status, error);140 130 // On error, assume valid to not block user 141 131 callback(true, null); … … 168 158 // Check if it's a Twilio auth error (401) - skip validation 169 159 if (response.data && response.data.status_code === 401) { 170 console.log('[Phone Validation] Twilio auth error, skipping validation');171 160 callback(true, null); 172 161 } else { … … 184 173 // // Initialize modal handlers 185 174 function initModalHandlers() { 186 console.log('[initModalHandlers] Called');187 175 188 176 const roiForm = document.getElementById('roiForm'); … … 193 181 // Check if already has listener to prevent duplicates 194 182 if (roiForm.dataset.listenerAttached === 'true') { 195 console.log('[initModalHandlers] Form already has listener, skipping');196 183 return; 197 184 } 198 185 199 console.log('[initModalHandlers] Attaching submit listener to form');200 186 roiForm.dataset.listenerAttached = 'true'; 201 187 … … 206 192 // Prevent double submission 207 193 if (window.formSubmissionInProgress) { 208 console.log('[Form] Submission already in progress, ignoring');209 194 return; 210 195 } … … 212 197 // Check if form has been submitted successfully 213 198 if (window.formSubmittedSuccessfully) { 214 console.log('[Form] Form already submitted successfully, ignoring');215 199 return; 216 200 } … … 224 208 // If form fields don't exist, this is a duplicate submission after form was replaced 225 209 if (!emailEl || !fullNameEl) { 226 console.log('[Form] Form elements missing (already replaced), ignoring submission');227 210 return; 228 211 } … … 306 289 }; 307 290 308 console.log('[AJAX SUBMISSION DATA]', submissionData);309 310 291 jQuery.ajax({ 311 292 url: ksradData.ajaxUrl, … … 313 294 data: submissionData, 314 295 success: function(response) { 315 console.log('Form submission response:', response);316 296 317 297 // Check if submission was successful … … 402 382 if (form && form.id === 'roiUserForm') { 403 383 e.preventDefault(); 404 console.log('Global failsafe: blocked roiUserForm submit');405 384 } 406 385 }, true); -
keiste-solar-report/trunk/assets/js/solar-calculator-main.js
r3446582 r3448482 5 5 (() => { 6 6 'use strict'; 7 8 // ========= DEBUG LOGGING FLAG ========= 9 // Set keiste_log = 1 to enable comprehensive calculation logging 10 let keiste_log = 0; 7 11 8 12 // ========= 1) CONSTANTS & DEFAULTS ========= … … 122 126 // Use the building type's cost directly 123 127 if (typeof costs[buildingType] === 'number' && costs[buildingType] > 0) { 124 console.log('Using cost for', buildingType, ':', costs[buildingType], '€/kWp');125 128 return Number(costs[buildingType]); 126 129 } 127 130 128 131 // Fallback: default cost 129 console.warn('No cost configured for', buildingType, '- using default 1200 €/kWp');130 132 return 1200; 131 133 } catch (e) { 132 console.error('Error resolving cost per kWp:', e);133 134 return 1200; 134 135 } … … 197 198 let yearlyEnergy = 0; 198 199 // prefer parsed DOM configs, then server-provided `solarConfigs` (may be a top-level const, not on window) 199 console.log('Looking for configs - window.__parsedSolarConfigs:', window.__parsedSolarConfigs, 'window.KSRAD_UtilityConfig:', window.KSRAD_UtilityConfig);200 200 const availableConfigs = (Array.isArray(window.__parsedSolarConfigs) && window.__parsedSolarConfigs.length > 0) 201 201 ? window.__parsedSolarConfigs … … 203 203 ? window.KSRAD_UtilityConfig.solarConfigs 204 204 : (typeof solarConfigs !== 'undefined' && Array.isArray(solarConfigs) && solarConfigs.length > 0 ? solarConfigs : [])); 205 console.log('availableConfigs found:', availableConfigs.length, 'configs');206 205 if (availableConfigs.length > 0) { 207 206 // helper: try to extract a numeric kWh value from a config object safely … … 234 233 const config = availableConfigs[i]; 235 234 const configPanels = parseInt(config['panelsCount'] || config['panels'] || config['Number of Panels'] || config['Panels']) || 0; 236 console.log('Config', i, '- panels:', configPanels, 'config:', config);237 235 if (configPanels === panels) { 238 236 yearlyEnergy = extractKwh(config) || 0; 239 console.log('Found exact match - panels:', panels, 'yearlyEnergy:', yearlyEnergy);240 237 break; 241 238 } … … 264 261 const kWp = (panels * PANEL_POWER_W) / 1000; 265 262 const baseCost = Math.round(estimateSolarCost(state.panels)); // € 266 console.log('baseCost', baseCost);267 263 268 264 // Resolve grant settings based on building type (Residential vs Non-Residential) … … 273 269 const btEl = document.getElementById('userBuildingType'); 274 270 const selected = (btEl && btEl.value) ? btEl.value.trim() : 'Residential'; 275 console.log('Building type:', selected);276 271 // Map building types to grant categories 277 272 const isResidential = (selected === 'Residential'); 278 273 const category = isResidential ? 'Residential' : 'Non-Residential'; 279 274 if (grants[category]) { 280 console.log('Grant:', category, '- rate:', grants[category].rate, 'cap:', grants[category].cap);281 275 return { rate: grants[category].rate || 0.30, cap: grants[category].cap || 162000 }; 282 276 } 283 277 return { rate: 0.30, cap: 162000 }; // fallback 284 278 } catch (e) { 285 console.error('Error getting grant settings:', e);286 279 return { rate: 0.30, cap: 162000 }; 287 280 } … … 289 282 const grantSettings = getGrantSettings(); 290 283 const seaiGrant = state.inclGrant ? Math.min(Number(baseCost * grantSettings.rate), grantSettings.cap) : 0; 291 console.log('Grant applied:', seaiGrant, '(', baseCost, '*', grantSettings.rate, '= capped at', grantSettings.cap, ')');292 284 const acaAllowance = state.inclACA ? Math.min(Number(baseCost - seaiGrant), Number(baseCost) * CORPORATION_TAX ) : 0; 293 console.log('acaAllowance', acaAllowance);294 285 295 286 // interest multiplier used when including loan-related uplift (simple proxy) 296 287 const interest = Math.min(Number(APR ? APR * LENGTH_OF_PAYBACK : 0) || 0, 0.5); // cap at 50% 297 console.log('interest', interest);298 288 299 289 // Install costs 300 290 // convert computed floats to rounded integers for display/consistency 301 291 const install_cost = Math.round(Number(baseCost)); 302 console.log('install_cost', install_cost);303 292 304 293 // Production … … 315 304 // Net install cost: if loan, show total loan payments; otherwise show upfront cost after grant 316 305 const net_install_cost = inclLoan ? Math.round(yearlyLoanCost * LENGTH_OF_PAYBACK) : Math.round(baseCost - seaiGrant); 317 console.log('net_install_cost', net_install_cost);318 306 319 307 // Total 25-year savings (benefits - cost + ACA if included) … … 367 355 // Total benefit (before loan / adjustments) 368 356 const savings_year0 = bill_savings + export_income - yearlyLoanCost; 369 370 console.log(371 'YEAR 0 BREAKDOWN:\n' +372 ' annual_solar_kwh: ' + annual_solar_kwh + '\n' +373 ' current_usage_kwh: ' + current_usage_kwh + '\n' +374 ' exportRate: ' + exportRate + '\n' +375 ' max_self_consumption_kwh: ' + max_self_consumption_kwh + '\n' +376 ' actual_self_consumption_kwh: ' + actual_self_consumption_kwh + '\n' +377 ' export_kwh: ' + export_kwh + '\n' +378 ' RETAIL: ' + RETAIL + '\n' +379 ' FIT: ' + FIT + '\n' +380 ' bill_savings: ' + bill_savings + '\n' +381 ' export_income: ' + export_income + '\n' +382 ' yearlyLoanCost: ' + yearlyLoanCost + '\n' +383 ' savings_year0: ' + savings_year0384 );385 357 386 358 // Monthly charge (Year 0) - based on actual savings … … 406 378 ).reduce((a, b) => a + b, 0); 407 379 380 // ========= COMPREHENSIVE LOGGING (when keiste_log = 1) ========= 381 if (keiste_log === 1) { 382 console.log('\n' + '='.repeat(80)); 383 console.log('KEISTE SOLAR CALCULATOR - COMPREHENSIVE CALCULATION LOG'); 384 console.log('='.repeat(80)); 385 386 // 1. CONSTANTS 387 console.log('\n[1] CONSTANTS:'); 388 console.log(' DAYS_IN_YR: ' + DAYS_IN_YR); 389 console.log(' MONTHS_IN_YR: ' + MONTHS_IN_YR); 390 console.log(' HOURS_IN_DAY: ' + HOURS_IN_DAY); 391 console.log(' CORPORATION_TAX: ' + (CORPORATION_TAX * 100) + '%'); 392 console.log(' LOAN_APR_DEFAULT: ' + (LOAN_APR_DEFAULT * 100) + '%'); 393 console.log(' FEED_IN_TARIFF_DEFAULT: €' + FEED_IN_TARIFF_DEFAULT + '/kWh'); 394 console.log(' ANNUAL_INCREASE: ' + (ANNUAL_INCREASE * 100) + '%'); 395 console.log(' SOLAR_PANEL_DEGRADATION: ' + (SOLAR_PANEL_DEGRADATION * 100) + '%/yr'); 396 console.log(' LENGTH_OF_PAYBACK: ' + LENGTH_OF_PAYBACK + ' years'); 397 console.log(' PANEL_POWER_W: ' + PANEL_POWER_W + 'W'); 398 console.log(' YRS_OF_SYSTEM: ' + YRS_OF_SYSTEM + ' years'); 399 console.log(' CO2_COEFFICIENT_TONNES: ' + CO2_COEFFICIENT_TONNES + ' tonnes/kWh'); 400 console.log(' DAY_POWER_AVG: ' + DAY_POWER_AVG + ' kWh/day per panel'); 401 console.log(' CURRENCY_SYMBOL: ' + CURRENCY_SYMBOL); 402 403 // 2. INPUT VARIABLES 404 console.log('\n[2] INPUT VARIABLES:'); 405 console.log(' panels: ' + panels); 406 console.log(' billMonthly: €' + billMonthly); 407 console.log(' electricityRate (RETAIL): €' + RETAIL + '/kWh'); 408 console.log(' feedInTariff (FIT): €' + FIT + '/kWh'); 409 console.log(' exportRate: ' + (exportRate * 100) + '%'); 410 console.log(' APR: ' + (APR * 100) + '%'); 411 console.log(' inclGrant: ' + inclGrant); 412 console.log(' inclACA: ' + inclACA); 413 console.log(' inclLoan: ' + inclLoan); 414 console.log(' yearlyEnergy (from config): ' + yearlyEnergy + ' kWh'); 415 console.log(' grantSettings.rate: ' + (grantSettings.rate * 100) + '%'); 416 console.log(' grantSettings.cap: €' + grantSettings.cap); 417 418 // 3. DERIVED SYSTEM VALUES 419 console.log('\n[3] DERIVED SYSTEM VALUES:'); 420 console.log(' kWp = panels × PANEL_POWER_W ÷ 1000'); 421 console.log(' = ' + panels + ' × ' + PANEL_POWER_W + ' ÷ 1000'); 422 console.log(' = ' + kWp.toFixed(2) + ' kWp'); 423 424 // 4. COST CALCULATIONS 425 console.log('\n[4] COST CALCULATIONS:'); 426 console.log(' baseCost = estimateSolarCost(panels)'); 427 console.log(' = €' + baseCost); 428 console.log(' '); 429 console.log(' seaiGrant = inclGrant ? min(baseCost × grantRate, grantCap) : 0'); 430 console.log(' = ' + inclGrant + ' ? min(€' + baseCost + ' × ' + grantSettings.rate + ', €' + grantSettings.cap + ') : 0'); 431 console.log(' = €' + seaiGrant); 432 console.log(' '); 433 console.log(' acaAllowance = inclACA ? min(baseCost - seaiGrant, baseCost × CORPORATION_TAX) : 0'); 434 console.log(' = ' + inclACA + ' ? min(€' + baseCost + ' - €' + seaiGrant + ', €' + baseCost + ' × ' + CORPORATION_TAX + ') : 0'); 435 console.log(' = €' + acaAllowance); 436 console.log(' '); 437 console.log(' install_cost = €' + install_cost); 438 439 // 5. LOAN CALCULATIONS 440 console.log('\n[5] LOAN CALCULATIONS:'); 441 console.log(' m (months/year) = ' + m); 442 console.log(' n (total months) = LENGTH_OF_PAYBACK × m = ' + LENGTH_OF_PAYBACK + ' × ' + m + ' = ' + n); 443 console.log(' principal = max(0, baseCost - seaiGrant)'); 444 console.log(' = max(0, €' + baseCost + ' - €' + seaiGrant + ')'); 445 console.log(' = €' + principal); 446 console.log(' r (monthly rate) = APR ÷ m = ' + APR + ' ÷ ' + m + ' = ' + r.toFixed(6)); 447 console.log(' '); 448 console.log(' monthlyRepay = inclLoan ? principal × (r ÷ (1 - (1 + r)^-n)) : 0'); 449 console.log(' = ' + inclLoan + ' ? €' + principal + ' × (' + r.toFixed(6) + ' ÷ (1 - (1 + ' + r.toFixed(6) + ')^-' + n + ')) : 0'); 450 console.log(' = €' + monthlyRepay); 451 console.log(' '); 452 console.log(' yearlyLoanCost = inclLoan ? monthlyRepay × 12 : 0'); 453 console.log(' = ' + inclLoan + ' ? €' + monthlyRepay + ' × 12 : 0'); 454 console.log(' = €' + yearlyLoanCost); 455 console.log(' '); 456 console.log(' net_install_cost = inclLoan ? yearlyLoanCost × LENGTH_OF_PAYBACK : baseCost - seaiGrant'); 457 console.log(' = ' + inclLoan + ' ? €' + yearlyLoanCost + ' × ' + LENGTH_OF_PAYBACK + ' : €' + baseCost + ' - €' + seaiGrant); 458 console.log(' = €' + net_install_cost); 459 460 // 6. ENERGY PRODUCTION CALCULATIONS 461 console.log('\n[6] ENERGY PRODUCTION CALCULATIONS (Year 0):'); 462 console.log(' yearlyEnergyKWh (displayed) = ' + yearlyEnergyKWh + ' kWh'); 463 console.log(' '); 464 console.log(' annual_solar_kwh = panels × (PANEL_POWER_W ÷ 1000) × DAY_POWER_AVG × DAYS_IN_YR'); 465 console.log(' = ' + panels + ' × (' + PANEL_POWER_W + ' ÷ 1000) × ' + DAY_POWER_AVG + ' × ' + DAYS_IN_YR); 466 console.log(' = ' + annual_solar_kwh.toFixed(2) + ' kWh'); 467 console.log(' '); 468 console.log(' current_usage_kwh = (billMonthly × MONTHS_IN_YR) ÷ RETAIL'); 469 console.log(' = (€' + billMonthly + ' × ' + MONTHS_IN_YR + ') ÷ €' + RETAIL); 470 console.log(' = ' + current_usage_kwh.toFixed(2) + ' kWh'); 471 472 // 7. SELF-CONSUMPTION & EXPORT 473 console.log('\n[7] SELF-CONSUMPTION & EXPORT CALCULATIONS:'); 474 console.log(' max_self_consumption_kwh = annual_solar_kwh × (1 - exportRate)'); 475 console.log(' = ' + annual_solar_kwh.toFixed(2) + ' × (1 - ' + exportRate + ')'); 476 console.log(' = ' + max_self_consumption_kwh.toFixed(2) + ' kWh'); 477 console.log(' '); 478 console.log(' actual_self_consumption_kwh = min(max_self_consumption_kwh, current_usage_kwh)'); 479 console.log(' = min(' + max_self_consumption_kwh.toFixed(2) + ', ' + current_usage_kwh.toFixed(2) + ')'); 480 console.log(' = ' + actual_self_consumption_kwh.toFixed(2) + ' kWh'); 481 console.log(' '); 482 console.log(' export_kwh = annual_solar_kwh - actual_self_consumption_kwh'); 483 console.log(' = ' + annual_solar_kwh.toFixed(2) + ' - ' + actual_self_consumption_kwh.toFixed(2)); 484 console.log(' = ' + export_kwh.toFixed(2) + ' kWh'); 485 486 // 8. YEAR 0 FINANCIAL SAVINGS 487 console.log('\n[8] YEAR 0 FINANCIAL SAVINGS:'); 488 console.log(' bill_savings = actual_self_consumption_kwh × RETAIL'); 489 console.log(' = ' + actual_self_consumption_kwh.toFixed(2) + ' × €' + RETAIL); 490 console.log(' = €' + bill_savings.toFixed(2)); 491 console.log(' '); 492 console.log(' export_income = export_kwh × FIT'); 493 console.log(' = ' + export_kwh.toFixed(2) + ' × €' + FIT); 494 console.log(' = €' + export_income.toFixed(2)); 495 console.log(' '); 496 console.log(' savings_year0 = bill_savings + export_income - yearlyLoanCost'); 497 console.log(' = €' + bill_savings.toFixed(2) + ' + €' + export_income.toFixed(2) + ' - €' + yearlyLoanCost); 498 console.log(' = €' + savings_year0.toFixed(2)); 499 500 // 9. 25-YEAR PROJECTIONS 501 console.log('\n[9] 25-YEAR PROJECTIONS:'); 502 console.log(' loanYearsCount = min(YRS_OF_SYSTEM, LENGTH_OF_PAYBACK)'); 503 console.log(' = min(' + YRS_OF_SYSTEM + ', ' + LENGTH_OF_PAYBACK + ')'); 504 console.log(' = ' + loanYearsCount); 505 console.log(' '); 506 console.log(' loanCost25 = inclLoan ? (monthlyRepay × 12 × loanYearsCount) : principal'); 507 console.log(' = ' + inclLoan + ' ? (€' + monthlyRepay + ' × 12 × ' + loanYearsCount + ') : €' + principal); 508 console.log(' = €' + loanCost25); 509 console.log(' '); 510 console.log(' benefits25 (sum of 25 years with degradation & escalation) = €' + benefits25.toFixed(2)); 511 console.log(' '); 512 console.log(' total_yr_savings = benefits25 - loanCost25 + (inclACA ? acaAllowance : 0)'); 513 console.log(' = €' + benefits25.toFixed(2) + ' - €' + loanCost25 + ' + (' + inclACA + ' ? €' + acaAllowance + ' : 0)'); 514 console.log(' = €' + total_yr_savings.toFixed(2)); 515 516 // 10. KEY INTERFACE FIGURES 517 console.log('\n[10] KEY INTERFACE FIGURES:'); 518 console.log(' monthly_charge = billMonthly > 0 ? (savings_year0 ÷ 12) - billMonthly : 0'); 519 console.log(' = ' + billMonthly + ' > 0 ? (€' + savings_year0.toFixed(2) + ' ÷ 12) - €' + billMonthly + ' : 0'); 520 console.log(' = €' + monthly_charge.toFixed(2)); 521 console.log(' '); 522 console.log(' investment = inclLoan ? loanCost25 : net_install_cost'); 523 console.log(' = ' + inclLoan + ' ? €' + loanCost25 + ' : €' + net_install_cost); 524 console.log(' = €' + investment); 525 console.log(' '); 526 console.log(' payback_period = savings_year0 > 0 ? investment ÷ savings_year0 : 0'); 527 console.log(' = ' + savings_year0.toFixed(2) + ' > 0 ? €' + investment + ' ÷ €' + savings_year0.toFixed(2) + ' : 0'); 528 console.log(' = ' + payback_period.toFixed(2) + ' years'); 529 console.log(' '); 530 const roi_cost = inclLoan ? (monthlyRepay * 12 * loanYearsCount) : principal; 531 console.log(' ROI_25Y = cost > 0 ? ((benefits25 - cost) ÷ cost) × 100 : 0'); 532 console.log(' = €' + roi_cost + ' > 0 ? ((€' + benefits25.toFixed(2) + ' - €' + roi_cost + ') ÷ €' + roi_cost + ') × 100 : 0'); 533 console.log(' = ' + ROI_25Y.toFixed(2) + '%'); 534 console.log(' '); 535 const total_co2_energy = Array.from({ length: YRS_OF_SYSTEM }, (_, y) => 536 panels * DAY_POWER_AVG * Math.pow(1 - SOLAR_PANEL_DEGRADATION, y) * DAYS_IN_YR 537 ).reduce((a, b) => a + b, 0); 538 console.log(' co2_reduction = CO2_COEFFICIENT_TONNES × (sum of 25 years production)'); 539 console.log(' = ' + CO2_COEFFICIENT_TONNES + ' × ' + total_co2_energy.toFixed(2)); 540 console.log(' = ' + co2_reduction.toFixed(2) + ' tonnes'); 541 542 // 11. SUMMARY 543 console.log('\n[11] CALCULATION SUMMARY:'); 544 console.log(' Installation Cost: €' + install_cost); 545 console.log(' Grant: €' + seaiGrant); 546 console.log(' ACA Allowance: €' + acaAllowance); 547 console.log(' Net Install Cost: €' + net_install_cost); 548 console.log(' Annual Energy (Year 0): ' + yearlyEnergyKWh + ' kWh'); 549 console.log(' Annual Savings (Year 0): €' + savings_year0.toFixed(2)); 550 console.log(' Monthly Net Income: €' + monthly_charge.toFixed(2)); 551 console.log(' Payback Period: ' + payback_period.toFixed(2) + ' years'); 552 console.log(' 25-Year Total Savings: €' + total_yr_savings.toFixed(2)); 553 console.log(' 25-Year ROI: ' + ROI_25Y.toFixed(2) + '%'); 554 console.log(' CO2 Reduction (25 years): ' + co2_reduction.toFixed(2) + ' tonnes'); 555 556 console.log('\n' + '='.repeat(80)); 557 console.log('END OF CALCULATION LOG'); 558 console.log('='.repeat(80) + '\n'); 559 } 560 408 561 return { 409 562 baseCost, seaiGrant, acaAllowance, … … 437 590 }); 438 591 } catch (e) { 439 console.error('Error updating grant description:', e);440 592 } 441 593 } … … 517 669 // Minimal canvas updates so the IDs react without external libs 518 670 function updateBreakEvenChart(state, figs) { 519 console.log('updateBreakEvenChart called', {520 hasChart: !!window.breakEvenChart,521 hasChartData: !!(window.breakEvenChart && window.breakEvenChart.data),522 hasFunc: typeof window.calculateBreakEvenDataSimple === 'function',523 billMonthly: state.billMonthly,524 panels: state.panels525 });526 527 671 // Prefer updating Chart.js instance when available (keeps rendering consistent) 528 672 if (window.breakEvenChart && window.breakEvenChart.data && typeof window.calculateBreakEvenDataSimple === 'function') { 529 673 try { 530 console.log('[updateBreakEvenChart] Inside try block, billMonthly:', state.billMonthly);531 532 674 // On page load with no bill, show zero baseline 533 675 if (!state.billMonthly || state.billMonthly === 0) { 534 console.log('Setting chart to zero baseline');535 676 window.breakEvenChart.data.datasets[0].data = Array(25).fill(0); 536 677 window.breakEvenChart.data.datasets[0].label = '0 Panels'; … … 539 680 } 540 681 541 console.log('[updateBreakEvenChart] About to create config object');542 console.log('[updateBreakEvenChart] figs.yearlyEnergyKWh:', figs.yearlyEnergyKWh);543 console.log('[updateBreakEvenChart] figs.baseCost:', figs.baseCost);544 545 682 const cfg = { 546 683 panelsCount: state.panels, … … 548 685 installCost: figs.baseCost 549 686 }; 550 console.log('Calling calculateBreakEvenDataSimple with:', cfg);551 687 const be = window.calculateBreakEvenDataSimple(cfg); 552 console.log('Break even data:', be);553 688 554 689 if (be && be.savings && window.breakEvenChart.data && window.breakEvenChart.data.datasets && window.breakEvenChart.data.datasets[0]) { 555 console.log('Updating chart with', be.savings.length, 'data points');556 690 window.breakEvenChart.data.datasets[0].data = [...be.savings]; 557 691 window.breakEvenChart.data.datasets[0].label = `${state.panels} Panels`; … … 560 694 window.breakEvenChart.options.scales.y.max = undefined; 561 695 window.breakEvenChart.update('active'); 562 console.log('Chart updated successfully');563 696 return; 564 } else {565 console.warn('Missing chart data structure:', {566 hasBe: !!be,567 hasSavings: be?.savings,568 hasChartData: !!window.breakEvenChart.data569 });570 697 } 571 698 } catch (e) { 572 console.error('Chart update error:', e);573 699 // fall back to canvas drawing below 574 700 } 575 } else {576 console.warn('Chart not available:', {577 hasChart: !!window.breakEvenChart,578 hasFunc: typeof window.calculateBreakEvenDataSimple579 });580 701 } 581 702 … … 657 778 658 779 function calculateROI() { 659 console.log('[calculateROI] Function called');660 780 const state = readInputs(); 661 console.log('[calculateROI] State:', state);662 781 663 782 // Modal popup timer - only trigger ONCE after user interaction … … 672 791 modalPopupTimer = setTimeout(() => { 673 792 if (!window.formSubmittedSuccessfully && !modalShown && typeof window.showModal === 'function') { 674 console.log('Opening modal popup after 3 seconds of interaction');675 793 window.showModal(); 676 794 modalShown = true; // Prevent modal from showing again … … 702 820 // ========= 7) EVENT WIRING ========= 703 821 function wireEvents() { 704 console.log('[wireEvents] Attaching event listeners');705 822 const onChangeRecalc = (id, ev = 'change') => { 706 823 const el = byId(id); 707 824 if (el) { 708 console.log('[wireEvents] Attached', ev, 'listener to', id);709 825 el.addEventListener(ev, () => { 710 console.log('[Event]', id, ev, 'fired');711 826 // Mark that user has interacted 712 827 window.ksradUserInteracted = true; 713 828 calculateROI(); 714 829 }); 715 } else {716 console.warn('[wireEvents] Element not found:', id);717 830 } 718 831 }; … … 771 884 // ========= 9) INITIALIZATION ========= 772 885 function init() { 773 console.log('[INIT] solar-calculator-main.js initializing...');774 console.log('[INIT] document.readyState:', document.readyState);775 776 886 // Apply configuration from PHP if available (don't wait, just use defaults if not ready) 777 887 if (window.KSRAD_CalcConfig) { 778 console.log('[INIT] KSRAD_CalcConfig found:', window.KSRAD_CalcConfig);779 888 CURRENCY_SYMBOL = window.KSRAD_CalcConfig.currencySymbol || CURRENCY_SYMBOL; 780 889 window.CURRENCY_SYMBOL = CURRENCY_SYMBOL; 781 } else { 782 console.warn('[INIT] KSRAD_CalcConfig not found - using defaults'); 783 } 784 785 console.log('[INIT] Calling wireEvents...'); 890 } 891 786 892 wireEvents(); 787 console.log('[INIT] Calling initialPopulate...');788 893 initialPopulate(); 789 894 … … 802 907 window.calculateROI = calculateROI; 803 908 window.KSRAD_initCalculator = init; // Expose init for AJAX re-initialization 804 console.log('[SCRIPT LOAD] solar-calculator-main.js loaded, readyState:', document.readyState); 909 // Expose keiste_log flag for debugging (set window.keiste_log = 1 to enable logging) 910 Object.defineProperty(window, 'keiste_log', { 911 get: () => keiste_log, 912 set: (val) => { keiste_log = val; calculateROI(); } 913 }); 805 914 806 915 // Auto-initialize when DOM is ready 807 916 if (document.readyState === 'loading') { 808 console.log('[SCRIPT LOAD] readyState is loading, waiting for DOMContentLoaded');809 917 document.addEventListener('DOMContentLoaded', init); 810 918 } else { 811 console.log('[SCRIPT LOAD] readyState is', document.readyState, ', initializing immediately');812 919 // DOM already loaded - initialize immediately 813 920 init(); -
keiste-solar-report/trunk/includes/plugin-init.php
r3447073 r3448482 3 3 * Keiste Solar Report - Plugin Initialization 4 4 * Handles WordPress integration, shortcodes, and asset loading 5 * Version: 1.1. 05 * Version: 1.1.3 6 6 */ 7 7 … … 217 217 'googleSolarApiKey' => ksrad_get_option('google_solar_api_key', ''), 218 218 'reportKey' => ksrad_get_option('report_key', ''), 219 'defaultElectricityRate' => ksrad_get_option('default_electricity_rate', '0. 36'),219 'defaultElectricityRate' => ksrad_get_option('default_electricity_rate', '0.18'), 220 220 'defaultExportRate' => ksrad_get_option('default_export_rate', '5'), 221 'defaultFeedInTariff' => ksrad_get_option('default_feed_in_tariff', '0.2 0'),221 'defaultFeedInTariff' => ksrad_get_option('default_feed_in_tariff', '0.25'), 222 222 'defaultLoanApr' => ksrad_get_option('default_loan_apr', '5'), 223 223 'loanTerm' => ksrad_get_option('loan_term', '7'), 224 224 'annualPriceIncrease' => ksrad_get_option('annual_price_increase', '5'), 225 'currency' => ksrad_get_option('currency', ' €'),226 'country' => ksrad_get_option('country', ' Republic of Ireland'),227 'systemCostRatio' => ksrad_get_option('system_cost_ratio', ' 1600'),228 'grantRateDomestic' => ksrad_get_option('grant_rate_domestic', ' 30'),229 'grantCapDomestic' => ksrad_get_option('grant_cap_domestic', ' 7500'),230 'grantRateNonDomestic' => ksrad_get_option('grant_rate_non_domestic', ' 30'),231 'grantCapNonDomestic' => ksrad_get_option('grant_cap_non_domestic', ' 50000'),225 'currency' => ksrad_get_option('currency', '$'), 226 'country' => ksrad_get_option('country', 'United States'), 227 'systemCostRatio' => ksrad_get_option('system_cost_ratio', '3500'), 228 'grantRateDomestic' => ksrad_get_option('grant_rate_domestic', '0'), 229 'grantCapDomestic' => ksrad_get_option('grant_cap_domestic', '0'), 230 'grantRateNonDomestic' => ksrad_get_option('grant_rate_non_domestic', '0'), 231 'grantCapNonDomestic' => ksrad_get_option('grant_cap_non_domestic', '0'), 232 232 'acaRate' => ksrad_get_option('aca_rate', ''), 233 233 'enablePdfExport' => ksrad_get_option('enable_pdf_export', true), … … 313 313 'default_electricity_rate' => '0.34', 314 314 'default_export_rate' => '5', 315 'default_feed_in_tariff' => '0.2 0',315 'default_feed_in_tariff' => '0.21', 316 316 'default_loan_apr' => '5', 317 317 'loan_term' => '7', 318 318 'annual_price_increase' => '5', 319 'currency' => ' €',320 'country' => ' Republic of Ireland',321 'system_cost_ratio' => ' 1800',322 'cost_domestic' => ' 1800',323 'cost_small' => ' 1600',324 'cost_medium' => ' 1200',325 'cost_large' => '1 000',326 'grant_rate_domestic' => ' 30',327 'grant_cap_domestic' => ' 7500',328 'grant_rate_non_domestic' => ' 30',329 'grant_cap_non_domestic' => ' 50000',319 'currency' => '$', 320 'country' => 'United States', 321 'system_cost_ratio' => '3500', 322 'cost_domestic' => '3500', 323 'cost_small' => '2450', 324 'cost_medium' => '2200', 325 'cost_large' => '1800', 326 'grant_rate_domestic' => '0', 327 'grant_cap_domestic' => '0', 328 'grant_rate_non_domestic' => '0', 329 'grant_cap_non_domestic' => '0', 330 330 'aca_rate' => '', 331 331 'enable_pdf_export' => true, -
keiste-solar-report/trunk/keiste-solar-report.php
r3447835 r3448482 5 5 * Plugin URI: https://keiste.com/keiste-solar-report 6 6 * Description: Comprehensive solar panel analysis tool with ROI calculations, Google Solar API integration, interactive charts, and PDF report generation. 7 * Version: 1.1. 27 * Version: 1.1.3 8 8 * Author: Dara Burke, Keiste 9 9 * Author URI: https://keiste.com … … 34 34 // Define plugin constants (only once) with ksrad_ namespace 35 35 if (!defined('KSRAD_VERSION')) { 36 define('KSRAD_VERSION', '1. 0.26');36 define('KSRAD_VERSION', '1.1.3'); 37 37 } 38 38 if (!defined('KSRAD_PLUGIN_DIR')) { -
keiste-solar-report/trunk/readme.txt
r3447835 r3448482 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1.1. 27 Stable tag: 1.1.3 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 68 68 = Demo = 69 69 70 Check out our Keiste Solar Report demo (Irish version) at [Keiste.com](https:// solar-suprise.instawp.site/solar-report/)70 Check out our Keiste Solar Report demo (Irish version) at [Keiste.com](https://keiste.instawp.site/) 71 71 72 72 = How It Works = … … 199 199 200 200 == Changelog == 201 202 = 1.1.3 = 203 * Added comprehensive logging system (set window.keiste_log = 1 to enable detailed calculation proofs) 204 * Updated default feed-in tariff from 0.20 to 0.21 for fresh installations 205 * Removed all console logging by default for cleaner production output 206 * Minor bug fixes and optimizations 201 207 202 208 = 1.0.21 =
Note: See TracChangeset
for help on using the changeset viewer.