dty-fy
v0.4.0
Published
Librería completa para gestionar Documentos Tributarios Electrónicos (DTE) del SII de Chile. Soporta Facturas, Boletas, Notas de Crédito/Débito, Guías de Despacho y documentos de Exportación.
Maintainers
Readme
dty-fy
Libreria completa para gestionar Documentos Tributarios Electronicos (DTE) ante el Servicio de Impuestos Internos (SII) de Chile.
Soporta los 12 tipos de DTE: facturas, boletas, notas de credito/debito, guias de despacho y documentos de exportacion.
Tabla de Contenidos
- Instalacion
- Inicio Rapido
- Arquitectura
- Certificados Digitales
- Gestion de CAF
- Constructor de DTE
- Cliente SII
- Funciones Utiles
- Constantes y Tipos
- Manejo de Errores
- Ambientes
- Tests
- Contribucion
- Licencia
Instalacion
npm install dty-fyRequisitos
- Node.js 18+
- Certificado digital (.pfx/.p12) de una CA acreditada por el SII
- Archivos CAF (Codigo de Autorizacion de Folios) entregados por el SII
Formatos de Modulo
La libreria distribuye tanto ESM como CommonJS:
// ESM (recomendado)
import { DteBuilder, SiiClient } from 'dty-fy';
// CommonJS
const { DteBuilder, SiiClient } = require('dty-fy');Inicio Rapido
import { SiiClient, DteBuilder, CafManager, CertificateLoader } from 'dty-fy';
// 1. Cargar certificado digital
const cert = await CertificateLoader.fromPfx('./certificado.pfx', 'password');
// 2. Cargar folios autorizados (CAF)
const cafManager = new CafManager();
await cafManager.loadCaf('./caf-factura-33.xml');
// 3. Configurar cliente SII
const sii = new SiiClient({
environment: 'certification',
certificate: cert,
rutSender: '11111111-1',
rutCompany: '76543210-3',
fechaResolucion: '2024-01-15',
numeroResolucion: 0,
});
// 4. Construir una Factura Electronica (TipoDTE 33)
const factura = new DteBuilder()
.tipo(33)
.folio(cafManager.nextFolio(33))
.emisor({
rut: '76543210-3',
razonSocial: 'Mi Empresa SpA',
giro: 'Desarrollo de Software',
acteco: 620200,
direccion: 'Av. Providencia 1234',
comuna: 'Providencia',
})
.receptor({
rut: '87654321-4',
razonSocial: 'Cliente Ejemplo Ltda',
giro: 'Comercio',
direccion: 'Los Leones 999',
comuna: 'Providencia',
})
.addDetalle({ nombre: 'Servicio de desarrollo', cantidad: 1, precioUnitario: 500000 })
.addDetalle({ nombre: 'Hosting anual', cantidad: 12, unidad: 'mes', precioUnitario: 15000 })
.formaPago('credito')
.build();
// 5. Firmar, timbrar y enviar al SII
const result = await sii.emitir(factura, cafManager);
if (result.success) {
console.log(`DTE enviado! TrackID: ${result.trackId}`);
console.log(`Folio: ${result.folio}`);
const estado = await sii.consultarEstadoEnvio(result.trackId!);
console.log(`Estado: ${estado.status} - ${estado.glosa}`);
} else {
console.error(`Error: ${result.error}`);
}Arquitectura
┌─────────────────────────────────────────────────────────┐
│ SiiClient │
│ (orquestador: autenticacion, firma, envio, consulta) │
└──────┬───────────────────────────────────────┬─────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────┐ ┌──────────────────────┐
│ DteBuilder │ │ XmlSigner│ │ CertificateLoader │
│ (fluido) │ │(XMLDSig) │ │ (.pfx, .pem, base64) │
└──────┬───────┘ └──────────┘ └──────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────────────────┐
│ CafManager│ │ TED Generator│ │ SII Auth & Sender │
│ (folios) │ │(Timbre Elec)│ │ (seed, token, POST) │
└──────────┘ └──────────────┘ └──────────────────────┘Certificados Digitales
El certificado digital se obtiene a traves de una Autoridad Certificadora (CA) acreditada por el SII, no directamente desde el SII. La CA entrega un archivo .pfx (o .p12) que contiene la llave privada y el certificado X.509, protegido por una contrasena.
Metodos de Carga
import { CertificateLoader } from 'dty-fy';
// Desde archivo .pfx (el mas comun)
const cert = await CertificateLoader.fromPfx('./cert.pfx', 'password');
// Desde Buffer (base de datos, S3, cloud storage)
const cert = CertificateLoader.fromPfxBuffer(buffer, 'password');
// Desde string base64 (variables de entorno, serverless, CI/CD)
const cert = CertificateLoader.fromPfxBase64(process.env.CERT_PFX_B64!, process.env.CERT_PASSWORD!);
// Desde archivos PEM separados
const cert = await CertificateLoader.fromPem('./cert.pem', './key.pem');
// Desde strings PEM en memoria
const cert = CertificateLoader.fromPemStrings(certPem, keyPem);Utilidades del Certificado
import {
isCertificateValid,
daysUntilCertExpiry,
getRutFromCertificate,
getCertificateSummary,
} from 'dty-fy';
const cert = await CertificateLoader.fromPfx('./cert.pfx', 'pass');
isCertificateValid(cert); // boolean — esta vigente?
daysUntilCertExpiry(cert); // number | null — dias restantes
getRutFromCertificate(cert); // string | null — RUT embebido por la CA
getCertificateSummary(cert); // string — resumen legibleGestion de CAF
CafManager administra la carga, el parseo y la asignacion de folios desde los archivos CAF (Codigo de Autorizacion de Folios) entregados por el SII.
import { CafManager } from 'dty-fy';
const caf = new CafManager();
// Cargar desde archivo XML
await caf.loadCaf('./caf-33.xml');
// Cargar desde string XML
caf.addCaf(xmlString);
// Cargar datos CAF pre-parseados directamente
caf.addCafData(cafData);
// Obtener siguiente folio disponible (marca automaticamente como usado)
const folio = caf.nextFolio(33);
// Consultar folios restantes
const remaining = caf.remainingFolios(33);
// Obtener datos CAF para un folio especifico
const cafData = caf.getCaf(33, folio);
// Verificar y marcar uso manualmente
caf.isFolioUsed(33, folio); // boolean
caf.markFolioUsed(33, folio); // void
// Listar todos los CAF cargados para un tipo de DTE
const cafs = caf.getCafsForType(33);
// Reiniciar todo el estado
caf.clearAll();Constructor de DTE
DteBuilder proporciona una API fluida (builder pattern) para construir documentos DTE. Todos los metodos son encadenables.
Metodos
| Metodo | Parametros | Descripcion |
|--------|-----------|-------------|
| tipo | code: TipoDteCode | Establecer tipo de DTE (33, 39, 61, etc.) |
| folio | n: number | Establecer numero de folio |
| fechaEmision | date: string \| Date | Fecha de emision (default: hoy) |
| fechaVencimiento | date: string \| Date | Fecha de vencimiento (facturas credito) |
| formaPago | tipo: 'contado' \| 'credito' \| 'gratis' | Establecer forma de pago |
| montoBruto | bruto: boolean | Activar montos brutos (requerido para boletas) |
| emisor | data: EmisorInput | Datos del emisor |
| receptor | data: ReceptorInput | Datos del receptor |
| indTraslado | code: number | Establecer indicador de traslado (obligatorio para DTE 52) |
| tpoImpresion | code: number | Establecer tipo de impresión (opcional) |
| transporte | data: TransporteInput | Establecer datos logísticos del transporte terrestre (DTE 52) |
| addDetalle | data: DetalleInput | Agregar linea de detalle |
| addReferencia | data: ReferenciaInput | Agregar referencia a otro documento (requerido para NC/ND) |
| addDescuento | data: DescuentoRecargoInput | Agregar descuento o recargo global |
| build | — | Validar y retornar DteDocument |
Tipos de Entrada
interface EmisorInput {
rut: string;
razonSocial: string;
giro: string;
acteco: number;
direccion: string;
comuna: string;
ciudad?: string;
telefono?: string;
correo?: string;
sucursal?: string;
}
interface ReceptorInput {
rut: string;
razonSocial?: string;
giro?: string;
direccion?: string;
comuna?: string;
ciudad?: string;
contacto?: string;
correo?: string;
}
interface DetalleInput {
nombre: string;
descripcion?: string;
cantidad?: number; // default: 1
unidad?: string; // default: 'unidad'
precioUnitario: number;
montoItem?: number;
descuentoPct?: number;
descuentoMonto?: number;
exento?: boolean;
codigos?: Array<{ tipo: string; valor: string }>;
}
interface ReferenciaInput {
tipoDocRef: number;
folioRef: number;
fechaRef: string;
codigoRef?: number; // 1=anula, 2=corrige texto, 3=corrige montos
razon?: string;
}
interface DescuentoRecargoInput {
tipo: 'descuento' | 'recargo';
glosa?: string;
tipoValor: 'porcentaje' | 'monto';
valor: number;
}
interface ChoferInput {
rut?: string;
nombre?: string;
}
interface TransporteInput {
patente?: string;
patenteCarro?: string;
rutTrans?: string;
chofer?: ChoferInput;
fchSalida?: string | Date;
hraSalida?: string;
fchLlegada?: string | Date;
dirDest?: string;
cmnaDest?: string;
ciudadDest?: string;
}Ejemplos
Factura con descuento global:
const factura = new DteBuilder()
.tipo(33)
.folio(1)
.emisor(emisorData)
.receptor(receptorData)
.addDetalle({ nombre: 'Producto A', cantidad: 10, precioUnitario: 5000 })
.addDetalle({ nombre: 'Producto B', cantidad: 5, precioUnitario: 8000 })
.addDescuento({ tipo: 'descuento', tipoValor: 'porcentaje', valor: 10, glosa: 'Volumen' })
.build();
// IVA se calcula sobre el neto posterior al descuentoNota de Credito referenciando una factura:
const notaCredito = new DteBuilder()
.tipo(61)
.folio(cafManager.nextFolio(61))
.emisor(emisorData)
.receptor(receptorData)
.addDetalle({ nombre: 'Servicio web', cantidad: 1, precioUnitario: 500000 })
.addReferencia({
tipoDocRef: 33,
folioRef: 123,
fechaRef: '2024-03-15',
codigoRef: 1,
razon: 'Anulacion por devolucion',
})
.build();Boleta Electronica con montos brutos:
const boleta = new DteBuilder()
.tipo(39)
.folio(cafManager.nextFolio(39))
.emisor({ rut: '76543210-3', razonSocial: 'Mi Tienda', giro: 'Venta al detalle', acteco: 471100, direccion: 'Calle 1', comuna: 'Santiago' })
.receptor({ rut: '66666666-6', razonSocial: 'Consumidor Final' })
.montoBruto(true)
.addDetalle({ nombre: 'Cafe Latte', cantidad: 2, precioUnitario: 3500 })
.addDetalle({ nombre: 'Croissant', cantidad: 1, precioUnitario: 2500 })
.build();
// Los montos de boleta incluyen IVA (MntBruto=true)Guía de Despacho (DTE 52) con datos de transporte:
const guiaDespacho = new DteBuilder()
.tipo(52)
.folio(cafManager.nextFolio(52))
.emisor(emisorData)
.receptor(receptorData)
.indTraslado(5) // 5 = Traslados internos (obligatorio para DTE 52)
.transporte({
patente: 'AA1122',
patenteCarro: 'BB3344',
rutTrans: '77777777-7',
chofer: {
rut: '11111111-1',
nombre: 'Juan Pérez'
},
dirDest: 'Av. Vitacura 5000',
cmnaDest: 'Vitacura',
ciudadDest: 'Santiago'
})
.addDetalle({ nombre: 'Pallets de madera', cantidad: 50, precioUnitario: 3500 })
.build();Cliente SII
SiiClient orquesta el ciclo de vida completo del DTE: autenticacion, generacion de TED, firma XML, construccion del sobre de envio y envio al SII.
Constructor
import { SiiClient } from 'dty-fy';
const sii = new SiiClient({
environment: 'certification' | 'production',
certificate: certificateData,
rutSender: string, // RUT de la persona/sistema que envia
rutCompany: string, // RUT de la empresa (emisor)
fechaResolucion?: string, // YYYY-MM-DD (default: vacio)
numeroResolucion?: number, // 0 para certificacion (default: 0)
});Metodos
| Metodo | Firma | Descripcion |
|--------|-------|-------------|
| authenticate | (): Promise<string> | Obtener y cachear token de sesion SII (auto-llamado por emitir) |
| emitir | (doc: DteDocument, caf: CafManager): Promise<EmitirResult> | Flujo completo: TED -> firma -> sobre -> envio |
| consultarEstadoEnvio | (trackId: string): Promise<EstadoEnvio> | Consultar estado de envio por TrackID |
| consultarEstadoDte | (tipoDte, folio, fechaEmision, montoTotal, rutReceptor): Promise<EstadoDte> | Consultar estado de un DTE especifico |
Resultado de Emision
interface EmitirResult {
success: boolean;
trackId?: string; // TrackID del SII (en exito)
folio: number;
tipoDte: TipoDteCode;
xml: string; // XML del sobre firmado
error?: string; // Mensaje de error (en fallo)
}Resultados de Estado
interface EstadoEnvio {
status: string; // 'SOK' | 'CRT' | 'EPR' | 'RSC' | 'RFR' | 'RCT' | 'RPS'
glosa: string; // Descripcion legible
trackId: string;
numDtes?: number;
informados?: number;
aceptados?: number;
rechazados?: number;
reparos?: number;
}
interface EstadoDte {
status: string; // 'DOK' | 'RCH' | 'RPR' | 'DNK'
glosa: string;
tipoDte: number;
folio: number;
fechaEmision?: string;
rutEmisor?: string;
rutReceptor?: string;
montoTotal?: number;
errorCode?: string;
}Funciones Utiles
Validacion y Formateo de RUT
import { validateRut, formatRut, formatRutPretty, cleanRut, calculateDv } from 'dty-fy';
validateRut('11111111-1'); // true
validateRut('11111111-2'); // false
formatRut('111111111'); // '11111111-1'
formatRutPretty('111111111'); // '11.111.111-1'
cleanRut('11.111.111-1'); // '11111111-1'
calculateDv('11111111'); // '1'Calculos de Impuestos
import { calculateIva, calculateNetoFromBruto, calculateTotals, calculateMontoItem } from 'dty-fy';
calculateIva(100000); // 19000 (IVA 19%)
calculateIva(100000, 10); // 10000 (tasa personalizada)
calculateNetoFromBruto(119000); // 100000
calculateMontoItem(10, 5000); // 50000
calculateMontoItem(10, 5000, 10); // 45000 (10% descuento)Construccion XML (Bajo Nivel)
import { buildDocumentoXml, buildEnvioDteXml, buildEnvioBoletaXml } from 'dty-fy';
const docXml: string = buildDocumentoXml(dteDocument);
const envelope: string = buildEnvioDteXml([signedDocXml], caratula);
const boletaEnvelope: string = buildEnvioBoletaXml([signedBoletaXml], caratula);Parseo XML
import { parseSiiResponse, parseUploadResponse } from 'dty-fy';
const result = parseSiiResponse(siiXmlResponse); // { estado, seed?, token?, glosa? }
const upload = parseUploadResponse(siiHtmlResponse); // { success, trackId?, error? }Fechas
import { formatDate, formatTimestamp } from 'dty-fy';
formatDate(); // '2024-01-15'
formatDate(new Date('2024-06-01')); // '2024-06-01'
formatTimestamp(); // '2024-01-15T14:30:00'Constantes y Tipos
Codigos de Tipo de DTE
import { TipoDTE, TIPO_DTE_DESCRIPTIONS, VALID_DTE_CODES } from 'dty-fy';
TipoDTE.FacturaElectronica // 33
TipoDTE.FacturaExenta // 34
TipoDTE.BoletaElectronica // 39
TipoDTE.BoletaExenta // 41
TipoDTE.LiquidacionFactura // 43
TipoDTE.FacturaCompra // 46
TipoDTE.GuiaDespacho // 52
TipoDTE.NotaDebito // 56
TipoDTE.NotaCredito // 61
TipoDTE.FacturaExportacion // 110
TipoDTE.NotaDebitoExportacion // 111
TipoDTE.NotaCreditoExportacion // 112
TIPO_DTE_DESCRIPTIONS[33]; // 'Factura Electronica'
VALID_DTE_CODES; // Set { 33, 34, 39, 41, 43, 46, 52, 56, 61, 110, 111, 112 }Conjuntos por Tipo
import { BOLETA_TYPES, EXPORT_TYPES, EXENTO_TYPES } from 'dty-fy';
BOLETA_TYPES // Set { 39, 41 }
EXPORT_TYPES // Set { 110, 111, 112 }
EXENTO_TYPES // Set { 34, 41 }Constantes del Sistema
import { IVA_RATE, RUT_SII, SII_URLS, SII_NAMESPACES } from 'dty-fy';
IVA_RATE // 19
RUT_SII // '60803000-K'
SII_URLS.certification // { host, getSeed, getToken, upload, ... }
SII_NAMESPACES // { DTE, DS, C14N, SHA1, RSA_SHA1, ... }Codigos de Estado
import { ESTADO_ENVIO, ESTADO_DTE } from 'dty-fy';
ESTADO_ENVIO.SOK // '0' — Aceptado OK
ESTADO_ENVIO.CRT // '?' — En proceso
ESTADO_DTE.DOK // '0' — DTE Aceptado OK
ESTADO_DTE.RCH // '1' — DTE RechazadoTipos Principales
import type {
DteDocument, // Estructura completa del documento DTE
TipoDteCode, // 33 | 34 | 39 | 41 | 43 | 46 | 52 | 56 | 61 | 110 | 111 | 112
SiiEnvironment, // 'certification' | 'production'
SiiConfig, // Objeto de configuracion del cliente
EmitirResult, // Resultado de emision
EstadoEnvio, // Estado del envio batch
EstadoDte, // Estado del DTE individual
CafeData, // Datos de CAF parseados
CertificateData, // Datos del certificado parseados
} from 'chile-dte';Manejo de Errores
La libreria define una jerarquia de clases de error para un manejo granular:
import {
SiiError, // Error base para todas las fallas SII/DTE
SiiAuthError, // Falla de autenticacion (seed/token)
SiiSendError, // Falla de envio (puede incluir trackId)
SiiValidationError,// Falla de validacion local (puede incluir field)
CertificateError, // Falla de carga/parseo de certificado
CafError, // Falla de CAF/asignacion de folio (puede incluir tipoDte)
} from 'dty-fy';
try {
const result = await sii.emitir(factura, cafManager);
if (!result.success) {
console.error(`Emision fallida: ${result.error}`);
}
} catch (error) {
if (error instanceof SiiAuthError) {
// Error de autenticacion (ej. certificado vencido)
} else if (error instanceof SiiValidationError) {
// Error de validacion (revisar error.field)
} else if (error instanceof CafError) {
// Error de CAF (ej. sin folios disponibles)
}
}Ambientes
| Ambiente | Host SII | Uso |
|----------|----------|-----|
| certification | maullin.sii.cl | Pruebas y certificacion |
| production | palena.sii.cl | Produccion |
const sii = new SiiClient({
environment: 'certification', // o 'production'
// ...
});Licencia
EULA (End User License Agreement) — Copyright (c) 2026 bm0x.
Ver el archivo LICENSE para los terminos completos.
