feat(gre): Guía de Remisión Electrónica REST API#7
Merged
Merged
Conversation
End-to-end emission of GRE 2022 (CPE tipo 09) via SUNAT's REST API, the third major SUNAT integration after CPE SOAP (PRs #1-#2) and SIRE (PRs #4, #6). Reuses the XAdES-BES signer. Why GRE matters: every empresa que mueve inventario (retail, ecommerce, distribución) needs guías de remisión per traslado. SUNAT requires GRE electrónica since 2022. Until this PR the command was a stub. What's new: 1. OAuth scope + host (oauth.ts) - SUNAT_REST_BASES.cpe = "https://api-cpe.sunat.gob.pe/v1" - SCOPES.gre = "https://api-cpe.sunat.gob.pe" - callRestApi gains baseHost: "cpe" (in addition to "api" / "sire") - Uses password grant (same as SIRE), separate client_id/secret per SOL menu URI = "GRE Emisión de Comprobantes" 2. UBL 2.1 DespatchAdvice builder (src/cpe/ubl/gre.ts) - Distinct schema from Invoice (Factura/Boleta) - DespatchSupplierParty (emisor) + DeliveryCustomerParty (destinatario) - Shipment block with HandlingCode (catalog 20, motivo de traslado), TransportModeCode (catalog 18, modal), GrossWeightMeasure - ShipmentStage with TransitPeriod + DriverPerson (chofer) - Delivery with DeliveryAddress (llegada) + Despatch.DespatchAddress (partida) - TransportEquipment with placa - DespatchLine per item (UBL/GS1 commodity classification) - cac:Signature stub for XAdES injection (reuses common.ts helper) 3. REST client (src/sunat-rest/gre.ts) - greCredentials() — password grant for api-cpe scope - enviarGre({filename, signedXml}) — POST with body: {archivo: {nomArchivo, arcGreZip(b64), hashZip(sha256)}} - consultarGreTicket(numTicket) — GET status - pollGreTicket() — backoff polling (2s/4s/8s/16s/30s, max 5min) - Codes: 0001=Aceptado, 0002=Anulado, 0003=Rechazado, 0098=En proceso 4. Commands - sunat cpe gre emit --params '{...}' [--dry-run] [--yes] [--wait] [--timeout] - sunat cpe gre status --ticket <id> [--wait] - Old "cpe guia" stub now redirects to "cpe gre" with a clear notice 5. Scope of THIS PR (deliberate) - tipoDoc 09 (Guía Remitente). GRE Transportista (31) is a separate schema, deferred. - modTraslado 02 (transporte privado, emisor mueve los bienes). Modal 01 (transporte público / CarrierParty + nroMtc) deferred. - codTraslado 01 (Venta) primary use case; other catalog 20 codes accepted by typing. - No BuyerCustomerParty (when buyer != destinatario), no SellerSupplierParty (tercero), no AdditionalDocumentReference. Easy adds when needed. Tests: 265 pass / 2 skip / 0 fail in 3.1s (was 240) - ubl-gre.test.ts (16) — XML structure assertions, ID format, namespaces, party blocks, shipment, transport equipment, weight, line count, BOM check - gre-rest.test.ts (9) — OAuth password grant for api-cpe scope, POST URL shape, JSON body (archivo.nomArchivo/arcGreZip/hashZip), sha256 hash matches zip bytes, GET status URL, polling state transitions LIMITATIONS.md updated: - Move "Guía de Remisión" out of "shaped" — now a partial implementation with clear sub-limitations (modal 01, transportista doc 31, buyer/tercero, additional refs, multiple choferes)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End-to-end emission of GRE 2022 (CPE tipo 09) via SUNAT's REST API. Third major SUNAT integration after CPE SOAP (PRs #1-#2) and SIRE (PRs #4, #6). Reuses the XAdES-BES signer from PR #1.
Why GRE matters: every empresa que mueve inventario (retail, ecommerce, distribución) needs guías de remisión per traslado. SUNAT requires GRE electrónica desde 2022. Hasta este PR el comando era un stub.
What's in this PR
OAuth scope + host (
oauth.ts)SUNAT_REST_BASES.cpe=https://api-cpe.sunat.gob.pe/v1SCOPES.gre=https://api-cpe.sunat.gob.pecallRestApiahora soportabaseHost: "cpe"(además de"api"/"sire")UBL 2.1 DespatchAdvice builder (
src/cpe/ubl/gre.ts)DespatchSupplierParty(emisor) +DeliveryCustomerParty(destinatario)ShipmentconHandlingCode(catalog 20, motivo de traslado),TransportModeCode(catalog 18, modal),GrossWeightMeasureShipmentStageconTransitPeriod+DriverPerson(chofer)DeliveryconDeliveryAddress(llegada) +Despatch.DespatchAddress(partida)TransportEquipmentcon placaDespatchLinepor item (UBL/GS1 commodity classification)cac:Signaturestub para inyección de XAdES (reusa helper común)REST client (
src/sunat-rest/gre.ts)enviarGre({filename, signedXml})— POST con body{archivo: {nomArchivo, arcGreZip(b64), hashZip(sha256)}}consultarGreTicket(numTicket)— GET statuspollGreTicket()— backoff 2s/4s/8s/16s/30s, max 5min0001Aceptado ·0002Anulado ·0003Rechazado ·0098En procesoCommands
The old
cpe guiastub now redirects tocpe grewith a clear notice.Tests
Out of scope (deferred per LIMITATIONS.md)
SUNAT_GRE_CLIENT_ID/SECRETfrom real RUC's SOL menu (test cert from PR feat(cpe): CPE namespace + sunat-direct driver (Factura, verified end-to-end) #1 doesn't have these). Code matches Greenter twig template byte-for-byte.<cac:CarrierParty>+ RUC + nroMtc. Only modal 02 (privado) shipped.Test plan
bun testgreen (265/2 skip/0 fail)sunat cpe gre --helplists emit + statussunat cpe gre emitrequires--params(E2E gate test)sunat cpe guia(legacy) prints redirect notice (E2E test)LIMITATIONS.mdupdated (sub-limitations enumerated)