/** * Script de validación directa para campos de DNI/documento * Versión: 1.0.1 */ // Iniciar cuando el DOM esté cargado document.addEventListener('DOMContentLoaded', inicializarValidador); // También intentar inicializar después de que la página esté completamente cargada window.addEventListener('load', inicializarValidador); // Definir variable global para controlar inicialización window.dniValidatorInitialized = window.dniValidatorInitialized || false; /** * Inicializa el validador de documentos */ function inicializarValidador() { // Evitar inicializar múltiples veces if (window.dniValidatorInitialized) return; console.log("Iniciando validador de documentos..."); // Inicializar la validación para los campos específicos const campos = [ document.getElementById('delivery_dni'), document.getElementById('field-dni'), ...Array.from(document.getElementsByName('dni')), ...Array.from(document.querySelectorAll('[data-validation*="isDniLite"]')) ].filter(campo => campo !== null); // Si no encontramos ningún campo, intentar una búsqueda más amplia if (campos.length === 0) { console.log("No se encontraron campos de DNI con los selectores principales. Buscando alternativas..."); // Buscar campos por sus atributos const camposAdicionales = [ ...Array.from(document.querySelectorAll('input[placeholder*="Identificaci"]')), ...Array.from(document.querySelectorAll('input[placeholder*="DNI"]')), ...Array.from(document.querySelectorAll('input[id*="dni"]')), ...Array.from(document.querySelectorAll('input[id*="DNI"]')), ...Array.from(document.querySelectorAll('input[name*="dni"]')), ...Array.from(document.querySelectorAll('input[name*="DNI"]')) ].filter(campo => campo !== null); campos.push(...camposAdicionales); } // Eliminar duplicados const camposUnicos = Array.from(new Set(campos)); console.log(`Se encontraron ${camposUnicos.length} campos para validar:`, camposUnicos); if (camposUnicos.length > 0) { camposUnicos.forEach(configurarCampoDNI); window.dniValidatorInitialized = true; // Configurar también la validación para campos que puedan cargarse dinámicamente configurarObservadorMutaciones(); // Integración con el sistema de validación existente if (window.$ && window.$.formUtils) { window.$.formUtils.addValidator({ name: 'isDniLite', validatorFunction: function(value) { return validarDocumento(value).valido; }, errorMessage: 'Documento de identidad no válido', errorMessageKey: 'badDNI' }); console.log("Integración con jQuery Form Validator completada"); } } else { console.log("No se encontraron campos de DNI/documento en la página actual"); } } /** * Configura un observador de mutaciones para detectar cambios en el DOM * y aplicar la validación a nuevos campos que puedan aparecer */ function configurarObservadorMutaciones() { // Crear un observador de mutaciones const observer = new MutationObserver((mutations) => { let newNodes = false; // Revisar si se han añadido nuevos nodos mutations.forEach(mutation => { if (mutation.addedNodes.length) { newNodes = true; } }); // Si hay nuevos nodos, buscar campos de DNI if (newNodes) { const nuevosCampos = [ ...Array.from(document.querySelectorAll('#delivery_dni:not([data-dni-validator])')), ...Array.from(document.querySelectorAll('#field-dni:not([data-dni-validator])')), ...Array.from(document.querySelectorAll('input[name="dni"]:not([data-dni-validator])')), ...Array.from(document.querySelectorAll('[data-validation*="isDniLite"]:not([data-dni-validator])')) ].filter(campo => campo !== null); if (nuevosCampos.length > 0) { console.log(`Se encontraron ${nuevosCampos.length} nuevos campos para validar`); nuevosCampos.forEach(configurarCampoDNI); } } }); // Iniciar la observación observer.observe(document.body, { childList: true, subtree: true }); console.log("Observador de mutaciones configurado para detectar nuevos campos"); } /** * Configura un campo de DNI con los eventos necesarios */ function configurarCampoDNI(campo) { // Marcar el campo como configurado campo.setAttribute('data-dni-validator', 'true'); console.log("Configurando campo:", campo.id || campo.name || "sin id/nombre"); // Validar al perder el foco campo.addEventListener('blur', function() { const resultado = validarDocumento(this.value); console.log("Resultado validación:", resultado); mostrarResultadoValidacion(this, resultado); }); // Convertir a mayúsculas durante la escritura campo.addEventListener('input', function() { if (/[a-zA-Z]/.test(this.value)) { const start = this.selectionStart; const end = this.selectionEnd; this.value = this.value.toUpperCase(); this.setSelectionRange(start, end); } }); // Configurar validación en el formulario const form = campo.closest('form'); if (form && !form.hasAttribute('data-dni-validator')) { form.setAttribute('data-dni-validator', 'true'); form.addEventListener('submit', function(e) { // Validar todos los campos de documento en este formulario const camposDNI = form.querySelectorAll('[data-dni-validator]'); let formValido = true; camposDNI.forEach(campoDNI => { // Solo validar campos visibles if (campoDNI.offsetParent !== null) { const resultado = validarDocumento(campoDNI.value); if (!resultado.valido) { formValido = false; e.preventDefault(); mostrarResultadoValidacion(campoDNI, resultado); campoDNI.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } }); return formValido; }); } // Añadir icono de información si es necesario // (Comentado para evitar posibles problemas de diseño) /* if (!campo.nextElementSibling || !campo.nextElementSibling.classList.contains('info-icon')) { const infoIcon = document.createElement('span'); infoIcon.className = 'info-icon'; infoIcon.innerHTML = ''; infoIcon.title = 'Ver formatos aceptados'; campo.insertAdjacentElement('afterend', infoIcon); infoIcon.addEventListener('click', function() { alert('Documentos aceptados:\\n\n' + '• Personas físicas (España):\n' + ' - DNI: 12345678Z\n' + ' - NIE: X1234567L\n' + ' - Pasaporte: AAA000000\n\n' + '• Empresas:\n' + ' - CIF español: B70915004\n' + ' - VAT europeo: ESB70915004, FR12345678901\n\n' + '• Otros países:\n' + ' - Portugal, Italia, Francia, Reino Unido, etc.'); }); } */ // Validación inicial const resultado = validarDocumento(campo.value); if (campo.value) { mostrarResultadoValidacion(campo, resultado); } } /** * Muestra el resultado de la validación */ function mostrarResultadoValidacion(inputElement, resultado) { // Crear ID único para el mensaje const mensajeId = (inputElement.id ? inputElement.id : 'dni') + '-validation-message'; // Buscar o crear elemento para mensajes let mensajeElement = document.getElementById(mensajeId); if (!mensajeElement) { mensajeElement = document.createElement('div'); mensajeElement.id = mensajeId; mensajeElement.style.fontSize = '12px'; mensajeElement.style.marginTop = '5px'; mensajeElement.style.marginBottom = '5px'; // Insertar después del campo o su contenedor más cercano if (inputElement.parentNode) { inputElement.parentNode.appendChild(mensajeElement); } } // Actualizar mensaje según resultado if (!resultado.valido) { // DNI incompleto if (resultado.tipo === 'DNI_incompleto') { mensajeElement.textContent = resultado.mensaje || 'DNI incompleto. Añade la letra.'; // Calcular letra correcta if (/^\d{8}$/.test(inputElement.value.trim())) { const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(inputElement.value.trim()) % 23); mensajeElement.textContent += ' La letra correcta es: ' + letraCalculada; } } // DNI con letra incorrecta else if (resultado.tipo === 'DNI_letra_incorrecta') { const numero = inputElement.value.trim().substring(0, 8); const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numero) % 23); mensajeElement.textContent = 'La letra del DNI no es correcta. Debería ser: ' + letraCalculada; } // NIE con letra incorrecta else if (resultado.tipo === 'NIE_letra_incorrecta') { const valor = inputElement.value.trim().toUpperCase(); const primera = valor.charAt(0); const numero = valor.substring(1, 8); let numeroCompleto; switch (primera) { case 'X': numeroCompleto = '0' + numero; break; case 'Y': numeroCompleto = '1' + numero; break; case 'Z': numeroCompleto = '2' + numero; break; } const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numeroCompleto) % 23); mensajeElement.textContent = 'La letra del NIE no es correcta. Debería ser: ' + letraCalculada; } // Formato similar a un DNI pero incorrecto else if (resultado.tipo === 'formato_similar_dni') { mensajeElement.textContent = 'Formato similar a un DNI/NIE pero incorrecto. Verifica el documento.'; } // Otros errores else { mensajeElement.textContent = 'Documento no válido. Verifica el formato.'; } // Aplicar estilos para errores mensajeElement.style.color = '#d9534f'; // Rojo inputElement.style.borderColor = '#d9534f'; // Añadir clases de error según el tema de PrestaShop inputElement.classList.add('is-invalid'); inputElement.classList.remove('valid'); inputElement.classList.add('error'); } else { // Documento válido let tipoDocumento = getTipoDocumentoNombre(resultado.tipo); mensajeElement.textContent = 'Documento válido: ' + tipoDocumento; mensajeElement.style.color = '#5cb85c'; // Verde inputElement.style.borderColor = '#5cb85c'; // Añadir clases de validez según el tema de PrestaShop inputElement.classList.remove('is-invalid', 'error'); inputElement.classList.add('is-valid', 'valid'); } } /** * Validar documento de identidad */ function validarDocumento(value) { if (!value) return { valido: false, tipo: 'desconocido' }; value = value.trim().toUpperCase(); // Caso especial: DNI incompleto (8 dígitos) if (/^\d{8}$/.test(value)) { return { valido: false, tipo: 'DNI_incompleto', mensaje: 'Parece un DNI español sin letra. Añade la letra correcta.' }; } // Validar CIF de empresa española if (validarCIF(value)) { return { valido: true, tipo: 'CIF_ESP' }; } // Validar VAT europeo if (validarVAT(value)) { return { valido: true, tipo: 'VAT_EU' }; } // Caso especial: formato similar a DNI (7 dígitos + 1 letra) if (/^\d{7}[A-Z]$/.test(value)) { return { valido: false, tipo: 'formato_similar_dni', mensaje: 'Formato similar a un DNI pero incorrecto (7 dígitos + letra).' }; } // Validar DNI español if (validarDNI(value)) { return { valido: true, tipo: 'DNI_ESP' }; } else if (/^\d{8}[A-Z]$/.test(value)) { // DNI con letra incorrecta return { valido: false, tipo: 'DNI_letra_incorrecta', mensaje: 'La letra del DNI no es correcta.' }; } // Validar NIE if (validarNIE(value)) { return { valido: true, tipo: 'NIE_ESP' }; } else if (/^[XYZ]\d{7}[A-Z]$/.test(value)) { // NIE con letra incorrecta return { valido: false, tipo: 'NIE_letra_incorrecta', mensaje: 'La letra del NIE no es correcta.' }; } // Validar pasaporte español if (validarPasaporteEspanol(value)) { return { valido: true, tipo: 'pasaporte_ESP' }; } // Validar NIF Portugal if (validarNIFPortugal(value)) { return { valido: true, tipo: 'NIF_PT' }; } // Validar Codice Fiscale Italia if (validarCodiceFiscaleItalia(value)) { return { valido: true, tipo: 'CF_IT' }; } // Validar Carte Nationale d'Identité Francia if (validarCNIFrancia(value)) { return { valido: true, tipo: 'CNI_FR' }; } // Validar National Insurance Number UK if (validarNINOReinoUnido(value)) { return { valido: true, tipo: 'NINO_UK' }; } // Validar pasaporte extranjero if (validarPasaporteExtranjero(value)) { return { valido: true, tipo: 'pasaporte_extranjero' }; } return { valido: false, tipo: 'desconocido' }; } // Resto de funciones (validaciones específicas) /** * Validar DNI español */ function validarDNI(dni) { dni = dni.toUpperCase(); const dniRegex = /^(\d{8})([A-Z])$/; if (!dniRegex.test(dni)) return false; const match = dni.match(dniRegex); const numero = match[1]; const letra = match[2]; // Calcular letra correcta const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numero) % 23); return letra === letraCalculada; } /** * Validar NIE */ function validarNIE(nie) { nie = nie.toUpperCase(); const nieRegex = /^([XYZ])(\d{7})([A-Z])$/; if (!nieRegex.test(nie)) return false; const match = nie.match(nieRegex); const primera = match[1]; const numero = match[2]; const letra = match[3]; // Reemplazar la primera letra con su equivalente numérico let numeroCompleto; switch (primera) { case 'X': numeroCompleto = '0' + numero; break; case 'Y': numeroCompleto = '1' + numero; break; case 'Z': numeroCompleto = '2' + numero; break; } // Calcular letra correcta const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numeroCompleto) % 23); return letra === letraCalculada; } /** * Validar CIF español */ function validarCIF(cif) { cif = cif.toUpperCase(); // Si es un VAT español, quitar el prefijo ES if (/^ES[A-Z0-9]{9}$/.test(cif)) { cif = cif.substring(2); } // Comprobar formato del CIF const cifRegex = /^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/; if (!cifRegex.test(cif)) return false; const match = cif.match(cifRegex); const letra = match[1]; const numero = match[2]; const control = match[3]; // Calcular dígito de control let suma = 0; // Suma dígitos pares for (let i = 1; i < 7; i += 2) { suma += parseInt(numero.charAt(i)); } // Suma dígitos impares (multiplicados por 2) for (let i = 0; i < 7; i += 2) { let temp = parseInt(numero.charAt(i)) * 2; if (temp > 9) { temp = Math.floor(temp/10) + (temp % 10); } suma += temp; } // Calcular el dígito de control let controlCalculado = (10 - (suma % 10)) % 10; // Para ciertos tipos de entidades, el control es numérico const letrasCifNumero = 'ABCDEFGHJUV'; if (letrasCifNumero.indexOf(letra) >= 0) { return controlCalculado.toString() === control; } else { // Para el resto, el control es una letra const letrasControl = 'JABCDEFGHI'; return letrasControl.charAt(controlCalculado) === control; } } /** * Validar VAT europeo */ function validarVAT(vat) { vat = vat.toUpperCase(); // España (ESB12345678) if (/^ES[A-Z0-9]{9}$/.test(vat)) { return validarCIF(vat.substring(2)); } // Portugal (PT123456789) if (/^PT\d{9}$/.test(vat)) { return validarNIFPortugal(vat.substring(2)); } // Francia (FR12345678901) if (/^FR[A-Z0-9]{11}$/.test(vat)) { return true; // Validación simplificada } // Italia (IT12345678901) if (/^IT\d{11}$/.test(vat)) { return true; // Validación simplificada } // Reino Unido (GB123456789, GB123456789012) if (/^GB(\d{9}|\d{12})$/.test(vat)) { return true; // Validación simplificada } // Alemania (DE123456789) if (/^DE\d{9}$/.test(vat)) { return true; // Validación simplificada } return false; } /** * Validar pasaporte español */ function validarPasaporteEspanol(pasaporte) { pasaporte = pasaporte.toUpperCase(); const pasaporteRegex = /^[A-Z]{3}\d{6}$/; return pasaporteRegex.test(pasaporte); } /** * Validar NIF Portugal */ function validarNIFPortugal(nif) { const nifRegex = /^(\d{9})$/; if (!nifRegex.test(nif)) return false; // Algoritmo de validación const numero = nif.substring(0, 8); const control = parseInt(nif.charAt(8), 10); let suma = 0; for (let i = 0; i < 8; i++) { suma += parseInt(numero.charAt(i)) * (9 - i); } let resto = suma % 11; let checkDigit; if (resto === 0 || resto === 1) { checkDigit = 0; } else { checkDigit = 11 - resto; } return control === checkDigit; } /** * Validar Codice Fiscale Italia */ function validarCodiceFiscaleItalia(cf) { cf = cf.toUpperCase(); const cfRegex = /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/; return cfRegex.test(cf); } /** * Validar Carte Nationale d'Identité Francia */ function validarCNIFrancia(cni) { const cniRegex = /^\d{12}$/; return cniRegex.test(cni); } /** * Validar National Insurance Number UK */ function validarNINOReinoUnido(nino) { nino = nino.toUpperCase(); const ninoRegex = /^[A-CEGHJ-PR-TW-Z][A-CEGHJ-NPR-TW-Z]\d{6}[A-D]$/; return ninoRegex.test(nino); } /** * Validar pasaporte extranjero */ function validarPasaporteExtranjero(pasaporte) { pasaporte = pasaporte.toUpperCase(); // 1. Longitud 7-9 caracteres if (pasaporte.length < 7 || pasaporte.length > 9) return false; // 2. Patrón alfanumérico const pasaporteExtRegex = /^[A-Z0-9]{7,9}$/; if (!pasaporteExtRegex.test(pasaporte)) return false; // 3. No confundir con DNI y formatos similares if (/^\d{8}$/.test(pasaporte)) return false; if (/^\d{7}[A-Z]$/.test(pasaporte)) return false; if (/^\d{8}[A-Z]$/.test(pasaporte)) return false; // 4. No confundir con NIE o CIF if (/^[A-Z]\d{7}[A-Z]$/.test(pasaporte)) { // Si primera letra es X, Y, Z (NIE) o letras de CIF const primeraLetra = pasaporte.charAt(0); if ('XYZ'.includes(primeraLetra)) return false; if ('ABCDEFGHJKLMNPQRSUVW'.includes(primeraLetra) && validarCIF(pasaporte)) return false; } // 5. Otros casos especiales if (/^\d{9}$/.test(pasaporte)) { const primeros8 = pasaporte.substring(0, 8); if (/^[0-7]\d{7}$/.test(primeros8)) return false; } return true; } /** * Obtener nombre descriptivo del tipo de documento */ function getTipoDocumentoNombre(tipo) { switch(tipo) { case 'DNI_ESP': return 'DNI español'; case 'NIE_ESP': return 'NIE'; case 'pasaporte_ESP': return 'Pasaporte español'; case 'CIF_ESP': return 'CIF de empresa española'; case 'VAT_EU': return 'VAT Number europeo'; case 'NIF_PT': return 'NIF portugués'; case 'CF_IT': return 'Codice Fiscale italiano'; case 'CNI_FR': return 'Carte d\'identité francesa'; case 'NINO_UK': return 'National Insurance Number británico'; case 'pasaporte_extranjero': return 'Pasaporte extranjero'; default: return 'Documento válido'; } } // Iniciar validador en caso de que el evento DOMContentLoaded ya haya ocurrido if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(inicializarValidador, 1); }

Los más vendidos

Aceite KOMPLEX Aceite KOMPLEX 2
  • Nuevo
Consultar entrega.
Accesorios

Aceite KOMPLEX

Komplex
40102
4,50 €
Aceite de KOMPLEX para rodamientos. Botella de 10 ml. de capacidad, dosificador y con tapa de seguridad.
Suspensiones KOMPLEX Silver 016 Suspensiones KOMPLEX Silver 016 2
  • Nuevo
Consultar entrega.
Artístico

Suspensiones KOMPLEX Silver 016

Komplex
40051
19,00 €
Las suspensión de KOMPLEX garantizan una excelente estabilidad con buena respuesta elástica. El juego de suspensiones está formado por 4 suspensiones inferiores y 4 superiores. La 1ª opción es para un peso inferior a 30 kg. La 2ª es de 30 hasta 55 kg. La 3ª es de 55 hasta 70 kg. La 4ª a partir de 70 kg.
Juego de ruedas KOMPLEX FELIX  Ø57
  • Nuevo
Consultar entrega.
Caja 8 Ruedas

Juego de ruedas KOMPLEX FELIX Ø57

Komplex
40012
23,50 €
Caja con 8 ruedas. Ruedas FELIX 52 para principiantes o nivel medio. Moldeado por inyección en poliuretano. Superficie: madera y cemento liso. Dureza: HD 52. Diámetro: 57 mm.
Plancha KOMPLEX NEXT Plancha KOMPLEX NEXT 2
  • Nuevo
Consultar entrega.
Planchas Artístico

Plancha KOMPLEX NEXT

Komplex
40003
122,00 €
Komplex Next, patín indicado para patinaje artístico y hockey en nivel de iniciación a la competición. Estructura de aluminio con cruces de aluminio y acero Suspensiones disponibles en dos durezas diferentes La talla ESTÁNDAR se utiliza sólo para patines completos.
Juego de ruedas KOMPLEX IRIS  Ø57 Juego de ruedas KOMPLEX IRIS  Ø57 2
  • Nuevo
Consultar entrega.
Caja 8 Ruedas

Juego de ruedas KOMPLEX IRIS Ø57

Komplex
40011
20,00 €
Caja con 8 ruedas. Rueda IRIS diseñada para principiantes. Superficie: madera y cemento liso. Dureza:HD 52/53. Diámetro: 57 mm.
Plancha KOMPLEX SILVER 016
  • Nuevo
Consultar entrega.
Planchas Artístico

Plancha KOMPLEX SILVER 016

Komplex
40002
185,00 €
Komplex Silver 016, patín de nivel semiprofesional indicado para patinaje artístico y hockey. La talla ESTÁNDAR se utiliza sólo para patines completos.
Ruedas sueltas KOMPLEX BOLERO Ruedas sueltas KOMPLEX BOLERO 2
  • Nuevo
Consultar entrega.
Caja 8 Ruedas

Ruedas sueltas KOMPLEX BOLERO

Komplex
40021.1
7,25 €
Ruedas Bi-Component con formidable Grip y muy buena suavidad para Patinadores de Grupos de Danza y Show, expresamente diseñadas para superficies extremadamente resbaladizas. Diámetro de 63 mm. y perfil medio. Durezas: HD 38: Parquet, madera muy resbaladiza. HD 40: Parquet, madera muy resbaladiza. HD 43: Parquet, madera resbaladiza, cemento...
Frenos KOMPLEX AVANA Frenos KOMPLEX AVANA 2
  • Nuevo
Consultar entrega.
En Línea

Frenos KOMPLEX AVANA

Komplex
40033
21,00 €
Set de dos frenos modelo AVANA fabricados en goma natural. El freno ofrece una buena respuesta elástica, un buen agarre y una óptima duración. Tornillo forrado en aluminio de alta resistencia. Diseño especialmente estudiado para aumentar la superficie de apoyo. Consumo: 3,5 Agarre: 3,5 Elasticidad: 3
Ruedas sueltas KOMPLEX TANGO Ø63 Ruedas sueltas KOMPLEX TANGO Ø63 2
  • Nuevo
Consultar entrega.
Ruedas Sueltas

Ruedas sueltas KOMPLEX TANGO Ø63

Komplex
40023.1
9,60 €
Ruedas Tango de Komplex: Excelencia en Patinaje Artístico Excelencia en Patinaje Artístico Explora las ruedas Tango de Komplex, perfectas para patinadores artísticos que buscan el mejor rendimiento. Disponibles en diferentes niveles de dureza, estas ruedas están diseñadas para proporcionar un excelente agarre y...
Frenos KOMPLEX BLACK Frenos KOMPLEX BLACK 2
  • Nuevo
Consultar entrega.
En Línea

Frenos KOMPLEX BLACK

Komplex
40034
21,00 €
Freno de excepcional respuesta elástica. Óptima capacidad de resistencia a la abrasión. Testado y utilizado por los mejores atletas de patinaje del mundo. Consumo: 3 Agarre: 4,5 Elasticidad: 4
Rodamientos KOMPLEX ABEC 5 PRO
  • Nuevo
Consultar entrega.
Artístico

Rodamientos KOMPLEX ABEC 5 PRO

Komplex
40044
37,00 €
Rodamientos Komplex ABEC 5 PRO fabricados en acero blindado para patinaje artístico de competición. Cerramiento de una tapa removible en Fibra de Carbono. Lubricados con aceite, de alta suavidad. Rodamientos de alta precisión de 7 Esferas interiores. Juego de 16 rodamientos.
Product added to wishlist
Product added to compare.