<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RENOVÉ CLÍNICA & SPA - CRM Notas de Remisión</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.31/jspdf.plugin.autotable.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
* {
font-family: 'Inter', sans-serif;
}
.clinic-gradient {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.form-container {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.print-view {
display: none;
}
@media print {
body * {
visibility: hidden;
}
.print-view, .print-view * {
visibility: visible;
}
.print-view {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: block !important;
background: white;
z-index: 9999;
}
@page {
margin: 20mm;
size: A4;
}
}
.patient-card {
transition: all 0.3s ease;
border-left: 4px solid #667eea;
}
.patient-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0,0,0,0.1);
}
.stats-card {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
}
.stats-card.blue {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.stats-card.green {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.btn-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-1px);
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
.input-focus:focus {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.notification {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
padding: 15px 20px;
border-radius: 8px;
color: white;
font-weight: 500;
transform: translateX(400px);
transition: transform 0.3s ease;
}
.notification.show {
transform: translateX(0);
}
.notification.success { background-color: #10b981; }
.notification.error { background-color: #ef4444; }
.notification.info { background-color: #3b82f6; }
.custom-treatment-container {
display: none;
background: #f8f9fa;
border: 2px dashed #667eea;
border-radius: 8px;
padding: 20px;
margin-top: 10px;
animation: slideDown 0.3s ease;
}
.custom-treatment-container.show {
display: block;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.custom-treatment-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
color: #667eea;
font-weight: 600;
}
.btn-success {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}
.btn-success:hover {
background: linear-gradient(135deg, #059669 0%, #047857 100%);
}
.btn-secondary {
background: linear-gradient(135deg, #6b7280 0%, #4b5563 100%);
}
.btn-secondary:hover {
background: linear-gradient(135deg, #4b5563 0%, #374151 100%);
}
.patient-actions {
display: flex;
gap: 8px;
align-items: center;
}
.action-btn {
padding: 8px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
transition: all 0.3s ease;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 5px;
border: none;
cursor: pointer;
}
.print-btn {
background: #3b82f6;
color: white;
}
.print-btn:hover {
background: #2563eb;
transform: translateY(-1px);
}
.delete-btn {
background: #ef4444;
color: white;
}
.delete-btn:hover {
background: #dc2626;
transform: translateY(-1px);
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<!-- Header -->
<header class="clinic-gradient shadow-lg">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center py-6">
<div class="flex items-center space-x-4">
<div class="w-12 h-12 bg-white rounded-full flex items-center justify-center">
<i class="fas fa-clinic-medical text-2xl text-purple-600"></i>
</div>
<div>
<h1 class="text-2xl font-bold text-white">RENOVÉ CLÍNICA & SPA</h1>
<p class="text-purple-200">Sistema CRM - Notas de Remisión</p>
</div>
</div>
<div class="flex items-center space-x-4">
<span class="text-white text-sm" id="currentDate"></span>
<button onclick="exportToPDF()" class="bg-white text-purple-600 px-4 py-2 rounded-lg hover:bg-gray-100 transition-colors duration-200 flex items-center space-x-2">
<i class="fas fa-file-pdf"></i>
<span>Exportar PDF Completo</span>
</button>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="stats-card rounded-xl p-6 text-center">
<div class="text-3xl font-bold" id="totalPatients">0</div>
<div class="text-sm opacity-90">Total Pacientes</div>
</div>
<div class="stats-card blue rounded-xl p-6 text-center">
<div class="text-3xl font-bold" id="totalPromotions">$0</div>
<div class="text-sm opacity-90">Promociones Aplicadas</div>
</div>
<div class="stats-card green rounded-xl p-6 text-center">
<div class="text-3xl font-bold" id="totalPaid">$0</div>
<div class="text-sm opacity-90">Total Pagado Hoy</div>
</div>
<div class="stats-card rounded-xl p-6 text-center" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
<div class="text-3xl font-bold" id="totalRegular">$0</div>
<div class="text-sm opacity-90">Total Regular</div>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-3 gap-8">
<!-- Form Section -->
<div class="xl:col-span-1">
<div class="form-container rounded-2xl shadow-xl p-8">
<div class="flex items-center space-x-3 mb-6">
<i class="fas fa-user-plus text-2xl text-purple-600"></i>
<h2 class="text-2xl font-bold text-gray-800">Agregar Paciente</h2>
</div>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Sucursal</label>
<select id="sucursal" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200">
<option value="">Seleccionar sucursal</option>
<option value="Saltillo">Saltillo</option>
<option value="Monterrey">Monterrey</option>
<option value="Monclova">Monclova</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Nombre del Cliente</label>
<input type="text" id="cliente" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200" placeholder="Ej. Georgina Moreno">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Teléfono</label>
<input type="tel" id="telefono" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200" placeholder="844-667-2245">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tratamiento/Producto</label>
<select id="tratamiento" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200" onchange="handleTreatmentChange()">
<option value="">Seleccionar tratamiento/producto</option>
<option value="Sculptra 1ra Aplicación" data-price="15000" data-promo="8000">Sculptra 1ra Aplicación</option>
<option value="Sculptra 2da Aplicación" data-price="12000" data-promo="6000">Sculptra 2da Aplicación</option>
<option value="Botox Full" data-price="6500" data-promo="2999">Botox Full</option>
<option value="Botox Parcial" data-price="4000" data-promo="1999">Botox Parcial</option>
<option value="Rellenos Labiales" data-price="8000" data-promo="4500">Rellenos Labiales</option>
<option value="Facial Rejuveness" data-price="3500" data-promo="1500">Facial Rejuveness</option>
<option value="Lifting sin Cirugía" data-price="25000" data-promo="15000">Lifting sin Cirugía</option>
<option value="Radiofrecuencia" data-price="2500" data-promo="1200">Radiofrecuencia</option>
<option value="Crema Anti-Aging" data-price="850" data-promo="650">Crema Anti-Aging</option>
<option value="Serum Vitamina C" data-price="650" data-promo="450">Serum Vitamina C</option>
<option value="Protector Solar SPF 50" data-price="450" data-promo="350">Protector Solar SPF 50</option>
<option value="Kit de Limpieza Facial" data-price="1200" data-promo="900">Kit de Limpieza Facial</option>
<option value="personalizado">✏️ Agregar Tratamiento/Producto Personalizado</option>
</select>
<!-- Campo para tratamiento personalizado -->
<div id="customTreatmentContainer" class="custom-treatment-container">
<div class="custom-treatment-header">
<i class="fas fa-plus-circle"></i>
<span>Agregar Nuevo Tratamiento/Producto</span>
</div>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Nombre del tratamiento/producto</label>
<input type="text" id="customTreatment" placeholder="Ej. Masaje Relajante, Crema Hidratante, etc." class="input-focus w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200">
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Precio Regular</label>
<input type="number" id="customPrice" placeholder="0" min="0" class="input-focus w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Precio Promoción</label>
<input type="number" id="customPromo" placeholder="0" min="0" class="input-focus w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200">
</div>
</div>
<div class="flex gap-2 pt-2">
<button type="button" onclick="addCustomTreatment()" class="btn-success text-white px-4 py-2 rounded-lg font-medium flex items-center space-x-2 transition-all duration-200">
<i class="fas fa-check"></i>
<span>Agregar</span>
</button>
<button type="button" onclick="cancelCustomTreatment()" class="btn-secondary text-white px-4 py-2 rounded-lg font-medium flex items-center space-x-2 transition-all duration-200">
<i class="fas fa-times"></i>
<span>Cancelar</span>
</button>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Costo Regular</label>
<input type="number" id="costoRegular" min="0" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200" placeholder="0">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Promoción</label>
<input type="number" id="promocion" min="0" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200" placeholder="0">
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Pago Realizado</label>
<input type="number" id="pagoRealizado" min="0" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200" placeholder="0">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Observaciones</label>
<textarea id="observaciones" class="input-focus w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none transition-all duration-200 h-24" placeholder="Aplicado hoy, próxima cita..."></textarea>
</div>
<button onclick="addPatient()" class="btn-primary w-full text-white py-3 px-6 rounded-lg font-medium flex items-center justify-center space-x-2">
<i class="fas fa-plus"></i>
<span>Agregar Paciente</span>
</button>
</div>
</div>
</div>
<!-- Patients List Section -->
<div class="xl:col-span-2">
<div class="bg-white rounded-2xl shadow-xl overflow-hidden">
<div class="bg-gradient-to-r from-purple-600 to-blue-600 px-8 py-6">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<i class="fas fa-list text-2xl text-white"></i>
<h2 class="text-2xl font-bold text-white">Pacientes de Hoy</h2>
</div>
<div class="flex space-x-2">
<button onclick="clearAllData()" class="bg-red-500 text-white px-4 py-2 rounded-lg hover:bg-red-600 transition-colors duration-200 flex items-center space-x-2">
<i class="fas fa-trash"></i>
<span>Limpiar Todo</span>
</button>
<button onclick="printAllRemissions()" class="bg-white text-purple-600 px-4 py-2 rounded-lg hover:bg-gray-100 transition-colors duration-200 flex items-center space-x-2">
<i class="fas fa-print"></i>
<span>Imprimir Todo</span>
</button>
</div>
</div>
</div>
<div class="p-8">
<div id="patientsList" class="space-y-4">
<div class="text-center text-gray-500 py-8">
<i class="fas fa-user-friends text-4xl text-gray-300 mb-4"></i>
<p class="text-lg">No hay pacientes registrados hoy</p>
<p class="text-sm">Agrega el primer paciente usando el formulario</p>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Print View Individual -->
<div class="print-view" id="printViewIndividual">
<div style="width: 100%; max-width: 210mm; margin: 0 auto; padding: 30px; font-family: Arial, sans-serif; background: white; min-height: 297mm; box-sizing: border-box;">
<!-- Encabezado -->
<div style="text-align: center; margin-bottom: 40px; padding-bottom: 20px; border-bottom: 2px solid #667eea;">
<h1 style="font-size: 28px; margin: 0; color: #333; font-weight: bold;">RENOVÉ CLÍNICA & SPA</h1>
<h2 style="font-size: 20px; margin: 10px 0; color: #666; font-weight: normal;">Comprobante de Servicio</h2>
<div style="margin-top: 15px;">
<span style="font-weight: bold; color: #667eea;">Sucursal:</span> <span id="printIndividualSucursal" style="margin-right: 30px;"></span>
<span style="font-weight: bold; color: #667eea;">Fecha:</span> <span id="printIndividualDate"></span>
</div>
</div>
<!-- Información del Cliente -->
<div style="border: 3px solid #667eea; border-radius: 12px; padding: 30px; margin-bottom: 30px; background-color: #f8f9fa;">
<h3 style="color: #667eea; margin-top: 0; margin-bottom: 25px; font-size: 22px; font-weight: bold; text-align: center;">INFORMACIÓN DEL CLIENTE</h3>
<table style="width: 100%; border-spacing: 0; border-collapse: separate;">
<tr>
<td style="padding: 12px 0; width: 35%; font-weight: bold; font-size: 16px; color: #333; vertical-align: top;">Cliente:</td>
<td style="padding: 12px 0; font-size: 16px; color: #666; vertical-align: top;" id="printIndividualCliente"></td>
</tr>
<tr style="border-top: 1px solid #ddd;">
<td style="padding: 12px 0; font-weight: bold; font-size: 16px; color: #333; vertical-align: top;">Teléfono:</td>
<td style="padding: 12px 0; font-size: 16px; color: #666; vertical-align: top;" id="printIndividualTelefono"></td>
</tr>
<tr style="border-top: 1px solid #ddd;">
<td style="padding: 12px 0; font-weight: bold; font-size: 16px; color: #333; vertical-align: top;">Tratamiento/Producto:</td>
<td style="padding: 12px 0; font-size: 16px; color: #666; vertical-align: top;" id="printIndividualTratamiento"></td>
</tr>
</table>
</div>
<!-- Información Financiera -->
<div style="border: 2px solid #e5e7eb; border-radius: 12px; padding: 30px; margin-bottom: 30px; background-color: #ffffff;">
<h3 style="color: #667eea; margin-top: 0; margin-bottom: 25px; font-size: 22px; font-weight: bold; text-align: center;">DETALLE DEL SERVICIO</h3>
<table style="width: 100%; border-spacing: 0; border-collapse: separate;">
<tr>
<td style="padding: 12px 0; width: 35%; font-weight: bold; font-size: 16px; color: #333; vertical-align: top;">Precio Regular:</td>
<td style="padding: 12px 0; font-size: 18px; color: #374151; font-weight: bold; vertical-align: top;" id="printIndividualCostoRegular"></td>
</tr>
<tr style="border-top: 1px solid #ddd;">
<td style="padding: 12px 0; font-weight: bold; font-size: 16px; color: #333; vertical-align: top;">Precio con Promoción:</td>
<td style="padding: 12px 0; font-size: 18px; color: #059669; font-weight: bold; vertical-align: top;" id="printIndividualPromocion"></td>
</tr>
<tr style="border-top: 2px solid #667eea; background-color: #f8f9fa;">
<td style="padding: 15px 10px; font-weight: bold; font-size: 18px; color: #667eea; vertical-align: top;">TOTAL PAGADO:</td>
<td style="padding: 15px 10px; font-size: 20px; color: #667eea; font-weight: bold; vertical-align: top;" id="printIndividualPagoRealizado"></td>
</tr>
</table>
</div>
<!-- Observaciones (Solo si hay observaciones) -->
<div style="border: 2px solid #e5e7eb; border-radius: 12px; padding: 25px; margin-bottom: 40px; background-color: #ffffff;" id="printIndividualObservacionesContainer">
<h4 style="color: #667eea; margin-top: 0; margin-bottom: 15px; font-size: 18px; font-weight: bold;">Observaciones:</h4>
<p style="margin: 0; font-size: 16px; color: #666; line-height: 1.6;" id="printIndividualObservaciones"></p>
</div>
<!-- Firma -->
<div style="margin-top: 50px; margin-bottom: 40px;">
<div style="border-bottom: 2px solid #333; width: 300px; margin: 0 auto 10px auto;"></div>
<p style="text-align: center; margin: 0; font-size: 16px; font-weight: bold; color: #333;">Firma del Cliente</p>
</div>
<!-- Cupón promocional -->
<div style="border: 3px dashed #667eea; border-radius: 12px; padding: 25px; background: linear-gradient(135deg, #f8f9fa 0%, #e3f2fd 100%); text-align: center;">
<h3 style="color: #667eea; margin: 0 0 15px 0; font-size: 24px; font-weight: bold;">CUPÓN REGENERESS</h3>
<p style="margin: 8px 0; font-size: 20px; font-weight: bold; color: #333;"><strong>Facial Rejuveness por $1,500 MXN</strong></p>
<p style="margin: 8px 0; font-size: 16px; color: #666; text-decoration: line-through;">(antes $3,500)</p>
<p style="margin: 15px 0 20px 0; font-size: 14px; color: #667eea; font-weight: bold;">Válido únicamente en su próxima cita</p>
<div style="text-align: left; max-width: 400px; margin: 0 auto;">
<p style="font-size: 14px; margin: 8px 0; color: #333;"><strong>✓</strong> Regenera con exosomas y células madre</p>
<p style="font-size: 14px; margin: 8px 0; color: #333;"><strong>✓</strong> Mejora textura, firmeza y poros</p>
<p style="font-size: 14px; margin: 8px 0; color: #333;"><strong>✓</strong> Luzca una piel renovada y descansada</p>
</div>
</div>
<!-- Pie de página -->
<div style="margin-top: 40px; text-align: center; padding-top: 20px; border-top: 1px solid #ddd;">
<p style="margin: 0; font-size: 12px; color: #666;">¡Gracias por confiar en RENOVÉ CLÍNICA & SPA!</p>
<p style="margin: 5px 0 0 0; font-size: 12px; color: #666;">Su belleza y bienestar son nuestra prioridad</p>
</div>
</div>
</div>
<!-- Print View Complete -->
<div class="print-view" id="printViewComplete">
<div style="padding: 40px; font-family: Arial, sans-serif; background: white;">
<div style="text-align: center; margin-bottom: 30px;">
<h1 style="font-size: 24px; margin: 0; color: #333;">RENOVÉ CLÍNICA & SPA</h1>
<h2 style="font-size: 18px; margin: 5px 0; color: #666;">Nota de Remisión – Registro Diario</h2>
<p style="margin: 5px 0;"><strong>Sucursal:</strong> <span id="printCompleteSucursal"></span></p>
<p style="margin: 5px 0;"><strong>Fecha:</strong> <span id="printCompleteDate"></span></p>
</div>
<table style="width: 100%; border-collapse: collapse; margin-bottom: 20px;" id="printTable">
<thead>
<tr style="background-color: #f8f9fa;">
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Cliente</th>
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Teléfono</th>
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Tratamiento/Producto</th>
<th style="border: 1px solid #ddd; padding: 8px; text-align: right;">Costo Regular</th>
<th style="border: 1px solid #ddd; padding: 8px; text-align: right;">Promoción</th>
<th style="border: 1px solid #ddd; padding: 8px; text-align: right;">Pago Realizado</th>
<th style="border: 1px solid #ddd; padding: 8px; text-align: left;">Observaciones</th>
</tr>
</thead>
<tbody id="printCompleteTableBody">
</tbody>
</table>
<div style="margin-top: 30px;">
<p><strong>TOTAL PACIENTES DEL DÍA:</strong> <span id="printCompleteTotalPatients"></span></p>
<p><strong>TOTAL PROMOCIONES APLICADAS:</strong> $<span id="printCompleteTotalPromotions"></span></p>
<p><strong>TOTAL PAGADO HOY:</strong> $<span id="printCompleteTotalPaid"></span></p>
</div>
<div style="margin-top: 50px;">
<p>____________________________________</p>
<p>Firma del Responsable de Caja / Médico</p>
</div>
<div style="margin-top: 30px;">
<p><strong>Comentarios o Incidencias:</strong></p>
<p style="border-bottom: 1px solid #ddd; height: 50px;"></p>
</div>
</div>
</div>
<script>
// Variables globales
let patients = [];
let currentSucursal = '';
let customTreatments = JSON.parse(localStorage.getItem('renove_custom_treatments')) || [];
// Inicializar la aplicación
window.onload = function() {
console.log('Aplicación iniciada');
loadData();
updateCurrentDate();
renderPatients();
updateStats();
loadCustomTreatments();
};
// Cargar tratamientos personalizados
function loadCustomTreatments() {
const tratamientoSelect = document.getElementById('tratamiento');
const personalizedOption = tratamientoSelect.querySelector('option[value="personalizado"]');
// Eliminar tratamientos personalizados anteriores
const existingCustom = tratamientoSelect.querySelectorAll('.custom-option');
existingCustom.forEach(option => option.remove());
// Agregar tratamientos personalizados antes de la opción "Agregar Personalizado"
customTreatments.forEach(treatment => {
const option = document.createElement('option');
option.value = treatment.name;
option.textContent = treatment.name + ' (Personalizado)';
option.className = 'custom-option';
option.dataset.price = treatment.price || '0';
option.dataset.promo = treatment.promo || '0';
tratamientoSelect.insertBefore(option, personalizedOption);
});
}
// Manejar cambio de tratamiento
function handleTreatmentChange() {
const tratamiento = document.getElementById('tratamiento');
const customContainer = document.getElementById('customTreatmentContainer');
if (tratamiento.value === 'personalizado') {
customContainer.classList.add('show');
document.getElementById('customTreatment').focus();
} else {
customContainer.classList.remove('show');
updatePrices();
}
}
// Agregar tratamiento personalizado
function addCustomTreatment() {
const customName = document.getElementById('customTreatment').value.trim();
const customPrice = parseFloat(document.getElementById('customPrice').value) || 0;
const customPromo = parseFloat(document.getElementById('customPromo').value) || 0;
if (!customName) {
showNotification('Por favor ingresa el nombre del tratamiento/producto', 'error');
document.getElementById('customTreatment').focus();
return;
}
// Verificar si ya existe
if (customTreatments.find(t => t.name.toLowerCase() === customName.toLowerCase())) {
showNotification('Este tratamiento ya existe', 'error');
return;
}
const newTreatment = {
name: customName,
price: customPrice,
promo: customPromo
};
customTreatments.push(newTreatment);
localStorage.setItem('renove_custom_treatments', JSON.stringify(customTreatments));
loadCustomTreatments();
// Seleccionar el nuevo tratamiento
document.getElementById('tratamiento').value = customName;
// Limpiar campos del formulario personalizado
document.getElementById('customTreatment').value = '';
document.getElementById('customPrice').value = '';
document.getElementById('customPromo').value = '';
document.getElementById('customTreatmentContainer').classList.remove('show');
// Establecer precios en el formulario principal
document.getElementById('costoRegular').value = customPrice;
document.getElementById('promocion').value = customPromo;
document.getElementById('pagoRealizado').value = customPromo;
showNotification('Tratamiento personalizado agregado exitosamente', 'success');
}
// Cancelar tratamiento personalizado
function cancelCustomTreatment() {
document.getElementById('customTreatment').value = '';
document.getElementById('customPrice').value = '';
document.getElementById('customPromo').value = '';
document.getElementById('customTreatmentContainer').classList.remove('show');
document.getElementById('tratamiento').value = '';
}
// Cargar datos del localStorage
function loadData() {
try {
const savedPatients = localStorage.getItem('renove_patients');
const savedSucursal = localStorage.getItem('renove_sucursal');
if (savedPatients) {
patients = JSON.parse(savedPatients);
}
if (savedSucursal) {
currentSucursal = savedSucursal;
document.getElementById('sucursal').value = currentSucursal;
}
} catch (error) {
console.error('Error cargando datos:', error);
patients = [];
}
}
// Guardar datos en localStorage
function saveData() {
try {
localStorage.setItem('renove_patients', JSON.stringify(patients));
localStorage.setItem('renove_sucursal', currentSucursal);
} catch (error) {
console.error('Error guardando datos:', error);
}
}
// Actualizar fecha actual
function updateCurrentDate() {
const now = new Date();
const options = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
};
document.getElementById('currentDate').textContent = now.toLocaleDateString('es-MX', options);
}
// Actualizar precios cuando se selecciona un tratamiento
function updatePrices() {
const tratamiento = document.getElementById('tratamiento');
const selected = tratamiento.options[tratamiento.selectedIndex];
if (selected && selected.dataset.price) {
document.getElementById('costoRegular').value = selected.dataset.price;
document.getElementById('promocion').value = selected.dataset.promo;
document.getElementById('pagoRealizado').value = selected.dataset.promo;
}
}
// Agregar paciente
function addPatient() {
const sucursal = document.getElementById('sucursal').value.trim();
const cliente = document.getElementById('cliente').value.trim();
const telefono = document.getElementById('telefono').value.trim();
const tratamiento = document.getElementById('tratamiento').value.trim();
const costoRegular = parseFloat(document.getElementById('costoRegular').value) || 0;
const promocion = parseFloat(document.getElementById('promocion').value) || 0;
const pagoRealizado = parseFloat(document.getElementById('pagoRealizado').value) || 0;
const observaciones = document.getElementById('observaciones').value.trim();
// Validar campos obligatorios
if (!sucursal || !cliente || !telefono || !tratamiento) {
showNotification('Por favor completa todos los campos obligatorios', 'error');
return;
}
if (tratamiento === 'personalizado') {
showNotification('Por favor completa el tratamiento personalizado o selecciona uno de la lista', 'error');
return;
}
if (costoRegular < 0 || promocion < 0 || pagoRealizado < 0) {
showNotification('Los montos no pueden ser negativos', 'error');
return;
}
const patient = {
id: Date.now(),
sucursal: sucursal,
cliente: cliente,
telefono: telefono,
tratamiento: tratamiento,
costoRegular: costoRegular,
promocion: promocion,
pagoRealizado: pagoRealizado,
observaciones: observaciones,
fecha: new Date().toLocaleDateString('es-MX')
};
patients.push(patient);
currentSucursal = sucursal;
saveData();
clearForm();
renderPatients();
updateStats();
showNotification('Paciente agregado exitosamente', 'success');
}
// Limpiar formulario
function clearForm() {
document.getElementById('cliente').value = '';
document.getElementById('telefono').value = '';
document.getElementById('tratamiento').value = '';
document.getElementById('costoRegular').value = '';
document.getElementById('promocion').value = '';
document.getElementById('pagoRealizado').value = '';
document.getElementById('observaciones').value = '';
document.getElementById('customTreatmentContainer').classList.remove('show');
document.getElementById('customTreatment').value = '';
document.getElementById('customPrice').value = '';
document.getElementById('customPromo').value = '';
// Mantener la sucursal seleccionada
document.getElementById('sucursal').value = currentSucursal;
}
// Renderizar lista de pacientes
function renderPatients() {
const patientsList = document.getElementById('patientsList');
if (patients.length === 0) {
patientsList.innerHTML = `
<div class="text-center text-gray-500 py-8">
<i class="fas fa-user-friends text-4xl text-gray-300 mb-4"></i>
<p class="text-lg">No hay pacientes registrados hoy</p>
<p class="text-sm">Agrega el primer paciente usando el formulario</p>
</div>
`;
return;
}
patientsList.innerHTML = patients.map(patient => `
<div class="patient-card bg-white rounded-lg shadow-md p-6 fade-in">
<div class="flex justify-between items-start mb-4">
<div>
<h3 class="text-xl font-bold text-gray-800">${patient.cliente}</h3>
<p class="text-gray-600 flex items-center mt-1">
<i class="fas fa-phone text-sm mr-2"></i>
${patient.telefono}
</p>
</div>
<div class="patient-actions">
<button onclick="printIndividualRemission(${patient.id})" class="action-btn print-btn">
<i class="fas fa-print"></i>
Imprimir
</button>
<button onclick="removePatient(${patient.id})" class="action-btn delete-btn">
<i class="fas fa-trash"></i>
Eliminar
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<p class="text-sm text-gray-500">Tratamiento/Producto</p>
<p class="font-medium text-gray-800">${patient.tratamiento}</p>
</div>
<div>
<p class="text-sm text-gray-500">Sucursal</p>
<p class="font-medium text-gray-800">${patient.sucursal}</p>
</div>
</div>
<div class="grid grid-cols-3 gap-4 mb-4">
<div class="text-center">
<p class="text-sm text-gray-500">Costo Regular</p>
<p class="font-bold text-gray-800">$${patient.costoRegular.toLocaleString()}</p>
</div>
<div class="text-center">
<p class="text-sm text-gray-500">Promoción</p>
<p class="font-bold text-green-600">$${patient.promocion.toLocaleString()}</p>
</div>
<div class="text-center">
<p class="text-sm text-gray-500">Pago Realizado</p>
<p class="font-bold text-blue-600">$${patient.pagoRealizado.toLocaleString()}</p>
</div>
</div>
${patient.observaciones ? `
<div class="bg-gray-50 rounded-lg p-3">
<p class="text-sm text-gray-600">
<i class="fas fa-comment text-gray-400 mr-2"></i>
${patient.observaciones}
</p>
</div>
` : ''}
</div>
`).join('');
}
// Actualizar estadísticas
function updateStats() {
const totalPatients = patients.length;
const totalPromotions = patients.reduce((sum, p) => sum + p.promocion, 0);
const totalPaid = patients.reduce((sum, p) => sum + p.pagoRealizado, 0);
const totalRegular = patients.reduce((sum, p) => sum + p.costoRegular, 0);
document.getElementById('totalPatients').textContent = totalPatients;
document.getElementById('totalPromotions').textContent = '$' + totalPromotions.toLocaleString();
document.getElementById('totalPaid').textContent = '$' + totalPaid.toLocaleString();
document.getElementById('totalRegular').textContent = '$' + totalRegular.toLocaleString();
}
// Imprimir nota de remisión individual (CORREGIDO)
function printIndividualRemission(patientId) {
const patient = patients.find(p => p.id === patientId);
if (!patient) {
showNotification('Paciente no encontrado', 'error');
return;
}
console.log('Datos del paciente:', patient); // Para debug
// Forzar la actualización del DOM antes de imprimir
setTimeout(() => {
// Llenar datos con innerHTML en lugar de textContent para asegurar que se muestren
document.getElementById('printIndividualSucursal').innerHTML = patient.sucursal || 'No especificada';
document.getElementById('printIndividualDate').innerHTML = new Date().toLocaleDateString('es-MX');
document.getElementById('printIndividualCliente').innerHTML = patient.cliente || 'No especificado';
document.getElementById('printIndividualTelefono').innerHTML = patient.telefono || 'No especificado';
document.getElementById('printIndividualTratamiento').innerHTML = patient.tratamiento || 'No especificado';
document.getElementById('printIndividualCostoRegular').innerHTML = '$' + (patient.costoRegular || 0).toLocaleString('es-MX');
document.getElementById('printIndividualPromocion').innerHTML = '$' + (patient.promocion || 0).toLocaleString('es-MX');
document.getElementById('printIndividualPagoRealizado').innerHTML = '$' + (patient.pagoRealizado || 0).toLocaleString('es-MX');
// Manejar observaciones
const observacionesContainer = document.getElementById('printIndividualObservacionesContainer');
const observacionesElement = document.getElementById('printIndividualObservaciones');
if (patient.observaciones && patient.observaciones.trim() !== '') {
observacionesElement.innerHTML = patient.observaciones;
observacionesContainer.style.display = 'block';
} else {
observacionesContainer.style.display = 'none';
}
// Mostrar vista de impresión
document.getElementById('printViewComplete').style.display = 'none';
document.getElementById('printViewIndividual').style.display = 'block';
// Imprimir después de otro pequeño retraso
setTimeout(() => {
window.print();
}, 300);
// Ocultar después de imprimir
const afterPrintHandler = function() {
document.getElementById('printViewIndividual').style.display = 'none';
window.removeEventListener('afterprint', afterPrintHandler);
};
window.addEventListener('afterprint', afterPrintHandler);
}, 100);
}
// Eliminar paciente
function removePatient(id) {
if (confirm('¿Estás seguro de que quieres eliminar este paciente?')) {
patients = patients.filter(p => p.id !== id);
saveData();
renderPatients();
updateStats();
showNotification('Paciente eliminado exitosamente', 'success');
}
}
// Limpiar todos los datos
function clearAllData() {
if (confirm('¿Estás seguro de que quieres eliminar todos los datos? Esta acción no se puede deshacer.')) {
patients = [];
localStorage.removeItem('renove_patients');
renderPatients();
updateStats();
showNotification('Todos los datos han sido eliminados', 'success');
}
}
// Imprimir todas las notas de remisión
function printAllRemissions() {
if (patients.length === 0) {
showNotification('No hay pacientes para imprimir', 'error');
return;
}
document.getElementById('printCompleteSucursal').textContent = currentSucursal || 'No especificada';
document.getElementById('printCompleteDate').textContent = new Date().toLocaleDateString('es-MX');
const tableBody = document.getElementById('printCompleteTableBody');
tableBody.innerHTML = patients.map(patient => `
<tr>
<td style="border: 1px solid #ddd; padding: 8px;">${patient.cliente}</td>
<td style="border: 1px solid #ddd; padding: 8px;">${patient.telefono}</td>
<td style="border: 1px solid #ddd; padding: 8px;">${patient.tratamiento}</td>
<td style="border: 1px solid #ddd; padding: 8px; text-align: right;">$${patient.costoRegular.toLocaleString()}</td>
<td style="border: 1px solid #ddd; padding: 8px; text-align: right;">$${patient.promocion.toLocaleString()}</td>
<td style="border: 1px solid #ddd; padding: 8px; text-align: right;">$${patient.pagoRealizado.toLocaleString()}</td>
<td style="border: 1px solid #ddd; padding: 8px;">${patient.observaciones || ''}</td>
</tr>
`).join('');
document.getElementById('printCompleteTotalPatients').textContent = patients.length;
document.getElementById('printCompleteTotalPromotions').textContent = patients.reduce((sum, p) => sum + p.promocion, 0).toLocaleString();
document.getElementById('printCompleteTotalPaid').textContent = patients.reduce((sum, p) => sum + p.pagoRealizado, 0).toLocaleString();
// Mostrar vista completa
document.getElementById('printViewIndividual').style.display = 'none';
document.getElementById('printViewComplete').style.display = 'block';
setTimeout(() => {
window.print();
}, 100);
// Escuchar el evento de después de imprimir
const afterPrintHandler = function() {
document.getElementById('printViewComplete').style.display = 'none';
window.removeEventListener('afterprint', afterPrintHandler);
};
window.addEventListener('afterprint', afterPrintHandler);
}
// Exportar a PDF
function exportToPDF() {
if (patients.length === 0) {
showNotification('No hay pacientes para exportar', 'error');
return;
}
try {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
// Encabezado
doc.setFontSize(18);
doc.setFont(undefined, 'bold');
doc.text('RENOVÉ CLÍNICA & SPA', 105, 20, { align: 'center' });
doc.setFontSize(14);
doc.setFont(undefined, 'normal');
doc.text('Nota de Remisión – Registro Diario', 105, 30, { align: 'center' });
doc.setFontSize(12);
doc.text(`Sucursal: ${currentSucursal || 'No especificada'}`, 20, 45);
doc.text(`Fecha: ${new Date().toLocaleDateString('es-MX')}`, 20, 55);
// Tabla
const tableData = patients.map(patient => [
patient.cliente,
patient.telefono,
patient.tratamiento,
`$${patient.costoRegular.toLocaleString()}`,
`$${patient.promocion.toLocaleString()}`,
`$${patient.pagoRealizado.toLocaleString()}`,
patient.observaciones || ''
]);
doc.autoTable({
head: [['Cliente', 'Teléfono', 'Tratamiento/Producto', 'Costo Regular', 'Promoción', 'Pago Realizado', 'Observaciones']],
body: tableData,
startY: 65,
styles: { fontSize: 8 },
headStyles: { fillColor: [102, 126, 234] }
});
// Totales
const finalY = doc.lastAutoTable.finalY + 20;
doc.setFontSize(12);
doc.setFont(undefined, 'bold');
doc.text(`TOTAL PACIENTES DEL DÍA: ${patients.length}`, 20, finalY);
doc.text(`TOTAL PROMOCIONES APLICADAS: $${patients.reduce((sum, p) => sum + p.promocion, 0).toLocaleString()}`, 20, finalY + 10);
doc.text(`TOTAL PAGADO HOY: $${patients.reduce((sum, p) => sum + p.pagoRealizado, 0).toLocaleString()}`, 20, finalY + 20);
// Firma
doc.setFont(undefined, 'normal');
doc.text('____________________________________', 20, finalY + 40);
doc.text('Firma del Responsable de Caja / Médico', 20, finalY + 50);
// Comentarios
doc.text('Comentarios o Incidencias:', 20, finalY + 70);
doc.line(20, finalY + 80, 190, finalY + 80);
// Cupón opcional
doc.setDrawColor(102, 126, 234);
doc.setLineWidth(1);
doc.rect(20, finalY + 90, 170, 40);
doc.setFontSize(14);
doc.setFont(undefined, 'bold');
doc.setTextColor(102, 126, 234);
doc.text('CUPÓN REGENERESS', 105, finalY + 100, { align: 'center' });
doc.setFontSize(10);
doc.setTextColor(0, 0, 0);
doc.setFont(undefined, 'normal');
doc.text('Facial Rejuveness por $1,500 MXN (antes $3,500)', 105, finalY + 110, { align: 'center' });
doc.text('Válido únicamente en su próxima cita', 105, finalY + 118, { align: 'center' });
doc.setFontSize(8);
doc.text('✓ Regenera con exosomas y células madre ✓ Mejora textura, firmeza y poros', 30, finalY + 125);
doc.text('✓ Luzca una piel renovada y descansada', 30, finalY + 132);
// Guardar
const fileName = `Remision_Completa_${currentSucursal || 'General'}_${new Date().toLocaleDateString('es-MX').replace(/\//g, '')}.pdf`;
doc.save(fileName);
showNotification('PDF exportado exitosamente', 'success');
} catch (error) {
console.error('Error exportando PDF:', error);
showNotification('Error al exportar PDF', 'error');
}
}
// Mostrar notificaciones
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.innerHTML = `
<div style="display: flex; align-items: center; gap: 10px;">
<i class="fas ${type === 'success' ? 'fa-check-circle' : type === 'error' ? 'fa-exclamation-circle' : 'fa-info-circle'}"></i>
<span>${message}</span>
</div>
`;
document.body.appendChild(notification);
setTimeout(() => notification.classList.add('show'), 100);
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => notification.remove(), 300);
}, 3000);
}
// Permitir agregar paciente con Enter
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && e.target.tagName !== 'TEXTAREA') {
e.preventDefault();
if (document.getElementById('customTreatmentContainer').classList.contains('show')) {
if (e.target.id === 'customTreatment' || e.target.id === 'customPrice' || e.target.id === 'customPromo') {
addCustomTreatment();
}
} else {
addPatient();
}
}
});
</script>
</body>
</html>