import { ValidacionFiscalException } from '../exceptions/ValidacionFiscalException.js'; /** * Value Object para el Número de Identificación Tributaria (NIT) en Colombia * Incluye algoritmo de Módulo 11 oficial de la DIAN para cálculo y verificación del DV. */ export class Nit { private readonly _numero: string; private readonly _dv: string; private static readonly PRIMOS_DIAN = [3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71]; constructor(numero: string, dv?: string) { const cleanNumber = numero.replace(/\D/g, ''); if (!cleanNumber || cleanNumber.length < 5 || cleanNumber.length > 15) { throw new ValidacionFiscalException(`El NIT suministrado "${numero}" no es válido. Debe contener entre 5 y 15 dígitos.`); } this._numero = cleanNumber; const computedDv = Nit.calcularDigitoVerificacion(cleanNumber); if (dv !== undefined && dv !== null && dv !== '') { const cleanDv = dv.toString().trim(); if (cleanDv !== computedDv) { throw new ValidacionFiscalException( `Dígito de verificación inválido para el NIT ${cleanNumber}. Calculado: ${computedDv}, Proporcionado: ${cleanDv}` ); } this._dv = cleanDv; } else { this._dv = computedDv; } } public static calcularDigitoVerificacion(nitLimpio: string): string { let suma = 0; const len = nitLimpio.length; for (let i = 0; i < len; i++) { const digito = parseInt(nitLimpio.charAt(len - 1 - i), 10); suma += digito * Nit.PRIMOS_DIAN[i]; } const residuo = suma % 11; if (residuo === 0 || residuo === 1) { return residuo.toString(); } return (11 - residuo).toString(); } public get numero(): string { return this._numero; } public get dv(): string { return this._dv; } public get nitCompleto(): string { return `${this._numero}-${this._dv}`; } public toString(): string { return this.nitCompleto; } public equals(otro: Nit): boolean { return this._numero === otro._numero && this._dv === otro._dv; } }