function openTermsConditions() { window.open("/terminoscondiciones", "Términos y Condiciones", 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,width=630,height=700'); } function openAvisoPrivacidad() { window.open("/avisoprivacidad", "Aviso de Privacidad", 'directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,width=630,height=700'); } function toggleModules() { const table = document.getElementById("modulesTable"); const icon = document.getElementById("modulesIcon"); icon.classList.toggle("icon-rotate"); if (table.classList.contains("show")) { table.classList.remove("show"); setTimeout(() => { if (!table.classList.contains("show")) { table.classList.add("d-none"); } }, 500); } else { table.classList.remove("d-none"); table.offsetHeight; table.classList.add("show"); } } //function initStickyLogo() { // const stickyLogo = $('#stickyLogo'); // const heroSection = $('.hero-siac'); // // $('.sticky-logo').on('click', function() { // $('html, body').animate({ scrollTop: 0 }, 500); // return false; // }); //} // ============================================== // VARIABLES GLOBALES Y FUNCIONES EXISTENTES // ============================================== let countdownInterval = null; let countdownExpiresAt = null; let cotizacionData = { xmlCount: 10000, unlimitedXml: false, lead_id: null, lead_code: null, rfcCount: 1, userCount: 1, unlimitedRfcs: false, integration: [], modules: [], repse: false, repseProviders: 0, plan: 'base', contactInfo: {}, totalPrice: 0, generatedCode: null, validated: false, codigoPromo: null }; function initForm() { const form = document.getElementById('leadForm'); form.addEventListener('submit', function(e) { e.preventDefault(); if (!form.checkValidity()) { e.stopPropagation(); } else { cotizacionData.contactInfo = { nombre: $('#inputNombre').val() || '', apellido: $('#inputApellido').val() || '', empresa: $('#inputEmpresa').val() || '', email: $('#inputEmail').val() || '', telefono: $('#inputTelefono').val() || '', cargo: $('#inputCargo').val() || '', tamano: $('#selectTamano').val() || '', industria: $('#inputIndustria').val() || '' }; const codigoPromoActivo = $('#checkCodigoPromo').is(':checked'); cotizacionData.codigoPromo = codigoPromoActivo ? ($('#inputCodigoPromo').val().trim() || null) : null; enviarCotizacion(); } form.classList.add('was-validated'); }); } function enviarCotizacion() { swalFireMessage("info", "Procesando cotización...", false, "Por favor espere mientras procesamos su información", null, true); if (cotizacionData.unlimitedRfcs === true) { cotizacionData.rfcCount = 0; } if (cotizacionData.unlimitedXml === true) { cotizacionData.xmlCount = 0; } $.ajax({ url: '/landing-page/cotizacion', type: 'POST', headers: { 'X-CSRFToken': TokenFormData().get('csrf_token'), }, contentType: 'application/json', data: JSON.stringify(cotizacionData), success: function(response) { Swal.close(); cotizacionData.lead_id = response.lead_id; cotizacionData.lead_code = response.lead_code; changeStep(3); }, error: function(xhr) { Swal.close(); manejarError(xhr); } }); } function initRangeSlider() { const slider = $('#xmlRange'); const display = $('#xmlDisplay'); const input = $('#xmlInput'); function determinarPlanPorXml(xmlCount) { let plan = ''; if (xmlCount >= 1000 && xmlCount <= 10000) { plan = 'base'; } else if (xmlCount >= 10001 && xmlCount <= 20000) { plan = 'pyme'; } else if (xmlCount >= 20001 && xmlCount <= 200000) { plan = 'pyme pro'; } else if (xmlCount > 200000) { plan = 'empresarial'; } cotizacionData.plan = plan; return plan; } function updateValue(val) { const value = parseInt(val) || 10000; const isUnlimited = value >= 201000; if ($('#xmlDisplay').data('custom') !== true) { display.text(isUnlimited ? '200,000+' : value.toLocaleString()); } slider.val(value); input.val(value); cotizacionData.xmlCount = value; cotizacionData.unlimitedXml = isUnlimited; determinarPlanPorXml(value); if (isUnlimited) { $('#xmlUnlimitedBadge').removeClass('d-none'); } else { $('#xmlUnlimitedBadge').addClass('d-none'); } } slider.on('input', function() { updateValue(this.value); }); input.on('input', function() { let value = parseInt(this.value) || 1000; value = Math.min(200000, Math.max(1000, value)); updateValue(value); }); $('#rfcCount, #userCount').on('input', function() { cotizacionData[this.id === 'rfcCount' ? 'rfcCount' : 'userCount'] = parseInt(this.value) || 1; }); $('input[name="modules"]').on('change', function () { cotizacionData.modules = $('input[name="modules"]:checked') .map(function () { return this.value; }) .get(); }); $('input[name="integration"]').on('change', function () { cotizacionData.integration = $('input[name="integration"]:checked') .map(function () { return this.value; }) .get(); }); $('#repseCheck').on('change', function () { if ($(this).is(':checked')) { $('#repseInputWrapper').removeClass('d-none'); cotizacionData.repse = true; cotizacionData.repseProviders = 1; $('#repseProviders').val(1); } else { $('#repseInputWrapper').addClass('d-none'); cotizacionData.repse = false; cotizacionData.repseProviders = 0; $('#repseProviders').val(''); } }); $('#repseProviders').on('input', function () { let value = parseInt($(this).val()); if (isNaN(value) || value < 0) { value = 0; } $(this).val(value); cotizacionData.repseProviders = value; }); } function changeStep(step) { $('.step-panel').removeClass('active'); $('.wizard-step').removeClass('active'); $(`#step-${step}`).addClass('active'); $(`#step-indicator-${step}`).addClass('active'); for (let i = 1; i < step; i++) { $(`#step-indicator-${i}`).addClass('completed'); } setTimeout(() => { document.getElementById('ref-cotizacion').scrollIntoView({ behavior: 'smooth', block: 'start' }); }, 100); } function resendValidationCode() { if (!cotizacionData.lead_id || !cotizacionData.lead_code) { showToast('No se pudo identificar la solicitud.', 'danger'); return; } showToast('Reenviando código...', 'info'); $.ajax({ url: '/landing-page/reenviar-codigo', type: 'POST', headers: { 'X-CSRFToken': TokenFormData().get('csrf_token'), }, contentType: 'application/json', data: JSON.stringify({ lead_id: cotizacionData.lead_id, lead_code: cotizacionData.lead_code }), success: function(response) { showToast('Código reenviado correctamente', 'success'); countdownExpiresAt = Date.now() + (60 * 1000); startCountdown(60); }, error: function(xhr) { let message = 'Error al reenviar el código.'; if (xhr.responseJSON && xhr.responseJSON.message) { message = xhr.responseJSON.message; } showToast(message, 'danger'); } }); } function showValidationModal() { const email = cotizacionData.contactInfo.email; $('#userEmailDisplay').text(email); $('.code-input').val('').removeClass('is-invalid is-valid'); $('#codeError').hide(); if (!countdownExpiresAt || Date.now() >= countdownExpiresAt) { countdownExpiresAt = Date.now() + (60 * 1000); } startCountdown(60); const modal = new bootstrap.Modal(document.getElementById('emailValidationModal')); modal.show(); } function initCodeInputs() { const inputs = $('.code-input'); inputs.on('input', function() { const value = $(this).val(); const index = parseInt($(this).data('index')); if (!/^\d*$/.test(value)) { $(this).val(''); return; } if (value.length === 1 && index < 4) { inputs.eq(index).focus(); } updateFullCode(); }); inputs.on('keydown', function(e) { const index = parseInt($(this).data('index')); if (e.key === 'Backspace' && $(this).val() === '' && index > 1) { inputs.eq(index - 2).focus(); } }); } function updateFullCode() { let fullCode = ''; $('.code-input').each(function() { fullCode += $(this).val(); }); $('#fullCode').val(fullCode); return fullCode; } function startCountdown(seconds) { const timerElement = $('#countdown'); const resendBtn = $('#resendCodeBtn'); if (!countdownExpiresAt) { countdownExpiresAt = Date.now() + (seconds * 1000); } if (countdownInterval) { clearInterval(countdownInterval); countdownInterval = null; } timerElement.parent().show(); resendBtn.prop('disabled', true); resendBtn.text('Reenviar código'); function updateTimer() { const timeLeft = Math.max( 0, Math.floor((countdownExpiresAt - Date.now()) / 1000) ); timerElement.text(timeLeft); if (timeLeft <= 0) { clearInterval(countdownInterval); countdownInterval = null; countdownExpiresAt = null; timerElement.parent().hide(); resendBtn.prop('disabled', false); resendBtn.text('Reenviar código ahora'); } } updateTimer(); countdownInterval = setInterval(updateTimer, 1000); resendBtn.off('click').on('click', function () { if (!$(this).prop('disabled')) { resendValidationCode(); showToast('Código reenviado correctamente', 'info'); } }); } function validateCode() { const enteredCode = updateFullCode(); if (enteredCode.length !== 4) { showError('Por favor ingresa el código completo de 4 dígitos'); return false; } $.ajax({ url: '/landing-page/validar-codigo', type: 'POST', headers: { 'X-CSRFToken': TokenFormData().get('csrf_token'), }, contentType: 'application/json', data: JSON.stringify({ lead_id: cotizacionData.lead_id, lead_code: cotizacionData.lead_code, codigo: enteredCode, }), success: function(response) { $('.code-input').addClass('is-valid').removeClass('is-invalid'); $('#codeError').hide(); cotizacionData.validated = true; if (response.cotizacion) { cotizacionData.cotizacionServidor = response.cotizacion; } bootstrap.Modal.getInstance(document.getElementById('emailValidationModal')).hide(); changeStep(4); confetti({ particleCount: 100, spread: 70, origin: { y: 0.6 } }); showToast('¡Correo validado correctamente!', 'success'); }, error: function(xhr) { showError('Código incorrecto. Por favor verifica e intenta de nuevo.'); $('.code-input').addClass('is-invalid').removeClass('is-valid'); } }); } function obtenerPDF() { swalFireMessage( "info", "Obteniendo PDF...", false, "Por favor espere mientras obtenemos su cotización", null, true ); const iframe = $('#iframePDFModal'); iframe.off('load').on('load', function () { Swal.close(); }); iframe.attr( 'src', `/landing-page/obtener-pdf?lead_id=${cotizacionData.lead_id}&lead_code=${cotizacionData.lead_code}` ); const modal = new bootstrap.Modal(document.getElementById('modalVerPDF')); modal.show(); } function showError(message) { $('.code-input').addClass('is-invalid').removeClass('is-valid'); $('#codeError').text(message).show(); } function showSummaryModal() { if (!cotizacionData.validated) { showValidationModal(); return; } updateSummaryModal(); const modal = new bootstrap.Modal(document.getElementById('summaryModal')); modal.show(); } function updateSummaryModal() { const cot = cotizacionData.cotizacionServidor || null; const subtotal = cot ? cot.subtotal : 0; const iva = cot ? cot.iva : 0; const totalConIva = cot ? cot.total_con_iva : 0; const xmlCount = cot ? cot.xml_count : cotizacionData.xmlCount; const planNombre = cot ? cot.plan.toUpperCase() : (cotizacionData.plan || '').toUpperCase(); // ── Encabezado ────────────────────────────────────────────────────── $('#summaryClientName').text( `${cotizacionData.contactInfo.nombre} ${cotizacionData.contactInfo.apellido}` ); $('#summaryDate').text(new Date().toLocaleDateString('es-MX')); $('#summaryId').text(cotizacionData.lead_code || `SIAC-${Date.now().toString().slice(-6)}`); // Precio destacado (header del modal) $('#summaryPrice').text(`$${subtotal.toLocaleString('es-MX')}`); // ── Configuración ──────────────────────────────────────────────────── const xmlDisplay = (xmlCount === 0 || cotizacionData.unlimitedXml) ? 'Ilimitados' : xmlCount.toLocaleString('es-MX'); $('#summaryXmlCount').text(xmlDisplay); $('#summaryRfcCount').text( cotizacionData.unlimitedRfcs ? 'Ilimitados' : (cotizacionData.rfcCount || 1) ); // ── Módulos: badges desde el detalle del servidor ──────────────────── const modulesContainer = $('#summaryModules'); modulesContainer.empty(); if (cot && cot.detalle) { const modulosDetalle = cot.detalle.filter(d => d.concepto.startsWith('Módulo')); if (modulosDetalle.length > 0) { modulosDetalle.forEach(m => { const nombre = m.concepto.replace('Módulo ', ''); modulesContainer.append( `${nombre}` ); }); } else { modulesContainer.append('Sin módulos adicionales'); } } else { const moduleNames = { vi: 'Verificación Identidad', ia: 'Inteligencia Artificial', fe: 'Firma Electrónica' }; if (cotizacionData.modules && cotizacionData.modules.length > 0) { cotizacionData.modules.forEach(m => { modulesContainer.append( `${moduleNames[m] || m}` ); }); } else { modulesContainer.append('Sin módulos adicionales'); } } // ── Tabla de desglose ──────────────────────────────────────────────── const tableBody = $('#summaryTableBody'); tableBody.empty(); if (cot && cot.detalle && cot.detalle.length > 0) { cot.detalle.forEach(item => { const esPorCotizar = item.monto === null || item.monto === undefined; const esDescuento = !esPorCotizar && Number(item.monto) < 0; const detalleTxt = item.detalle || '—'; let costoHtml; if (esPorCotizar) { costoHtml = `-`; } else if (esDescuento) { costoHtml = `-$${Math.abs(Number(item.monto)).toLocaleString('es-MX', { minimumFractionDigits: 2 })}`; } else { costoHtml = `$${Number(item.monto).toLocaleString('es-MX', { minimumFractionDigits: 2 })}`; } const trClass = esDescuento ? ' class="table-success"' : ''; tableBody.append(` ${item.concepto} ${detalleTxt} ${costoHtml} `); }); } // ── Totales en el tfoot ────────────────────────────────────────────── $('#summaryTotal').text(`$${Number(subtotal).toLocaleString('es-MX', { minimumFractionDigits: 2 })}`); $('#summaryIVA').text(`$${Number(iva).toLocaleString('es-MX', { minimumFractionDigits: 2 })}`); $('#summaryTotalIVA').text(`$${Number(totalConIva).toLocaleString('es-MX', { minimumFractionDigits: 2 })}`); // ── Sección de Ahorro Estimado ──────────────────────────────────────── if ($('#summaryAhorroContainer').length === 0) { $('#summaryModal .alert.alert-success').before('
'); } const ahorroContainer = $('#summaryAhorroContainer'); const ae = cot && cot.ahorro_estimado ? cot.ahorro_estimado : null; if (ae && ae.personas > 0 && ae.ahorro_mensual > 0) { const fmt = (n) => Number(n).toLocaleString('es-MX', { minimumFractionDigits: 2 }); const mesesTexto = ae.meses_recuperacion !== null ? `${ae.meses_recuperacion} meses (recuperas tu inversión a mediados del mes ${ae.mes_recuperacion_int})` : '—'; ahorroContainer.html(`
Ahorro Estimado con SIAC
Estimación basada en ${ae.personas} persona(s) del área contable a un costo de $18,000/mes c/u y un ahorro prometido del 18% anual.
Concepto Importe
Costo mensual actual del área contable $${fmt(ae.costo_mensual_area)}
Costo anual actual del área contable $${fmt(ae.costo_anual_area)}
Ahorro anual estimado (18%) $${fmt(ae.ahorro_anual)}
Ahorro mensual estimado $${fmt(ae.ahorro_mensual)}
Tu inversión anual con SIAC (con IVA) $${fmt(ae.inversion_anual)}
⏱ Tiempo para recuperar tu inversión ${mesesTexto}
`).removeClass('d-none'); } else { ahorroContainer.html('').addClass('d-none'); } setTimeout(() => { $('#summaryModal .modal-body').css('font-size', '0.95em'); $('#summaryModal h4').css('font-size', '1.5rem'); $('#summaryModal h6').css('font-size', '1rem'); $('#summaryModal table td, #summaryModal table th').css('padding', '0.5rem 0.75rem'); }, 100); } function initScrollObserver() { let lastScrollTop = 0; const stickyCta = $('#stickyCta'); const heroHeight = $('.hero-siac').outerHeight(); $(window).on('scroll', function() { const st = $(this).scrollTop(); if (st > heroHeight) { stickyCta.addClass('show'); } else { stickyCta.removeClass('show'); } if (st > lastScrollTop && st > 100) { stickyCta.removeClass('show'); } lastScrollTop = st; }); } function showToast(message, type = 'info') { const toast = $(` `); $('body').append(toast); const bsToast = new bootstrap.Toast(toast[0]); bsToast.show(); toast.on('hidden.bs.toast', function() { $(this).remove(); }); } function selectPlan(plan) { cotizacionData.plan = plan; cotizacionData.unlimitedRfcs = false; cotizacionData.unlimitedXml = false; cotizacionData.repse = false; cotizacionData.repseProviders = 0; $('#repseCheck').prop('checked', false); $('#repseInputWrapper').addClass('d-none'); $('#repseProviders').val(''); $('#xmlUnlimitedBadge').addClass('d-none'); switch (plan) { case 'base': cotizacionData.xmlCount = 10000; cotizacionData.rfcCount = 1; $('#repseCheck').prop('disabled', false); $('#rfcCount').attr('type', 'number').val(1).prop('disabled', false); $('#xmlDisplay').data('custom', false); break; case 'pyme': cotizacionData.xmlCount = 20000; cotizacionData.rfcCount = 3; $('#repseCheck').prop('disabled', false); $('#rfcCount').attr('type', 'number').val(3).prop('disabled', false); $('#xmlDisplay').data('custom', false); break; case 'pyme pro': cotizacionData.xmlCount = 200000; cotizacionData.repse = true; $('#repseCheck').prop('checked', true); $('#repseCheck').prop('disabled', true); $('#repseInputWrapper').removeClass('d-none'); cotizacionData.repseProviders = 1; $('#repseProviders').val(1); cotizacionData.unlimitedRfcs = true; $('#xmlDisplay').data('custom', false).text('200,000'); $('#xmlUnlimitedBadge').removeClass('d-none'); $('#rfcCount') .attr('type', 'text') .val('Ilimitados') .prop('disabled', true); break; case 'empresarial': cotizacionData.xmlCount = 215000; cotizacionData.unlimitedXml = true; cotizacionData.repse = true; $('#repseCheck').prop('checked', true); $('#repseCheck').prop('disabled', true); $('#repseInputWrapper').removeClass('d-none'); cotizacionData.repseProviders = 1; $('#repseProviders').val(1); cotizacionData.unlimitedRfcs = true; $('#xmlDisplay').data('custom', false).text('200,000+'); $('#xmlUnlimitedBadge').removeClass('d-none'); $('#rfcCount') .attr('type', 'text') .val('Ilimitados') .prop('disabled', true); break; default: $('#repseCheck').prop('disabled', false); $('#xmlDisplay').data('custom', false); $('#rfcCount') .attr('type', 'number') .val(1) .prop('disabled', false); $('#userCount') .attr('type', 'number') .val(1) .prop('disabled', false); cotizacionData.rfcCount = 1; cotizacionData.userCount = 1; break; } $('#xmlRange').val(cotizacionData.xmlCount).trigger('input'); document.getElementById('ref-cotizacion').scrollIntoView({ behavior: 'smooth', block: 'start' }); showToast(`Plan ${plan.toUpperCase()} seleccionado`, 'success'); } function initEventHandlers() { $('#validateCodeBtn').on('click', validateCode); $('#downloadPDFBtn').on('click', obtenerPDF); $('.code-input').on('keypress', function(e) { if (e.key === 'Enter') { validateCode(); } }); } function formatCurrency(amount) { return new Intl.NumberFormat('es-MX', { style: 'currency', currency: 'MXN', minimumFractionDigits: 0, maximumFractionDigits: 0 }).format(amount); }