Repository navigation
v0.1.0
The first release with a public API. Documents, stamps, signatures and envelopes; the SII web services client and the public registry of authorized issuers; the SII books; the portal, folios and CAF requests; the purchase and sales register and the MIPYME backup; the certification of documents and of receipts; and the printed samples. Four entries (dte-sdk, dte-sdk/node, dte-sdk/portal, dte-sdk/pdf), ES modules only, on Node ≥ 22.12.
Every area is tested against synthetic SII answers with a 100 % coverage gate, and the folio flows also against the pages the certification environment served to an enrolled company. The runs against the real SII come before 1.0.0, the first version recommended for production (#8); the README's Status table says what has met the SII so far. Published from CI with an npm provenance attestation: run npm audit signatures to verify an installed copy.
Added
- The receiver's answer with the eight-day rule.
receiverAnswer(events, receivedAt, today)is a pure helper over
the events oflistClaimEvents, thereceivedAtofqueryReceptionDate(or null) and today in Chile. It gives the
answer,annulled(NCA),claimed(RCD,RFP,RFT),accepted(ACD),tacitlyAccepted(past the eight
calendar days of Ley 19.983 with none of those),goodsReceived(ERM) orpending, in that order of precedence,
andclaimDeadline, the reception day plus eight.PAG("DTE Pagado al Contado", which the SII registers itself) is
inCLAIM_EVENT_CODES; it andENCchange nothing.receiverStatusis unchanged. - The public registry of authorized issuers.
queryAuthorizedIssuer(sii, { rut })asksee_empresa_ruton
maullin or palena, with no certificate and no session, and returns the business name, the resolution of the
environment (resolutionNumber,resolutionDate: theNroResolandFchResolof the cover, number 0 in
certification), the regional office and each document type with the days it was authorized and deauthorized. A RUT
that is not an issuer throwsSII_PORTAL_REJECTEDwithrejection: 'companyNotAuthorized'; labels that moved leave
their fields null, and a page with neither a name nor document types throwsSII_PORTAL_UNEXPECTED_PAGE. It is in
the root entry, which fits it under its 32 kB limit. - Core issuance:
createDocument,stampDocument(TED),signDocument(enveloped XMLDSig),
issueDocument,createEnvelope/signEnvelope(EnvioDTE,EnvioBOLETA), verification
helpers (verifyTed,verifyDocumentSignature,verifyEnvelopeSignature). - Domain model in English with bilingual (EN/ES) JSDoc, SII-shaped types and the
toSiiDocument/fromSiiDocumentcodec. - Certificates from PKCS#12 and PEM, CAF parsing and validity, Chile-local timestamps,
text sanitization and ISO-8859-1 encoding, SII status code classification. - Dependencies:
node-forge,@xmldom/xmldom,fast-xml-parser,rut.ts. Optional peers ofdte-sdk/pdf:pdf-lib,
bwip-js. - SII web services client:
createSiiClient(plain data, no methods) and free functions
for seed/token on the DTEWS SOAP and receipts REST channels (getSeed,getToken),
uploads (uploadEnvelope,uploadBook,uploadFolioConsumption) with duplicate
recovery, status queries (queryUploadStatus,waitForUploadStatus,
queryDocumentStatus,folioReceived) and the acceptance/claim registry
(registerClaim,listClaimEvents,queryTransferable,queryReceptionDate,
receiverStatus). Uploads andregisterClaimare never re-sent once the SII has
answered, even if the reply was cut off halfway (transport errors then carry
details.responseStarted: true), except once with a fresh token when the SII refused
the token.retry.retryOncan narrow what is retried, never widen it. Getting a token is
one retry loop around seed, signature and token (a fresh seed per attempt), and
waitForUploadStatuspolls inside a hardtimeoutMsbudget instead of applying the
retry policy to every poll. Uploaded XML must open with an XML declaration naming
ISO-8859-1 (the bytes sent are ISO-8859-1), elseINVALID_OPTION { field: 'xml' }
before anything is sent; whitespace before the declaration is dropped. Errors follow the
spec: transport failures carrydetails.operation(andtimeoutMsonREQUEST_TIMEOUT),
SII_HTTP_ERRORcarriesdetails.url(never in the message) and
SII_UPLOAD_REJECTED.details.statusis a number. - Injectable HTTP transport (
createFetchTransport,createNodeHttpsTransportwith TLS
verification on by default;tls.caadds to Node's bundled roots instead of replacing
them), token cache (createMemoryTokenCache, andcreateDirectoryTokenCachefrom
dte-sdk/node: tokens and portal sessions on disk, one owner-only file per key that also
holds the key, read only when it is a regular file of the same user and without blocking,
shared by that user's processes, never throwing), retry policy with backoff, HTTP capture with
redaction (createMemoryCapture,createDirectoryCapture) and upload archive
(createMemoryUploadArchive,createDirectoryUploadArchive; a duplicate answer is kept
as<trackId>-<kind>-duplicate-<timestamp>and archived replies and SOAP fault reasons have
tokens redacted). SOAP calls send an emptySOAPAction. The Node adapters load
node:modules lazily, so importing the package evaluates nonode:module. - Catalogs:
DTEUploadreception statuses, claim actions/events/response codes,
FANdocument status, theRCOenvelope status (rejected), REST per-document status
endpoint, WSRECLAMO service URLs (CLAIM_WS_ENDPOINTS) and their WSDLs
(CLAIM_WSDL_ENDPOINTS). - Helpers for custom adapters and tests:
buildMultipartBody,buildSoapEnvelope/parseSoapResponse,
signSeed,signRootElement,redactExchangeandtokenCacheKey. - SII books: the purchase and sales book (
createPurchaseSalesBook, IECV), the dispatch guide book
(createGuideBook) and the folio consumption report (createFolioConsumption, RCOF), each with
build*Xml,sign*,verify*SignatureandtoSii*, in all the submission kinds of their
schemas. The SDK computes the summaries from the lines;summaryOnlyTotalsandpreviousTotals
(withaccumulateBookTotals/accumulateGuideTotals) carry what cannot be derived. An explicit
line total that differs from the SII formula is kept and reported intotalMismatches, and
strictTotals: truethrows the newBOOK_TOTAL_MISMATCH.bookEntryFromDocument,
guideEntryFromDocumentandfolioConsumptionEntryFromDocumentderive the lines from documents. - Book catalogs:
BOOK_OPERATIONS,BOOK_KINDS,BOOK_SUBMISSIONS,BOOK_DOCUMENT_TYPES,
isBookDocumentType,SUMMARY_ONLY_DOCUMENT_TYPES,NON_RECOVERABLE_VAT_CODES,
GUIDE_TRANSFER_TYPES,GUIDE_VOID_CODES, pluscompactFolioRanges. uploadBookanduploadFolioConsumptionacceptfileName, and aLibroGuiauploads as
LibroGuia.xmlby default.- SII portal:
createPortalClient, certificate login with reused sessions (openPortalSession,closePortalSession,
createMemoryPortalLock), company data (fetchCompanyResolution,fetchTaxpayerData,fetchIssuerProfile), certification
state (queryCertificationSets), folios (listStampableTypes,queryFolioQuota,requestCaf,listFolioRanges,
annulFolios,listReobtainableRanges,reobtainCaf) and composite flows (requestCafExact,requestCafInBatches,
reobtainFolios), withSII_PORTAL_*error codes,PORTAL_REJECTIONSand redaction of session cookies. Measured
against the real SII up to the login, the logout and the refusal pages; the pages of an enrolled company are not. - SII purchase and sales register (RCV) on the portal session:
listPeriodDocuments,fetchRegisterSummary,
listPurchaseTypes,fetchPurchaseDocument, and the writeschangePurchaseType,moveVatToCommonUseand
moveVatToRecoverable, one attempt each and confirmed only by the SII'sOK. Response codes are not looked at, so a
month the SII refuses to show reads as an empty one.PortalClientOptions.randomIdis new. - MIPYME backup:
downloadMipymeBackupsplits a date range to fit the 20 documents the SII allows per download and
downloads the XML, in the result or throughonChunk. It reads production whatever the client's environment. Known
defect: a two-day range with more than 20 documents downloads only its first day, whiletotalcounts both. - Local folio registry:
createFolioRegistry,createMemoryFolioRegistry,createDirectoryFolioRegistry,cafFingerprint. - Printed samples (Node):
parsePrintableDocuments(anyEnvioDTE,EnvioBOLETA,SetDTEorDTEXML, with each
TEDverbatim),renderPrintedSample(one single-page PDF per the SII printed-samples manual, with the transferable
copy and acknowledgement box),renderTedBarcode(the PDF417 stamp as PNG with the signed bytes),needsTransferableCopy,
renderPrintedSamples(in-memory batch classified into the test and simulation sets, failures as data) and the Node
adapterwritePrintedSamples/findEnvelopeFiles(SET-PRUEBASandSET-SIMULACIONon disk).pdf-lib
andbwip-jsload on first use. Error codesDEPENDENCY_UNAVAILABLEandPDF_RENDER_FAILED, anderrorCode.
A folio that is not a run of digits is anINVALID_FOLIOfailure of its document and never names a file, and the
Node adapter refuses a sample path outside the folder of its set. - Certification, the deterministic half:
parseTestSetText(the SII test-set text to typed sets and cases),
planCertificationSets,createFolioAllocator(aFolioSourceover one or several CAFs),issueTestSet(the
basic, exempt, guide and purchase sets through phase 1, with theSETreference and the field rules),issueSimulation
(every case again in one envelope) andcreateCertificationSalesBook,createCertificationPurchaseBook,
createCertificationGuideBookthrough phase 3. CatalogTEST_SET_KINDS,TEST_SET_PORTAL_NAMES,
TEST_SET_REFERENCE_TYPE,TEST_SET_ENVELOPE_ID,CERTIFICATION_COUNTERPARTY.DocumentInput.withholdVatwithholds
the VAT on the notes of a purchase invoice. Bundle limit to 64 kB. - Certification, the portal half, in
dte-sdk/portal:downloadTestSet,declareProgress,readProgress,
advanceStage,listBookHistory,declareComplianceon the phase 4 session, with pure page modules;
CertificationStateand theCertificationStoreport (createMemoryCertificationStore,
createDirectoryCertificationStore, private files); the stepsobtainTestSet,prepareFolios,sendTestSet,
declareTestSets,waitForTestSetsApproval,runBooks,advanceToNextStage,sendSimulation,declareSimulation,
waitForSimulationApproval,declareComplianceFinal, each returning the saved state with an outcome, with typed
progress events; andrunCertification, which chains them in the field's order, resumes from the saved state and
makes the irreversible declaration of compliance only withdeclareCompliance: true. CatalogSET_KEYS,BOOK_KEYS,CERTIFICATION_STAGES,CERTIFICATION_STEPS,
DEFAULT_OPTIONAL_SETS; portal rejectionsnotEnrolled,advanceRefused,declarationDeclined. The 5b-1 books
accept the cases a run keeps and an adjustment submission.dte-sdk/portallimit to 56 kB. - Certification, the exchange and the printed samples (
dte-sdk/portal): the GWT-RPC codec of the SII's portals
(gwtBody,gwtAnswer,encodeGwtLong,decodeGwtLong) and the discovery of their hashes (discoverGwtHashes,
with the pairs known to work as the fallback andgwtas the override); the exchange portal operations
downloadExchangeSet,validateExchangeUser,uploadExchangeAnswers,confirmExchange; the samples portal
operationsreadSamplesReview,createSamplesReview,uploadSample(a 5xx retried up to four attempts, 2, 4 and
6 s apart),submitSamplesReview,readSamplesDetail;createExchangeAnswersandparseExchangeSet, the three
answers to an exchange set (the reception response, the receipts of Ley 19.983 and the commercial approval) signed and
valid against the officialRespuestaEnvioDTE_v10.xsdandEnvioRecibos_v10.xsd; the stepsrunExchangeand
uploadPrintedSamples;runCertificationnow answers the exchange and uploads the samples given by thesamples
option (readPrintedSamplesfromdte-sdk/pdfreads them from a directory), stopping withexchange,
printedSamplesorrejectedin front of what it lacks, andexchangeSetXmltakes a set downloaded by hand;
CertificationStategainsexchangeandsamples; progress eventsINTERCAMBIO_START,INTERCAMBIO_DESCARGADO,
INTERCAMBIO_DONE,MUESTRAS_UPLOADING,MUESTRAS_DONE; the portal session takes raw bodies; catalog
EXCHANGE_PORTAL,SAMPLES_PORTAL,EXCHANGE_ANSWER_FILES; portal rejectionsexchangeUploadRefused,
samplesReviewRefused,sampleUploadRefused.dte-sdk/portallimit to 64 kB. - Certification of receipts (
dte-sdk/portal), as pieces to chain:parseReceiptsTestSet(the plain-text set of the
receipts portal),issueReceiptsSet(one receipt of type 39 per case, theSETreference, the signedEnvioBOLETA),
sendReceiptsSet(the envelope, 20 s, its status, then the folio consumption report with the sequence number 100
plus the attempt, up to ten attempts) andresendReceiptsConsumption; the receipts portal operations
downloadReceiptsTestSet,declareReceiptsTrackId,readReceiptsStatus(P90ready to declare,P91declared),
declareReceiptsCompliance(irreversible; the software provider is mandatory; the representative is the owner of
the session) andverifyReceiptsAuthorization(production and certification, never throws).readProgressgives
the receipts row of the progress page. CatalogRECEIPTS_PORTAL; portal rejectionsreceiptsNotEnrolled,
receiptsTrackIdRefused,receiptsComplianceRefused.dte-sdk/portallimit to 68 kB. receiptReferencesonDocumentInputandDocument, withReceiptReferenceInput,ReceiptReferenceand
SiiReferenciaBoleta: the reference of a receipt (39, 41) as the receipts schema defines it.- CAF files on disk (
dte-sdk/node):findCafFileslists the usable CAF files of a type and company below a directory
(five folder levels deep), newest first by modification time:.xmlfiles that parse as a CAF of thatTD, whose
REis the company (read from the file, never from its folder) and that have not expired; unreadable folders and
files are skipped.findLatestCafFilegives the first, andresolveCafFilethe newest withrequiredfree folios in
aFolioRegistry(or in its whole range without one), with its registryscope, or null. TypesCafFile,
FindCafFilesOptions,ResolveCafFileOptions,ResolvedCafFile.dte-sdk/nodelimit to 8 kB. - The SII office of each commune (
dte-sdk/pdf):SII_OFFICES(355 commune names in 40 offices) and
siiOfficeForCommune, which ignores case, surrounding spaces and accents.renderPrintedSampleand the batch
functions print the office of the issuer's commune whensiiOfficeis not given, andS.I.I. - SANTIAGO CENTROonly
for a commune the table lacks.dte-sdk/pdflimit to 11 kB.
Changed
-
Four entries.
dte-sdkkeeps documents, stamps, signatures, envelopes, books and the web services client over
fetch, and reaches nonode:module, so it bundles for the browser with no configuration.dte-sdk/nodeholds
createNodeHttpsTransport,createDirectoryCapture,createDirectoryUploadArchive,createDirectoryTokenCache,
createDirectoryFolioRegistryand the search for CAF files on disk.
dte-sdk/portalholds the portal, the folio registry, the register, the MIPYME backup and the certification sets.
dte-sdk/pdfholds the printed samples. OneDteErrorcrosses them. Why and the measurements:
docs/decisions/entry-points.md. -
ES modules only, on Node ≥ 22.12. The CommonJS build is gone.
require()still loads every entry from that version
on. Jest in its default CommonJS mode needs its ESM mode ortransformIgnorePatterns. -
pdf-libandbwip-jsare optional peers ofdte-sdk/pdf. The install drops from 44 MB to 6.6 MB. Whoever prints
installs them; without them the render functions throwDEPENDENCY_UNAVAILABLE. -
The certification run keeps to field behaviour: the test sets and their declaration. In what the SII receives and
in how the run flows, the runner now does what is known to work with the SII. The test set is asked for with the company in the last post (RUT_EMP,DV_EMP), a fixed
referer and the progress pages read first when no session is cached; no page on the way is searched for a refusal.
The documents of the test sets carry the UTC day and UTC stamps with milliseconds, unit prices with six decimals
(LineItemInput.unitPriceDecimalsis new;SiiDetalle.PrcItemis nownumber | string, a text when the price is
written with fixed decimals), zero totals without a VAT rate on the notes that correct a text, the unit
UNon the exempt notes, and every case of the guide set is planned as a guide.declareProgressreads the form by
its quoted attributes, posts even when no row has a field, verifies with one post and returns the new
DeclarationResult(success,verified,inReview,emptyFields,contentErrors,allRejected); the outcomes
areaccepted,inReview,contentErrors,allRejected,notSaved,inconsistent,declinedandfailed, and
DeclarationVerificationreplacesDeclarationRowandVerificationState. The declaration carries today's Chile
date for every track id.readProgressreads each state as the first bold text after its label anywhere on the
page andItemStategainsobjections; the wait for the sets counts a failed read as an attempt, takes a page that
shows none of the sets sent as approval and goes on waiting on objections alone. The envelopes of the run are
uploaded with eight attempts on network failures only and their answers read anew (STATUS99 is a
failed send;SII_UPLOAD_REJECTEDcarriestrackIdElement).DEFAULT_PORTAL_TIMEOUT_MSis 20 s, for every portal
operation that sets notimeoutMsof its own, not only the certification ones.
CertificationDependencies.receiverand.resolutionare optional and the issuer may leave out its activity, its
activity code, its commune and its city (DEFAULT_CERTIFICATION_RECEIVER,DEFAULT_CERTIFICATION_ISSUER,
CertificationIssuerInput).StampOptions.stampedAt, thesignedAtoption ofsignDocumentand
IssueDocumentInput.timestamplet a caller set the stamps.dte-sdk/portallimit to 70 kB. -
The certification run keeps to field behaviour: the books, the advance, the simulation and the closing.
runBooks
starts over on every run: the period is the UTC month the test set was read in (CertificationState.setReadDateis
new) when the set brought a purchase book, else the current UTC month, and the approved books are what the portal
shows, by the name each row holds. The uploads follow the retries and the reading of the run; a purchase book goes
again as an adjustment only on a duplicate without a track id or a schema rule on the first error line. The SOAP
status is read for a minute with a count of failures per book; every book with a track id is declared with the sets;
while every row comes back empty all the books go again; the books the SOAP status rejected or the declaration named
with content errors are not awaited; after the wait the books the page shows rejected, closed or declared and never
reviewed go again under their exact name; no portal read stops the phase.BooksOutcomekeeps its values, but only
incompletestops the runner, andBOOKS_DONE.successmeans the three mandatory books were sent.
queryCertificationSetsreturns no sets for a page without rows instead of throwing.advanceToNextStagereads the
progress page (30 tries 10 s apart while it cannot be read), asks for the advance at once, reads the page again and
returnsadvanced,unchanged,failedortimedOutwithout throwing for a portal answer; the runner stops with
the portal's sentence when the portal does not move. The three certification books acceptsubmission: 'adjustment'(the guide book too), the withheld VAT rate ofOtrosImpis written 0.19, the common-use credit is
rounded per document (BookTotals.commonUseCreditis new), the summaries carry noTpoImp, and the exempt purchase
book and the purchase-book sets are read anew. The simulation carries the local date of the process, UTC stamps to
the second, its own totals (0 with no VAT rate when the lines add up to nothing) and a guide withoutTpoDespacho; it is declared
unless the progress page names the exchange, and awaited with reads that never throw,REPAROas a rejection and
one SOAP query when the polls run out.advanceStageanddeclareCompliancefollow the client's retry policy;
the compliance wizard posts every named input of the page and counts the declaration as made when the last page no
longer shows its form;declareComplianceFinalasks for the advance once, without reading the progress, and declares
whatever came of it. Found while checking each of these, and fixed: a separator line
no longer ends the purchase-book set for exempt taxpayers; a document flagged as common use with no VAT stays out of
TotOpIVAUsoComun; a receiver's business activity is cut at 40 characters instead of refused, so an issuer with a
longer one can be the receiver of its purchase documents, internal transfers and simulation; the books are declared
sales first, which is the order a diagnosis asks the status service in; after the first wait every failed row of the
page keeps the search going and is awaited in the order of the page, also one of a book the run does not send; the
first post of the declaration of compliance namespe_avance7as its referer and its pages are read with fixed
patterns; and a progress page that cannot be read before the simulation is declared no longer ends
the run. -
The certification run keeps to field behaviour: folios and web services. Most of this reaches every caller,
not only the run. SOAP calls send an emptySOAPActionand escape their parameters with&,<and>only
(escapeXmlMarkupis internal); the REST status queries send the uploadUser-Agent;folioReceivedasks as the
company and reads the answer from the code and the state gloss alone (FAUor "no recibido" is free, any other
"recibido" is used, the rest is undetermined), andqueryDocumentStatustakesconsultantRut. An authorised range
is recovered with the UTC date, and "company not authorised" is only the wordingempresa no está autorizada para operar. The reobtention sends referers without a host, picks its forms by their exact opening tag, reads only
inputs with a quoted name and value, does no session handling on the way in and looks for no refusal: an expired
session or a refusal page is an empty list, and inreobtainFoliosa listing that fails for any reason is no ranges
(ReobtainResultlosesrejection).annulFoliosappliesmaxRangesto each pass, not to the call (up to four
passes: up to 200 ranges by default, 80 inrequestCafExact), and tries each step up to three times whatever the
error.FolioRegistry.reservetakes{ lowestFree: true }(ReserveOptions): the lowest folio of the range that
is neither used nor annulled, instead of the next one after the last reserved, which stays the default. In the run,
folios are taken with that option, because the run marks used the folios the SII did not show free;
prepareFoliosasks the SII for the folios it is about to use (30 queries per CAF at the most) and marks the
received ones used, reads a maximum it cannot read as no cap, obtains again with the whole need (the ranges kept
take the place of the CAFs in hand; ranges only listed cover nothing), never asks for a blocked type, asks in as
many batches as folios are missing, reads the maximum again after annulling, never annuls a range it downloaded,
keeps a range obtained again only through the folios the SII showed free, saves every CAF as it is obtained, and
remembers the annulled ranges in the newCertificationState.annulledRanges.dte-sdk/portallimit to 72 kB. -
The certification run keeps to field behaviour: the exchange and the printed samples. None of this changes a
default outside the two portals: the shared pieces it needs are options that only their stages turn on. The exchange
portal is called with the known pair of hashes, without the discovery request, and its user validation writes the
fixed table of strings. Each portal is entered once per stage of work: one warm-up for the download of the set, one
for the validation, the uploads and the confirmation, one for the whole of the samples; the saved session is checked
once per stage, the cookies of a warm-up stay in its stage, and when the warm-up of the samples gets no answer the
known hashes stand. The calls of both portals are sent once, with no time-out of their own, a fixed set of
headers and their answers read as UTF-8 (withExchangeStage,withSamplesStageandGwtStageare new; the
operations takestage). Inside a stage every answer goes back to its call whatever its status, with no look for
the firewall's page: a 502, 503 or 504 on the user validation or on the set validation no longer stops the exchange,
and a warm-up that answers an error is a warm-up all the same. Any failure of the set download issetUnavailable,
the page that came back kept when the store takes it (a downloaded set the store cannot keep is an error of the
run); the download uses its own multipart limit. The exchange set is read loosely (no well-formedness check, tags by
their full name, numbers as the parser reads them, unreadable ones 0, missing dates and RUTs empty, only the
known document shapes) and the contact of the answers travels as given. A sample keeps its file name
as given, written as UTF-8 in the part header (buildMultipartPartstakesutf8Headers, off by default); after the
review is submitted its state is read again whatever the status of the answer (readSamplesReviewtakes
anyStatus, off by default), and a re-read that gets no answer leaves the stage as submitted. -
The certification run keeps to field behaviour: the receipts.
parseReceiptsTestSetreads the set by position
(tabs or two or more spaces, the header andOBSERVACIONin exact case, a price without its dots and first comma,
the unit as the last word after " en "). The receipts carry the UTC day and each is stamped and signed with the UTC
instant to the second (only the envelope keeps the time of Chile);issueReceiptsSettakes an issuer without
activity, activity code, commune or city and a missing or partial resolution, with the defaults of the document
runner.sendReceiptsSetandresendReceiptsConsumptionupload through the reading and the retries of the run
(envelopeTrackIdisstring | null: null for a duplicate the SII names no track id for), ask each status once,
take a query that never got through as accepted and an unanswered or unknown state as a rejection, name the report
RCOF_<rut>_<clock>and report a rejection with the SII's own gloss. Every request to the receipts portal and to
the production authorisation check carries only a fixed set of headers, is sent once, waits 30 s (20 s in
production) and is read as UTF-8 whatever its status, the firewall's page included; the operations take
sessionChecked. The representative comes from the session's cookies (the list is read again as the fallback, the
check digit falls back to8); the statesP90andP91are searched in the raw answer; the posts of the track id
and of the declaration are judged by//OKalone; the declaration is dated with the local date and writes the
provider's name and mail and the business name as given; the track id is declared as given.
verifyReceiptsAuthorizationreads the progress page with one request and fixed wordings, and posts the
stamping form with the company as the caller wrote it. Also here:advanceStageanddeclareComplianceno longer
search their pages for a refusal.
Fixed
- Every official commune has its SII office.
SII_OFFICEScovered 306 names in 37 offices, and 49 of the 346
official communes had none, so a printed sample of an issuer in Talcahuano, Chimbarongo or San Vicente got the
default legend. They are now placed by the jurisdiction of the SII unit that serves each: under the office the table
gives to the commune where that unit sits, or under a new office named after it (S.I.I. - TALCAHUANO,
S.I.I. - PANGUIPULLI,S.I.I. - CHAITÉN); the official spellings of names it had (Llay-Llay, Treguaco, Mostazal,
Saavedra) go with them, and Quemchi, which two units serve, goes with the one that serves fewer communes. No existing
name changed office: 355 names in 40 offices. - The proportionality factor of the register reads with a decimal comma.
dcvFctPropreportedly comes as a text
with spaces and a decimal comma (" 1,0000","0,8532"), whichfetchRegisterSummaryread as no factor. It now
reads that form too; a value outside 0 to 1 is not a factor, so it is null and stays inraw. - A certificate not valid yet is refused.
loadCertificateFromPemandloadCertificateFromPkcs12checked only
notAfter; a certificate whosenotBeforeis still ahead, by the samenowoption, now throws the new
CERT_NOT_YET_VALIDwithdetails.validFrom.allowExpiredlets either case load. - Portal pages that declare UTF-8 only in a
<meta>are read as UTF-8. The login pages of herculesr say
charset=UTF-8in the page and not in the header, and a page without a charset in its header was always decoded as
Latin-1, so what they said reacheddetails.portalMessagegarbled ("Autenticación"). With no charset in the header,
the first 1024 bytes are now read for a<meta>that declares UTF-8; a charset in the header still decides. - A CAF authorized at the end of a month expires on the last day of the sixth month.
cafExpiresAtlet the day run
over into the next month: a CAF authorized on 2026-08-31 expired on 2027-03-03 instead of 2027-02-28, so it could
stamp documents the SII rejects withCAF-3-517. The day is now kept within the month (2027-08-31 gives
2028-02-29), still at midnight continental Chile;isCafExpiredandfindCafFilesfollow. - The reobtention is entered like the other procedures.
listReobtainableRangesasked for the procedure with a
plain request, so with a session that had expired it got the login page and returned an empty list and no error, as
it did in the certification environment. It now goes through the login on demand and the representation screen, and
only a listing gives a list (empty when it has no ranges): a stated refusal throwsSII_PORTAL_REJECTED, a login
pageSII_PORTAL_SESSION_EXPIREDand any other pageSII_PORTAL_UNEXPECTED_PAGE.reobtainFoliosstill does not
throw for a failed listing: it reads as no ranges, with the failure inreason. - Stamping reads the quota form of the type, and never sends a request twice. The page of the company, with only
-1 NINGUNOchosen, also posts toof_confirma_folio, soqueryFolioQuotacould report a type as unrationed and
requestCafcould skip choosing the type. A page is now the quota form only when the type asked for is the option its
selector has chosen; otherwise the type is chosen first, and a last page that is not that form (a login page, an
unknown page) throwsSII_PORTAL_SESSION_EXPIREDorSII_PORTAL_UNEXPECTED_PAGE. The request form itself posts to
of_confirma_foliowithFOLIO_INICIAL0 too: when the SII shows it again after a request, its button ("Solicitar
Numeración", not "Confirmar Folio Inicial") tells it apart, nothing is sent a second time, and the new rejection
stampingUncertainsays to check the reobtainable ranges before asking again; a refusal the page states is that
refusal.requestCafInBatchesreportsstampingUncertainas such instead of asquotaCapReached. "No está autorizado
para solicitar timbraje" reads asuserWithoutPermission. Thedte-sdk/portalsize limit goes from 72 kB to 74 kB. - An annulment answer is read only by its own words. Every page of the annulment says it is for folios "que no han
sido recepcionados por el SII", and the listings say "ningún folio haya sido recepcionado": those sentences are
taken out before an answer is read. Before, any answerannulFoliosdid not know read as a conflict and then as
received, which is final, so the folios went intoknownAnnulledand were never tried again. An answer now counts
only by a concrete sentence ("ha autorizado la anulación" or the headingSOLICITUD ANULACION DE FOLIOS, received,
annulled before, error 500), and anything else isunknown, which is not final and never entersknownAnnulled.
Therefusedreason is gone: it came from loose words that matched every page. A single folio whose answer is a
conflict keeps that answer instead of being sent again, and a rangeaf_anular3reports as annulled before is
alreadyAnnulledonly for the folios that page lists ("Folio Inicial Anulado", "Folio Final Anulado"), the rest of
itunknown. - The test set is read in the case field behaviour reads it.
EXENTOin the name of an invoice item,ANULAin the
reason of a basic-set note andMODIFICA MONTOin a reason count in capitals only, and so do the words that keep a
row of a case from being an item (DOCUMENTO,REFERENCIAorRAZONopening the row,ITEM,CANTIDADor
UNITARIOin its first part). They were matched in any case, so a word in lower case changed the documents sent: a
"Servicio exento" line was exempt, a note whose reason said "anula" took the items of the cancelled case, the value of
a two-part row under "modifica monto" was read as a price, and an item named "Razones varias" was dropped. - A receipt (39, 41) with a reference was written with the invoice shape of
Referencia(FchRef), which the receipts
schema does not allow. Receipts now takereceiptReferences, andreferenceson a receipt is refused with
INVALID_OPTION, as isreceiptReferenceson any other type. The officialEnvioBOLETA_v11.xsdis in the test
fixtures and the receipts envelope validates against it. - ES module consumers on
moduleResolution: nodenextget the real types. The declarations lacked extensions in their
relative imports, which was 165 errors, or every type silentlyanyunderskipLibCheck.
Removed
- The placeholder
hello()export.
Full notes: CHANGELOG.md