document.addEventListener('DOMContentLoaded', () => { const tipoReporte = document.getElementById('tipo-reporte'); const parametros = document.getElementById('parametros'); const generarBtn = document.getElementById('generar-reporte'); const exportarBtn = document.getElementById('exportar-pdf'); const reporteContainer = document.getElementById('reporte-container'); const reporteContenido = document.getElementById('reporte-contenido'); const spinner = document.getElementById('spinner'); const errorMessage = document.getElementById('error-message'); // Variable global para almacenar el período actual let periodoActual = { tipo: 'diario', fecha: new Date().toISOString().split('T')[0], nombreArchivo: 'reporte' }; // ========== FUNCIONES AUXILIARES ========== function formatoMoneda(valor) { return new Intl.NumberFormat('es-AR', { style: 'currency', currency: 'ARS' }).format(valor); } function obtenerSemanaActual() { const hoy = new Date(); const diaSemana = hoy.getDay(); const lunes = new Date(hoy); const diferenciaDias = diaSemana === 0 ? -6 : 1 - diaSemana; lunes.setDate(hoy.getDate() + diferenciaDias); const fechaReferencia = new Date(lunes.getFullYear(), 0, 4); const diaSemanaRef = fechaReferencia.getDay(); const lunesRef = new Date(fechaReferencia); lunesRef.setDate(fechaReferencia.getDate() - (diaSemanaRef === 0 ? 6 : diaSemanaRef - 1)); const diffMs = lunes - lunesRef; const diffDias = Math.floor(diffMs / (24 * 60 * 60 * 1000)); const numeroSemana = Math.floor(diffDias / 7) + 1; const ano = lunes.getFullYear(); return `${ano}-W${String(numeroSemana).padStart(2, '0')}`; } function mostrarSpinner() { spinner.style.display = 'flex'; } function ocultarSpinner() { spinner.style.display = 'none'; } function mostrarError(mensaje) { errorMessage.textContent = mensaje; errorMessage.style.display = 'block'; } function ocultarError() { errorMessage.style.display = 'none'; } function generarNombresYMetadatos(tipo, data) { let nombreArchivo = 'reporte'; if (tipo === 'diario') { const fecha = new Date(data.periodo + 'T00:00:00'); const fechaCorta = fecha.getDate().toString().padStart(2, '0') + '-' + (fecha.getMonth() + 1).toString().padStart(2, '0') + '-' + fecha.getFullYear().toString().slice(-2); nombreArchivo = 'reporte_' + fechaCorta; } else if (tipo === 'semanal') { const inicio = new Date(data.fecha_inicio + 'T00:00:00'); const fin = new Date(data.fecha_fin + 'T00:00:00'); const diaInicio = inicio.getDate().toString().padStart(2, '0'); const diaFin = fin.getDate().toString().padStart(2, '0'); const mesNombre = inicio.toLocaleDateString('es-ES', { month: 'long' }); nombreArchivo = `reporte_semana_${diaInicio}-${diaFin}_${mesNombre}`; } else if (tipo === 'mensual') { const mesesNombres = ['', 'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre']; let nombreMes = 'mensual'; let anio = new Date().getFullYear(); if (data.nombre_mes) { nombreMes = data.nombre_mes; anio = data.nombre_anio || anio; } else if (data.fecha_inicio) { const f = new Date(data.fecha_inicio + 'T00:00:00'); if (!isNaN(f.getTime())) { nombreMes = f.toLocaleDateString('es-ES', { month: 'long' }); anio = f.getFullYear(); } } else if (data.periodo && /^\d{4}-\d{2}$/.test(String(data.periodo))) { const parts = String(data.periodo).split('-'); nombreMes = mesesNombres[parseInt(parts[1] || '0')] || nombreMes; anio = parts[0] || anio; } nombreArchivo = 'reporte_' + nombreMes + '_' + anio; } else if (tipo === 'anual') { const anio = data.periodo || data.anio || (data.fecha_inicio ? (new Date(data.fecha_inicio + 'T00:00:00')).getFullYear() : new Date().getFullYear()); nombreArchivo = 'reporte_' + anio; } periodoActual.tipo = tipo; periodoActual.nombreArchivo = nombreArchivo; } function renderizarDiario(data) { const fecha = new Date(data.periodo + 'T00:00:00'); const opciones = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; const fechaFormato = fecha.toLocaleDateString('es-ES', opciones); const fechaCorta = fecha.getDate().toString().padStart(2, '0') + '-' + (fecha.getMonth() + 1).toString().padStart(2, '0') + '-' + fecha.getFullYear().toString().slice(-2); let html = `

📅 Reporte Diario ${fechaCorta} - Cierre de Caja

Reporte ${fechaFormato}
`; if (data.transacciones && data.transacciones.length > 0) { data.transacciones.forEach(tx => { const monto = parseFloat(tx.monto); const claseNegativo = monto < 0 ? 'negativo' : ''; html += ` `; }); } else { html += ``; } html += `
Hora Tipo de Operación Descripción / Detalle Monto ($) Usuario
${tx.hora || '--:--'} ${tx.tipo_operacion} ${tx.descripcion || '--'} ${formatoMoneda(monto)} ${tx.usuario_registro || 'Sistema'}
Sin transacciones registradas

Resumen del Día

Ingresos Reservas: ${formatoMoneda(data.resumen.ingresos_reservas)}
Ingresos Cantina: ${formatoMoneda(data.resumen.ingresos_cantina)}
Total Ingresos: ${formatoMoneda(data.resumen.total_ingresos)}
Egresos Totales: -${formatoMoneda(data.resumen.egresos)}

💰 SALDO NETO: ${formatoMoneda(data.resumen.saldo_neto)}
`; reporteContenido.innerHTML = html; } function renderizarSemanal(data) { const inicio = new Date(data.fecha_inicio + 'T00:00:00'); const fin = new Date(data.fecha_fin + 'T00:00:00'); const opciones = { month: 'short', day: 'numeric' }; const inicioCorta = inicio.getDate().toString().padStart(2, '0') + '-' + (inicio.getMonth() + 1).toString().padStart(2, '0'); const finCorta = fin.getDate().toString().padStart(2, '0') + '-' + (fin.getMonth() + 1).toString().padStart(2, '0') + '-' + fin.getFullYear().toString().slice(-2); let html = `

📆 Reporte Semanal ${inicioCorta} al ${finCorta} - Flujo de Caja

Reporte Semana del ${inicio.toLocaleDateString('es-ES', opciones)} al ${fin.toLocaleDateString('es-ES', opciones)}
`; if (data.dias && data.dias.length > 0) { data.dias.forEach(dia => { const nombreDia = new Date(dia.dia + 'T00:00:00').toLocaleDateString('es-ES', { weekday: 'long' }); const saldoNeto = dia.saldo_neto; const claseNegativo = saldoNeto < 0 ? 'negativo' : ''; html += ` `; }); } html += `
Día de la Semana Ingresos Reservas ($) Ingresos Cantina ($) Costo Mercadería ($) Saldo Neto del Día ($)
${nombreDia.charAt(0).toUpperCase() + nombreDia.slice(1)} (${dia.dia}) ${formatoMoneda(dia.ingresos_reservas)} ${formatoMoneda(dia.ingresos_cantina)} ${formatoMoneda(dia.costo_mercaderia)} ${formatoMoneda(saldoNeto)}
Resumen de la Semana
Ingresos Reservas Total: ${formatoMoneda(data.resumen.ingresos_reservas_totales)}
Ingresos Cantina Total: ${formatoMoneda(data.resumen.ingresos_cantina_totales)}
Costo Mercadería Total: ${formatoMoneda(data.resumen.costo_mercaderia_total)}
💰 Saldo Neto Semana: ${formatoMoneda(data.resumen.saldo_neto_semana)}

% Ocupación Promedio

Turnos Ocupados: ${data.resumen.turnos_ocupados} / ${data.resumen.turnos_disponibles}
Porcentaje Ocupación: ${data.resumen.ocupacion_promedio}%
`; reporteContenido.innerHTML = html; } function renderizarMensual(data) { const fechaInicio = new Date(data.fecha_inicio + 'T00:00:00'); const mesCorta = (fechaInicio.getMonth() + 1).toString().padStart(2, '0') + '-' + fechaInicio.getFullYear().toString().slice(-2); const nombreMes = data.nombre_mes || fechaInicio.toLocaleDateString('es-ES', { month: 'long' }); let html = `

📊 Reporte Mensual ${mesCorta} - Rentabilidad

Reporte de ${nombreMes.charAt(0).toUpperCase() + nombreMes.slice(1)}

Ingreso por Categoría

`; if (data.categorias && data.categorias.length > 0) { data.categorias.forEach(cat => { html += ` `; }); } html += `
Concepto / Categoría Operaciones Monto ($)
${cat.categoria} ${cat.operaciones} ${formatoMoneda(cat.monto)}

Gastos Fijos

`; if (data.gastos_fijos && data.gastos_fijos.length > 0) { data.gastos_fijos.forEach(gasto => { html += ` `; }); } else { html += ` `; } html += `
Nombre del Gasto Monto Gasto ($)
${gasto.descripcion} ${formatoMoneda(gasto.monto)}
Sin gastos registrados

Estado de Resultados

Ingresos Totales: ${formatoMoneda(data.resumen.ingresos_totales)}
Costo de Mercadería: -${formatoMoneda(data.resumen.costo_mercaderia)}

Ganancia Bruta: ${formatoMoneda(data.resumen.ganancia_bruta)}
Gastos Fijos: -${formatoMoneda(data.resumen.gastos_fijos_total)}

💰 GANANCIA NETA: ${formatoMoneda(data.resumen.ganancia_neta)}
`; reporteContenido.innerHTML = html; } function renderizarAnual(data) { let notaAnoActual = ''; if (data.es_ano_actual) { notaAnoActual = `
ℹ️ Nota: Este es el año en curso. El reporte muestra datos hasta el ${data.mes_actual}° mes (mes actual).
`; } let html = `

📈 Reporte Anual ${data.periodo} - Visión Estratégica

Reporte Año ${data.periodo}
${notaAnoActual} `; if (data.meses && data.meses.length > 0) { data.meses.forEach(mes => { const gananciaNeta = parseFloat(mes.ganancia_neta); const claseNegativo = gananciaNeta < 0 ? 'negativo' : ''; html += ` `; }); } html += `
Mes Ingreso Operativo ($) Costo Bruto ($) Costo Operativo ($) Ganancia Bruta ($) Ganancia Neta ($)
${mes.mes} ${formatoMoneda(mes.ingreso_operativo)} ${formatoMoneda(mes.costo_bruto)} ${formatoMoneda(mes.costo_operativo)} ${formatoMoneda(mes.ganancia_bruta)} ${formatoMoneda(gananciaNeta)}

Totales Anuales

Ingreso Operativo Total: ${formatoMoneda(data.totales.ingreso_operativo_total)}
Costo Bruto Total: -${formatoMoneda(data.totales.costo_bruto_total)}
Costo Operativo Total: -${formatoMoneda(data.totales.costo_operativo_total)}

Ganancia Bruta Total: ${formatoMoneda(data.totales.ganancia_bruta_total)}

💰 GANANCIA NETA ANUAL: ${formatoMoneda(data.totales.ganancia_neta_total)}
`; reporteContenido.innerHTML = html; } // ========== INICIALIZACIÓN ========== // Establecer valores por defecto const hoy = new Date(); document.getElementById('fecha-diario').valueAsDate = hoy; const semanaActual = obtenerSemanaActual(); document.getElementById('semana-input').value = semanaActual; const mesActual = hoy.toISOString().slice(0, 7); document.getElementById('mes-input').value = mesActual; document.getElementById('anio-input').value = hoy.getFullYear(); // Cambiar parámetros según tipo de reporte tipoReporte.addEventListener('change', () => { document.querySelectorAll('.param-section').forEach(el => el.style.display = 'none'); const tipo = tipoReporte.value; if (tipo === 'diario') { document.getElementById('param-diario').style.display = 'block'; } else if (tipo === 'semanal') { document.getElementById('param-semanal').style.display = 'block'; } else if (tipo === 'mensual') { document.getElementById('param-mensual').style.display = 'block'; } else if (tipo === 'anual') { document.getElementById('param-anual').style.display = 'block'; } }); // Generar reporte generarBtn.addEventListener('click', async () => { const tipo = tipoReporte.value; let url = '../php/Obtener_Reporte.php?tipo_reporte=' + tipo; // Agregar parámetros según el tipo if (tipo === 'diario') { const fecha = document.getElementById('fecha-diario').value; if (!fecha) { mostrarError('Por favor selecciona una fecha'); return; } url += '&fecha=' + fecha; } else if (tipo === 'semanal') { const semana = document.getElementById('semana-input').value; if (!semana) { mostrarError('Por favor selecciona una semana'); return; } url += '&semana=' + semana; } else if (tipo === 'mensual') { const mes = document.getElementById('mes-input').value; if (!mes) { mostrarError('Por favor selecciona un mes'); return; } url += '&mes=' + mes; } else if (tipo === 'anual') { const anio = document.getElementById('anio-input').value; if (!anio) { mostrarError('Por favor selecciona un año'); return; } url += '&anio=' + anio; } ocultarError(); mostrarSpinner(); try { const response = await fetch(url); const data = await response.json(); if (data.error) { mostrarError(data.error); ocultarSpinner(); return; } ocultarSpinner(); // Generar nombres de archivo generarNombresYMetadatos(tipo, data); // Renderizar según tipo if (tipo === 'diario') { renderizarDiario(data); } else if (tipo === 'semanal') { renderizarSemanal(data); } else if (tipo === 'mensual') { renderizarMensual(data); } else if (tipo === 'anual') { renderizarAnual(data); } reporteContainer.style.display = 'block'; exportarBtn.style.display = 'inline-block'; } catch (error) { mostrarError('Error al cargar el reporte: ' + error.message); ocultarSpinner(); } }); // Exportar a PDF exportarBtn.addEventListener('click', () => { const elemento = document.getElementById('reporte-contenido'); const nombreArchivo = periodoActual.nombreArchivo; const opciones = { margin: 10, filename: nombreArchivo + '.pdf', image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true }, jsPDF: { orientation: 'portrait', unit: 'mm', format: 'a4', compress: true } }; html2pdf() .set(opciones) .from(elemento) .save(nombreArchivo + '.pdf'); }); });