Cotizador de Servicios Contables – DAFIC
https://cdn.jsdelivr.net/npm/flatpickr
https://npmcdn.com/flatpickr/dist/l10n/es.js
body {
font-family: ‘Montserrat’, sans-serif;
margin: 20px;
background-color: #e6e6e6;
color: black;
}
.container {
max-width: 700px;
margin: auto;
padding: 25px;
background-color: #e6e6e6;
border-radius: 8px;
box-shadow: none;
}
h1 {
font-family: ‘Cinzel’, serif;
font-weight: 700;
color: black;
text-align: center;
margin-top: 0;
margin-bottom: 30px;
letter-spacing: 1px;
}
.servicio-grupo, .info-cliente-grupo {
margin-bottom: 25px;
border-bottom: 1px solid #eee;
padding-bottom: 20px;
}
.servicio-grupo h3, .info-cliente-grupo h3 {
font-family: ‘Cinzel’, serif;
font-weight: 700;
color: black;
border-bottom: 2px solid black;
padding-bottom: 5px;
text-align: center;
}
.servicio-item {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 15px 5px;
}
.servicio-item-info {
flex-grow: 1;
overflow: hidden;
word-wrap: break-word;
padding-right: 15px;
}
.servicio-item-info label {
font-size: 1.1em;
font-weight: 500;
color: black;
cursor: pointer;
}
.servicio-item-info .descripcion {
font-size: 0.9em;
color: black;
padding-left: 20px;
display: block;
margin-top: 4px;
}
.servicio-item-info .descripcion.no-padding {
padding-left: 0;
}
.servicio-item .precio-control {
display: flex;
align-items: center;
min-width: 150px;
justify-content: flex-end;
text-align: right;
padding-top: 3px;
}
.servicio-item .precio {
font-size: 0.9em;
color: black;
font-weight: 500;
}
.leyenda-consultas {
text-align: center;
font-style: italic;
color: black;
font-weight: 500;
margin-top: 20px;
padding: 10px;
background-color: #f0f0f0;
border-radius: 5px;
}
input[type=»radio»], input[type=»checkbox»] {
transform: scale(1.3);
margin-right: 10px;
cursor: pointer;
}
input[type=»number»] {
width: 70px;
padding: 5px;
font-size: 1em;
border: 1px solid #ccc;
border-radius: 4px;
text-align: center;
margin-left: 15px;
}
.info-cliente-grupo .campo {
margin-bottom: 15px;
}
.info-cliente-grupo label {
font-weight: 500;
display: block;
margin-bottom: 5px;
font-size: 1.1em;
color: black;
}
.info-cliente-grupo input[type=»text»],
.info-cliente-grupo input[type=»number»],
.info-cliente-grupo textarea {
width: 100%;
padding: 10px;
font-size: 1em;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.info-cliente-grupo textarea {
min-height: 80px;
resize: vertical;
}
.info-cliente-grupo .opciones-radio label {
display: inline-block;
margin-right: 20px;
font-weight: normal;
}
.info-cliente-grupo .opciones-radio input[type=»radio»] {
margin-right: 5px;
transform: scale(1.1);
}
.campo-condicional {
display: none;
margin-left: 20px;
padding-left: 15px;
border-left: 2px solid #eee;
margin-top: 10px;
}
.referido-grupo {
background-color: #f0f0f0;
padding: 20px;
border-radius: 8px;
margin-top: 20px;
}
.referido-grupo label {
font-weight: 500;
font-size: 1.1em;
display: block;
margin-bottom: 8px;
}
.referido-grupo input[type=»text»] {
width: 100%;
padding: 10px;
font-size: 1em;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.referido-grupo small {
display: block;
font-size: 0.9em;
color: black;
margin-top: 8px;
}
.descuento-aplicado {
display: none;
font-size: 1em;
font-weight: bold;
color: black;
margin-top: 10px;
text-align: center;
}
.total-container {
text-align: right;
margin-top: 30px;
font-size: 1.9em;
font-weight: bold;
color: black;
}
.total-container span {
display: inline-block;
min-width: 150px;
text-align: left;
background-color: #f0f0f0;
padding: 10px 15px;
border-radius: 5px;
}
.boton-whatsapp {
display: block;
width: 100%;
padding: 15px;
background-color: #25D366;
color: #ffffff;
text-align: center;
font-size: 1.2em;
font-weight: bold;
text-decoration: none;
border-radius: 8px;
margin-top: 30px;
box-sizing: border-box;
cursor: pointer;
border: none;
}
.boton-whatsapp:hover {
background-color: #128C7E;
}
.boton-whatsapp.boton-secundario {
background-color: #ffffff;
color: black;
border: 2px solid black;
margin-top: 15px;
}
.boton-whatsapp.boton-secundario:hover {
background-color: #f0f0f0;
color: black;
}
input[type=»text»]#dias_visita {
cursor: pointer;
}
@keyframes flash {
0% { background-color: #f0f0f0; }
50% { background-color: #e0f8e6; }
100% { background-color: #f0f0f0; }
}
.total-actualizado {
animation: flash 0.8s ease-out;
}
/* INICIO: Media Queries para Pantallas Pequeñas (Celulares) */
@media (max-width: 600px) {
.container {
margin: 0 10px;
padding: 15px;
}
.container a img {
max-width: 250px !important;
}
h1 {
font-size: 1.5em;
margin-bottom: 20px;
}
.servicio-item {
flex-direction: column;
align-items: flex-start;
padding: 10px 0;
}
.servicio-item .precio-control {
width: 100%;
justify-content: flex-start;
padding-top: 5px;
}
.total-container {
font-size: 1.4em;
}
}
/* FIN: Media Queries */
COTIZADOR DE SERVICIOS
Mensualidades
Paquete PF Básico
Ideal para RESICO (PF) y Arrendamiento. Incluye: Cálculo y presentación de impuestos mensuales (ISR, IVA). Límite: 25 CFDI/mes.
$300 – $800
Paquete PF Intermedio (Plataformas)
Únicamente para Plataformas Digitales. Incluye: Cálculo de impuestos (ISR, IVA) y DIOT. Límite: 50 CFDI/mes.
$800 – $1,500
Paquete PF Avanzado (RAEP)
Para Personas Físicas con Actividad Empresarial (RAEP). Incluye: Impuestos (ISR, IVA), DIOT y Cont. Electrónica. Límite: 100 CFDI/mes.
$1,000 – $4,000
Paquete Persona Moral (A cotizar)Para PM (Régimen General o RESICO). El precio final se define según volumen y complejidad.
$3,000 – $15,000
Servicio de Contador ExternoServicios de contraloría, auditoría interna, consultoría financiera o fiscal estratégica.
$5,000 – $10,000
Asesoría Inicial (Persona Física)Consulta única (2hrs) para diagnóstico fiscal o planificación PF.
$1,000.00
Asesoría Inicial (Persona Moral)Consulta única (3hrs) para diagnóstico fiscal o planificación PM.
$3,000.00
Nota: Todos los Paquetes (PF y PM) incluyen consultas ilimitadas.
Servicios Recurrentes
Empleados en Nómina
Cálculo, timbrado de recibos y cálculo de impuestos (IMSS, ISN).$90.00 c/u
Servicios Adicionales (Pago Único)
Declaración Anual (Persona Física)Presentación anual (externo). **Si hay saldo a favor, se cobra 10% adicional sobre el monto recuperado**.
$1,200.00
Declaración Anual (Persona Moral)Presentación de declaración anual para PM (clientes externos).
$5,000.00
Alta Patronal IMSSTrámite único de registro de la empresa ante el IMSS.
$500.00
Gestión de Devolución de ImpuestosTrámite de devolución de IVA, ISR, etc. **Se cobra el 20% sobre el monto total devuelto**.
(Bajo %)
Trámite de e.firma (Gestión)Asesoría y gestión para obtención de cita o renovación de e.firma.
$500.00
Información Adicional
Tu Nombre
Giro de la empresa
Años con el negocio
¿Están dados de alta en el SAT?
Sí No
Si sí, ¿presentan declaraciones actualmente?
Sí No
Si no declaran, ¿cuántos meses de atraso tienen aproximadamente?
Dirección del negocio (Calle, Número, Colonia, Municipio)
Días y horarios preferidos para visita
¿Alguien te recomendó con nosotros?
¡Si es tu primera vez, ambos (tú y la persona que te refirió) obtienen un 10% de descuento en la primera mensualidad de un paquete!
¡10% de descuento aplicado a la mensualidad!
TOTAL MÍNIMO (MXN): $ 0.00
Enviar Cotización por WhatsApp
Solicitar más Información
document.addEventListener(‘DOMContentLoaded’, () => {
// — Inicialización del calendario Flatpickr —
flatpickr.localize(flatpickr.l10ns.es);
flatpickr(«#dias_visita», {
enableTime: true,
minDate: «today»,
dateFormat: «Y-m-d H:i»,
time_24hr: true
});
// — Fin Flatpickr —
// — Lista de Referidos Válidos —
const listaNombresValidos = [«ALEJANDRA DELGADO GAYTAN»,»ALEJANDRA ENRIQUEZ LUNA»,»ALEJANDRO PRIETO AVILA»,»ALONZO MARMOLEJOMENDIOLA»,»ARACELI ROBLES CASTILLO»,»ASTRID PARRA NORIEGA»,»BRYAN YAIR AVILA SANTILLAN»,»CARLOS ANTONIO CARDONA ALERIANO»,»CARLOS OCTAVIO ROSALES GARCIA»,»COLEGIO DE REUMATOLOGOS DE AGUASCALIENTES»,»DANIELA ALEJANDRA SALDAÑA GAYTAN»,»EDSG»,»ERICK GEOVANNI MIRANDA BALDOVINES»,»GUADALUPE ESTHER CHAVEZ MATA»,»GUILLERMO JOSEPH GARCIA»,»IVAN ALEJANDRO MEDINA PEREZ»,»JESUS ALBERTO SOTOMAYOR»,»JESUS OMAR AVILA SANTILLAN»,»JOSE ANTONIO DURAN HERNANDEZ»,»JOSE LUIS ESPINOZA LOPEZ»,»JUAN ANGEL FLORES PACHECO»,»JUAN ANTONIO DIAZ RODRIGUEZ»,»JULIA MENDOZA NUÑEZ»,»KAREN JUAREZ NICOLAS»,»LUCY GARCIA»,»MARCO ANTONIO PAREDES VELAZQUEZ»,»MARIZA SANTILLAN ORTIZ»,»MARTIN SANTILLAN GOMEZ»,»MIGUEL ANGEL VIVEROS PEREZ»,»NIDIA FERNANDEZ ESPINOSA»,»ROBEROTO OLMEDO HERNANDEZ»,»RODOLFO CARDENAS JIMENEZ»,»VIANNEY PARRA NORIEGA»,»VICTOR HUGO TENORIO MARTINEZ»,»YADIRA CAROLANA MORALES SANCHEZ»,»JONATHAN»];
const validReferrers = listaNombresValidos.map(name => name.toUpperCase().trim());
// — Selectores de Elementos —
const inputsCalculo = document.querySelectorAll(‘.servicio-calculo’);
const totalDisplay = document.getElementById(‘total-display’);
const campoReferido = document.getElementById(‘referido’);
const textoDescuento = document.getElementById(‘descuento-texto’);
const radioAltaSatSi = document.getElementById(‘alta_sat_si’);
const radioAltaSatNo = document.getElementById(‘alta_sat_no’);
const grupoDeclaraciones = document.getElementById(‘grupo_declaraciones’);
const radioDeclaranSi = document.getElementById(‘declaran_si’);
const radioDeclaranNo = document.getElementById(‘declaran_no’);
const grupoAtraso = document.getElementById(‘grupo_atraso’);
const botonWhatsApp = document.getElementById(‘enviar-whatsapp’);
const botonInfo = document.getElementById(‘info-whatsapp’);
const telefono = «523329780881»;
// — FUNCIÓN DE CÁLCULO (CORREGIDA CON ID) —
function getCalculo() {
let total = 0;
let descuentoAplicado = false;
const nombreReferidoEstandarizado = campoReferido ? campoReferido.value.trim().toUpperCase() : «»;
const esReferidoValido = validReferrers.includes(nombreReferidoEstandarizado);
// — 1. Mensualidades —
const paqueteSeleccionado = document.querySelector(‘input[name=»paquete_iguala»]:checked’);
let precioPaquete = 0;
if (paqueteSeleccionado) {
precioPaquete = parseFloat(paqueteSeleccionado.dataset.precio) || 0;
const esMensualidad = paqueteSeleccionado.dataset.esMensualidad === ‘true’;
if (esMensualidad && esReferidoValido) {
precioPaquete *= 0.90;
descuentoAplicado = true;
}
}
total += precioPaquete;
// — 2. Servicios Recurrentes (Nómina) —
const nominaInput = document.getElementById(‘nomina’);
const nominaCantidad = nominaInput ? (parseInt(nominaInput.value) || 0) : 0;
if (nominaCantidad > 0) {
total += (parseFloat(nominaInput.dataset.precio) || 0) * nominaCantidad;
}
// — 3. Servicios Adicionales (Pago Único) —
const adicionales = document.querySelectorAll(‘#grupo-adicionales input[type=»checkbox»]’);
adicionales.forEach(input => {
if (input.checked) {
total += (parseFloat(input.dataset.precio) || 0);
}
});
return {
montoTotal: total,
descuentoFueAplicado: descuentoAplicado,
esReferidoValido: esReferidoValido
};
}
// — Función para ACTUALIZAR LA PANTALLA —
function actualizarDisplay() {
const calculo = getCalculo();
if (totalDisplay) {
totalDisplay.textContent = calculo.montoTotal.toLocaleString(‘en-US’, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
const totalContainer = document.querySelector(‘.total-container span’);
totalContainer.classList.add(‘total-actualizado’);
setTimeout(() => {
totalContainer.classList.remove(‘total-actualizado’);
}, 800);
}
if (textoDescuento) {
textoDescuento.style.display = calculo.descuentoFueAplicado ? ‘block’ : ‘none’;
}
}
// — Event Listeners para Recalcular —
inputsCalculo.forEach(input => {
input.addEventListener(‘change’, actualizarDisplay);
input.addEventListener(‘input’, actualizarDisplay);
});
// — Lógica Campos Condicionales —
function manejarVisibilidadCampos() {
if (radioAltaSatSi && grupoDeclaraciones && grupoAtraso && radioDeclaranNo && radioDeclaranSi) {
if (radioAltaSatSi.checked) {
grupoDeclaraciones.style.display = ‘block’;
if (radioDeclaranNo.checked) {
grupoAtraso.style.display = ‘block’;
} else {
grupoAtraso.style.display = ‘none’;
}
} else {
grupoDeclaraciones.style.display = ‘none’;
grupoAtraso.style.display = ‘none’;
}
}
}
if(radioAltaSatSi) radioAltaSatSi.addEventListener(‘change’, manejarVisibilidadCampos);
if(radioAltaSatNo) radioAltaSatNo.addEventListener(‘change’, manejarVisibilidadCampos);
if(radioDeclaranSi) radioDeclaranSi.addEventListener(‘change’, manejarVisibilidadCampos);
if(radioDeclaranNo) radioDeclaranNo.addEventListener(‘change’, manejarVisibilidadCampos);
// — Función para Generar Mensaje WhatsApp —
function generarMensaje() {
const nombreCliente = document.getElementById(‘nombre_cliente’)?.value.trim() || «Cliente»;
const giro = document.getElementById(‘giro’)?.value.trim() || «No especificado»;
const anios = document.getElementById(‘anios’)?.value.trim() || «No especificado»;
const altaSatRadio = document.querySelector(‘input[name=»alta_sat»]:checked’);
let infoSituacionFiscal = «Situación SAT no especificada.»;
if (altaSatRadio) {
if (altaSatRadio.value === ‘si’) {
infoSituacionFiscal = » Sí estoy dado de alta en el SAT.»;
const declaranRadio = document.querySelector(‘input[name=»declaran»]:checked’);
if (declaranRadio) {
if (declaranRadio.value === ‘si’) {
infoSituacionFiscal += » Actualmente declaro.»;
} else {
infoSituacionFiscal += » No declaro actualmente.»;
const mesesAtrasoInput = document.getElementById(‘meses_atraso’);
const mesesAtraso = mesesAtrasoInput ? mesesAtrasoInput.value.trim() : «»;
if (mesesAtraso && mesesAtraso !== «0») {
infoSituacionFiscal += ` Tengo aproximadamente ${mesesAtraso} meses de atraso.`;
}
}
} else {
infoSituacionFiscal += » (No especificó si declara actualmente)»;
}
} else {
infoSituacionFiscal = » No estoy dado de alta en el SAT.»;
}
}
const direccion = document.getElementById(‘direccion’)?.value.trim() || «No especificada»;
const diasVisita = document.getElementById(‘dias_visita’)?.value.trim() || «No especificados»;
let mensajeIntro = `¡Hola DAFIC! Soy ${nombreCliente}. `;
mensajeIntro += `El giro de mi negocio es ${giro}. `;
mensajeIntro += `Tengo ${anios} años con él.`;
mensajeIntro += infoSituacionFiscal;
mensajeIntro += ` Mi negocio está ubicado en ${direccion}.`;
mensajeIntro += ` Me gustaría que me visitaran preferentemente: ${diasVisita}.`;
const calculo = getCalculo();
const totalCalculado = calculo.montoTotal;
const descuentoAplicado = calculo.descuentoFueAplicado;
let hayMensualidad = false, hayRecurrentes = false, hayAdicionales = false, esRango = false;
const nombreReferido = campoReferido ? campoReferido.value.trim() : «»;
let resumenServicios = «»;
// Mensualidades (Texto)
const paqueteSeleccionado = document.querySelector(‘input[name=»paquete_iguala»]:checked’);
if (paqueteSeleccionado) {
let precioOriginal = parseFloat(paqueteSeleccionado.dataset.precio) || 0;
if (precioOriginal > 0) {
const label = document.querySelector(`label[for=’${paqueteSeleccionado.id}’]`);
const precioTextoElement = paqueteSeleccionado.closest(‘.servicio-item’)?.querySelector(‘.precio’);
const precioTexto = precioTextoElement ? precioTextoElement.textContent : «»;
let precioFinalTexto = «»;
let precioActual = precioOriginal;
if (descuentoAplicado) {
precioActual = precioOriginal * 0.90;
}
if (precioTexto.includes(‘-‘)) {
esRango = true;
precioFinalTexto = ` (Rango: ${precioTexto}`;
if (descuentoAplicado) {
precioFinalTexto += `, con 10% desc. ref. sobre mínimo)`;
} else {
precioFinalTexto += `)`;
}
} else {
precioFinalTexto = ` ($${precioActual.toFixed(2)}`;
if (descuentoAplicado) {
precioFinalTexto += `, precio original $${precioOriginal.toFixed(2)})`;
} else {
precioFinalTexto += `)`;
}
}
resumenServicios += `- Mensualidad: ${label ? label.textContent : ‘Paquete seleccionado’}${precioFinalTexto}\n`;
hayMensualidad = true;
}
}
// Recurrentes (Texto)
const nominaInput = document.getElementById(‘nomina’);
const nominaCantidad = nominaInput ? (parseInt(nominaInput.value) || 0) : 0;
if (nominaCantidad > 0) {
const precio = parseFloat(nominaInput.dataset.precio) || 0;
const subtotal = precio * nominaCantidad;
resumenServicios += `- Empleados en Nómina: ${nominaCantidad} ($${subtotal.toFixed(2)})\n`;
hayRecurrentes = true;
}
// Adicionales (Texto)
const adicionales = document.querySelectorAll(‘#grupo-adicionales input[type=»checkbox»]’);
adicionales.forEach(input => {
if (input.checked) {
hayAdicionales = true;
const precio = parseFloat(input.dataset.precio) || 0;
const label = document.querySelector(`label[for=’${input.id}’]`);
if (precio > 0) {
resumenServicios += `- Adicional: ${label ? label.textContent : ‘Servicio adicional’} ($${precio.toFixed(2)})\n`;
} else {
resumenServicios += `- Adicional: ${label ? label.textContent : ‘Servicio adicional’} (Cobro bajo %)\n`;
}
}
});
if (!hayMensualidad && !hayRecurrentes && !hayAdicionales) {
resumenServicios = «(No se seleccionaron servicios específicos)\n»;
}
// Construir mensaje final
let mensajeFinal = `${mensajeIntro}\n\nEstoy interesado/a en los siguientes servicios:\n${resumenServicios}`;
mensajeFinal += `\n———————–\n`;
const totalFormateado = totalCalculado.toLocaleString(‘en-US’, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
if (esRango) {
mensajeFinal += `*TOTAL MÍNIMO ESTIMADO: $${totalFormateado} MXN*\n(El paquete a cotizar se definirá dentro del rango)\n`;
} else {
mensajeFinal += `*TOTAL ESTIMADO: $${totalFormateado} MXN*\n`;
}
if (nombreReferido.length > 0) {
mensajeFinal += `\n*Referido por: ${nombreReferido}*\n`;
if (descuentoAplicado) {
mensajeFinal += `(¡Descuento del 10% para ambos aplicado en 1ra mensualidad!)\n`;
}
}
if (hayMensualidad && paqueteSeleccionado && !paqueteSeleccionado.id.includes(‘asesoria_inicial’)) {
mensajeFinal += `(Total incluye consultas ilimitadas)\n`;
}
mensajeFinal += `\n*Todos los precios mostrados incluyen IVA.*\n(Sujeto a revisión y confirmación)`;
return { mensaje: mensajeFinal };
}
// — Event Listeners Botones —
if(botonWhatsApp) {
botonWhatsApp.addEventListener(‘click’, (e) => {
e.preventDefault();
try {
const { mensaje } = generarMensaje();
const mensajeCodificado = encodeURIComponent(mensaje);
const url = `https://wa.me/${telefono}?text=${mensajeCodificado}`;
window.open(url, ‘_blank’);
} catch (error) {
console.error(«Error al generar o enviar mensaje de cotización:», error);
alert(«Hubo un error al intentar enviar la cotización. Revisa la consola (F12) para más detalles.»);
}
});
}
if(botonInfo) {
botonInfo.addEventListener(‘click’, (e) => {
e.preventDefault();
try {
const mensaje = «¡Hola DAFIC! Saludos. Me gustaría pedir más información sobre sus servicios.»;
const mensajeCodificado = encodeURIComponent(mensaje);
const url = `https://wa.me/${telefono}?text=${mensajeCodificado}`;
window.open(url, ‘_blank’);
} catch (error) {
console.error(«Error al enviar mensaje de información:», error);
alert(«Hubo un error al intentar contactar. Revisa la consola (F12) para más detalles.»);
}
});
}
// — Carga Inicial —
actualizarDisplay();
manejarVisibilidadCampos();
});