@pholguinc/sunat-validators
v1.0.1
Published
Validadores para SUNAT Perú (RUC, DNI, nombre de archivo, estructura XML) usando Zod
Readme
@pholguinc/sunat-validators
Librería completa de validadores para facturación electrónica SUNAT Perú usando Zod. Incluye validación de RUC/DNI, nombres de archivo, estructura XML UBL 2.1, catálogos tributarios y cálculo de impuestos.
Instalación
npm install @pholguinc/sunat-validators zod
# o
bun add @pholguinc/sunat-validators zod
zodes una peer dependency — debes instalarlo junto al paquete.
Características
| Módulo | Descripción | |---|---| | RUC / DNI | Validación con dígito verificador oficial SUNAT | | Nombre de archivo | Parseo y validación de nombres ZIP/XML según convención SUNAT | | Estructura XML | Validador UBL 2.1 con +800 códigos de error oficiales | | Catálogo 05 | Tributos: IGV, IVAP, ISC, ICBPER, Exportación, Exonerado, Inafecto | | Catálogo 06 | 11 tipos de documentos de identidad soportados | | Catálogo 07 | Afectación IGV: todos los códigos (10–40) | | Cálculo impuestos | IGV (18%), IVAP (4%), ISC, ICBPER (S/ 0.50) con redondeo bancario | | UN/ECE | Códigos 5153 (tipo tributo) y 5305 (categoría tributo) | | Números a letras | Función oficial de monto a texto con soporte PEN, USD, EUR | | Tipo de cambio | Conversión USD ↔ PEN aplicando redondeo oficial SUNAT |
Uso
Validar RUC
import { rucSchema } from "@pholguinc/sunat-validators";
const ruc = rucSchema.parse("20100070970");
const result = rucSchema.safeParse("99999999999");
if (!result.success) {
console.error(result.error.issues[0].message);
}Validar nombre de archivo SUNAT
import {
parsearNombreArchivo,
nombreArchivoXmlSchema,
nombreArchivoZipSchema,
} from "@pholguinc/sunat-validators";
// Parsear y validar
const info = parsearNombreArchivo("20123456789-01-F001-00000001.xml");
// → { tipo: "cpe", ruc: "20123456789", tipoDocumento: "01", serie: "F001", ... }
// Con Zod schema
const result = nombreArchivoXmlSchema.safeParse("20123456789-01-F001-00000001.xml");Validar estructura XML (UBL 2.1)
import { validarXml } from "@pholguinc/sunat-validators";
const xmlString = fs.readFileSync("factura.xml", "utf-8");
const resultado = validarXml(xmlString);
if (!resultado.valido) {
for (const error of resultado.errores) {
console.log(`[${error.codigo}] ${error.mensaje}`);
// → [2075] El XML no contiene el tag UBLVersionID
}
}Catálogos SUNAT
import {
CATALOGO_05_TRIBUTOS,
CATALOGO_06_DOCUMENTOS_IDENTIDAD,
CATALOGO_07_AFECTACION_IGV,
codigoTributoSchema,
codigoAfectacionIGVSchema,
validarDocumentoIdentidad,
} from "@pholguinc/sunat-validators";
// Validar tipo de tributo
codigoTributoSchema.parse("1000"); // IGV
// Validar documento de identidad
const res = validarDocumentoIdentidad("1", "12345678"); // DNI
// → { valido: true, errores: [] }
// Consultar catálogo
const igv = CATALOGO_05_TRIBUTOS["1000"];
// → { nombre: "IGV", tasa: 0.18, codigoUNECE_5153: "VAT", codigoUNECE_5305: "S" }Cálculo de impuestos
import {
calcularImpuestoItem,
redondeoSunat,
obtenerCodigosUNECE,
} from "@pholguinc/sunat-validators";
// Calcular IGV de un ítem
const resultado = calcularImpuestoItem({
cantidad: 10,
valorUnitario: 100,
codigoAfectacionIGV: "10", // Gravado
});
// → { valorVenta: 1000, montoIGV: 180, precioVenta: 1180, ... }
// IVAP (arroz pilado)
const arroz = calcularImpuestoItem({
cantidad: 50,
valorUnitario: 2.50,
codigoAfectacionIGV: "17", // IVAP 4%
});
// Con ICBPER (bolsas de plástico)
const conBolsas = calcularImpuestoItem({
cantidad: 3,
valorUnitario: 10,
codigoAfectacionIGV: "10",
cantidadBolsas: 3, // S/ 0.50 por bolsa
});
// Redondeo bancario SUNAT
redondeoSunat(1.255); // → 1.26
redondeoSunat(1.245); // → 1.24
// Obtener códigos UN/ECE
const unece = obtenerCodigosUNECE("10");
// → { codigoUNECE_5153: "VAT", codigoUNECE_5305: "S", nombreTributo: "IGV" }Números a Letras
Convierte importes a su representación legal requerida por SUNAT (incluye decimales como XX/100).
import { numeroALetras } from "@pholguinc/sunat-validators";
numeroALetras(236);
// → "DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
numeroALetras(1180.50);
// → "MIL CIENTO OCHENTA CON 50/100 SOLES"
// Soporte para otras monedas (USD, EUR)
numeroALetras(1500.99, { moneda: "USD" });
// → "MIL QUINIENTOS CON 99/100 DOLARES AMERICANOS"Tipo de Cambio
Convierte montos de Soles a Dólares y viceversa, usando el tipo de cambio oficial de SUNAT y su redondeo estricto.
import { solesADolares, dolaresASoles } from "@pholguinc/sunat-validators";
const tipoCambio = 3.80; // Ej: TC Venta SUNAT
solesADolares(1000, { tipoCambio });
// → 263.16
dolaresASoles(500, { tipoCambio });
// → 1900.00Helpers de clasificación
import {
esGravado,
esExonerado,
esInafecto,
esExportacion,
esOperacionGratuita,
} from "@pholguinc/sunat-validators";
esGravado("10"); // true
esExonerado("20"); // true
esInafecto("30"); // true
esExportacion("40"); // true
esOperacionGratuita("11"); // true (retiro por premio)
esOperacionGratuita("10"); // false (operación onerosa)Tipos TypeScript
import type {
Ruc,
Dni,
Linea,
NombreArchivoParseado,
ErrorValidacionXml,
CodigoErrorSunat,
CodigoTributo,
CodigoAfectacionIGV,
CodigoDocIdentidad,
CodigoUNECE5153,
CodigoUNECE5305,
ResultadoCalculoImpuesto,
OpcionesCalculoItem,
} from "@pholguinc/sunat-validators";Validaciones del RUC
| Regla | Detalle |
|---|---|
| Longitud | Exactamente 11 dígitos numéricos |
| Prefijo | 10 (persona natural) · 20 (persona jurídica) |
| Dígito verificador | Algoritmo oficial SUNAT |
Catálogo 05 — Tributos
| Código | Nombre | Tasa | UN/ECE 5153 | UN/ECE 5305 | |---|---|---|---|---| | 1000 | IGV | 18% | VAT | S | | 1016 | IVAP | 4% | VAT | S | | 2000 | ISC | Variable | EXC | S | | 7152 | ICBPER | S/ 0.50/bolsa | OTH | S | | 9995 | Exportación | 0% | FRE | G | | 9996 | Gratuito | 0% | FRE | Z | | 9997 | Exonerado | 0% | VAT | E | | 9998 | Inafecto | 0% | FRE | O | | 9999 | Otros | Variable | OTH | S |
Catálogo 06 — Documentos de Identidad
| Código | Tipo | Longitud | |---|---|---| | 0 | Doc. Trib. No Domiciliado sin RUC | — | | 1 | DNI | 8 | | 4 | Carnet de Extranjería | 12 | | 6 | RUC | 11 | | 7 | Pasaporte | 12 | | A | Cédula Diplomática | 15 | | B | Doc. Identidad País Residencia | 15 | | C | TIN (PP.NN.) | 15 | | D | IN (PP.JJ.) | 15 | | E | TAM | 15 | | - | Varios (Boletas < S/700) | — |
Ejecutar pruebas
bun run src/test-validators.tsChangelog
v1.0.1 (2026-03-24)
Soporte dual ESM + CommonJS — la librería ahora funciona en NestJS y cualquier entorno CJS.
Cambios
- Compilación dual: se genera
dist/index.js(ESM) ydist/index.cjs(CJS) en cada build. package.json— campomain: apunta a./dist/index.cjspara compatibilidad con entornos CJS (NestJS, Jest, require).package.json— campoexports: agregada condición"require"apuntando a./dist/index.cjs; la condición"import"sigue apuntando a./dist/index.js.- Script
build: actualizado para ejecutar dos pasadas debun build(--format esmy--format cjs) seguido detscpara las declaraciones. tsconfig.build.json: agregadodeclarationMap: truepara generación de source maps de tipos.
Uso en NestJS (CJS)
// NestJS lo resuelve automáticamente con require()
import { rucSchema } from "@pholguinc/sunat-validators";Compatibilidad
| Entorno | Formato | Archivo |
|---|---|---|
| NestJS, Jest, require() | CJS | dist/index.cjs |
| Vite, ESM nativo, Bun | ESM | dist/index.js |
| TypeScript | Tipos | dist/index.d.ts |
v1.0.0 (2026-03-24)
Lanzamiento inicial con validación completa para facturación electrónica SUNAT.
v0.1.0 (2026-03-24)
Lanzamiento inicial con validación completa para facturación electrónica SUNAT.
Módulos incluidos
- error-codes.ts — +800 códigos de error oficiales SUNAT (100–4112)
- filename-validator.ts — Validación de nombres ZIP/XML según convención SUNAT
- Soporte para CPE (01, 03, 07, 08, 09, 20, 40), Resúmenes (RC) y Bajas (RA)
- Validación de prefijos de serie por tipo de documento
- Zod schemas:
nombreArchivoXmlSchema,nombreArchivoZipSchema - Funciones:
parsearNombreArchivo,validarCoincidenciaNombres,validarRucEnNombre
- xml-validator.ts — Validador de estructura XML UBL 2.1
- Validación de: UBLVersionID, CustomizationID, IssueDate, DocumentCurrencyCode
- Emisor/Receptor: CustomerAssignedAccountID, RegistrationName, AdditionalAccountID
- Firma digital, TaxTotal, LegalMonetaryTotal, líneas de detalle
- Soporte para: Facturas, Boletas, Notas de Crédito/Débito, Guías de Remisión
- Mensajes de error desde catálogo centralizado CODIGOS_ERROR_SUNAT
- catalogos-sunat.ts — Catálogos tributarios completos
- Catálogo 05: 9 tributos (IGV, IVAP, ISC, ICBPER, EXP, GRA, EXO, INA, OTROS)
- Catálogo 06: 11 tipos de documentos de identidad con validación por tipo
- Catálogo 07: 19 códigos de afectación IGV (gravado, exonerado, inafecto, exportación)
- Códigos UN/ECE 5153 y 5305 mapeados a cada tributo
- Cálculo de impuestos con redondeo bancario (half-even)
- Funciones helper:
esGravado,esExonerado,esInafecto,esExportacion,esOperacionGratuita
- numero-a-letras.ts — Conversión de importes a texto
- Función
numeroALetras(monto, opciones)para conversión SUNAT (ej. "CIEN CON 00/100 SOLES") - Soporte hasta billones y múltiples monedas (PEN, USD, EUR)
- Función
- tipo-cambio.ts — Conversión de monedas
- Funciones
solesADolares(monto, { tipoCambio })ydolaresASoles - Incluye redondeo estricto SUNAT a 2 decimales
- Funciones
- index.ts — Barrel file principal
Dependencias
zod>= 3.0.0 (peer dependency)fast-xml-parser^5.5.9
Licencia
MIT
