Centro de Control

Centro de Control
Visión global

Sedes en Paraguay

Consumo Mantenimiento Ambos
Clientes activos
Sedes con sistemas
Medidores instalados

📊 Comparar tableros

Últimas 24 h · tildá los tableros que querés comparar
Unidad:

Resumen del cliente

Sedes

Sistemas / Módulos en esta sede

Cargando datos del módulo…
center; padding:40px; color:#888;">Cargando datos del mes...'; const sel = document.getElementById('factura-mes-sel'); const [year, month] = sel.value.split('-').map(Number); const monthStart = new Date(year, month - 1, 1); const monthEnd = new Date(year, month, 1); const { data, error } = await sbConsumo.from('lecturas') .select('*') .eq('medidor_id', medidor.id) .gte('recorded_at', monthStart.toISOString()) .lt('recorded_at', monthEnd.toISOString()) .order('recorded_at', { ascending:true }) .limit(100000); if (error) { body.innerHTML = `
Error: ${error.message}
`; return; } if (!data || data.length < 2) { body.innerHTML = `
Sin datos suficientes para este mes.
`; return; } const porDia = {}; data.forEach(r => { const dia = r.recorded_at.substring(0, 10); if (!porDia[dia]) porDia[dia] = []; porDia[dia].push(r); }); const filasDia = Object.keys(porDia).sort().map(dia => { const lect = porDia[dia]; const kwh = calcKwh(lect); const avgP = lect.reduce((s,r) => s + Math.abs(Number(r.power_w||0)), 0) / lect.length; const maxP = Math.max(...lect.map(r => Math.abs(Number(r.power_w||0)))); const avgPF = lect.reduce((s,r) => s + Number(r.power_factor||0), 0) / lect.length; return { dia, kwh, avgP, maxP, avgPF }; }); const totalKwh = filasDia.reduce((s,d) => s + d.kwh, 0); const tarifa = tarifaSimple(cliente.id); const tarifaNombre = (TARIFAS.find(t => t.activa && (t.cliente_id === cliente.id || t.cliente_id == null)) || {}).nombre || 'tarifa estándar'; const totalCost = tarifaEscalonada(totalKwh, cliente.id); const avgPMes = data.reduce((s,r) => s + Math.abs(Number(r.power_w||0)), 0) / data.length; const maxPMes = Math.max(...data.map(r => Math.abs(Number(r.power_w||0)))); const avgPFMes = data.reduce((s,r) => s + Number(r.power_factor||0), 0) / data.length; const avgV = data.reduce((s,r) => s + Number(r.voltage||0), 0) / data.length; const avgFreq = data.filter(r => r.frequency_hz > 0).length > 0 ? data.filter(r => r.frequency_hz > 0).reduce((s,r,_,a) => s + Number(r.frequency_hz)/a.length, 0) : 0; const phaseData = data.filter(r => r.voltage_a != null && r.voltage_b != null); let vImb = 0; if (phaseData.length > 0) { const last = phaseData[phaseData.length - 1]; const vAvg = (Number(last.voltage_a) + Number(last.voltage_b) + Number(last.voltage_c)) / 3; if (vAvg > 0) vImb = Math.max(Math.abs(last.voltage_a - vAvg), Math.abs(last.voltage_b - vAvg), Math.abs(last.voltage_c - vAvg)) / vAvg * 100; } const pfColor = avgPFMes >= 0.92 ? '#2e7d32' : avgPFMes >= 0.85 ? '#e6a23c' : '#c0392b'; const pfLabel = avgPFMes >= 0.92 ? 'Óptimo' : avgPFMes >= 0.85 ? 'Aceptable' : 'Bajo — se recomienda corrección'; const vImbColor = vImb <= 2 ? '#2e7d32' : vImb <= 3 ? '#e6a23c' : '#c0392b'; const vImbLabel = vImb <= 2 ? 'Normal' : vImb <= 3 ? 'Atención' : 'Fuera de norma'; const monthLabel = monthStart.toLocaleDateString('es-PY', { month:'long', year:'numeric' }); const monthLabelCap = monthLabel.charAt(0).toUpperCase() + monthLabel.slice(1); const facturaNum = `CHS-${cliente.slug.toUpperCase()}-${year}${String(month).padStart(2,'0')}`; const generadaEl = new Date().toLocaleDateString('es-PY', { day:'2-digit', month:'long', year:'numeric' }); const periodoFrom = monthStart.toLocaleDateString('es-PY', { day:'2-digit', month:'2-digit', year:'numeric' }); const periodoTo = new Date(year, month, 0).toLocaleDateString('es-PY', { day:'2-digit', month:'2-digit', year:'numeric' }); const ahora = new Date(); const esEnCurso = year === ahora.getFullYear() && month === ahora.getMonth() + 1; const diasDelMes = new Date(year, month, 0).getDate(); const diasTranscurridos = esEnCurso ? ahora.getDate() : diasDelMes; const banner = esEnCurso ? `
⚠ Mes en curso — factura parcial
Esta factura cubre solo ${diasTranscurridos} de ${diasDelMes} días del mes actual. Para que el documento represente el consumo completo del período, generá la factura el último día del mes o el primer día del mes siguiente.
` : ''; let filasHtml = ''; filasDia.forEach(d => { const fecha = new Date(d.dia + 'T12:00:00').toLocaleDateString('es-PY', { day:'2-digit', month:'2-digit' }); filasHtml += ` ${fecha} ${fmtNum(d.kwh, 2)} ${fmtNum(d.avgP, 0)} ${fmtNum(d.maxP, 0)} ${fmtNum(d.avgPF, 2)} Gs ${fmtGsRaw(tarifaEscalonada(d.kwh, cliente.id))} `; }); body.innerHTML = banner + `

⚡ CHS Soluciones Electromecánicas

Plataforma de Monitoreo Energético
Ciudad del Este, Paraguay · chsparaguay.com

FACTURA DE ENERGÍA

${facturaNum}

Cliente / Sede

${cliente.nombre}

${sede.nombre}

Tablero: ${tablero.nombre}

Período de Facturación

${periodoFrom} al ${periodoTo}

${monthLabelCap}

Fecha de Emisión

${generadaEl}

Lecturas analizadas: ${data.length.toLocaleString('es-PY')}

${filasHtml}
Día kWh Pot. Media (W) Pot. Pico (W) FP Prom. Costo
TOTAL ${fmtNum(totalKwh, 2)} ${fmtNum(avgPMes, 0)} ${fmtNum(maxPMes, 0)} ${fmtNum(avgPFMes, 2)} Gs ${fmtGsRaw(totalCost)}
Total estimado a pagar
Gs. ${fmtGsRaw(totalCost)}
${fmtNum(totalKwh, 2)} kWh × ${tarifa} Gs/kWh · ${tarifaNombre}

📊 Indicadores de calidad eléctrica del período

${fmtNum(avgPFMes, 3)}
Factor de potencia
${pfLabel}
${fmtNum(avgV, 1)} V
Voltaje promedio
${fmtNum(avgFreq, 1)} Hz
${fmtNum(vImb, 1)}%
Desbalance de voltaje
${vImbLabel}
`; } async function renderMantenimiento(c, s, body) { const { data: ordenes, error } = await sbMant.from('v_ordenes').select('*').eq('cliente_id', c.id).order('fecha_generada', { ascending:false }).limit(20); if (error) { body.innerHTML = `

Error

${error.message}

`; return; } const totalAbiertas = (ordenes || []).filter(o => ['generada','lanzada','en_ejecucion'].includes(o.estado)).length; const totalProc = (ordenes || []).filter(o => o.estado === 'en_ejecucion').length; body.innerHTML = `

OS abiertas

${totalAbiertas}

En ejecución

${totalProc}

Últimas 20

${(ordenes || []).length}

Órdenes de Servicio recientes

${(ordenes || []).length === 0 ? '

Aún no hay órdenes cargadas para este cliente.

' : ` ${ordenes.map(o => ``).join('')}
OSSectorMáquinaÁreaEstadoGenerada
${o.codigo} ${o.sector_nombre || '—'} ${o.maquina_codigo || '—'} ${o.area || '—'} ${o.estado} ${new Date(o.fecha_generada).toLocaleDateString('es-PY')}
`}
`; } const saved = sessionStorage.getItem('chs_perfil'); if (saved) { try { perfil = JSON.parse(saved); iniciarSesion(); } catch (e) { sessionStorage.removeItem('chs_perfil'); } } document.getElementById('usr').focus(); `} `; } const saved = sessionStorage.getItem('chs_perfil'); if (saved) { try { perfil = JSON.parse(saved); iniciarSesion(); } catch (e) { sessionStorage.removeItem('chs_perfil'); } } document.getElementById('usr').focus(); pt>