Files
romfast-website/efactura-generator/js/validation/cif.js
Claude Agent 85ccdae2cb sync efactura-generator -> 0.9-beta-14
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>
2026-05-05 13:02:16 +00:00

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: '' };
}