@devlas/dte-sii 2.5.13 → 2.5.15

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.
@@ -16,9 +16,10 @@
16
16
  */
17
17
 
18
18
  const SiiSession = require('./SiiSession.js');
19
+ const { STEPS, emitProgress } = require('./utils/progress');
19
20
 
20
21
  /**
21
- * Etapas de certificación DTE
22
+ * Etapas de certificacion DTE
22
23
  */
23
24
  const ETAPAS_CERTIFICACION = {
24
25
  SET_BASICO: 'SET_BASICO',
@@ -71,6 +72,20 @@ class SiiCertificacion {
71
72
  pfxPassword: options.pfxPassword,
72
73
  ambiente: 'certificacion',
73
74
  });
75
+
76
+ // Reutilización de sesión: cargar desde archivo y guardar automáticamente tras cada login
77
+ if (options.sessionPath) {
78
+ this._sessionPath = options.sessionPath;
79
+ this.session.loadSession(options.sessionPath);
80
+ const _origEnsure = this.session.ensureSession.bind(this.session);
81
+ const _sess = this.session;
82
+ const _sp = options.sessionPath;
83
+ this.session.ensureSession = async function(targetPath) {
84
+ const result = await _origEnsure(targetPath);
85
+ _sess.saveSession(_sp);
86
+ return result;
87
+ };
88
+ }
74
89
  }
75
90
 
76
91
  /**
@@ -518,7 +533,7 @@ class SiiCertificacion {
518
533
  }
519
534
 
520
535
  if (process.env.DEBUG_SII) {
521
- console.log(' [DEBUG] Campos hidden encontrados:', Object.keys(hiddenFields).join(', '));
536
+ console.log(' [DEBUG] Campos hidden encontrados:', Object.keys(hiddenFields).join(', '));
522
537
  }
523
538
 
524
539
  // Si no hay formulario para declarar (página de estado/reparos)
@@ -559,7 +574,7 @@ class SiiCertificacion {
559
574
  }
560
575
  const debugPath = path.join(debugDir, 'pe_avance2_form.html');
561
576
  fs.writeFileSync(debugPath, formHtml, 'utf8');
562
- console.log(' 📄 HTML pe_avance2 formulario guardado en debug/cert-v2/pe_avance2_form.html');
577
+
563
578
  }
564
579
 
565
580
  // Extraer todas las filas <tr>...</tr> del formulario
@@ -596,7 +611,7 @@ class SiiCertificacion {
596
611
  // Solo agregar si tiene NUM_ENV (no si tiene REVISADO CONFORME o EN REVISION)
597
612
  fieldMapping[pattern.name] = parseInt(numEnvMatch[1]);
598
613
  if (process.env.DEBUG_SII) {
599
- console.log(` [DEBUG] ${pattern.name} → NUM_ENV${numEnvMatch[1]}`);
614
+ console.log(` [DEBUG] ${pattern.name} → NUM_ENV${numEnvMatch[1]}`);
600
615
  }
601
616
  }
602
617
  break; // Ya encontramos la fila para este pattern
@@ -605,7 +620,7 @@ class SiiCertificacion {
605
620
  }
606
621
 
607
622
  if (process.env.DEBUG_SII) {
608
- console.log(' [DEBUG] Mapeo dinámico de índices:', fieldMapping);
623
+ console.log(' [DEBUG] Mapeo dinámico de índices:', fieldMapping);
609
624
  }
610
625
 
611
626
  if (sets.setSimulacion && !fieldMapping.setSimulacion) {
@@ -646,7 +661,7 @@ class SiiCertificacion {
646
661
  numEnvValues[index] = cleanTrackId;
647
662
  fecEnvValues[index] = formatDate(fecha);
648
663
  if (String(trackId) !== cleanTrackId) {
649
- console.log(` [TrackID] Normalizado: ${trackId} → ${cleanTrackId}`);
664
+
650
665
  }
651
666
  }
652
667
  }
@@ -677,16 +692,16 @@ class SiiCertificacion {
677
692
 
678
693
  // Debug: mostrar datos del formulario
679
694
  if (process.env.DEBUG_SII) {
680
- console.log(' [DEBUG] Datos del formulario a enviar:');
695
+ console.log(' [DEBUG] Datos del formulario a enviar:');
681
696
  for (const [k, v] of Object.entries(formData)) {
682
- console.log(` ${k}: ${v || '(vacío)'}`);
697
+ console.log(` ${k}: ${v || '(vacío)'}`);
683
698
  }
684
699
 
685
700
  // Mostrar el body codificado
686
701
  const SiiSession = require('./SiiSession');
687
702
  const encodedBody = SiiSession.formEncode(formData);
688
- console.log(' [DEBUG] Body codificado (primeros 500 chars):');
689
- console.log(` ${encodedBody.substring(0, 500)}`);
703
+ console.log(' [DEBUG] Body codificado (primeros 500 chars):');
704
+ console.log(` ${encodedBody.substring(0, 500)}`);
690
705
  }
691
706
 
692
707
  // 5. Enviar formulario de declaración
@@ -706,7 +721,7 @@ class SiiCertificacion {
706
721
 
707
722
  // Debug - guardar respuesta
708
723
  if (process.env.DEBUG_SII) {
709
- console.log(` [DEBUG] Respuesta: ${body.length} bytes, status: ${declareResponse.status}`);
724
+ console.log(` [DEBUG] Respuesta: ${body.length} bytes, status: ${declareResponse.status}`);
710
725
  // Guardar respuesta de pe_avance3 para debug
711
726
  const fs = require('fs');
712
727
  const path = require('path');
@@ -716,7 +731,7 @@ class SiiCertificacion {
716
731
  }
717
732
  const debugPath = path.join(debugDir, 'pe_avance3_response.html');
718
733
  fs.writeFileSync(debugPath, body);
719
- console.log(` [DEBUG] Respuesta guardada en: ${debugPath}`);
734
+ console.log(` [DEBUG] Respuesta guardada en: ${debugPath}`);
720
735
  }
721
736
 
722
737
  const bodyLower = body.toLowerCase();
@@ -767,7 +782,7 @@ class SiiCertificacion {
767
782
  const debugDir = process.env.SII_DEBUG_DIR || path.join(__dirname, '../../debug/cert-v2');
768
783
  if (!fs.existsSync(debugDir)) fs.mkdirSync(debugDir, { recursive: true });
769
784
  fs.writeFileSync(path.join(debugDir, 'pe_avance3_response.html'), body, 'utf8');
770
- console.log(' 📄 HTML pe_avance3 guardado en debug/cert-v2/pe_avance3_response.html');
785
+
771
786
  }
772
787
 
773
788
  // 7. VERIFICACIÓN POST-DECLARACIÓN: Re-leer pe_avance2 y confirmar que los TrackIDs se guardaron
@@ -776,6 +791,7 @@ class SiiCertificacion {
776
791
  let verificado = true;
777
792
  let verificacionError = '';
778
793
  let enRevision = false;
794
+ let camposVacios = [];
779
795
  try {
780
796
  const verifyResponse = await this.session.submitForm(
781
797
  '/cvc_cgi/dte/pe_avance2',
@@ -791,12 +807,11 @@ class SiiCertificacion {
791
807
  const debugDir = process.env.SII_DEBUG_DIR || path.join(__dirname, '../../debug/cert-v2');
792
808
  if (!fs.existsSync(debugDir)) fs.mkdirSync(debugDir, { recursive: true });
793
809
  fs.writeFileSync(path.join(debugDir, 'pe_avance2_verify.html'), verifyHtml, 'utf8');
794
- console.log(' 📄 HTML pe_avance2 verificación guardado en debug/cert-v2/pe_avance2_verify.html');
810
+
795
811
  }
796
812
 
797
813
  // Para cada set que declaramos, verificar estado
798
814
  const verifyRows = verifyHtml.split(/<\/tr>/i);
799
- const camposVacios = [];
800
815
  const camposEnRevision = [];
801
816
  for (const [setName, index] of Object.entries(fieldMapping)) {
802
817
  if (!sets[setName]) continue;
@@ -832,23 +847,28 @@ class SiiCertificacion {
832
847
 
833
848
  if (camposEnRevision.length > 0) {
834
849
  enRevision = true;
835
- console.log(` 🔄 EN REVISION: ${camposEnRevision.join(', ')} — declaración aceptada, SII procesando`);
850
+ console.log(` [...] EN REVISION: ${camposEnRevision.join(', ')} — declaración aceptada, SII procesando`);
836
851
  }
837
852
 
838
853
  if (camposVacios.length > 0 && !enRevision) {
839
854
  verificado = false;
840
855
  verificacionError = `Declaración NO se guardó en el portal SII. Campos vacíos para: ${camposVacios.join(', ')}. Posible error de sesión o TrackID no reconocido.`;
841
- console.log(` ⚠️ ${verificacionError}`);
856
+ console.log(` [!] ${verificacionError}`);
842
857
  }
843
858
  } catch (verifyErr) {
844
- console.log(` ⚠️ No se pudo verificar la declaración: ${verifyErr.message}`);
859
+ console.log(` [!] No se pudo verificar la declaración: ${verifyErr.message}`);
845
860
  }
846
861
 
862
+ // allRejected: SII rechazó todos los sets declarados — período incorrecto, no tiene sentido reintentar
863
+ const _declaredCount = Object.keys(fieldMapping).filter(k => sets[k]).length;
864
+ const allRejected = !enRevision && camposVacios.length > 0 && camposVacios.length >= _declaredCount && _declaredCount > 0;
865
+
847
866
  return {
848
867
  success: verificado || enRevision,
849
868
  error: verificacionError || errorMsg || undefined,
850
869
  verificado,
851
870
  enRevision,
871
+ allRejected,
852
872
  status: declareResponse.status,
853
873
  rawHtml: body,
854
874
  formHtml,
@@ -906,7 +926,7 @@ class SiiCertificacion {
906
926
  }
907
927
  const debugPath = path.join(debugDir, 'pe_avance2_avanzar.html');
908
928
  fs.writeFileSync(debugPath, formHtml, 'utf8');
909
- console.log(' [DEBUG] HTML avanzar guardado en:', debugPath);
929
+ console.log(' [DEBUG] HTML avanzar guardado en:', debugPath);
910
930
  }
911
931
 
912
932
  let avanceResponse = await this.session.submitForm(
@@ -932,7 +952,7 @@ class SiiCertificacion {
932
952
  }
933
953
  const debugPath = path.join(debugDir, 'pe_avance3_avanzar_response.html');
934
954
  fs.writeFileSync(debugPath, body);
935
- console.log(' [DEBUG] Respuesta avanzar guardada en:', debugPath);
955
+ console.log(' [DEBUG] Respuesta avanzar guardada en:', debugPath);
936
956
  }
937
957
 
938
958
  const hasError = body.toLowerCase().includes('error') && !body.includes('Error de Sesión');
@@ -1269,6 +1289,7 @@ class SiiCertificacion {
1269
1289
  if (onProgress) {
1270
1290
  onProgress({ intento, maxIntentos, estado: 'polling' });
1271
1291
  }
1292
+ emitProgress(STEPS.POLLING, { intento, max: maxIntentos, label: 'sets' });
1272
1293
 
1273
1294
  const result = await this.verAvanceParsed();
1274
1295
  if (!result.success) continue;
@@ -1288,10 +1309,12 @@ class SiiCertificacion {
1288
1309
  }
1289
1310
 
1290
1311
  if (todosConformes) {
1312
+ emitProgress(STEPS.SETS_APPROVED);
1291
1313
  return { success: true, estados: estadosRelevantes };
1292
1314
  }
1293
1315
 
1294
1316
  if (algunoRechazado) {
1317
+ emitProgress(STEPS.SETS_REJECTED);
1295
1318
  return { success: false, error: 'Sets rechazados', estados: estadosRelevantes };
1296
1319
  }
1297
1320
  }
package/SiiPortalAuth.js CHANGED
@@ -173,10 +173,10 @@ class SiiPortalAuth {
173
173
  if (cached) {
174
174
  const valida = await this._validarSesion(cached);
175
175
  if (valida) {
176
- console.log('[SiiPortalAuth] ♻️ Reutilizando sesión SII cacheada');
176
+ console.log('[SiiPortalAuth] Reutilizando sesión SII cacheada');
177
177
  return cached;
178
178
  }
179
- console.log('[SiiPortalAuth] ⚠️ Sesión cacheada expirada, re-autenticando...');
179
+ console.warn('[SiiPortalAuth] Sesión cacheada expirada, re-autenticando...');
180
180
  }
181
181
 
182
182
  // ── 2. Nueva autenticación ────────────────────────────────────────────────
@@ -187,6 +187,7 @@ class SiiPortalAuth {
187
187
  { cookieJar }
188
188
  );
189
189
 
190
+ console.log('[SiiPortalAuth] Autenticando con certificado en herculesr.sii.cl...');
190
191
  const r2 = await this._request(
191
192
  `https://herculesr.sii.cl/cgi_AUT2000/CAutInicio.cgi?${TARGET}`,
192
193
  {
@@ -196,6 +197,7 @@ class SiiPortalAuth {
196
197
  usarCert: true,
197
198
  }
198
199
  );
200
+ console.log(`[SiiPortalAuth] Respuesta herculesr: status=${r2.status}`);
199
201
 
200
202
  // Verificar mensaje de límite de sesiones
201
203
  if (r2.body.includes('m\u00e1ximo de sesiones') || r2.body.includes('maximo de sesiones') ||
@@ -222,19 +224,25 @@ class SiiPortalAuth {
222
224
  */
223
225
  async _validarSesion(cookieJar) {
224
226
  try {
227
+ console.log('[SiiPortalAuth] Validando sesión cacheada en SII...');
225
228
  const res = await this._request(
226
229
  'https://maullin.sii.cl/cvc_cgi/dte/ad_empresa1',
227
230
  { cookieJar: { ...cookieJar } } // copia para no contaminar
228
231
  );
229
232
  // Si redirige al login SII → expirada
230
233
  const loc = res.headers['location'] || '';
231
- if (loc.includes('InicioAutenticacion') || loc.includes('IngresoRutClave')) return false;
234
+ if (loc.includes('InicioAutenticacion') || loc.includes('IngresoRutClave')) {
235
+ console.warn('[SiiPortalAuth] Validación: SII redirigió al login → sesión expirada');
236
+ return false;
237
+ }
232
238
  // Si el body contiene formulario de empresa → válida
233
239
  const valida = res.status === 200 && (res.body.includes('RUT_EMP') || res.body.includes('ad_empresa'));
240
+ console.log(`[SiiPortalAuth] Validación: status=${res.status} → sesión ${valida ? 'VÁLIDA ✓' : 'INVÁLIDA ✗'}`);
234
241
  // Refrescar timestamp del caché para extender TTL mientras la sesión se usa activamente
235
242
  if (valida) SiiPortalAuth._guardarSesionCache(this._certHash, cookieJar);
236
243
  return valida;
237
- } catch {
244
+ } catch (err) {
245
+ console.warn('[SiiPortalAuth] Validación: error de red →', err.message);
238
246
  return false;
239
247
  }
240
248
  }
@@ -242,13 +250,25 @@ class SiiPortalAuth {
242
250
  /** Lee sesión cacheada del disco para el cert dado. @private */
243
251
  static _cargarSesionCache(certHash) {
244
252
  try {
245
- if (!fs.existsSync(SESSION_CACHE_PATH)) return null;
253
+ if (!fs.existsSync(SESSION_CACHE_PATH)) {
254
+ console.log('[SiiPortalAuth] Cache: archivo no existe →', SESSION_CACHE_PATH);
255
+ return null;
256
+ }
246
257
  const data = JSON.parse(fs.readFileSync(SESSION_CACHE_PATH, 'utf8'));
247
- if (data.certHash !== certHash) return null;
258
+ if (data.certHash !== certHash) {
259
+ console.log(`[SiiPortalAuth] Cache: cert no coincide (guardado=${data.certHash} actual=${certHash})`);
260
+ return null;
261
+ }
262
+ const edadMin = Math.round((Date.now() - data.ts) / 60000);
248
263
  // TTL: 90 minutos (SII permite ~2h de inactividad; se refresca en cada validación)
249
- if (Date.now() - data.ts > 90 * 60 * 1000) return null;
264
+ if (Date.now() - data.ts > 90 * 60 * 1000) {
265
+ console.log(`[SiiPortalAuth] Cache: sesión expirada (edad=${edadMin} min, TTL=90 min)`);
266
+ return null;
267
+ }
268
+ console.log(`[SiiPortalAuth] Cache: sesión encontrada`);
250
269
  return data.cookies;
251
- } catch {
270
+ } catch (err) {
271
+ console.warn('[SiiPortalAuth] Cache: error leyendo caché →', err.message);
252
272
  return null;
253
273
  }
254
274
  }
@@ -262,7 +282,11 @@ class SiiPortalAuth {
262
282
  ts: Date.now(),
263
283
  cookies: cookieJar,
264
284
  }), 'utf8');
265
- } catch { /* no crítico */ }
285
+ const cookieKeys = Object.keys(cookieJar);
286
+ console.log(`[SiiPortalAuth] Cache: sesión guardada`);
287
+ } catch (err) {
288
+ console.warn('[SiiPortalAuth] Cache: error guardando caché →', err.message);
289
+ }
266
290
  }
267
291
 
268
292
  /** Borra la sesión cacheada (útil para forzar re-login). */
package/SiiSession.js CHANGED
@@ -279,7 +279,7 @@ class SiiSession {
279
279
  // Detectar bloqueo por demasiadas sesiones
280
280
  if (response.body && response.body.includes('superado el m')) {
281
281
  const errorMsg = 'SII: Demasiadas sesiones abiertas. Espera ~30 min o cierra sesión manualmente en el portal SII.';
282
- console.error(`\n ${errorMsg}\n`);
282
+ console.error(`\n[ERR] ${errorMsg}\n`);
283
283
  throw new Error(errorMsg);
284
284
  }
285
285
 
@@ -292,7 +292,7 @@ class SiiSession {
292
292
  // Verificar si el login resultó en bloqueo por sesiones
293
293
  if (response.body && response.body.includes('superado el m')) {
294
294
  const errorMsg = 'SII: Demasiadas sesiones abiertas. Espera ~30 min o cierra sesión manualmente en el portal SII.';
295
- console.error(`\n ${errorMsg}\n`);
295
+ console.error(`\n[ERR] ${errorMsg}\n`);
296
296
  throw new Error(errorMsg);
297
297
  }
298
298
  }
@@ -386,10 +386,10 @@ class SiiSession {
386
386
  }
387
387
 
388
388
  this.cookieJar = data.cookieJar || '';
389
- console.log('Sesión SII cargada desde archivo');
389
+ console.log('[SessionSii] Sesión SII cargada desde archivo');
390
390
  return true;
391
391
  } catch (err) {
392
- console.log('Error cargando sesión SII:', err.message);
392
+ console.log('[SessionSii] Error cargando sesión SII:', err.message);
393
393
  return false;
394
394
  }
395
395
  }
@@ -302,11 +302,11 @@ class BoletaCert {
302
302
  const { DOMParser: XMLParser } = require('@xmldom/xmldom');
303
303
 
304
304
  console.log('\n' + '═'.repeat(60));
305
- console.log('📊 REENVÍO RCOF (ConsumoFolio)');
305
+ console.log('REENVÍO RCOF (ConsumoFolio)');
306
306
  console.log('═'.repeat(60));
307
307
 
308
308
  // 1. Parsear el EnvioBOLETA existente para extraer info
309
- console.log('\n📄 Leyendo EnvioBOLETA...');
309
+ console.log('\nLeyendo EnvioBOLETA...');
310
310
  const envioBOLETAXml = fs.readFileSync(options.envioBOLETAPath, 'utf-8');
311
311
  const parser = new XMLParser();
312
312
  const doc = parser.parseFromString(envioBOLETAXml, 'text/xml');
@@ -333,11 +333,11 @@ class BoletaCert {
333
333
  Totales: { MntNeto: mntNeto, MntExe: mntExe, IVA: iva, MntTotal: mntTotal }
334
334
  }
335
335
  });
336
- console.log(` - Folio ${folio}: Neto=${mntNeto}, Exento=${mntExe}, IVA=${iva}, Total=${mntTotal}`);
336
+ console.log(` - Folio ${folio}: Neto=${mntNeto}, Exento=${mntExe}, IVA=${iva}, Total=${mntTotal}`);
337
337
  }
338
338
 
339
339
  // 2. Crear RCOF
340
- console.log(`\n📊 Generando RCOF con SecEnvio=${options.secEnvio}...`);
340
+ console.log(`\nGenerando RCOF con SecEnvio=${options.secEnvio}...`);
341
341
  const { ConsumoFolio } = this._lib();
342
342
  const consumoFolio = new ConsumoFolio(this.certificado);
343
343
 
@@ -354,26 +354,26 @@ class BoletaCert {
354
354
  });
355
355
 
356
356
  consumoFolio.generar();
357
- console.log(` ✓ XML generado: ${consumoFolio.xml.length} bytes`);
357
+ console.log(` ✓ XML generado: ${consumoFolio.xml.length} bytes`);
358
358
 
359
359
  // Guardar debug
360
360
  if (this.debugDir) {
361
361
  const debugPath = path.join(this.debugDir, 'boleta-cert');
362
362
  fs.mkdirSync(debugPath, { recursive: true });
363
363
  fs.writeFileSync(path.join(debugPath, `ConsumoFolio-sec${options.secEnvio}.xml`), consumoFolio.xml, 'utf-8');
364
- console.log(` 📄 Guardado en: ${path.join(debugPath, `ConsumoFolio-sec${options.secEnvio}.xml`)}`);
364
+ console.log(` Guardado en: ${path.join(debugPath, `ConsumoFolio-sec${options.secEnvio}.xml`)}`);
365
365
  }
366
366
 
367
367
  // 3. Enviar RCOF
368
- console.log('\n📤 Enviando RCOF al SII...');
368
+ console.log('\nEnviando RCOF al SII...');
369
369
  const enviador = new EnviadorSII(this.certificado, this.ambiente);
370
370
  const resultadoRCOF = await enviador.enviarConsumoFolios(consumoFolio);
371
371
 
372
372
  if (!resultadoRCOF.ok) {
373
- console.log(` Error: ${resultadoRCOF.error}`);
373
+ console.log(` [ERR] Error: ${resultadoRCOF.error}`);
374
374
  return { success: false, error: resultadoRCOF.error };
375
375
  }
376
- console.log(` Enviado - TrackId: ${resultadoRCOF.trackId}`);
376
+ console.log(` [OK] Enviado - TrackId: ${resultadoRCOF.trackId}`);
377
377
 
378
378
  return { success: true, trackIdRCOF: resultadoRCOF.trackId };
379
379
  }
@@ -390,71 +390,71 @@ class BoletaCert {
390
390
  const { EnviadorSII } = this._lib();
391
391
 
392
392
  console.log('\n' + '═'.repeat(60));
393
- console.log('🎫 CERTIFICACIÓN BOLETAS ELECTRÓNICAS');
393
+ console.log('CERTIFICACIÓN BOLETAS ELECTRÓNICAS');
394
394
  console.log('═'.repeat(60));
395
395
 
396
396
  // 1. Parsear set de pruebas
397
- console.log('\n📋 Parseando set de pruebas...');
397
+ console.log('\nParseando set de pruebas...');
398
398
  const casos = this.parseSetPruebas(options.setPath);
399
- console.log(` ✓ ${casos.length} casos encontrados`);
399
+ console.log(` ✓ ${casos.length} casos encontrados`);
400
400
 
401
401
  // 2. Generar boletas
402
- console.log('\n📝 Generando boletas...');
402
+ console.log('\nGenerando boletas...');
403
403
  const { boletas, foliosUsados, folioInicial, folioFinal } = await this.generarBoletasSet(
404
404
  casos,
405
405
  options.cafBoleta,
406
406
  options.folioInicial
407
407
  );
408
- console.log(` ✓ ${boletas.length} boletas generadas (folios ${folioInicial}-${folioFinal})`);
408
+ console.log(` ✓ ${boletas.length} boletas generadas (folios ${folioInicial}-${folioFinal})`);
409
409
 
410
410
  for (const b of boletas) {
411
411
  const monto = b.dte.montoTotal || 0;
412
- console.log(` - CASO-${b.caso}: Folio ${b.folio} - $${monto.toLocaleString('es-CL')}`);
412
+ console.log(` - CASO-${b.caso}: Folio ${b.folio} - $${monto.toLocaleString('es-CL')}`);
413
413
  }
414
414
 
415
415
  // 3. Generar EnvioBOLETA
416
- console.log('\n📦 Generando EnvioBOLETA...');
416
+ console.log('\nGenerando EnvioBOLETA...');
417
417
  const envioBoleta = this.generarEnvioBoleta(boletas);
418
- console.log(` ✓ XML generado: ${envioBoleta.xml.length} bytes`);
418
+ console.log(` ✓ XML generado: ${envioBoleta.xml.length} bytes`);
419
419
 
420
420
  // Guardar debug
421
421
  if (this.debugDir) {
422
422
  const debugPath = path.join(this.debugDir, 'boleta-cert');
423
423
  fs.mkdirSync(debugPath, { recursive: true });
424
424
  fs.writeFileSync(path.join(debugPath, 'EnvioBOLETA.xml'), envioBoleta.xml, 'utf-8');
425
- console.log(` 📄 Guardado en: ${path.join(debugPath, 'EnvioBOLETA.xml')}`);
425
+ console.log(` Guardado en: ${path.join(debugPath, 'EnvioBOLETA.xml')}`);
426
426
  }
427
427
 
428
428
  // 4. Enviar EnvioBOLETA
429
- console.log('\n📤 Enviando EnvioBOLETA al SII...');
429
+ console.log('\nEnviando EnvioBOLETA al SII...');
430
430
  const enviador = new EnviadorSII(this.certificado, this.ambiente);
431
431
  const resultadoBoleta = await enviador.enviarBoletaSoap(envioBoleta);
432
432
 
433
433
  if (!resultadoBoleta.ok) {
434
- console.log(` Error: ${resultadoBoleta.error}`);
434
+ console.log(` [ERR] Error: ${resultadoBoleta.error}`);
435
435
  return { success: false, error: resultadoBoleta.error, fase: 'EnvioBOLETA' };
436
436
  }
437
- console.log(` Enviado - TrackId: ${resultadoBoleta.trackId}`);
437
+ console.log(` [OK] Enviado - TrackId: ${resultadoBoleta.trackId}`);
438
438
 
439
439
  // 5. Generar RCOF
440
- console.log('\n📊 Generando RCOF (ConsumoFolio)...');
440
+ console.log('\nGenerando RCOF (ConsumoFolio)...');
441
441
  const consumoFolio = this.generarConsumoFolio(envioBoleta);
442
442
  consumoFolio.generar(); // generar() ya incluye firmar() internamente
443
- console.log(` ✓ XML generado: ${consumoFolio.xml.length} bytes`);
443
+ console.log(` ✓ XML generado: ${consumoFolio.xml.length} bytes`);
444
444
 
445
445
  // Guardar debug
446
446
  if (this.debugDir) {
447
447
  const debugPath = path.join(this.debugDir, 'boleta-cert');
448
448
  fs.writeFileSync(path.join(debugPath, 'ConsumoFolio.xml'), consumoFolio.xml, 'utf-8');
449
- console.log(` 📄 Guardado en: ${path.join(debugPath, 'ConsumoFolio.xml')}`);
449
+ console.log(` Guardado en: ${path.join(debugPath, 'ConsumoFolio.xml')}`);
450
450
  }
451
451
 
452
452
  // 6. Enviar RCOF
453
- console.log('\n📤 Enviando RCOF al SII...');
453
+ console.log('\nEnviando RCOF al SII...');
454
454
  const resultadoRCOF = await enviador.enviarConsumoFolios(consumoFolio);
455
455
 
456
456
  if (!resultadoRCOF.ok) {
457
- console.log(` Error: ${resultadoRCOF.error}`);
457
+ console.log(` [ERR] Error: ${resultadoRCOF.error}`);
458
458
  return {
459
459
  success: false,
460
460
  error: resultadoRCOF.error,
@@ -462,16 +462,16 @@ class BoletaCert {
462
462
  trackIdBoleta: resultadoBoleta.trackId
463
463
  };
464
464
  }
465
- console.log(` Enviado - TrackId: ${resultadoRCOF.trackId}`);
465
+ console.log(` [OK] Enviado - TrackId: ${resultadoRCOF.trackId}`);
466
466
 
467
467
  // Resumen
468
468
  console.log('\n' + '═'.repeat(60));
469
- console.log(' CERTIFICACIÓN BOLETAS COMPLETADA');
469
+ console.log('[OK] CERTIFICACIÓN BOLETAS COMPLETADA');
470
470
  console.log('═'.repeat(60));
471
- console.log(` 📄 EnvioBOLETA: ${resultadoBoleta.trackId}`);
472
- console.log(` 📊 RCOF: ${resultadoRCOF.trackId}`);
473
- console.log(` 📦 Boletas: ${boletas.length}`);
474
- console.log(` 📑 Folios: ${folioInicial} - ${folioFinal}`);
471
+ console.log(` EnvioBOLETA: ${resultadoBoleta.trackId}`);
472
+ console.log(` RCOF: ${resultadoRCOF.trackId}`);
473
+ console.log(` Boletas: ${boletas.length}`);
474
+ console.log(` Folios: ${folioInicial} - ${folioFinal}`);
475
475
 
476
476
  return {
477
477
  success: true,
@@ -494,9 +494,9 @@ class BoletaCert {
494
494
  const forge = require('node-forge');
495
495
 
496
496
  console.log('\n' + '═'.repeat(60));
497
- console.log('📋 DECLARAR AVANCE BOLETAS');
497
+ console.log('DECLARAR AVANCE BOLETAS');
498
498
  console.log('═'.repeat(60));
499
- console.log(` TrackId: ${trackId}`);
499
+ console.log(` TrackId: ${trackId}`);
500
500
 
501
501
  const host = this.ambiente === 'produccion' ? 'palena.sii.cl' : 'maullin.sii.cl';
502
502
  const endpoint = '/cgi_dte/UPL/DTEauth?3';
@@ -548,7 +548,7 @@ class BoletaCert {
548
548
  req.end();
549
549
  });
550
550
 
551
- console.log(` 🔗 URL: ${url}`);
551
+ console.log(` URL: ${url}`);
552
552
 
553
553
  try {
554
554
  const response = await requestWithCert({
@@ -561,7 +561,7 @@ class BoletaCert {
561
561
  },
562
562
  }, body);
563
563
 
564
- console.log(` 📥 Status: ${response.status}`);
564
+ console.log(` Status: ${response.status}`);
565
565
 
566
566
  // Guardar respuesta para debug
567
567
  if (this.debugDir) {
@@ -583,24 +583,24 @@ class BoletaCert {
583
583
  const enRevision = /EN REVISION|PROCESANDO/i.test(html);
584
584
 
585
585
  if (esAprobado) {
586
- console.log(' BOLETAS APROBADAS');
586
+ console.log(' [OK] BOLETAS APROBADAS');
587
587
  return { success: true, estado: 'APROBADO', html };
588
588
  } else if (esRechazado) {
589
- console.log(' BOLETAS RECHAZADAS');
589
+ console.log(' [ERR] BOLETAS RECHAZADAS');
590
590
  // Extraer mensaje de error si existe
591
591
  const errorMatch = html.match(/<font[^>]*color[^>]*red[^>]*>([^<]+)</i);
592
592
  const errorMsg = errorMatch ? errorMatch[1].trim() : 'Error desconocido';
593
593
  return { success: false, estado: 'RECHAZADO', error: errorMsg, html };
594
594
  } else if (enRevision) {
595
- console.log(' 🔄 EN REVISIÓN');
595
+ console.log(' [...] EN REVISIÓN');
596
596
  return { success: true, estado: 'EN_REVISION', html };
597
597
  } else {
598
- console.log(' 📋 Respuesta recibida (verificar manualmente)');
598
+ console.log(' Respuesta recibida (verificar manualmente)');
599
599
  return { success: true, estado: 'DESCONOCIDO', html };
600
600
  }
601
601
 
602
602
  } catch (error) {
603
- console.error(` Error: ${error.message}`);
603
+ console.error(` [ERR] Error: ${error.message}`);
604
604
  return { success: false, error: error.message };
605
605
  }
606
606
  }
@@ -614,8 +614,8 @@ class BoletaCert {
614
614
  const https = require('https');
615
615
  const forge = require('node-forge');
616
616
 
617
- console.log(`\n Consultando estado del set...`);
618
- console.log(` TrackId: ${trackId}`);
617
+ console.log(`\n Consultando estado del set...`);
618
+ console.log(` TrackId: ${trackId}`);
619
619
 
620
620
  const host = this.ambiente === 'produccion' ? 'www4.sii.cl' : 'www4.sii.cl';
621
621
 
@@ -718,7 +718,7 @@ class BoletaCert {
718
718
  }
719
719
 
720
720
  } catch (error) {
721
- console.error(` ⚠️ Error consultando estado: ${error.message}`);
721
+ console.error(` [!] Error consultando estado: ${error.message}`);
722
722
  return {
723
723
  success: true,
724
724
  estado: 'DESCONOCIDO',