πŸ’°

Consultas 2026

Registro de consultas psiquiΓ‘tricas
y honorarios profesionales

o
function renderInforme() { const mes = document.getElementById('informe-mes')?.value || mesActual(); const dias = ld(); const fil = dias.filter(d => mesDeF(d.fecha) === mes); const ingTar = fil.reduce((s, d) => s + (d.tarjeta || 0) * (d.precio || TARIFA), 0); const facsPorDia = []; fil.forEach(d => { (d.facturas || []).forEach(f => { facsPorDia.push({ ...f, precio: d.precio || TARIFA }); }); }); const nFac = facsPorDia.length; const nEnv = facsPorDia.filter(f => f.estado === 'enviada').length; const nPend = nFac - nEnv; const facStd = facsPorDia.filter(f => f.precio === TARIFA); const facDif = facsPorDia.filter(f => f.precio !== TARIFA); const otrosLista = ldOI().filter(o => o.mes === mes); const totalOtros = otrosLista.reduce((s, o) => s + (o.monto || 0), 0); const hoy = new Date().toLocaleDateString('es-MX', { day: '2-digit', month: 'long', year: 'numeric' }); const facLinea = facStd.length > 0 ? `
${facStd.length} factura${facStd.length > 1 ? 's' : ''} Γ— ${fmt(TARIFA)}${fmt(facStd.length * TARIFA)}
` : ''; const facDifLineas = facDif.map(f => `
1 factura precio especial${fmt(f.precio)}
` ).join(''); const html = `
Informe de ingresos
Joel A. Alejandro Panti
${mes}
${hoy}
Ingreso tarjeta / transferencia ${fmt(ingTar)}
Facturas emitidas β€” ${nFac} total (${nEnv} enviadas Β· ${nPend} pendientes)
${facLinea}${facDifLineas} ${nFac === 0 ? '
Ninguna
' : ''}
Otros ingresos ${totalOtros > 0 ? fmt(totalOtros) : 'Ninguno'}
Total ${fmt(ingTar + totalOtros)}
Informe Contabilidad Β· Consultas 2026
`; document.getElementById('informe-contenido').innerHTML = html; } function generarInforme() { renderInforme(); document.getElementById('informe-preview').style.display = 'block'; } function copiarInforme() { const el = document.getElementById('informe-print'); if (!el) return; navigator.clipboard.writeText(el.innerText).then(() => { alert('Informe copiado al portapapeles'); }); } function exportarInforme(tipo) { if (tipo === 'pdf') { exportarPDF(); } else { compartirInforme(); } } function exportarPDF() { const el = document.getElementById('informe-print'); if (!el) { alert('Primero genera el informe'); return; } const w = window.open('', '_blank', 'width=520,height=780'); if (!w) { alert('Permite popups e intenta de nuevo'); return; } w.document.write(` Informe
${el.innerHTML}
`); w.document.close(); } function compartirInforme() { const el = document.getElementById('informe-print'); if (!el) { alert('Primero genera el informe'); return; } const wrapper = document.createElement('div'); wrapper.style.cssText = 'position:fixed;left:-9999px;top:0;background:#f0f0ef;width:460px;padding:20px;font-family:Inter,sans-serif;color:#1a2340;'; wrapper.innerHTML = el.outerHTML; document.body.appendChild(wrapper); const doCapture = () => { html2canvas(wrapper, { backgroundColor: '#f0f0ef', scale: 3, useCORS: true, logging: false }).then(canvas => { document.body.removeChild(wrapper); canvas.toBlob(blob => { if (!blob) return; const file = new File([blob], 'informe-contador.png', { type: 'image/png' }); if (navigator.share && navigator.canShare && navigator.canShare({ files: [file] })) { navigator.share({ title: 'Informe', files: [file] }).catch(() => descargar(blob)); } else { descargar(blob); } }, 'image/png', 1.0); }).catch(() => { document.body.removeChild(wrapper); alert('No se pudo generar la imagen.'); }); }; if (typeof html2canvas !== 'undefined') { doCapture(); } else { const s = document.createElement('script'); s.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js'; s.onload = doCapture; s.onerror = () => { document.body.removeChild(wrapper); alert('Sin conexiΓ³n.'); }; document.head.appendChild(s); } } function descargar(blob) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'informe.png'; a.click(); setTimeout(() => URL.revokeObjectURL(url), 2000); } function renderComparativo() { const dias = ld(); const meses = ['Enero 2026', 'Febrero 2026', 'Marzo 2026', 'Abril 2026', 'Mayo 2026', 'Junio 2026', 'Julio 2026', 'Agosto 2026', 'Septiembre 2026', 'Octubre 2026', 'Noviembre 2026', 'Diciembre 2026']; let html = ''; meses.forEach(mes => { const fil = dias.filter(d => mesDeF(d.fecha) === mes); if (fil.length > 0) { const totalConsultas = fil.reduce((s, d) => s + (d.efectivo || 0) + (d.tarjeta || 0), 0); const ingEfec = fil.reduce((s, d) => s + (d.efectivo || 0) * TARIFA, 0); const ingTar = fil.reduce((s, d) => s + (d.tarjeta || 0) * (d.precio || TARIFA), 0); const total = ingEfec + ingTar; const facsPorDia = []; fil.forEach(d => { (d.facturas || []).forEach(f => { facsPorDia.push({ ...f, precio: d.precio || TARIFA }); }); }); const nFac = facsPorDia.length; const otrosLista = ldOI().filter(o => o.mes === mes); const totalOtros = otrosLista.reduce((s, o) => s + (o.monto || 0), 0); html += `
${mes} ${fmt(total + totalOtros)}
Consultas
${totalConsultas}
Facturas
${nFac}
`; } }); if (!html) { html = `
πŸ“Š
No hay datos para comparar
`; } document.getElementById('comparativo-contenido').innerHTML = html; } // MODALS function abrirDia() { editandoDia = null; document.getElementById('dia-fecha').value = hoyISO(); document.getElementById('dia-efectivo').value = ''; document.getElementById('dia-tarjeta').value = ''; document.getElementById('dia-precio').value = ''; document.getElementById('dia-facturas-lista').innerHTML = ''; document.getElementById('overlay-dia').classList.add('open'); } function editarDia(id) { const dias = ld(); const dia = dias.find(d => d.id === id); if (!dia) return; editandoDia = id; document.getElementById('dia-fecha').value = dia.fecha || ''; document.getElementById('dia-efectivo').value = dia.efectivo || ''; document.getElementById('dia-tarjeta').value = dia.tarjeta || ''; document.getElementById('dia-precio').value = dia.precio || ''; let html = ''; (dia.facturas || []).forEach((f, idx) => { html += `
${f.rfc}
${f.estado === 'enviada' ? 'Enviada' : 'Pendiente'}
`; }); document.getElementById('dia-facturas-lista').innerHTML = html; document.getElementById('overlay-dia').classList.add('open'); } function cerrarDia() { document.getElementById('overlay-dia').classList.remove('open'); editandoDia = null; } function guardarDia() { const fecha = document.getElementById('dia-fecha').value; const efectivo = parseInt(document.getElementById('dia-efectivo').value) || 0; const tarjeta = parseInt(document.getElementById('dia-tarjeta').value) || 0; const precioVal = document.getElementById('dia-precio').value; const precio = precioVal ? parseFloat(precioVal) : null; if (!fecha) { alert('Ingresa una fecha'); return; } const dias = ld(); if (editandoDia) { const idx = dias.findIndex(d => d.id === editandoDia); if (idx >= 0) { dias[idx] = { ...dias[idx], fecha, efectivo, tarjeta, precio }; } } else { dias.push({ id: `d${Date.now()}`, fecha, efectivo, tarjeta, precio, facturas: [] }); } sd(dias); cerrarDia(); renderTodo(); } function agregarFacturaDia() { document.getElementById('fac-rfc').value = ''; document.getElementById('fac-estado').value = 'pendiente'; document.getElementById('overlay-agregar-fac').classList.add('open'); } function cerrarAgregarFactura() { document.getElementById('overlay-agregar-fac').classList.remove('open'); } function confirmarAgregarFactura() { const rfc = document.getElementById('fac-rfc').value.trim(); const estado = document.getElementById('fac-estado').value; if (!rfc) { alert('Ingresa un RFC'); return; } const dias = ld(); if (editandoDia) { const idx = dias.findIndex(d => d.id === editandoDia); if (idx >= 0) { if (!dias[idx].facturas) dias[idx].facturas = []; dias[idx].facturas.push({ rfc, estado }); sd(dias); let html = ''; dias[idx].facturas.forEach((f, i) => { html += `
${f.rfc}
${f.estado === 'enviada' ? 'Enviada' : 'Pendiente'}
`; }); document.getElementById('dia-facturas-lista').innerHTML = html; } } cerrarAgregarFactura(); } function eliminarFacturaDia(idx) { if (!confirm('ΒΏEliminar esta factura?')) return; const dias = ld(); const diaIdx = dias.findIndex(d => d.id === editandoDia); if (diaIdx >= 0) { dias[diaIdx].facturas.splice(idx, 1); sd(dias); let html = ''; dias[diaIdx].facturas.forEach((f, i) => { html += `
${f.rfc}
${f.estado === 'enviada' ? 'Enviada' : 'Pendiente'}
`; }); document.getElementById('dia-facturas-lista').innerHTML = html; } } function abrirObservacion() { document.getElementById('obs-fecha').value = hoyISO(); document.getElementById('obs-mes').value = mesActual(); document.getElementById('obs-texto').value = ''; document.getElementById('obs-monto').value = ''; document.getElementById('overlay-obs').classList.add('open'); } function cerrarObservacion() { document.getElementById('overlay-obs').classList.remove('open'); } function guardarObservacion() { const fecha = document.getElementById('obs-fecha').value; const mes = document.getElementById('obs-mes').value; const texto = document.getElementById('obs-texto').value.trim(); const montoVal = document.getElementById('obs-monto').value; const monto = montoVal ? parseFloat(montoVal) : 0; if (!fecha || !texto) { alert('Completa fecha y texto'); return; } const obs = ldOb(); obs.push({ id: `o${Date.now()}`, fecha, mes, texto, monto }); sdOb(obs); if (monto > 0) { const otrosIng = ldOI(); otrosIng.push({ id: `oi${Date.now()}`, mes, monto, descripcion: texto }); sdOI(otrosIng); } cerrarObservacion(); renderTodo(); } function verObservacion(id) { const obs = ldOb(); const o = obs.find(x => x.id === id); if (!o) return; alert(`Fecha: ${formatFecha(o.fecha)}\nMes: ${o.mes}\n\n${o.texto}\n\nMonto: ${fmt(o.monto || 0)}`); } function abrirConstancia() { document.getElementById('const-paciente').value = ''; document.getElementById('const-fecha-entrega').value = hoyISO(); document.getElementById('const-mes').value = mesActual(); document.getElementById('const-estado').value = 'pendiente'; document.getElementById('overlay-constancia').classList.add('open'); } function cerrarConstancia() { document.getElementById('overlay-constancia').classList.remove('open'); } function guardarConstancia() { const paciente = document.getElementById('const-paciente').value.trim(); const fechaEntrega = document.getElementById('const-fecha-entrega').value; const mes = document.getElementById('const-mes').value; const estado = document.getElementById('const-estado').value; if (!paciente || !fechaEntrega) { alert('Completa paciente y fecha de entrega'); return; } const constancias = ldConst(); constancias.push({ id: `c${Date.now()}`, paciente, fechaEntrega, mes, estado }); sdConst(constancias); cerrarConstancia(); renderTodo(); } function editarConstancia(id) { const constancias = ldConst(); const c = constancias.find(x => x.id === id); if (!c) return; const nuevoEstado = c.estado === 'pendiente' ? 'entregada' : 'pendiente'; if (confirm(`ΒΏMarcar como ${nuevoEstado}?`)) { c.estado = nuevoEstado; sdConst(constancias); renderTodo(); } } function exportarDatos() { const data = { dias: ld(), observaciones: ldOb(), otrosIngresos: ldOI(), constancias: ldConst() }; const json = JSON.stringify(data, null, 2); const blob = new Blob([json], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'consultas-backup.json'; a.click(); setTimeout(() => URL.revokeObjectURL(url), 2000); } function importarDatos() { document.getElementById('import-input').click(); } document.getElementById('import-input')?.addEventListener('change', function(e) { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { try { const data = JSON.parse(e.target.result); if (data.dias) sd(data.dias); if (data.observaciones) sdOb(data.observaciones); if (data.otrosIngresos) sdOI(data.otrosIngresos); if (data.constancias) sdConst(data.constancias); renderTodo(); alert('Datos importados correctamente'); } catch (err) { alert('Error al importar: ' + err.message); } }; reader.readAsText(file); }); function borrarTodo() { if (!confirm('⚠️ ΒΏBorrar TODOS los datos?\n\nEsto eliminarΓ‘ todos los dΓ­as, facturas, constancias y otros ingresos registrados. Esta acciΓ³n no se puede deshacer.')) return; if (!confirm('ΒΏEstΓ‘s seguro? Se borrarΓ‘n todos tus registros permanentemente.')) return; localStorage.removeItem('d26'); localStorage.removeItem('o26'); localStorage.removeItem('oi26'); localStorage.removeItem('c26'); localStorage.removeItem('d26_seeded'); poblar(); renderTodo(); alert('βœ“ Datos borrados. Ahora puedes empezar a capturar tus consultas reales.'); } function renderTodo() { renderResumen(); renderDias(); renderFacturas(); renderQuincena(); renderObservaciones(); renderConstancias(); renderInforme(); renderComparativo(); actualizarTabBadges(); } // INIT window.addEventListener('DOMContentLoaded', () => { // Modal click handlers ['overlay-dia', 'overlay-obs', 'overlay-constancia', 'overlay-agregar-fac'].forEach(id => { const el = document.getElementById(id); if (el) { el.addEventListener('click', function(e) { if (e.target === this) this.classList.remove('open'); }); } }); initAuth(); });