@devlas/dte-sii 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BoletaService.js +109 -0
- package/CAF.js +173 -0
- package/CafSolicitor.js +380 -0
- package/Certificado.js +123 -0
- package/ConsumoFolio.js +376 -0
- package/DTE.js +399 -0
- package/EnviadorSII.js +1304 -0
- package/Envio.js +196 -0
- package/FolioRegistry.js +553 -0
- package/FolioService.js +703 -0
- package/LICENSE +27 -0
- package/LibroBase.js +134 -0
- package/LibroCompraVenta.js +205 -0
- package/LibroGuia.js +225 -0
- package/README.md +239 -0
- package/Signer.js +94 -0
- package/SiiCertificacion.js +1189 -0
- package/SiiPortalAuth.js +460 -0
- package/SiiSession.js +499 -0
- package/cert/BoletaCert.js +731 -0
- package/cert/CertFolioHelper.js +185 -0
- package/cert/CertRunner.js +2658 -0
- package/cert/ConfigLoader.js +133 -0
- package/cert/IntercambioCert.js +429 -0
- package/cert/LibroCompras.js +359 -0
- package/cert/LibroGuias.js +171 -0
- package/cert/LibroVentas.js +153 -0
- package/cert/MuestrasImpresas.js +676 -0
- package/cert/SetBase.js +321 -0
- package/cert/SetBasico.js +413 -0
- package/cert/SetCompra.js +472 -0
- package/cert/SetExenta.js +490 -0
- package/cert/SetGuia.js +283 -0
- package/cert/SetParser.js +1184 -0
- package/cert/SetsProvider.js +499 -0
- package/cert/Simulacion.js +521 -0
- package/cert/comunaOficina.js +460 -0
- package/cert/index.js +124 -0
- package/cert/types.js +330 -0
- package/dte-sii.d.ts +458 -0
- package/index.js +428 -0
- package/package.json +48 -0
- package/utils/c14n.js +275 -0
- package/utils/calculo.js +396 -0
- package/utils/config.js +276 -0
- package/utils/constants.js +302 -0
- package/utils/emisor.js +174 -0
- package/utils/endpoints.js +225 -0
- package/utils/error.js +235 -0
- package/utils/index.js +339 -0
- package/utils/logger.js +239 -0
- package/utils/pfx.js +203 -0
- package/utils/receptor.js +218 -0
- package/utils/referencia.js +169 -0
- package/utils/resolucion.js +119 -0
- package/utils/rut.js +169 -0
- package/utils/sanitize.js +124 -0
- package/utils/tokenCache.js +214 -0
- package/utils/xml.js +358 -0
- package/utils.js +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# @devlas/dte-sii
|
|
2
|
+
|
|
3
|
+
**Librería de facturación y boletas electrónicas para el SII de Chile.**
|
|
4
|
+
|
|
5
|
+
Genera, timbra, firma y envía facturas electrónicas, boletas electrónicas, libros contables y automatiza el proceso de certificación ante el SII.
|
|
6
|
+
|
|
7
|
+
> Desarrollada por [Devlas SpA](https://devlas.cl) y publicada bajo licencia MIT para la comunidad de desarrolladores chilenos.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Instalación
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @devlas/dte-sii
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Uso básico
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const {
|
|
21
|
+
Certificado, CAF, DTE, EnvioDTE, EnvioBOLETA, EnviadorSII,
|
|
22
|
+
ConsumoFolio, LibroCompraVenta, LibroGuia,
|
|
23
|
+
} = require('@devlas/dte-sii')
|
|
24
|
+
|
|
25
|
+
// Cargar certificado digital (.pfx)
|
|
26
|
+
const cert = new Certificado(fs.readFileSync('certificado.pfx'), 'contraseña')
|
|
27
|
+
|
|
28
|
+
// Cargar CAF (folios autorizados)
|
|
29
|
+
const caf = new CAF(fs.readFileSync('caf.xml', 'utf8'))
|
|
30
|
+
|
|
31
|
+
// Crear y timbrar una Factura Electrónica (tipo 33)
|
|
32
|
+
const dte = new DTE({ Encabezado: { ... }, Detalle: [ ... ] })
|
|
33
|
+
dte.generarXML().timbrar(caf).firmar(cert)
|
|
34
|
+
|
|
35
|
+
// Enviar al SII
|
|
36
|
+
const envio = new EnvioDTE({ certificado: cert })
|
|
37
|
+
envio.agregar(dte)
|
|
38
|
+
envio.setCaratula({ RutEmisor: '76354771-K', ... })
|
|
39
|
+
envio.generar()
|
|
40
|
+
|
|
41
|
+
const enviador = new EnviadorSII(cert, 'produccion') // o 'certificacion'
|
|
42
|
+
const resultado = await enviador.enviarDteSoap(envio)
|
|
43
|
+
console.log(resultado.trackId)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Módulos
|
|
47
|
+
|
|
48
|
+
| Clase | Descripción |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `Certificado` | Carga y maneja certificados digitales PFX/P12 |
|
|
51
|
+
| `CAF` | Código de Autorización de Folios del SII |
|
|
52
|
+
| `DTE` | Genera, timbra y firma documentos tributarios |
|
|
53
|
+
| `EnvioDTE` | Sobre XML para facturas, guías y notas |
|
|
54
|
+
| `EnvioBOLETA` | Sobre XML para boletas electrónicas |
|
|
55
|
+
| `EnviadorSII` | Comunicación SOAP/HTTP con el SII |
|
|
56
|
+
| `ConsumoFolio` | Genera RCOF (Resumen Consumo de Folios) |
|
|
57
|
+
| `LibroCompraVenta` | Libro electrónico de Compra/Venta |
|
|
58
|
+
| `LibroGuia` | Libro electrónico de Guías de Despacho |
|
|
59
|
+
| `FolioService` | Gestión y solicitud de folios (CAF) |
|
|
60
|
+
| `SiiSession` | Sesión autenticada con el portal SII |
|
|
61
|
+
| `SiiCertificacion` | Automatización del proceso de certificación |
|
|
62
|
+
|
|
63
|
+
## Tipos de DTE soportados
|
|
64
|
+
|
|
65
|
+
| Tipo | Documento |
|
|
66
|
+
|---|---|
|
|
67
|
+
| 33 | Factura Electrónica |
|
|
68
|
+
| 34 | Factura No Afecta o Exenta |
|
|
69
|
+
| 39 | Boleta Electrónica Afecta |
|
|
70
|
+
| 41 | Boleta Electrónica Exenta |
|
|
71
|
+
| 43 | Liquidación Factura |
|
|
72
|
+
| 46 | Factura de Compra |
|
|
73
|
+
| 52 | Guía de Despacho |
|
|
74
|
+
| 56 | Nota de Débito |
|
|
75
|
+
| 61 | Nota de Crédito |
|
|
76
|
+
|
|
77
|
+
## Ambientes
|
|
78
|
+
|
|
79
|
+
Soporta `'certificacion'` y `'produccion'`. Pasarlo al instanciar `EnviadorSII`.
|
|
80
|
+
|
|
81
|
+
## Licencia
|
|
82
|
+
|
|
83
|
+
MIT — Copyright (c) 2026 [Devlas SpA](https://devlas.cl)
|
|
84
|
+
|
|
85
|
+
Inspirada conceptualmente en [LibreDTE de SASCO SpA](https://libredte.cl).
|
|
86
|
+
Implementa el protocolo XML público del SII de Chile.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Estructura de Archivos
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
dte-sii/
|
|
94
|
+
├── index.js # Punto de entrada principal
|
|
95
|
+
├── utils.js # Utilidades y helpers
|
|
96
|
+
├── Certificado.js # Manejo de certificados PFX/P12
|
|
97
|
+
├── CAF.js # Código de Autorización de Folios
|
|
98
|
+
├── DTE.js # Documento Tributario Electrónico
|
|
99
|
+
├── Signer.js # Firma XML-DSig
|
|
100
|
+
├── Envio.js # EnvioBOLETA y EnvioDTE
|
|
101
|
+
├── EnviadorSII.js # Comunicación con servicios SII
|
|
102
|
+
├── BoletaService.js # Servicio simplificado para boletas
|
|
103
|
+
├── LibroBase.js # Clase base para libros
|
|
104
|
+
├── ConsumoFolio.js # RCOF (Resumen Consumo Folios)
|
|
105
|
+
├── LibroCompraVenta.js # Libro Compra/Venta
|
|
106
|
+
├── LibroGuia.js # Libro Guías de Despacho
|
|
107
|
+
├── FolioService.js # Gestión integral de folios (solicitar, consultar, anular)
|
|
108
|
+
├── FolioRegistry.js # Registro local de folios usados + helpers
|
|
109
|
+
└── SiiSession.js # Sesiones HTTP autenticadas con el SII
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Uso
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
const {
|
|
116
|
+
DTE, CAF, Certificado, EnvioDTE, EnviadorSII,
|
|
117
|
+
FolioRegistry, createCafFingerprint, resolveCafPath
|
|
118
|
+
} = require('@devlas/dte-sii');
|
|
119
|
+
|
|
120
|
+
// Instancia de registro de folios
|
|
121
|
+
const folioRegistry = new FolioRegistry();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Clases Principales
|
|
125
|
+
|
|
126
|
+
| Clase | Responsabilidad |
|
|
127
|
+
|-------|-----------------|
|
|
128
|
+
| `Certificado` | Carga y manejo de certificados digitales (.pfx/.p12) |
|
|
129
|
+
| `CAF` | Parseado y uso de Códigos de Autorización de Folios |
|
|
130
|
+
| `DTE` | Generación, timbraje y firma de documentos |
|
|
131
|
+
| `Signer` | Firma XML-DSig compatible con SII |
|
|
132
|
+
| `EnvioBOLETA` | Sobre para boletas electrónicas |
|
|
133
|
+
| `EnvioDTE` | Sobre para facturas y otros DTEs |
|
|
134
|
+
| `EnviadorSII` | Autenticación y envío al SII (REST + SOAP) |
|
|
135
|
+
| `BoletaService` | Servicio simplificado para crear boletas |
|
|
136
|
+
| `ConsumoFolio` | RCOF - Resumen Consumo de Folios |
|
|
137
|
+
| `LibroCompraVenta` | Libro electrónico de compras/ventas |
|
|
138
|
+
| `LibroGuia` | Libro electrónico de guías de despacho |
|
|
139
|
+
|
|
140
|
+
## Gestión de Folios
|
|
141
|
+
|
|
142
|
+
| Clase/Función | Responsabilidad |
|
|
143
|
+
|---------------|-----------------|
|
|
144
|
+
| `FolioService` | Servicio para solicitar, consultar y anular folios en el SII |
|
|
145
|
+
| `FolioRegistry` | Registro local de folios usados, reservados y enviados |
|
|
146
|
+
| `SiiSession` | Sesiones HTTP autenticadas con certificado digital |
|
|
147
|
+
| `createCafFingerprint(xml)` | Genera hash único de un CAF |
|
|
148
|
+
| `findLatestCaf(tipoDte, dir)` | Busca el CAF más reciente para un tipo de DTE |
|
|
149
|
+
| `resolveCafPath(opts)` | Resuelve ruta de CAF con validación de folios |
|
|
150
|
+
|
|
151
|
+
### Ejemplo de uso de FolioRegistry
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const {
|
|
155
|
+
FolioRegistry, CAF, createCafFingerprint, resolveCafPath
|
|
156
|
+
} = require('@devlas/dte-sii');
|
|
157
|
+
|
|
158
|
+
// Instancia de registro
|
|
159
|
+
const folioRegistry = new FolioRegistry();
|
|
160
|
+
|
|
161
|
+
// Resolver CAF automáticamente
|
|
162
|
+
const cafPath = resolveCafPath({
|
|
163
|
+
tipoDte: 33,
|
|
164
|
+
rutEmisor: '78206276-K',
|
|
165
|
+
requiredCount: 1,
|
|
166
|
+
ambiente: 'certificacion',
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Cargar CAF
|
|
170
|
+
const cafXml = fs.readFileSync(cafPath, 'utf8');
|
|
171
|
+
const caf = new CAF(cafXml);
|
|
172
|
+
const cafFingerprint = createCafFingerprint(cafXml);
|
|
173
|
+
|
|
174
|
+
// Reservar próximo folio
|
|
175
|
+
const folio = folioRegistry.reserveNextFolio({
|
|
176
|
+
rutEmisor: '78206276-K',
|
|
177
|
+
tipoDte: caf.getTipoDTE(),
|
|
178
|
+
folioDesde: caf.getFolioDesde(),
|
|
179
|
+
folioHasta: caf.getFolioHasta(),
|
|
180
|
+
ambiente: 'certificacion',
|
|
181
|
+
cafFingerprint,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Marcar folio como enviado (después de envío exitoso)
|
|
185
|
+
folioRegistry.markFolioSent({
|
|
186
|
+
rutEmisor: '78206276-K',
|
|
187
|
+
tipoDte: caf.getTipoDTE(),
|
|
188
|
+
folio,
|
|
189
|
+
folioDesde: caf.getFolioDesde(),
|
|
190
|
+
folioHasta: caf.getFolioHasta(),
|
|
191
|
+
ambiente: 'certificacion',
|
|
192
|
+
cafFingerprint,
|
|
193
|
+
trackId: '0245283324',
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Ejemplo de uso de FolioService (avanzado)
|
|
198
|
+
|
|
199
|
+
```javascript
|
|
200
|
+
const { FolioService, Certificado } = require('@devlas/dte-sii');
|
|
201
|
+
|
|
202
|
+
const certificado = new Certificado('certificado.pfx', 'password');
|
|
203
|
+
const folioService = new FolioService({
|
|
204
|
+
ambiente: 'certificacion',
|
|
205
|
+
rutEmisor: '78206276-K',
|
|
206
|
+
certificado: certificado,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Consultar folios en el SII
|
|
210
|
+
const consulta = await folioService.consultarFolios({ tipoDte: 33 });
|
|
211
|
+
console.log('Último folio:', consulta.ultimoFolioFinal);
|
|
212
|
+
|
|
213
|
+
// Anular folios no usados
|
|
214
|
+
const resultado = await folioService.anularFolios({
|
|
215
|
+
tipoDte: 33,
|
|
216
|
+
folioDesde: 50,
|
|
217
|
+
folioHasta: 60,
|
|
218
|
+
motivo: 'Folios no utilizados',
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Utilidades
|
|
223
|
+
|
|
224
|
+
| Función | Descripción |
|
|
225
|
+
|---------|-------------|
|
|
226
|
+
| `sanitizeSiiText()` | Elimina caracteres problemáticos (apóstrofes, comillas) |
|
|
227
|
+
| `formatRut()` | Formatea RUT chileno |
|
|
228
|
+
| `calcularDV()` | Calcula dígito verificador |
|
|
229
|
+
| `formatBase64InXml()` | Formatea base64 con saltos de línea |
|
|
230
|
+
|
|
231
|
+
## Filosofía
|
|
232
|
+
|
|
233
|
+
`@devlas/dte-sii` actúa como **facilitador transparente** entre el usuario y el SII:
|
|
234
|
+
|
|
235
|
+
1. **Sanitización automática**: El usuario no se preocupa por caracteres especiales
|
|
236
|
+
2. **Formatos flexibles**: Acepta datos simplificados o estructurados
|
|
237
|
+
3. **Encoding interno**: Maneja UTF-8/ISO-8859-1 automáticamente
|
|
238
|
+
4. **Firma automática**: Genera firmas XML-DSig compatibles con SII
|
|
239
|
+
5. **Gestión de folios**: Control automático de CAFs, folios y anulaciones
|
package/Signer.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright (c) 2026 Devlas SpA — https://devlas.cl
|
|
2
|
+
// Licencia MIT. Ver archivo LICENSE para mas detalles.
|
|
3
|
+
/**
|
|
4
|
+
* Signer (Firma XML-DSig)
|
|
5
|
+
*
|
|
6
|
+
* Implementa firma XML-DSig compatible con SII usando C14N
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
const { DOMParser } = require('@xmldom/xmldom');
|
|
11
|
+
const { formatBase64InXml } = require('./utils');
|
|
12
|
+
const { serializeNode, fixEntities, buildSignedInfo, buildSignature } = require('./utils/c14n');
|
|
13
|
+
|
|
14
|
+
// ============================================
|
|
15
|
+
// CLASE SIGNER
|
|
16
|
+
// ============================================
|
|
17
|
+
|
|
18
|
+
class Signer {
|
|
19
|
+
constructor(certificado) {
|
|
20
|
+
this.certificado = certificado;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Firmar un SetDTE dentro de un envío
|
|
25
|
+
* @param {string} xmlSinFirma - XML del envío sin firma
|
|
26
|
+
* @param {string} setId - ID del SetDTE
|
|
27
|
+
* @param {string} rootTag - Tag raíz del envío (EnvioDTE, EnvioBOLETA, etc.)
|
|
28
|
+
* @returns {string} - XML firmado
|
|
29
|
+
*/
|
|
30
|
+
firmarSetDTE(xmlSinFirma, setId, rootTag) {
|
|
31
|
+
const doc = new DOMParser().parseFromString(xmlSinFirma, 'application/xml');
|
|
32
|
+
const setDTEC14N = this._c14nSetDTE(doc, rootTag);
|
|
33
|
+
|
|
34
|
+
const digestValue = crypto.createHash('sha1')
|
|
35
|
+
.update(Buffer.from(setDTEC14N, 'utf8'))
|
|
36
|
+
.digest('base64');
|
|
37
|
+
|
|
38
|
+
// Usar helpers centralizados de c14n
|
|
39
|
+
const signedInfoParaFirmar = buildSignedInfo(setId, digestValue, { expandTags: true, includeXsi: true });
|
|
40
|
+
const signedInfoParaGuardar = buildSignedInfo(setId, digestValue, { expandTags: false, includeXsi: true });
|
|
41
|
+
|
|
42
|
+
const sign = crypto.createSign('RSA-SHA1');
|
|
43
|
+
sign.update(signedInfoParaFirmar);
|
|
44
|
+
const signatureValue = sign.sign(this.certificado.getPrivateKeyPem(), 'base64');
|
|
45
|
+
const formattedSignature = signatureValue.match(/.{1,76}/g).join('\n');
|
|
46
|
+
|
|
47
|
+
const signatureXml = buildSignature(signedInfoParaGuardar, formattedSignature, {
|
|
48
|
+
modulus: this.certificado.getModulus(),
|
|
49
|
+
exponent: this.certificado.getExponent(),
|
|
50
|
+
certificate: this.certificado.getCertificateBase64(),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const xmlFirmado = xmlSinFirma.replace(
|
|
54
|
+
`</SetDTE></${rootTag}>`,
|
|
55
|
+
`</SetDTE>${signatureXml}</${rootTag}>`
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return formatBase64InXml(xmlFirmado);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================
|
|
62
|
+
// CANONICALIZACIÓN (C14N)
|
|
63
|
+
// ============================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Calcular C14N del SetDTE - Usa utils/c14n.js
|
|
67
|
+
*/
|
|
68
|
+
_c14nSetDTE(doc, rootTag) {
|
|
69
|
+
const setDTE = doc.getElementsByTagName('SetDTE')[0];
|
|
70
|
+
const envio = doc.getElementsByTagName(rootTag)[0];
|
|
71
|
+
|
|
72
|
+
const inheritedNs = new Map();
|
|
73
|
+
const defaultNs = envio.getAttribute('xmlns');
|
|
74
|
+
if (defaultNs) inheritedNs.set('xmlns', defaultNs);
|
|
75
|
+
const xsiNs = envio.getAttribute('xmlns:xsi');
|
|
76
|
+
if (xsiNs) inheritedNs.set('xmlns:xsi', xsiNs);
|
|
77
|
+
|
|
78
|
+
const id = setDTE.getAttribute('ID');
|
|
79
|
+
|
|
80
|
+
let c14n = '<SetDTE';
|
|
81
|
+
if (inheritedNs.has('xmlns')) c14n += ` xmlns="${inheritedNs.get('xmlns')}"`;
|
|
82
|
+
if (inheritedNs.has('xmlns:xsi')) c14n += ` xmlns:xsi="${inheritedNs.get('xmlns:xsi')}"`;
|
|
83
|
+
c14n += ` ID="${id}">`;
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < setDTE.childNodes.length; i++) {
|
|
86
|
+
c14n += serializeNode(setDTE.childNodes[i], inheritedNs);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
c14n += '</SetDTE>';
|
|
90
|
+
return fixEntities(c14n);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = Signer;
|