@devlas/dte-sii 2.12.3 → 2.12.5

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/CafSolicitor.js CHANGED
@@ -395,6 +395,10 @@ class CafSolicitor {
395
395
  response = await this.session.submitForm('/cvc_cgi/dte/of_solicita_folios_dcto', selectFields);
396
396
  currentHtml = response.body || '';
397
397
  this._saveDebug(debugDir, 'select.html', currentHtml);
398
+
399
+ if (currentHtml.includes('NO SE AUTORIZA')) {
400
+ return response; // solicitar() detectará el bloqueo en response.body
401
+ }
398
402
  }
399
403
 
400
404
  // Paso 3: Solicitar numeración
@@ -597,4 +601,8 @@ class CafSolicitor {
597
601
 
598
602
  CafSolicitor._lastSolicitudAt = 0; // ms timestamp of last solicitar() call — for rate limiting
599
603
 
604
+ /** Retorna la sesión SII cacheada para un ambiente+rut, o null si no existe. */
605
+ CafSolicitor.getSession = (ambiente, rutEmisor) =>
606
+ _sessionRegistry.get(`${ambiente.toLowerCase()}::${rutEmisor}`) ?? null;
607
+
600
608
  module.exports = CafSolicitor;
package/FolioService.js CHANGED
@@ -57,13 +57,22 @@ class FolioService {
57
57
  this.cafDir = options.cafDir || path.join(this.baseDir, 'debug', 'auto-caf');
58
58
  this.debugDir = options.debugDir || path.join(this.baseDir, 'debug');
59
59
 
60
- // Sesión SII
61
- this.session = new SiiSession({
62
- ambiente: this.ambiente,
63
- certificado: options.certificado,
64
- pfxPath: options.pfxPath,
65
- pfxPassword: options.pfxPassword,
66
- });
60
+ // Sesión SII — priorizar reutilización para evitar bans del SII
61
+ // Orden: (1) sesión explícita, (2) registro de CafSolicitor, (3) nueva sesión
62
+ const cachedSession = CafSolicitor.getSession(this.ambiente, this.rutEmisor);
63
+ if (options.session) {
64
+ this.session = options.session;
65
+ } else if (cachedSession) {
66
+ this.session = cachedSession;
67
+ } else {
68
+ this.session = new SiiSession({
69
+ ambiente: this.ambiente,
70
+ certificado: options.certificado,
71
+ pfxPath: options.pfxPath,
72
+ pfxBuffer: options.pfxBuffer,
73
+ pfxPassword: options.pfxPassword,
74
+ });
75
+ }
67
76
 
68
77
  // Cargar sesión compartida si está disponible
69
78
  this.sessionPath = options.sessionPath || process.env.SII_SESSION_PATH;
@@ -351,7 +360,7 @@ class FolioService {
351
360
  * @param {string} [params.motivo]
352
361
  * @returns {Promise<{ok:boolean, anulados:Array, rechazados:Array, totalAnulados:number, totalRechazados:number}>}
353
362
  */
354
- async anularFolios({ tipoDte, folioDesde = null, folioHasta = null, motivo = 'Folios no utilizados' }) {
363
+ async anularFolios({ tipoDte, folioDesde = null, folioHasta = null, motivo = 'Folios no utilizados', maxRangos = 50 }) {
355
364
  const debugStampA = new Date().toISOString().replace(/[:.]/g, '-');
356
365
  const debugDirA = path.join(this.debugDir, 'auto-caf', 'anulacion', debugStampA);
357
366
  fs.mkdirSync(debugDirA, { recursive: true });
@@ -374,6 +383,9 @@ class FolioService {
374
383
  return !vistos.has(`${r.folioDesde}-${r.folioHasta}`);
375
384
  });
376
385
 
386
+ // Limitar a los más recientes para evitar operaciones masivas
387
+ if (rangos.length > maxRangos) rangos = rangos.slice(-maxRangos);
388
+
377
389
  if (rangos.length === 0) {
378
390
  console.log(`[FolioService] Pasada ${pasada + 1}: sin rangos nuevos, finalizando`);
379
391
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devlas/dte-sii",
3
- "version": "2.12.3",
3
+ "version": "2.12.5",
4
4
  "description": "Facturación y boletas electrónicas para el SII de Chile. Genera, timbra, firma y envía DTEs, libros electrónicos y automatiza la certificación.",
5
5
  "main": "index.js",
6
6
  "types": "dte-sii.d.ts",