Mirror sincronizat cu repo canonic /workspace/efactura-generator. CLAUDE.md: documentat workflow sync + exclude config.json din rsync deploy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
72 lines
2.4 KiB
JavaScript
72 lines
2.4 KiB
JavaScript
/**
|
|
* js/validation/cif.js — PR-VALID-IDS (A9)
|
|
* Validare CIF/CUI românesc prin sumă ponderată (mod 11, mod 10).
|
|
* Funcție pură, fără efecte secundare, fără dependențe externe.
|
|
*/
|
|
|
|
// Greutățile pentru cifrele 1-9 (se aplică pe primele 9 cifre ale CIF-ului).
|
|
const WEIGHTS = [7, 5, 3, 2, 1, 7, 5, 3, 2];
|
|
|
|
/**
|
|
* Validează un CIF/CUI românesc.
|
|
*
|
|
* Algoritm:
|
|
* 1. Elimină prefixul "RO" dacă există (case-insensitive).
|
|
* 2. Elimină spații.
|
|
* 3. Verifică că are între 2 și 10 cifre.
|
|
* 4. Completează cu zerouri la stânga până la 10 cifre.
|
|
* 5. Calculează suma ponderată pe primele 9 cifre cu WEIGHTS.
|
|
* 6. (sumă * 10) % 11 % 10 trebuie să fie egal cu cifra de control (ultima).
|
|
*
|
|
* @param {string} value — valoarea brută din câmp (poate fi goală, poate conține "RO")
|
|
* @returns {{ valid: boolean, message: string }}
|
|
*/
|
|
export function validateCIF(value) {
|
|
if (!value || value.trim() === '') {
|
|
return { valid: true, message: '' }; // câmp gol — valid (nu e required check)
|
|
}
|
|
|
|
let normalized = value.trim().toUpperCase();
|
|
|
|
// Elimină prefixul RO
|
|
if (normalized.startsWith('RO')) {
|
|
normalized = normalized.slice(2).trim();
|
|
}
|
|
|
|
// Elimină spații și cratime rămase
|
|
normalized = normalized.replace(/[\s\-]/g, '');
|
|
|
|
// Trebuie să conțină doar cifre
|
|
if (!/^\d+$/.test(normalized)) {
|
|
return { valid: false, message: 'CIF invalid: conține caractere nepermise' };
|
|
}
|
|
|
|
// Lungime: minim 2, maxim 10 cifre
|
|
if (normalized.length < 2 || normalized.length > 10) {
|
|
return { valid: false, message: 'CIF invalid: lungimea trebuie să fie între 2 și 10 cifre' };
|
|
}
|
|
|
|
// Completează cu zerouri la stânga până la 10 cifre
|
|
const padded = normalized.padStart(10, '0');
|
|
|
|
// Extrage primele 9 cifre (pentru ponderare) și cifra de control (ultima)
|
|
const digits = padded.split('').map(Number);
|
|
const checkDigit = digits[9];
|
|
const controlDigits = digits.slice(0, 9);
|
|
|
|
// Calculează suma ponderată
|
|
let sum = 0;
|
|
for (let i = 0; i < 9; i++) {
|
|
sum += controlDigits[i] * WEIGHTS[i];
|
|
}
|
|
|
|
// Cifra de control calculată
|
|
const computed = (sum * 10) % 11 % 10;
|
|
|
|
if (computed !== checkDigit) {
|
|
return { valid: false, message: 'CIF invalid: cifra de control nu se potrivește' };
|
|
}
|
|
|
|
return { valid: true, message: '' };
|
|
}
|