@devlas/dte-sii 2.5.14 → 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.
- package/cert/CertRunner.js +53 -39
- package/package.json +1 -1
package/cert/CertRunner.js
CHANGED
|
@@ -354,7 +354,7 @@ class CertRunner {
|
|
|
354
354
|
* @param {Object} [options] - { maxIntentos, intervalo, label }
|
|
355
355
|
*/
|
|
356
356
|
async _declararConReintentos(sets, debugPrefix, options = {}) {
|
|
357
|
-
const { maxIntentos = 10, intervalo = 5000, label = 'avance' } = options;
|
|
357
|
+
const { maxIntentos = 10, intervalo = 5000, label = 'avance', retryOnAllRejected = false } = options;
|
|
358
358
|
|
|
359
359
|
console.log(` Esperando 10s para que SII procese los envios...`);
|
|
360
360
|
await sleep(10000);
|
|
@@ -400,9 +400,14 @@ class CertRunner {
|
|
|
400
400
|
console.log(` [...] SII aún procesando, reintentando en ${intervalo / 1000}s...`);
|
|
401
401
|
await sleep(intervalo);
|
|
402
402
|
} else if (result.allRejected) {
|
|
403
|
-
// SII rechazó todos los sets/libros — período incorrecto
|
|
404
|
-
|
|
405
|
-
|
|
403
|
+
// SII rechazó todos los sets/libros — puede ser período incorrecto (libros) o TrackID no procesado aún (simulación)
|
|
404
|
+
if (retryOnAllRejected && intento < maxIntentos) {
|
|
405
|
+
console.log(` [!] S21 — SII aún procesando TrackID, reintentando en ${intervalo / 1000}s...`);
|
|
406
|
+
await sleep(intervalo);
|
|
407
|
+
} else {
|
|
408
|
+
console.log(` [ERR] SII rechazó todos los envíos (campos vacíos en portal) — período incorrecto. Corregir período y reenviar.`);
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
406
411
|
} else if (result.verificado === false && intento < maxIntentos) {
|
|
407
412
|
// Verificación post-declaración falló: los campos quedaron vacíos en el portal
|
|
408
413
|
console.log(` [!] Verificación fallida: ${result.error}`);
|
|
@@ -1476,7 +1481,7 @@ class CertRunner {
|
|
|
1476
1481
|
},
|
|
1477
1482
|
};
|
|
1478
1483
|
|
|
1479
|
-
const result = await this._declararConReintentos(sets, 'declaracion-simulacion-response', { maxIntentos, intervalo, label: 'simulación' });
|
|
1484
|
+
const result = await this._declararConReintentos(sets, 'declaracion-simulacion-response', { maxIntentos, intervalo, label: 'simulación', retryOnAllRejected: true });
|
|
1480
1485
|
if (result?.success) console.log(' [OK] Simulación declarada exitosamente');
|
|
1481
1486
|
return result;
|
|
1482
1487
|
}
|
|
@@ -2208,6 +2213,7 @@ class CertRunner {
|
|
|
2208
2213
|
browser = await puppeteer.launch({
|
|
2209
2214
|
headless: true,
|
|
2210
2215
|
ignoreHTTPSErrors: true,
|
|
2216
|
+
protocolTimeout: 300000, // 5 min — DOM.setFileInputFiles con 256 archivos supera el default de 30s
|
|
2211
2217
|
args: ['--no-sandbox', '--disable-setuid-sandbox', '--ignore-certificate-errors'],
|
|
2212
2218
|
});
|
|
2213
2219
|
const page = await browser.newPage();
|
|
@@ -2239,12 +2245,26 @@ class CertRunner {
|
|
|
2239
2245
|
if (debugDir) await page.screenshot({ path: path.join(debugDir, 'pdfte-02-after-rut.png'), fullPage: true }).catch(() => {});
|
|
2240
2246
|
|
|
2241
2247
|
// Paso 2: Diálogo "ya existe revisión" → click "Sí"
|
|
2248
|
+
// nuevaRevisionCreada=true cuando el usuario acepta crear una nueva revisión;
|
|
2249
|
+
// en ese caso NO se hace el early-exit por estado previo (el texto "EN REVISIÓN"
|
|
2250
|
+
// que queda visible corresponde a la revisión antigua, no a la nueva vacía).
|
|
2251
|
+
let nuevaRevisionCreada = false;
|
|
2242
2252
|
const hayDialog = await page.evaluate(() => {
|
|
2243
2253
|
const dlg = document.querySelector('.x-window');
|
|
2244
2254
|
return !!(dlg && dlg.offsetParent !== null);
|
|
2245
2255
|
});
|
|
2246
2256
|
if (hayDialog) {
|
|
2247
|
-
console.log(' → Diálogo
|
|
2257
|
+
console.log(' → Diálogo "Ya existe revisión" detectado → click "Sí"');
|
|
2258
|
+
if (debugDir) {
|
|
2259
|
+
await page.screenshot({ path: path.join(debugDir, 'pdfte-dialog-ya-existe.png'), fullPage: true }).catch(() => {});
|
|
2260
|
+
fs.writeFileSync(path.join(debugDir, 'pdfte-dialog-ya-existe.html'), await page.content().catch(() => ''), 'utf8');
|
|
2261
|
+
// Log texto del diálogo para debug
|
|
2262
|
+
const dlgText = await page.evaluate(() => {
|
|
2263
|
+
const dlg = document.querySelector('.x-window');
|
|
2264
|
+
return dlg ? dlg.textContent.trim().replace(/\s+/g, ' ') : '';
|
|
2265
|
+
}).catch(() => '');
|
|
2266
|
+
console.log(` [DEBUG] Texto del diálogo: "${dlgText}"`);
|
|
2267
|
+
}
|
|
2248
2268
|
const clicked = await page.evaluate(() => {
|
|
2249
2269
|
const si = Array.from(document.querySelectorAll('button.x-btn-text'))
|
|
2250
2270
|
.find(b => /^s[ií]$/i.test(b.textContent.trim()));
|
|
@@ -2253,6 +2273,8 @@ class CertRunner {
|
|
|
2253
2273
|
});
|
|
2254
2274
|
if (!clicked) await page.evaluate(() => { const b = document.querySelector('.x-window button'); if (b) b.click(); });
|
|
2255
2275
|
await new Promise(r => setTimeout(r, 2500));
|
|
2276
|
+
if (debugDir) await page.screenshot({ path: path.join(debugDir, 'pdfte-dialog-despues-si.png'), fullPage: true }).catch(() => {});
|
|
2277
|
+
nuevaRevisionCreada = true;
|
|
2256
2278
|
}
|
|
2257
2279
|
|
|
2258
2280
|
// Paso 3: RUT Proveedor (mismo RUT empresa)
|
|
@@ -2273,7 +2295,10 @@ class CertRunner {
|
|
|
2273
2295
|
if (debugDir) await page.screenshot({ path: path.join(debugDir, 'pdfte-03-after-consultar.png'), fullPage: true }).catch(() => {});
|
|
2274
2296
|
|
|
2275
2297
|
// ── Re-ejecución: detectar estado terminal antes de proceder ──
|
|
2276
|
-
|
|
2298
|
+
// Solo aplicable cuando NO se creó una nueva revisión.
|
|
2299
|
+
// Si se creó una nueva (nuevaRevisionCreada=true), el texto "EN REVISIÓN"
|
|
2300
|
+
// que aparece pertenece a la revisión anterior y no es válido como early-exit.
|
|
2301
|
+
const _estadoYaSubido = nuevaRevisionCreada ? null : await page.evaluate(() => {
|
|
2277
2302
|
const t = (document.body.textContent || '').toUpperCase();
|
|
2278
2303
|
if (t.includes('APROBADO')) return 'APROBADO';
|
|
2279
2304
|
if (t.includes('POR REVISAR')) return 'POR REVISAR';
|
|
@@ -2343,38 +2368,27 @@ class CertRunner {
|
|
|
2343
2368
|
if (!_hayInp) { await clickBoton(page, 'Crear'); await new Promise(r => setTimeout(r, 2500)); }
|
|
2344
2369
|
};
|
|
2345
2370
|
|
|
2346
|
-
// Cargar todos los PDFs
|
|
2347
|
-
//
|
|
2348
|
-
//
|
|
2349
|
-
//
|
|
2350
|
-
// (
|
|
2351
|
-
console.log(` → Cargando ${pdfPaths.length} PDFs
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
}
|
|
2368
|
-
const dz = document.querySelector('.dropFilesLabel');
|
|
2369
|
-
if (!dz) return 0;
|
|
2370
|
-
dz.dispatchEvent(new DragEvent('dragenter', { dataTransfer: dt, bubbles: true, cancelable: true }));
|
|
2371
|
-
dz.dispatchEvent(new DragEvent('dragover', { dataTransfer: dt, bubbles: true, cancelable: true }));
|
|
2372
|
-
dz.dispatchEvent(new DragEvent('drop', { dataTransfer: dt, bubbles: true, cancelable: true }));
|
|
2373
|
-
return dt.files.length;
|
|
2374
|
-
}, _fileDataList);
|
|
2375
|
-
|
|
2376
|
-
if (_dropped === 0) throw new Error('pdfdteInternet: drop zone no encontrado (.dropFilesLabel)');
|
|
2377
|
-
console.log(` → Drop ejecutado (${_dropped} archivos). Esperando procesamiento...`);
|
|
2371
|
+
// Cargar todos los PDFs a la vez en el input de archivo.
|
|
2372
|
+
// GWT no tiene atributo "multiple" por defecto — se fuerza vía DOM.
|
|
2373
|
+
// Puppeteer dispara el evento "change" internamente tras uploadFile(),
|
|
2374
|
+
// lo que dispara el handler GWT que encola todos los archivos para
|
|
2375
|
+
// procesarlos en batch (una POST por archivo vía iframe, sin re-navegación).
|
|
2376
|
+
console.log(` → Cargando ${pdfPaths.length} PDFs de una vez en el input...`);
|
|
2377
|
+
const fileInput = await page.$('input.gwt-FileUpload');
|
|
2378
|
+
if (!fileInput) throw new Error('pdfdteInternet: input.gwt-FileUpload no encontrado');
|
|
2379
|
+
|
|
2380
|
+
// Forzar múltiple selección y quitar restrict de accept (solo .PDF uppercase falla en algunos OS)
|
|
2381
|
+
await fileInput.evaluate(el => {
|
|
2382
|
+
el.setAttribute('multiple', '');
|
|
2383
|
+
el.removeAttribute('accept');
|
|
2384
|
+
});
|
|
2385
|
+
|
|
2386
|
+
await fileInput.uploadFile(...pdfPaths);
|
|
2387
|
+
console.log(` → ${pdfPaths.length} PDFs seleccionados, esperando que GWT encole los uploads...`);
|
|
2388
|
+
|
|
2389
|
+
// GWT necesita un pequeño tick antes de comenzar a procesar la cola
|
|
2390
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
2391
|
+
if (debugDir) await page.screenshot({ path: path.join(debugDir, 'pdfte-04b-despues-upload-file.png'), fullPage: true }).catch(() => {});
|
|
2378
2392
|
|
|
2379
2393
|
// ── Fase 1: esperar hasta 45s por primera señal de progreso o estado terminal ──
|
|
2380
2394
|
// Si el portal ya está en "POR REVISAR" (re-ejecución), lo detectamos aquí inmediatamente.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devlas/dte-sii",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.15",
|
|
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",
|