El ejecutor
runCertification hace todo el lado HTML de la certificación en el orden que espera el SII, y se reanuda desde un almacén: córrelo de nuevo tras una corrección y continúa donde lo indica el estado guardado, sin repetir lo que ya está hecho. Debajo, cada paso es una función que puedes llamar por separado (sendTestSet, declareTestSets, runBooks…), y lo mismo cada operación del portal (downloadTestSet, declareProgress, readProgress…).
Nada de esto se ha ejecutado todavía contra los portales. Las pruebas usan páginas sintéticas, así que cada forma de página sigue sin comprobarse. En tu primera corrida con una empresa inscrita, conserva los artefactos que escribe el almacén (ahí queda cada respuesta del portal) como fixtures. Ver Estado.
Dos cosas no se pueden deshacer. Descargar de nuevo el set de pruebas lo
regenera en el SII y deja sin efecto todo lo enviado para el anterior. La
declaración de cumplimiento es la declaración jurada del representante legal:
el ejecutor la hace solo con declareCompliance: true. Sin esa opción la
corrida termina en la detención compliance.
Uso básico#
import { readFileSync } from 'node:fs'
import { createSiiClient, loadCertificateFromPkcs12 } from 'dte-sdk'
import { createDirectoryFolioRegistry } from 'dte-sdk/node'
import { createPortalClient, createDirectoryCertificationStore, runCertification } from 'dte-sdk/portal'
import { readPrintedSamples } from 'dte-sdk/pdf'
const certificate = loadCertificateFromPkcs12(readFileSync('firma.pfx'), process.env.PFX_PASSWORD!)
const companyRut = '76543210-3'
const deps = {
portal: createPortalClient({ environment: 'certification', certificate, companyRut }),
sii: createSiiClient({ environment: 'certification', certificate, companyRut }),
store: createDirectoryCertificationStore({ dir: './certification' }), // state.json y los artefactos; guarda llaves de CAF
registry: createDirectoryFolioRegistry({ dir: './folios' }),
issuer: { rut: companyRut, businessName: 'Comercial Andina SpA', address: 'Av. Los Aromos 1540' },
certificate,
// receiver: el receptor de prueba 66666666-6 por defecto
// resolution: número 0 con la fecha UTC del día en que parte la corrida, por defecto
onProgress: (event) => console.log(event.step),
}
// Primera corrida: descarga el set de pruebas, obtiene los folios, envía y declara los cuatro sets,
// los libros, la simulación, responde el intercambio, y se detiene hasta que se entreguen las muestras
const first = await runCertification(deps)
first.stopped // 'printedSamples' cuando todo salió bien
// Segunda corrida: sube las muestras y se detiene en `compliance`: la declaración jurada necesita un permiso explícito
const second = await runCertification(deps, { samples: () => readPrintedSamples('./certification/samples') })
second.stopped // 'compliance'
// Tercera corrida, cuando ya leíste las páginas que guardó el almacén y estás seguro
const third = await runCertification(deps, { declareCompliance: true })
third.stopped // 'done'Córrelo de nuevo tras cualquier detención que no sea done. Un rechazo, un bloqueo o un timeout vuelven como datos (stopped, detail) con el estado guardado, así que puedes leerlos, corregir la causa y volver a correr. Un error lanzado por el portal, el SII o los folios se propaga después de guardar el estado, con un evento CERT_ERROR.
Dependencias#
runCertification(dependencies, options) recibe un CertificationDependencies. Cada función de paso recibe el mismo objeto.
| Campo | Significado |
|---|---|
portal | PortalClient en el ambiente de certificación (createPortalClient) |
sii | SiiClient en el ambiente de certificación (createSiiClient) |
store | El CertificationStore donde viven el estado y los artefactos |
registry | El registro de folios: createDirectoryFolioRegistry (dte-sdk/node) o createMemoryFolioRegistry |
issuer | La empresa: rut, businessName y address son obligatorios. El giro, el código de actividad, la comuna y la ciudad tienen valores por defecto |
certificate | El certificado de firma |
receiver | Opcional, campo por campo: por defecto el receptor de prueba |
resolution | { number, date } opcional: por defecto número 0 y la fecha UTC del día de la corrida |
now | Reloj. Las fechas que la corrida escribe para el SII son fechas de Chile de este reloj |
sleep | Función de espera. Por defecto las esperas reales; inyecta una para probar sin esperar |
onProgress | Recibe cada CertificationProgressEvent |
contact | El contacto (name, mail, phone) que nombran las respuestas del intercambio |
Opciones y resultado#
| Opción | Significado |
|---|---|
until | Una CertificationStage: detenerse al completar esa etapa |
optionalSets | Los sets opcionales a marcar al descargar, como códigos SETnn. Por defecto DEFAULT_OPTIONAL_SETS |
declareCompliance | Hacer la declaración de cumplimiento. Apagado por defecto |
exchangeSetXml | El set de intercambio, cuando lo descargaste a mano |
samples | Los PDF a subir, o una función que los entrega (readPrintedSamples). Sin ella la corrida se detiene en printedSamples |
runCertification devuelve { state, stopped, detail? }: el estado tal como quedó guardado, por qué se detuvo, y una palabra o frase sobre el porqué.
stopped | Significado |
|---|---|
done | Se hizo la declaración de cumplimiento |
compliance | Todo está hecho hasta la declaración, que espera declareCompliance: true |
printedSamples | Las muestras esperan la opción samples |
exchange | No se pudo descargar el set de intercambio, o la empresa no está en la etapa de intercambio. detail dice cuál: ver Intercambio y muestras |
until | La etapa en que pediste detenerte está completa |
rejected | El SII o el portal rechazó: una declaración que no se tomó, un set o la simulación rechazados, una revisión rechazada, o un portal que no avanzó más allá de los libros. detail trae su frase |
blocked | El portal dice que la postulación no está en la etapa (las muestras, o la declaración final). detail trae su frase |
timedOut | Una espera se agotó sin respuesta |
incomplete | No se pudo enviar un libro obligatorio |
El orden de la corrida#
Sets de pruebas
El set de pruebas se descarga una sola vez (cuando el estado no tiene
plan), se parsea y se planifica. La corrida obtiene los folios que necesita y
luego emite y envía cada set que trae el plan y que el estado aún no envió,
en el orden basic, guide, exempt, purchase. Declara los cuatro track
id y espera la aprobación.
Libros
Los libros de compras, ventas y guías (y el de compras para exentos cuando el set de pruebas lo trajo) se arman, envían, declaran y esperan. Con los tres libros obligatorios enviados, la corrida pide al portal la etapa siguiente.
Simulación
Folios nuevos, cada caso emitido de nuevo en un sobre, enviado, declarado y confirmado.
Intercambio
El set de intercambio se descarga (o se entrega), se responde con tres archivos firmados, se suben y se confirma.
Muestras impresas
Los PDF de samples se suben como una revisión, que se envía y se lee de
nuevo. Sin samples la corrida se detiene aquí.
Cumplimiento
La declaración de cumplimiento, solo con declareCompliance: true.
until se revisa entre etapas: la corrida devuelve until apenas la etapa guardada es posterior a la que pediste.
Reanudar desde el almacén#
El estado registra dónde va la corrida (stage), así que una corrida parte en la etapa que guardó. Dentro de ella nada se repite:
- un set con track id no se vuelve a enviar, y el set de pruebas no se vuelve a descargar mientras el estado tenga un plan;
- una simulación confirmada no se declara de nuevo, un intercambio confirmado no se responde de nuevo, y una revisión ya enviada no se vuelve a subir;
- la fase de libros es la excepción: parte de cero en cada corrida, y qué libros están aprobados lo dice el portal, no lo que recuerda el estado. Ver La fase de libros.
Un error que detiene un paso deja el estado como lo guardó lo último que salió bien. Cada CAF obtenido se guarda de inmediato, así que un paso que termina corto de folios los deja en mano para el siguiente intento en vez de pedirlos otra vez al SII.
Cada paso por separado#
Cada paso recibe las dependencias y el estado y devuelve { state, outcome, detail? } con el estado que guardó. Úsalos después de que el SII rechazó un set con observaciones, para rehacer una pieza sin correr el resto:
let state = (await deps.store.load())!
state = (await sendTestSet(deps, state, { kind: 'basic' })).state
state = (await declareTestSets(deps, state)).state| Paso | Qué hace | Resultados (outcome) |
|---|---|---|
obtainTestSet | Descarga el set de pruebas, lo parsea, lo planifica y guarda el texto y el plan como artefactos. Descargar regenera el set en el SII: un estado que ya tenía plan parte de cero (todo lo enviado queda sin efecto), conservando solo sus CAF y folios usados | loaded, regenerated |
prepareFolios | Se asegura de que la corrida tenga los folios que necesita cada tipo. Ver Folios | ready (y los cafs con que emitir) |
sendTestSet | Emite un set con los folios del registro, guarda el sobre y cada documento como artefactos, lo sube, marca los folios enviados pase lo que pase, y registra el track id y la fecha de Chile | sent. Lanza ante un rechazo |
declareTestSets | Declara los sets enviados hasta ahora con la fecha de hoy en Chile, y guarda cualquier diagnóstico | Un DeclarationOutcome, más success |
waitForTestSetsApproval | Consulta la página de avance hasta que los sets estén aprobados | approved, rejected, timedOut |
runBooks | La fase de libros | approved, incomplete, rejected, timedOut |
advanceToNextStage | Pide al portal la etapa posterior a los libros | advanced, unchanged, failed, timedOut |
sendSimulation | Obtiene folios nuevos (nunca los CAF de los sets), emite y envía la simulación | sent |
declareSimulation | Declara la simulación, salvo que el portal ya nombre el intercambio como la etapa | Un DeclarationOutcome o skipped, más success |
waitForSimulationApproval | Consulta hasta que la simulación esté aprobada y confirmada | done, confirmed, rejected, timedOut |
runExchange | La etapa de intercambio | done, alreadyDone, setUnavailable, notInExchange |
uploadPrintedSamples | La etapa de muestras impresas | submitted, alreadySubmitted, blocked, rejected |
declareComplianceFinal | Una petición más para avanzar, y luego la declaración de cumplimiento | declared, blocked |
Detalles que importan cuando los llamas por separado:
sendTestSetlanzaMISSING_FIELD(plan) sin el plan del set. Cuando la subida falla, igual marca los folios como enviados en el registro (un timeout pudo haber entregado el sobre, y un folio enviado dos veces rechaza el siguiente sobre) y emiteSET_ERROR.declareTestSetslanzaMISSING_FIELD(sets) cuando no se envió nada.sendSimulationydeclareSimulationlanzanMISSING_FIELD(plan,simulation) cuando falta su entrada.declareComplianceFinallanzaSII_PORTAL_UNEXPECTED_PAGEcuando la última página no confirma. Ver La detención en cumplimiento.setFolioNeeds,simulationFolioNeeds,previousPeriodynextFreePeriodson ayudantes exportados de los pasos de folios y de libros.
Las operaciones del portal que hay debajo#
Los pasos se construyen sobre estas funciones de dte-sdk/portal. Cada una recibe primero el PortalClient y, como último argumento, ajustes opcionales de la llamada.
| Operación | Qué hace |
|---|---|
downloadTestSet(portal, { optionalSets, download, previousAttentionNumber }) | Genera y descarga el set de pruebas. Devuelve su texto, su número de atención y si se regeneró. Con download: false solo lee la tabla de estados. Lanza SII_PORTAL_REJECTED con notEnrolled para una empresa no inscrita |
queryCertificationSets(portal) | Lee el estado de cada set y libro, y si los obligatorios están aprobados |
declareProgress(portal, { entries }) | Declara track id y fechas. Ver Declaraciones |
readProgress(portal) | Lee la página de avance: la etapa, el estado de cada set y libro, y si la simulación espera su confirmación |
advanceStage(portal) | Pide la etapa siguiente: advanced, unchanged (el portal dice que ya está ahí) o failed, con la frase |
listBookHistory(portal, { year }) | Lista los libros que el SII tiene para un año. Todo período listado está ocupado para un nuevo envío total |
declareCompliance(portal) | La declaración de cumplimiento: declared, blocked o unconfirmed, con la frase |
El almacén#
Un CertificationStore es donde viven el estado y los artefactos de una corrida:
type CertificationStore = {
load: () => Promise<CertificationState | null>
save: (state: CertificationState) => Promise<void>
writeArtefact: (name: string, content: string) => Promise<void>
readArtefact: (name: string) => Promise<string | null>
listArtefacts: () => Promise<readonly string[]>
}Los nombres de artefacto son rutas relativas con / de separador, hechas solo de letras, dígitos, ., _ y -; cualquier otra cosa lanza INVALID_OPTION (name). createMemoryCertificationStore() lo guarda todo en memoria, para pruebas y corridas cortas. createDirectoryCertificationStore({ dir }) guarda state.json (escrito de forma atómica, con un archivo temporal y un renombre) y los artefactos como archivos, con una / en un nombre como subdirectorio. Un servicio puede implementar el tipo sobre su propio almacenamiento.
El estado es un secreto. Contiene los archivos CAF, cada uno con su llave privada. El almacén en directorio crea sus directorios privados para ti (modo 0700) y sus archivos ilegibles para otros (0600); un directorio que ya existe conserva su modo. Está pensado para un solo proceso. Mantén el directorio fuera del control de versiones.
createCertificationState(companyRut) crea un estado nuevo. El estado es un valor JSON simple; sus campos principales:
| Campo | Contiene |
|---|---|
stage | Dónde va la corrida: una CertificationStage |
setText, attentionNumber, plan | El set de pruebas descargado, su número de atención y el plan |
setReadDate | El día UTC en que se leyó el set: su mes es el período base de los libros |
cafs | Los archivos CAF que tiene la corrida (con llaves privadas) |
usedFolios | Cada folio que usó la corrida |
annulledRanges | Los rangos que el SII dio por anulados o recibidos, por tipo de documento |
sets, setsApproved | Los sets enviados (track id, fecha de Chile, instante, casos) y si están aprobados |
books | El período en uso, los períodos ocupados, los ajustes intentados, los totales acumulados y cada libro enviado |
simulation | La simulación enviada, y si se confirmó |
lastDeclaration | La última declaración hecha y cómo terminó |
diagnosis | Lo que dijo el estado SOAP de un envío, por track id |
exchange, samples | Las etapas de intercambio y de muestras impresas |
blocked | La frase que bloqueó la declaración de cumplimiento |
Los artefactos son lo que inspeccionas, y de lo que se arman las muestras impresas:
| Artefacto | Qué es |
|---|---|
set-texto.txt, estructuras.json | El texto del set de pruebas y el plan |
sets-prueba/envio-set-basico.xml, …-guia.xml, …-exenta.xml, …-compra.xml | El sobre de cada set |
sets-prueba/dtes/dte-<tipo>-<folio>.xml | Cada documento de los sets (SET_ARTEFACT_NAMES nombra los sobres) |
libro-ventas.xml, libro-compras.xml, libro-guias.xml, libro-compras-exentos.xml | Los libros (BOOK_ARTEFACT_NAMES) |
simulacion/envio-simulacion.xml, simulacion/dtes/… | La simulación |
declaracion-sets-<n>.html, declaracion-libros-<n>.html, declaracion-simulacion-<n>.html (y …-pe_avance2-<n>.html, …-estado-<clave>-<trackId>.xml) | Cada página de declaración y cada respuesta del estado SOAP |
intercambio/…, muestras/… | Cada respuesta del portal del intercambio y de las muestras impresas, y las respuestas del intercambio |
findEnvelopeFiles de dte-sdk/pdf encuentra por nombre los sobres de los
sets y de la simulación dentro de este directorio, así que writePrintedSamples
puede generar los PDF directamente desde él. Ver Intercambio y muestras.
Eventos de progreso#
onProgress recibe un CertificationProgressEvent por cada paso de la corrida. Los nombres están en CERTIFICATION_STEPS:
| Fase | Eventos |
|---|---|
| Set de pruebas | SETS_DOWNLOADING, SETS_LOADED, SETS_REGENERATED |
| Folios | CAF_REQUESTING y CAF_OK, cada uno con el type del documento |
| Sets | SET_START (con set), SET_OK (con set y trackId), SET_ERROR (con set y error), SETS_DECLARING, SETS_DECLARED, SETS_APPROVED, SETS_REJECTED |
| Esperas | POLLING con attempt, max y label: sets, declaration, books o simulation |
| Libros | BOOKS_START, BOOK_SKIPPED, BOOK_SENDING, BOOK_OK (con trackId), BOOK_ERROR (con error), BOOK_PERIOD_RETRY (con period y attempt), BOOKS_DECLARING, BOOKS_DONE (con books y success) |
| Avance | ADVANCE_WAITING, ADVANCE_DONE (con el texto de stage del portal) |
| Simulación | SIM_START, SIM_SENDING, SIM_OK (con trackId), SIM_DECLARING, SIM_DONE |
| Intercambio | INTERCAMBIO_START, INTERCAMBIO_DESCARGADO, INTERCAMBIO_DONE (con uploaded) |
| Muestras | MUESTRAS_UPLOADING (con count), MUESTRAS_DONE (con success) |
| Fin | CERT_DONE, CERT_ERROR (con error) |
El avance final de declareComplianceFinal no lee ninguna etapa, así que no emite ningún evento.
Folios#
prepareFolios se asegura de que la corrida tenga los folios que necesita cada tipo, en el orden en que el SII los raciona. Nunca pide más de lo que necesitan los sets aún no enviados, porque folios autorizados sin usar hacen que el SII racione la próxima solicitud.
- Primero los CAF en mano. Un CAF vencido se omite, porque el SII rechaza sus folios. Los folios de esta corrida que el SII nunca recibió (un envío que falló) se devuelven al registro. Los folios que el SII ya recibió, de una corrida anterior o de otro software, se marcan como usados para saltarlos.
- Luego el cupo. Se lee el máximo del portal. Un rechazo o un fallo al leerlo no detiene: la corrida sigue sin tope. Un cupo bloqueado, o corto con folios sin usar en el SII, los reobtiene para toda la necesidad del tipo. Una respuesta completa cierra el tipo; una corta se conserva, en lugar de los CAF en mano, solo si descargó algo que cubre más que ellos.
- Luego una solicitud. Un máximo bloqueado no pide nada al portal. Si no, una solicitud exacta, o por tandas cuando el máximo está bajo la necesidad (tantas tandas como folios falten), cayendo a tandas cuando la exacta queda corta con un máximo que no es cero. Un bloqueo de la persona intenta la reobtención una vez antes que cualquier otra cosa.
- Anular es el último recurso. Solo cuando la negativa es racionamiento y el SII muestra más folios sin usar que los que tiene la corrida, se anulan rangos sin usar de los últimos 180 días: como máximo 10 por pasada, en hasta cuatro pasadas. Nunca toca un rango que la corrida descargó (los CAF del estado, incluidos los vencidos, los recién obtenidos y los que trajo una reobtención y la corrida no conservó). Los rangos que el SII reportó anulados se guardan en el estado (
annulledRanges) y no se vuelven a intentar. Si se anuló alguno, se lee de nuevo el máximo y se repite la solicitud siguiéndolo. Una anulación que falla antes de que el SII responda cuenta como ninguna.
Si aún falta, lanza FOLIO_OUT_OF_RANGE con type, required, available, maxAuthorized, availableFolios, rejection y un reason (noUnusedFolios o unusedFoliosBlock). Cuando las tandas se detuvieron por una falla y no por la respuesta del SII, los CAF que obtuvieron ya están en el estado, y el paso lanza en cambio el código de esa falla, con type, operation: 'requestCafInBatches' y step (queryFolioQuota o requestCaf). Antes de la 0.5.0 el mismo código salía de las propias tandas, y los CAF que habían obtenido se perdían.
Una reobtención cuyas descargas se detuvieron por una falla, o una anulación cortada cuando el SII ya había respondido, termina el paso de la misma forma: lo que trajo la reobtención se conserva con la regla del paso 2, y lo que anuló la anulación va a annulledRanges; luego el paso lanza el código de la falla con type, operation (reobtainFolios o annulFolios), step y, cuando el SII rechazó, rejection. Antes de la 0.6.0 una anulación cortada contaba como ninguna y el paso terminaba con FOLIO_OUT_OF_RANGE, que leía una falla de red como racionamiento. El error lanzado, y el evento CERT_ERROR, traen solo el código y esas claves: el error original, con su reason, httpStatus y attempts, va al logger del cliente del portal como sii portal flow stopped, keeping what it holds, con sus textos tachados y sin lo que dijo una página ni su url.
Una solicitud que el SII responde con el formulario de solicitud otra vez, sin folios y sin motivo, termina con rejection: 'stampingUncertain'. No es un rechazo de racionamiento, así que por ella no se anula nada. Puede que el SII haya autorizado el rango: revisa los rangos que se pueden reobtener antes de volver a correr.
Una tanda posterior que el SII rechaza también conserva su tipo. Antes de la 0.7.0 cualquier rechazo del segundo viaje o de uno posterior, salvo stampingUncertain, salía de las tandas como quotaCapReached, que se lee como racionamiento: un rechazo de la empresa o de la opción llevaba al paso a anular folios, y un bloqueo de la persona no se levantaba primero. Ahora solo un folio por sobre el máximo después de una entrega (quotaExceeded) se lee como quotaCapReached, así que un rechazo posterior que no es racionamiento nunca lleva a anular, y un bloqueo de la persona se levanta primero reobteniendo, como en el primer viaje.
Anular no se puede deshacer y cuenta contra el cupo durante seis meses. El ejecutor lo hace solo como último recurso, cuando el SII raciona el tipo y muestra más folios sin usar que los que tiene la corrida. Ver Portal.
Los folios se comprueban contra el SII antes de emitir. Antes de emitir un set, se le pregunta al SII si ya tiene los folios que la corrida está por usar (como la empresa, hasta 30 consultas por CAF, el CAF más antiguo primero, hasta cubrir la necesidad); uno que el SII tiene se marca como usado. Un folio por el que el SII no puede responder se usa. Un rango obtenido de nuevo se usa solo a través de los folios que el SII mostró libres: todo otro folio de él se marca como usado apenas se guarda el CAF, así el registro cuenta exactamente los libres. El registro entrega su folio libre más bajo, no el siguiente al último. sendTestSet y sendSimulation marcan cada folio como enviado en el registro sea cual sea el resultado del envío.
Declaraciones#
declareProgress(portal, { entries }) declara envíos en el formulario de avance del SII (pe_avance2). Una entrada es { trackId, date } con la fecha como AAAA-MM-DD; las claves son las filas del formulario (basic, guide, exempt, purchase, los libros, simulation).
- Del formulario se leen los campos ocultos y el índice del campo de cada fila, buscada por su etiqueta (los índices se mueven al aprobarse sets). Una página sin formulario no envía nada y el resultado es
declined. - Se envían todos los campos
NUM_ENV,FEC_ENV,SETyESThastaTOTREGen el orden del formulario, con los valores que ya trae la página: el track id sin ceros a la izquierda y la fecha comodd-mm-aaaa. Una fila sin campo (aprobada, o en revisión) no agrega nada y el formulario se envía igual. - La página se lee de nuevo para verificar. La declaración queda en pie cuando ningún campo declarado volvió vacío, o alguna fila muestra
EN REVISION. Una fila que quedó vacía se pregunta de nuevo en el ciclo. - Con cada track id va la fecha de hoy en Chile, sea cual sea el día en que se envió el sobre.
ENVIO CON ERRORES O REPAROSes un estado de un envío, no una falla de la declaración. La respuesta nombra las filas afectadas (contentErrors); la declaración puede seguir en pie. La corrida pregunta una vez el estado SOAP de esos envíos y guarda la respuesta como diagnóstico.
outcome | Significado |
|---|---|
accepted, inReview | La declaración quedó en pie |
contentErrors | El SII encuentra errores en algunos envíos (la declaración misma puede seguir en pie, ver success) |
allRejected | Toda fila declarada volvió vacía: el SII no tomó ninguna |
notSaved | Algunas filas declaradas volvieron vacías |
inconsistent | Una fecha o número que el SII dice que no corresponde |
declined | No había formulario que enviar |
failed | Un envío que el portal no aceptó |
El ciclo de la corrida (declareTestSets, declareSimulation y la fase de libros) espera 10 s y luego hace hasta 10 intentos separados por 5 s. Una declaración que queda en pie lo termina, salvo que la respuesta diga que el SII aún no procesó los envíos, que se pregunta de nuevo (una sesión perdida se lee así, y el intento siguiente vuelve a iniciar sesión). Los errores de contenido se preguntan de nuevo mientras los campos declarados vuelvan vacíos (el SII aún no vio los track id); con los campos en su lugar se diagnostican y el ciclo termina. Una declaración que no se guardó se pregunta de nuevo; toda fila declarada vacía termina el ciclo, salvo en la simulación, donde se reintenta porque el portal muestra la simulación sin declarar mientras aún procesa el track id. El último intento devuelve lo que obtuvo, y cada página va a los artefactos.
Envíos de la corrida#
Cada sobre y cada libro de la corrida pasa por una misma rutina de envío.
- Reintentos. Un envío se repite solo ante una falla de red que nombra un socket reiniciado, una conexión que expiró o un host que no se resolvió: 8 intentos, 2 s creciendo ×1,8 hasta 15 s, sin jitter. Una petición que expiró en el reloj del propio cliente, una conexión rechazada y toda respuesta del SII no se reintentan.
- Cómo se lee la respuesta. Solo
STATUS0 con un elementoTRACKIDes un archivo enviado.STATUS7 es un duplicado: con un elementoTRACKIDse recupera el track id y el envío sigue como uno enviado, salvo que su primera línea de error nombre un rechazo de charset o de esquema.STATUS99, y cualquier otra cosa, es un envío fallido:SII_UPLOAD_REJECTEDconstatusyerrors. Un duplicado sin track id, donde hace falta uno, es ese mismo error conduplicate: true. - Cómo se lee un estado. El estado de un envío se pregunta una vez, por el canal SOAP, sin reintentos. Los estados se clasifican por código: exitosos (
EPR,RPR,LOK), intermedios (REC,SOK,FOK,PRD,CRT,DNK,PDR,LSO,0, y los códigos de error propios del servicio de consulta,-1a-14, que se leen como "pregunta de nuevo") y rechazados (RPT,RFR,VOF,RCT,RCH,RLV,RSC,LNC,LRH). Un estado que nunca respondió, o que no trae estado, no es ninguno de los tres.
La fase de libros#
runBooks arma, envía, declara y espera los libros.
- El período. Se lee año a año el historial de libros que tiene el SII (hasta dos años vacíos) y se marcan los períodos ocupados. El período es el mes UTC en que se leyó el set de pruebas cuando el set trajo un libro de compras, si no el mes UTC actual, o el primer mes libre bajo él, buscado de nuevo en cada corrida.
- Qué se envía. Un libro que el portal muestra como
REVISADO CONFORMEse omite. Los libros de compras, ventas y guías (y el de compras para exentos, cuando el plan lo trae) se arman, se guardan como artefactos y se suben. Un libro de compras que el SII ya tiene para el período va de nuevo como ajuste. - Libros obligatorios. Sin los tres libros obligatorios (
MANDATORY_BOOK_KEYS) enviados u omitidos, la fase terminaincomplete. Es el único caso en querunBooksterminaincomplete. - Antes de declarar. Se lee el estado SOAP de los libros enviados durante cerca de un minuto. Un libro rechazado queda fuera de la espera.
- Declarar. Los libros se declaran junto con los cuatro sets. Mientras toda fila declarada vuelva vacía, como máximo 24 veces, todos los libros van de nuevo: como ajuste una vez por período cuando se guardan los totales del libro de ventas o del de compras, si no como envío total en el siguiente período libre.
- Esperar. A una declaración que queda en pie le sigue la espera de aprobación (40 consultas separadas por 15 s, el estado SOAP cada dos consultas, porque el portal muestra un sobre rechazado como declarado para siempre). Una fila que la página deja rechazada, cerrada o declarada y nunca revisada mantiene la búsqueda aunque sea de un libro que esta corrida no envía (un libro de compras para exentos que el set de pruebas no trajo): no se envía nada por ella, pero los libros se declaran otra vez y esa fila se espera, hasta 24 veces.
Cuando un período está ocupado, todos los libros van de nuevo como ajuste, también el libro de guías y el de compras para exentos. Los libros que la declaración nombra con ENVIO CON ERRORES O REPAROS, o que el estado SOAP rechaza, no se esperan sino que se envían de nuevo. Ninguna lectura del portal de esta fase detiene la corrida: una página que no se puede leer solo gasta su consulta.
Avanzar de etapa#
Con los tres libros obligatorios enviados, el ejecutor pide al portal la etapa siguiente estén o no aprobados los libros: decide el portal. advanceToNextStage lee la página de avance (hasta 30 veces, separadas por 10 s, mientras no se pueda leer), pide el avance de inmediato con la primera página que se lee, y luego lee la página de nuevo para saber la etapa. La etapa del estado pasa a la del portal cuando esa es posterior.
| Resultado | Significado |
|---|---|
advanced | El portal avanzó |
unchanged | El portal dice que ya está en ese paso |
failed | El portal lo negó, o no se pudo hacer la petición. detail es su frase |
timedOut | La página de avance no se pudo leer en 30 intentos |
Nada de esto lanza por una respuesta del portal. Si el portal no avanzó y la etapa sigue siendo los libros, runCertification se detiene con rejected y la frase del portal.
Valores por defecto del operador#
El operador entrega menos de lo que necesita el SII, y la corrida completa el resto.
| Qué | Valor por defecto |
|---|---|
| Receptor | DEFAULT_CERTIFICATION_RECEIVER: RUT 66666666-6, CLIENTE TEST, ACTIVIDADES VARIAS, AVENIDA PRINCIPAL 123, Santiago. Un campo que entregues gana, campo por campo; uno vacío toma el valor por defecto |
| Emisor | DEFAULT_CERTIFICATION_ISSUER: giro ACTIVIDADES DE PROGRAMACION INFORMATICA, código de actividad 620200, comuna y ciudad Santiago. El RUT, la razón social y la dirección no tienen valor por defecto |
| Resolución | Número 0 y la fecha UTC del día en que partió la corrida |
La fecha de resolución por defecto solo es correcta el día en que el SII
resolvió la postulación. Cualquier otro día, entrega resolution.date tú
mismo. Una resolución omitida se fecha una sola vez, al partir la corrida, así
que todos los sobres de la corrida llevan la misma fecha.
El giro de un receptor se corta en sus 40 caracteres en vez de rechazarse, y también el del emisor cuando el emisor es el receptor de sus propios documentos (el set de compra, los traslados internos, la simulación). Como emisor conserva sus 80.
Las esperas#
| Espera | Comportamiento |
|---|---|
| Aprobación de los sets | 5 consultas separadas por 10 s, durmiendo primero |
| Ciclo de declaración | Primero 10 s, luego hasta 10 intentos separados por 5 s |
| Aprobación de los libros | 40 consultas separadas por 15 s, durmiendo primero |
| Aprobación de la simulación | 30 consultas separadas por 10 s, consultando primero |
| Lectura de la página de avance para avanzar | Hasta 30 lecturas separadas por 10 s |
| Estado SOAP de los libros antes de declarar | 3 rondas separadas por 15 s, tras una primera espera de 15 s |
Inyecta sleep y now en las dependencias para probar sin esperar. Una lectura que falla durante una espera solo gasta su intento.
La detención en cumplimiento#
Cuando las muestras impresas están enviadas, la etapa es compliance y la corrida se detiene con compliance hasta que pases declareCompliance: true. Entonces declareComplianceFinal pide al portal avanzar la etapa una vez más (un rechazo o un error solo va al log), y hace la declaración.
- La declaración cuenta como hecha cuando la última página ya no muestra su formulario. Guarda la página que deja el almacén y revísala.
- Un bloqueo (el portal dice que la certificación no ha terminado) es un dato:
stopped: 'blocked', con la frase también enstate.blocked. - Una última página que no confirma lanza
SII_PORTAL_UNEXPECTED_PAGE. - Una declaración termina la corrida: la etapa es
doney se emiteCERT_DONE.
Solo el representante legal puede hacer la declaración, y no se puede deshacer. Antes, comprueba en el portal que la revisión de muestras impresas esté aprobada.
Catálogos#
| Export | Qué contiene |
|---|---|
SET_KEYS | Los cuatro sets en el orden en que se envían: basic, guide, exempt, purchase |
BOOK_KEYS | Los libros en el orden en que se envían: purchaseBook, salesBook, guideBook, exemptPurchaseBook |
MANDATORY_BOOK_KEYS | Los libros que toda certificación debe tener aprobados: purchaseBook, salesBook, guideBook |
CERTIFICATION_STAGES | testSets, books, simulation, exchange, printedSamples, compliance, done |
CERTIFICATION_STEPS | Los nombres de los eventos de progreso |
DEFAULT_OPTIONAL_SETS | SET03 guías, SET06 facturas exentas, SET07 libro de ventas, SET08 libro de compras, SET09 libro de guías, SET15 libro de compras para contribuyentes exentos y SET72 el set de compra. El set básico (SET01) siempre se pide. Exportación y liquidación nunca se marcan |
BOOK_FILE_NAMES, BOOK_ARTEFACT_NAMES, SET_ARTEFACT_NAMES | El nombre de archivo con que viaja cada libro, y los nombres de artefacto de los libros y de los sobres de los sets |
PORTAL_STAGE_WORDS | Las palabras con que el portal nombra cada etapa |
Errores#
Los rechazos vuelven como datos. Todo lo demás es un DteError que se propaga después de guardar el estado: los códigos del portal (SII_PORTAL_REJECTED con un rejection, SII_PORTAL_SESSION_EXPIRED, SII_PORTAL_UNEXPECTED_PAGE, SII_PORTAL_CERT_NOT_ENABLED), los códigos de envío al SII (SII_UPLOAD_REJECTED), FOLIO_OUT_OF_RANGE y MISSING_FIELD. Ver Errores.
Próximos pasos#
- Las últimas etapas en detalle: Intercambio y muestras.
- Qué emite cada set: Sets de pruebas.
- Folios y el registro: Portal.