@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.
Files changed (60) hide show
  1. package/BoletaService.js +109 -0
  2. package/CAF.js +173 -0
  3. package/CafSolicitor.js +380 -0
  4. package/Certificado.js +123 -0
  5. package/ConsumoFolio.js +376 -0
  6. package/DTE.js +399 -0
  7. package/EnviadorSII.js +1304 -0
  8. package/Envio.js +196 -0
  9. package/FolioRegistry.js +553 -0
  10. package/FolioService.js +703 -0
  11. package/LICENSE +27 -0
  12. package/LibroBase.js +134 -0
  13. package/LibroCompraVenta.js +205 -0
  14. package/LibroGuia.js +225 -0
  15. package/README.md +239 -0
  16. package/Signer.js +94 -0
  17. package/SiiCertificacion.js +1189 -0
  18. package/SiiPortalAuth.js +460 -0
  19. package/SiiSession.js +499 -0
  20. package/cert/BoletaCert.js +731 -0
  21. package/cert/CertFolioHelper.js +185 -0
  22. package/cert/CertRunner.js +2658 -0
  23. package/cert/ConfigLoader.js +133 -0
  24. package/cert/IntercambioCert.js +429 -0
  25. package/cert/LibroCompras.js +359 -0
  26. package/cert/LibroGuias.js +171 -0
  27. package/cert/LibroVentas.js +153 -0
  28. package/cert/MuestrasImpresas.js +676 -0
  29. package/cert/SetBase.js +321 -0
  30. package/cert/SetBasico.js +413 -0
  31. package/cert/SetCompra.js +472 -0
  32. package/cert/SetExenta.js +490 -0
  33. package/cert/SetGuia.js +283 -0
  34. package/cert/SetParser.js +1184 -0
  35. package/cert/SetsProvider.js +499 -0
  36. package/cert/Simulacion.js +521 -0
  37. package/cert/comunaOficina.js +460 -0
  38. package/cert/index.js +124 -0
  39. package/cert/types.js +330 -0
  40. package/dte-sii.d.ts +458 -0
  41. package/index.js +428 -0
  42. package/package.json +48 -0
  43. package/utils/c14n.js +275 -0
  44. package/utils/calculo.js +396 -0
  45. package/utils/config.js +276 -0
  46. package/utils/constants.js +302 -0
  47. package/utils/emisor.js +174 -0
  48. package/utils/endpoints.js +225 -0
  49. package/utils/error.js +235 -0
  50. package/utils/index.js +339 -0
  51. package/utils/logger.js +239 -0
  52. package/utils/pfx.js +203 -0
  53. package/utils/receptor.js +218 -0
  54. package/utils/referencia.js +169 -0
  55. package/utils/resolucion.js +119 -0
  56. package/utils/rut.js +169 -0
  57. package/utils/sanitize.js +124 -0
  58. package/utils/tokenCache.js +214 -0
  59. package/utils/xml.js +358 -0
  60. package/utils.js +4 -0
@@ -0,0 +1,276 @@
1
+ // Copyright (c) 2026 Devlas SpA — https://devlas.cl
2
+ // Licencia MIT. Ver archivo LICENSE para mas detalles.
3
+ /**
4
+ * Configuración Global
5
+ *
6
+ * Configuración centralizada para reintentos, timeouts, cache, etc.
7
+ *
8
+ * @module dte-sii/utils/config
9
+ */
10
+
11
+ // ============================================
12
+ // CONFIGURACIÓN DEFAULT
13
+ // ============================================
14
+
15
+ const DEFAULT_CONFIG = {
16
+ // Reintentos de conexión SII
17
+ retry: {
18
+ maxRetries: 8,
19
+ initialDelay: 2000,
20
+ maxDelay: 15000,
21
+ backoffMultiplier: 1.8,
22
+ retryableStatusCodes: [500, 502, 503, 504, 429],
23
+ retryableErrors: ['UND_ERR_SOCKET', 'ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND'],
24
+ },
25
+
26
+ // Cache de tokens SII
27
+ tokenCache: {
28
+ enabled: true,
29
+ ttlMinutes: 55,
30
+ },
31
+
32
+ // Timeouts
33
+ timeout: {
34
+ soap: 30000,
35
+ rest: 15000,
36
+ upload: 60000,
37
+ },
38
+
39
+ // Debug
40
+ debug: {
41
+ saveArtifacts: true,
42
+ logLevel: 'info',
43
+ },
44
+ };
45
+
46
+ // ============================================
47
+ // ESTADO GLOBAL
48
+ // ============================================
49
+
50
+ let currentConfig = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
51
+
52
+ // ============================================
53
+ // FUNCIONES DE CONFIGURACIÓN
54
+ // ============================================
55
+
56
+ /**
57
+ * Obtener configuración actual completa
58
+ * @returns {Object} Configuración actual
59
+ */
60
+ function getConfig() {
61
+ return JSON.parse(JSON.stringify(currentConfig));
62
+ }
63
+
64
+ /**
65
+ * Obtener una sección específica de la configuración
66
+ * @param {string} section - Nombre de la sección ('retry', 'tokenCache', 'timeout', 'debug')
67
+ * @returns {Object} Sección de configuración
68
+ */
69
+ function getConfigSection(section) {
70
+ return currentConfig[section] ? { ...currentConfig[section] } : null;
71
+ }
72
+
73
+ /**
74
+ * Configurar opciones (merge con existentes)
75
+ * @param {Object} options - Opciones a configurar
76
+ * @returns {Object} Configuración resultante
77
+ */
78
+ function configure(options = {}) {
79
+ // Merge profundo
80
+ for (const section of Object.keys(options)) {
81
+ if (currentConfig[section] && typeof options[section] === 'object') {
82
+ currentConfig[section] = {
83
+ ...currentConfig[section],
84
+ ...options[section],
85
+ };
86
+ } else {
87
+ currentConfig[section] = options[section];
88
+ }
89
+ }
90
+
91
+ return getConfig();
92
+ }
93
+
94
+ /**
95
+ * Configurar reintentos
96
+ * @param {Object} retryOptions - Opciones de reintento
97
+ */
98
+ function configureRetry(retryOptions = {}) {
99
+ currentConfig.retry = {
100
+ ...currentConfig.retry,
101
+ ...retryOptions,
102
+ };
103
+ return currentConfig.retry;
104
+ }
105
+
106
+ /**
107
+ * Configurar cache de tokens
108
+ * @param {Object} cacheOptions - Opciones de cache
109
+ */
110
+ function configureTokenCache(cacheOptions = {}) {
111
+ currentConfig.tokenCache = {
112
+ ...currentConfig.tokenCache,
113
+ ...cacheOptions,
114
+ };
115
+ return currentConfig.tokenCache;
116
+ }
117
+
118
+ /**
119
+ * Configurar timeouts
120
+ * @param {Object} timeoutOptions - Opciones de timeout
121
+ */
122
+ function configureTimeout(timeoutOptions = {}) {
123
+ currentConfig.timeout = {
124
+ ...currentConfig.timeout,
125
+ ...timeoutOptions,
126
+ };
127
+ return currentConfig.timeout;
128
+ }
129
+
130
+ /**
131
+ * Resetear a configuración default
132
+ * @returns {Object} Configuración reseteada
133
+ */
134
+ function resetConfig() {
135
+ currentConfig = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
136
+ return getConfig();
137
+ }
138
+
139
+ /**
140
+ * Configuración rápida para producción (menos logs, más reintentos)
141
+ */
142
+ function configureForProduction() {
143
+ return configure({
144
+ retry: {
145
+ maxRetries: 10,
146
+ initialDelay: 2000,
147
+ },
148
+ debug: {
149
+ saveArtifacts: false,
150
+ logLevel: 'warn',
151
+ },
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Configuración rápida para desarrollo (más logs, menos reintentos)
157
+ */
158
+ function configureForDevelopment() {
159
+ return configure({
160
+ retry: {
161
+ maxRetries: 3,
162
+ initialDelay: 500,
163
+ },
164
+ debug: {
165
+ saveArtifacts: true,
166
+ logLevel: 'debug',
167
+ },
168
+ });
169
+ }
170
+
171
+ // ============================================
172
+ // HELPERS DE RETRY
173
+ // ============================================
174
+
175
+ /**
176
+ * Calcular delay para un intento específico (backoff exponencial)
177
+ * @param {number} attempt - Número de intento (1-based)
178
+ * @returns {number} Delay en ms
179
+ */
180
+ function calculateRetryDelay(attempt) {
181
+ const { initialDelay, maxDelay, backoffMultiplier } = currentConfig.retry;
182
+ const delay = initialDelay * Math.pow(backoffMultiplier, attempt - 1);
183
+ return Math.min(delay, maxDelay);
184
+ }
185
+
186
+ /**
187
+ * Verificar si un error es retriable
188
+ * @param {Error} error - Error a verificar
189
+ * @returns {boolean} True si se puede reintentar
190
+ */
191
+ function isRetryableError(error) {
192
+ const { retryableErrors } = currentConfig.retry;
193
+ const errorCode = error?.code || error?.cause?.code || '';
194
+ return retryableErrors.some(code =>
195
+ errorCode.includes(code) || error?.message?.includes(code)
196
+ );
197
+ }
198
+
199
+ /**
200
+ * Verificar si un status HTTP es retriable
201
+ * @param {number} status - Status code HTTP
202
+ * @returns {boolean} True si se puede reintentar
203
+ */
204
+ function isRetryableStatus(status) {
205
+ return currentConfig.retry.retryableStatusCodes.includes(status);
206
+ }
207
+
208
+ /**
209
+ * Ejecutar función con reintentos
210
+ * @param {Function} fn - Función async a ejecutar
211
+ * @param {Object} options - Opciones
212
+ * @param {string} [options.name] - Nombre para logs
213
+ * @param {Function} [options.onRetry] - Callback en cada reintento
214
+ * @returns {Promise} Resultado de la función
215
+ */
216
+ async function withRetry(fn, options = {}) {
217
+ const { name = 'operación', onRetry } = options;
218
+ const { maxRetries } = currentConfig.retry;
219
+
220
+ let lastError;
221
+
222
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
223
+ try {
224
+ return await fn(attempt);
225
+ } catch (error) {
226
+ lastError = error;
227
+
228
+ const canRetry = attempt < maxRetries && (
229
+ isRetryableError(error) ||
230
+ isRetryableStatus(error?.status)
231
+ );
232
+
233
+ if (!canRetry) {
234
+ throw error;
235
+ }
236
+
237
+ const delay = calculateRetryDelay(attempt);
238
+
239
+ if (onRetry) {
240
+ onRetry(attempt, maxRetries, error, delay);
241
+ }
242
+
243
+ await new Promise(resolve => setTimeout(resolve, delay));
244
+ }
245
+ }
246
+
247
+ throw lastError;
248
+ }
249
+
250
+ // ============================================
251
+ // EXPORTS
252
+ // ============================================
253
+
254
+ module.exports = {
255
+ // Configuración
256
+ getConfig,
257
+ getConfigSection,
258
+ configure,
259
+ configureRetry,
260
+ configureTokenCache,
261
+ configureTimeout,
262
+ resetConfig,
263
+
264
+ // Presets
265
+ configureForProduction,
266
+ configureForDevelopment,
267
+
268
+ // Helpers
269
+ calculateRetryDelay,
270
+ isRetryableError,
271
+ isRetryableStatus,
272
+ withRetry,
273
+
274
+ // Constantes
275
+ DEFAULT_CONFIG,
276
+ };
@@ -0,0 +1,302 @@
1
+ // Copyright (c) 2026 Devlas SpA — https://devlas.cl
2
+ // Licencia MIT. Ver archivo LICENSE para mas detalles.
3
+ /**
4
+ * constants.js - Constantes centralizadas del SII
5
+ *
6
+ * Centraliza todas las constantes relacionadas con tipos de documentos,
7
+ * códigos y configuraciones del SII.
8
+ *
9
+ * @module utils/constants
10
+ */
11
+
12
+ /**
13
+ * Tipos de Documentos Tributarios Electrónicos
14
+ */
15
+ const TIPOS_DTE = {
16
+ FACTURA: 33,
17
+ FACTURA_ELECTRONICA: 33,
18
+ FACTURA_EXENTA: 34,
19
+ FACTURA_EXENTA_ELECTRONICA: 34,
20
+ BOLETA: 39,
21
+ BOLETA_ELECTRONICA: 39,
22
+ BOLETA_EXENTA: 41,
23
+ BOLETA_EXENTA_ELECTRONICA: 41,
24
+ LIQUIDACION_FACTURA: 43,
25
+ FACTURA_COMPRA: 46,
26
+ FACTURA_COMPRA_ELECTRONICA: 46,
27
+ GUIA_DESPACHO: 52,
28
+ GUIA_DESPACHO_ELECTRONICA: 52,
29
+ NOTA_DEBITO: 56,
30
+ NOTA_DEBITO_ELECTRONICA: 56,
31
+ NOTA_CREDITO: 61,
32
+ NOTA_CREDITO_ELECTRONICA: 61,
33
+ };
34
+
35
+ /**
36
+ * Tipos que son boletas (no requieren receptor identificado)
37
+ */
38
+ const TIPOS_BOLETA = [39, 41];
39
+
40
+ /**
41
+ * Tipos exentos de IVA
42
+ */
43
+ const TIPOS_EXENTOS = [34, 41];
44
+
45
+ /**
46
+ * Tipos que son notas (requieren referencia)
47
+ */
48
+ const TIPOS_NOTAS = [56, 61];
49
+
50
+ /**
51
+ * Tipos que son facturas
52
+ */
53
+ const TIPOS_FACTURA = [33, 34, 46];
54
+
55
+ /**
56
+ * Tipos que requieren receptor identificado
57
+ */
58
+ const TIPOS_RECEPTOR_REQUERIDO = [33, 34, 46, 52, 56, 61];
59
+
60
+ /**
61
+ * Nombres de los tipos de DTE
62
+ */
63
+ const NOMBRES_DTE = {
64
+ 33: 'Factura Electrónica',
65
+ 34: 'Factura Exenta Electrónica',
66
+ 39: 'Boleta Electrónica',
67
+ 41: 'Boleta Exenta Electrónica',
68
+ 43: 'Liquidación Factura Electrónica',
69
+ 46: 'Factura de Compra Electrónica',
70
+ 52: 'Guía de Despacho Electrónica',
71
+ 56: 'Nota de Débito Electrónica',
72
+ 61: 'Nota de Crédito Electrónica',
73
+ 110: 'Factura de Exportación Electrónica',
74
+ 111: 'Nota de Débito de Exportación Electrónica',
75
+ 112: 'Nota de Crédito de Exportación Electrónica',
76
+ };
77
+
78
+ /**
79
+ * Nombres de DTE para muestras impresas (mayúsculas según Manual SII)
80
+ */
81
+ const NOMBRES_DTE_IMPRESOS = {
82
+ 33: 'FACTURA ELECTRÓNICA',
83
+ 34: 'FACTURA NO AFECTA O EXENTA ELECTRÓNICA',
84
+ 39: 'BOLETA ELECTRÓNICA',
85
+ 41: 'BOLETA EXENTA ELECTRÓNICA',
86
+ 43: 'LIQUIDACIÓN FACTURA ELECTRÓNICA',
87
+ 46: 'FACTURA DE COMPRA ELECTRÓNICA',
88
+ 52: 'GUÍA DE DESPACHO ELECTRÓNICA',
89
+ 56: 'NOTA DE DÉBITO ELECTRÓNICA',
90
+ 61: 'NOTA DE CRÉDITO ELECTRÓNICA',
91
+ 110: 'FACTURA DE EXPORTACIÓN ELECTRÓNICA',
92
+ 111: 'NOTA DE DÉBITO DE EXPORTACIÓN ELECTRÓNICA',
93
+ 112: 'NOTA DE CRÉDITO DE EXPORTACIÓN ELECTRÓNICA',
94
+ };
95
+
96
+ /**
97
+ * Tipos que requieren copia cedible y recuadro de acuse de recibo
98
+ */
99
+ const TIPOS_CEDIBLES = [33, 34, 52, 46, 43];
100
+
101
+ /**
102
+ * Tipos que NO tienen cedible ni acuse (notas)
103
+ */
104
+ const TIPOS_NO_CEDIBLES = [56, 61, 111, 112];
105
+
106
+ /**
107
+ * Texto del acuse de recibo según Res. 51/2005
108
+ */
109
+ const DECLARACION_RECIBO = 'El acuse de recibo que se declara en este acto, de acuerdo a lo dispuesto en la letra b) del Art. 4°, y la letra c) del Art. 5° de la Ley 19.983, acredita que la entrega de mercaderías o servicio(s) prestado(s) ha(n) sido recibido(s).';
110
+
111
+ /**
112
+ * Nombres cortos de los tipos de DTE
113
+ */
114
+ const NOMBRES_DTE_CORTOS = {
115
+ 33: 'FACTURA',
116
+ 34: 'FACTURA EXENTA',
117
+ 39: 'BOLETA',
118
+ 41: 'BOLETA EXENTA',
119
+ 43: 'LIQUIDACION FACTURA',
120
+ 46: 'FACTURA COMPRA',
121
+ 52: 'GUIA DESPACHO',
122
+ 56: 'NOTA DEBITO',
123
+ 61: 'NOTA CREDITO',
124
+ };
125
+
126
+ /**
127
+ * Códigos de referencia según SII
128
+ */
129
+ const CODIGOS_REFERENCIA = {
130
+ ANULA: 1, // Anula documento de referencia
131
+ CORRIGE_TEXTO: 2, // Corrige texto del documento de referencia
132
+ CORRIGE_MONTOS: 3, // Corrige montos
133
+ SET_PRUEBAS: 0, // Referencia a set de pruebas (certificación)
134
+ };
135
+
136
+ /**
137
+ * Tipos de traslado para Guías de Despacho
138
+ */
139
+ const TIPOS_TRASLADO = {
140
+ OPERACION_CONSTITUYE_VENTA: 1,
141
+ VENTAS_POR_EFECTUAR: 2,
142
+ CONSIGNACIONES: 3,
143
+ ENTREGA_GRATUITA: 4,
144
+ TRASLADOS_INTERNOS: 5,
145
+ OTROS_NO_VENTA: 6,
146
+ GUIA_DEVOLUCION: 7,
147
+ TRASLADO_EXPORTACION: 8,
148
+ VENTA_EXPORTACION: 9,
149
+ };
150
+
151
+ /**
152
+ * Nombres de tipos de traslado para muestras impresas
153
+ */
154
+ const NOMBRES_TRASLADO = {
155
+ 1: 'Operación constituye venta',
156
+ 2: 'Ventas por efectuar',
157
+ 3: 'Consignaciones',
158
+ 4: 'Entrega gratuita',
159
+ 5: 'Traslados internos',
160
+ 6: 'Otros traslados no venta',
161
+ 7: 'Guía de devolución',
162
+ 8: 'Traslado para exportación (no venta)',
163
+ 9: 'Venta para exportación',
164
+ };
165
+
166
+ /**
167
+ * Tipos de despacho
168
+ */
169
+ const TIPOS_DESPACHO = {
170
+ DESPACHO_POR_CUENTA_RECEPTOR: 1,
171
+ DESPACHO_POR_CUENTA_EMISOR_LUGAR_RECEPTOR: 2,
172
+ DESPACHO_POR_CUENTA_EMISOR_OTRAS_INSTALACIONES: 3,
173
+ };
174
+
175
+ /**
176
+ * Indicadores de servicio (para boletas)
177
+ */
178
+ const INDICADORES_SERVICIO = {
179
+ SERVICIOS_PERIODICOS: 1,
180
+ SERVICIOS_PERIODICOS_DOMICILIARIOS: 2,
181
+ VENTAS_SERVICIOS: 3, // Más común
182
+ ESPECTACULOS_EMITIDOS: 4,
183
+ };
184
+
185
+ /**
186
+ * Formas de pago
187
+ */
188
+ const FORMAS_PAGO = {
189
+ CONTADO: 1,
190
+ CREDITO: 2,
191
+ SIN_COSTO: 3,
192
+ };
193
+
194
+ /**
195
+ * Tasa de IVA vigente (19%)
196
+ */
197
+ const TASA_IVA = 19;
198
+
199
+ /**
200
+ * RUT del consumidor final genérico
201
+ */
202
+ const RUT_CONSUMIDOR_FINAL = '66666666-6';
203
+
204
+ /**
205
+ * IDK para CAFs de certificación
206
+ */
207
+ const IDK_CERTIFICACION = 100;
208
+
209
+ /**
210
+ * Verificar si un tipo es boleta
211
+ * @param {number} tipo - Tipo de DTE
212
+ * @returns {boolean}
213
+ */
214
+ function esBoleta(tipo) {
215
+ return TIPOS_BOLETA.includes(Number(tipo));
216
+ }
217
+
218
+ /**
219
+ * Verificar si un tipo es exento
220
+ * @param {number} tipo - Tipo de DTE
221
+ * @returns {boolean}
222
+ */
223
+ function esExento(tipo) {
224
+ return TIPOS_EXENTOS.includes(Number(tipo));
225
+ }
226
+
227
+ /**
228
+ * Verificar si un tipo es nota (NC o ND)
229
+ * @param {number} tipo - Tipo de DTE
230
+ * @returns {boolean}
231
+ */
232
+ function esNota(tipo) {
233
+ return TIPOS_NOTAS.includes(Number(tipo));
234
+ }
235
+
236
+ /**
237
+ * Verificar si un tipo requiere receptor identificado
238
+ * @param {number} tipo - Tipo de DTE
239
+ * @returns {boolean}
240
+ */
241
+ function requiereReceptor(tipo) {
242
+ return TIPOS_RECEPTOR_REQUERIDO.includes(Number(tipo));
243
+ }
244
+
245
+ /**
246
+ * Obtener nombre del tipo de DTE
247
+ * @param {number} tipo - Tipo de DTE
248
+ * @param {boolean} [corto=false] - Si usar nombre corto
249
+ * @returns {string}
250
+ */
251
+ function getNombreDte(tipo, corto = false) {
252
+ const nombres = corto ? NOMBRES_DTE_CORTOS : NOMBRES_DTE;
253
+ return nombres[Number(tipo)] || `Tipo ${tipo}`;
254
+ }
255
+
256
+ /**
257
+ * Validar tipo de DTE
258
+ * @param {number} tipo - Tipo a validar
259
+ * @returns {boolean}
260
+ */
261
+ function esTipoValido(tipo) {
262
+ return Object.values(TIPOS_DTE).includes(Number(tipo));
263
+ }
264
+
265
+ module.exports = {
266
+ // Tipos
267
+ TIPOS_DTE,
268
+ TIPOS_BOLETA,
269
+ TIPOS_EXENTOS,
270
+ TIPOS_NOTAS,
271
+ TIPOS_FACTURA,
272
+ TIPOS_RECEPTOR_REQUERIDO,
273
+ TIPOS_CEDIBLES,
274
+ TIPOS_NO_CEDIBLES,
275
+
276
+ // Nombres
277
+ NOMBRES_DTE,
278
+ NOMBRES_DTE_CORTOS,
279
+ NOMBRES_DTE_IMPRESOS,
280
+ NOMBRES_TRASLADO,
281
+
282
+ // Códigos
283
+ CODIGOS_REFERENCIA,
284
+ TIPOS_TRASLADO,
285
+ TIPOS_DESPACHO,
286
+ INDICADORES_SERVICIO,
287
+ FORMAS_PAGO,
288
+
289
+ // Constantes
290
+ TASA_IVA,
291
+ RUT_CONSUMIDOR_FINAL,
292
+ IDK_CERTIFICACION,
293
+ DECLARACION_RECIBO,
294
+
295
+ // Funciones
296
+ esBoleta,
297
+ esExento,
298
+ esNota,
299
+ requiereReceptor,
300
+ getNombreDte,
301
+ esTipoValido,
302
+ };