sunat-engine-nest 2.0.0 → 2.0.1

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/README.md CHANGED
@@ -1,30 +1,8 @@
1
1
  # sunat-engine-nest
2
2
 
3
- ![npm](https://img.shields.io/npm/v/sunat-engine-nest)
4
- ![license](https://img.shields.io/npm/l/sunat-engine-nest)
5
-
6
3
  Motor de Facturación Electrónica SUNAT UBL 2.1 para NestJS.
7
4
 
8
- Soporta Facturas, Boletas, Notas de Crédito/Débito, Guías de Remisión (GRE), Resúmenes Diarios y Comunicaciones de Baja — firma XML, envío a SUNAT/OSE, parseo de CDR y generación de PDF.
9
-
10
- ## Índice
11
-
12
- - [Instalación](#instalación)
13
- - [Configuración](#configuración)
14
- - [Registro síncrono](#registro-síncrono)
15
- - [Registro asíncrono](#registro-asíncrono)
16
- - [Proveedor: SUNAT directo vs OSE](#proveedor-sunat-directo-vs-ose)
17
- - [Certificado digital](#certificado-digital)
18
- - [Variables de entorno](#variables-de-entorno)
19
- - [Uso](#uso)
20
- - [Enviar un comprobante](#enviar-un-comprobante)
21
- - [Documentos soportados](#documentos-soportados)
22
- - [Generación de PDF (función paga)](#generación-de-pdf-función-paga)
23
- - [Testing / Modo simulado](#testing--modo-simulado)
24
- - [Respuesta del motor](#respuesta-del-motor)
25
- - [Endpoints SUNAT](#endpoints-sunat)
26
- - [Soporte y actualizaciones](#soporte-y-actualizaciones)
27
- - [Licencia](#licencia)
5
+ Soporta Facturas, Boletas, Notas de Crédito/Débito, Guías de Remisión (GRE), Resúmenes Diarios y Comunicaciones de Baja.
28
6
 
29
7
  ## Instalación
30
8
 
@@ -38,11 +16,10 @@ pnpm add sunat-engine-nest
38
16
 
39
17
  Registra el módulo en tu `AppModule`. Puedes definir las credenciales de tu empresa **una sola vez** en el módulo usando el campo `sunat`, evitando repetirlas en cada llamada.
40
18
 
41
- ### Registro síncrono
42
-
43
19
  ```typescript
44
20
  import { SunatEngineModule } from 'sunat-engine-nest';
45
21
 
22
+ // Registro síncrono
46
23
  @Module({
47
24
  imports: [
48
25
  SunatEngineModule.forRoot({
@@ -65,14 +42,11 @@ import { SunatEngineModule } from 'sunat-engine-nest';
65
42
  export class AppModule {}
66
43
  ```
67
44
 
68
- ### Registro asíncrono
69
-
70
- Recomendado cuando las credenciales dependen de variables de entorno.
71
-
72
45
  ```typescript
73
46
  import { SunatEngineModule } from 'sunat-engine-nest';
74
47
  import { ConfigModule, ConfigService } from '@nestjs/config';
75
48
 
49
+ // Registro asíncrono (recomendado con variables de entorno)
76
50
  @Module({
77
51
  imports: [
78
52
  ConfigModule.forRoot({ isGlobal: true }),
@@ -105,7 +79,29 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
105
79
  export class AppModule {}
106
80
  ```
107
81
 
108
- ### Proveedor: SUNAT directo vs OSE
82
+ ## Variables de entorno
83
+
84
+ ```env
85
+ # Credenciales SUNAT
86
+ SUNAT_RUC=20123456789
87
+ SUNAT_SOL_USER=MODDATOS
88
+ SUNAT_SOL_PASS=moddatos
89
+ SUNAT_CERT_PEM=BASE64_DEL_P12
90
+ SUNAT_MODE=beta
91
+
92
+ # GRE (Guía de Remisión Electrónica)
93
+ GRE_AUTH_URL=https://gre-test.nubefact.com/v1
94
+ GRE_API_URL=https://gre-test.nubefact.com/v1
95
+ GRE_CLIENT_ID=tu_client_id
96
+ GRE_CLIENT_SECRET=tu_client_secret
97
+
98
+ # OSE (solo si provider=ose)
99
+ PROVIDER=ose
100
+ OSE_URL=https://api.tuose.com/v1/documents
101
+ OSE_TOKEN=tu_token_aqui
102
+ ```
103
+
104
+ ## Proveedor: SUNAT directo vs OSE
109
105
 
110
106
  Puedes elegir enviar tus comprobantes **directamente a SUNAT** o a través de un **OSE (Operador de Servicios Electrónicos)** autorizado como Nubefact, EFACT, DigiFlow, Bizlinks, entre otros.
111
107
 
@@ -132,7 +128,7 @@ SunatEngineModule.forRoot({
132
128
 
133
129
  > El `OseClient` es genérico y compatible con cualquier OSE que acepte `{ fileName, contentFile }` (ZIP en base64) vía POST con autenticación Bearer o Basic.
134
130
 
135
- ### Certificado digital
131
+ ## Certificado digital
136
132
 
137
133
  El motor acepta el certificado en tres formatos:
138
134
 
@@ -154,32 +150,8 @@ const credentials: CompanyCredentials = {
154
150
  };
155
151
  ```
156
152
 
157
- ### Variables de entorno
158
-
159
- ```env
160
- # Credenciales SUNAT
161
- SUNAT_RUC=20123456789
162
- SUNAT_SOL_USER=MODDATOS
163
- SUNAT_SOL_PASS=moddatos
164
- SUNAT_CERT_PEM=BASE64_DEL_P12
165
- SUNAT_MODE=beta
166
-
167
- # GRE (Guía de Remisión Electrónica)
168
- GRE_AUTH_URL=https://gre-test.nubefact.com/v1
169
- GRE_API_URL=https://gre-test.nubefact.com/v1
170
- GRE_CLIENT_ID=tu_client_id
171
- GRE_CLIENT_SECRET=tu_client_secret
172
-
173
- # OSE (solo si provider=ose)
174
- PROVIDER=ose
175
- OSE_URL=https://api.tuose.com/v1/documents
176
- OSE_TOKEN=tu_token_aqui
177
- ```
178
-
179
153
  ## Uso
180
154
 
181
- ### Enviar un comprobante
182
-
183
155
  Inyecta `SunatEngineService` en cualquier servicio o controlador. Si configuraste `sunat:{}` en el módulo, **no necesitas pasar credenciales en cada llamada**:
184
156
 
185
157
  ```typescript
@@ -250,85 +222,18 @@ return this.engine.sendInvoice(payload, {
250
222
  });
251
223
  ```
252
224
 
253
- ### Documentos soportados
254
-
255
- | Tipo | Método de envío | Descripción | PDF |
256
- |------|------------------|-------------|-----|
257
- | Factura (01) | `sendInvoice()` | Factura electrónica — SOAP síncrono | ✅ `generateInvoice()` |
258
- | Boleta (03) | `sendInvoice()` | Boleta de venta electrónica — SOAP síncrono | ✅ `generateInvoice()` |
259
- | Nota de Crédito (07) | `sendNote()` | NC electrónica — SOAP síncrono | ✅ `generateNote()` |
260
- | Nota de Débito (08) | `sendNote()` | ND electrónica — SOAP síncrono | ✅ `generateNote()` |
261
- | Guía de Remisión (09) | `sendDespatch()` | GRE 2022 — REST/OAuth asíncrono | ✅ `generateDespatch()` |
262
- | Resumen Diario (RC) | `sendSummary()` | Resumen de boletas — SOAP asíncrono | — (comunicación interna a SUNAT) |
263
- | Comunicación de Baja (RA) | `sendVoided()` | Baja de comprobantes — SOAP asíncrono | — (comunicación interna a SUNAT) |
264
- | Consulta de ticket | `getTicketStatus()` | Estado de procesos asíncronos | — |
265
-
266
- ## Generación de PDF (función paga)
267
-
268
- El envío a SUNAT (XML, firma, CDR, GRE) sigue siendo **MIT / gratuito**. La generación de PDF es una función **paga**: necesitas una license key para usarla — [escríbeme por WhatsApp](https://wa.me/51907596305) para adquirir una.
269
-
270
- La licencia se valida **localmente** (firma Ed25519), sin llamadas a ningún servidor externo — tus datos de facturación nunca salen de tu infraestructura.
271
-
272
- ```typescript
273
- SunatEngineModule.forRoot({
274
- sunat: { ruc: '...', solUser: '...', solPass: '...', certPem: '...' },
275
- pdf: {
276
- licenseKey: 'LA_LICENSE_KEY_QUE_TE_ENTREGO', // o desde tu ConfigService/env
277
- },
278
- })
279
- ```
280
-
281
- ```typescript
282
- import { DocumentPdfService } from 'sunat-engine-nest';
283
-
284
- @Injectable()
285
- export class InvoicesService {
286
- constructor(
287
- private readonly engine: SunatEngineService,
288
- private readonly pdf: DocumentPdfService,
289
- ) {}
290
-
291
- async getPdf(payload: InvoicePayload): Promise<Buffer> {
292
- return this.pdf.generateInvoice(payload, 'A4'); // 'A4' | 'TICKET_80MM' | 'STICKER_A6'
293
- }
294
- }
295
- ```
296
-
297
- Sin `pdf.licenseKey` configurada (o con una key inválida/expirada), los métodos de PDF lanzan un `PdfLicenseError`.
298
-
299
- ### Personalizar diseño (logo y color de marca)
300
-
301
- El formato `A4` acepta branding opcional. Si no se especifica, usa un azul corporativo por defecto.
302
-
303
- ```typescript
304
- return this.pdf.generateInvoice(payload, 'A4', {
305
- licenseKey: 'OTRA_LICENSE_KEY', // opcional — tiene prioridad sobre la del módulo
306
- branding: {
307
- color: '#0f766e', // hex, opcional
308
- logoBase64: 'data:image/png;base64,...', // opcional
309
- },
310
- });
311
- ```
312
-
313
- ### Nota de Crédito / Débito
225
+ ## Documentos soportados
314
226
 
315
- Mismo diseño y misma licencia que las facturas.
316
-
317
- ```typescript
318
- await this.pdf.generateNote(notePayload, 'A4'); // 'A4' | 'TICKET_80MM' | 'STICKER_A6'
319
- ```
320
-
321
- ### Guía de Remisión (GRE)
322
-
323
- Solo formato `A4` incluye destinatario, datos de traslado, punto de partida/llegada, transportista/vehículo/conductor.
324
-
325
- ```typescript
326
- await this.pdf.generateDespatch(despatchPayload, {
327
- branding: { color: '#0f766e' }, // opcional
328
- });
329
- ```
330
-
331
- > Resumen Diario (RC) y Comunicación de Baja (RA) no tienen representación en PDF — son comunicaciones internas a SUNAT, no documentos que se entreguen a un cliente ni que viajen con la mercadería.
227
+ | Tipo | Método | Descripción |
228
+ |------|--------|-------------|
229
+ | Factura (01) | `sendInvoice()` | Factura electrónica — SOAP síncrono |
230
+ | Boleta (03) | `sendInvoice()` | Boleta de venta electrónica — SOAP síncrono |
231
+ | Nota de Crédito (07) | `sendNote()` | NC electrónica — SOAP síncrono |
232
+ | Nota de Débito (08) | `sendNote()` | ND electrónica — SOAP síncrono |
233
+ | Guía de Remisión (09) | `sendDespatch()` | GRE 2022 — REST/OAuth asíncrono |
234
+ | Resumen Diario (RC) | `sendSummary()` | Resumen de boletas — SOAP asíncrono |
235
+ | Comunicación de Baja (RA) | `sendVoided()` | Baja de comprobantes SOAP asíncrono |
236
+ | Consulta de ticket | `getTicketStatus()` | Estado de procesos asíncronos |
332
237
 
333
238
  ## Testing / Modo simulado
334
239
 
@@ -383,6 +288,24 @@ const moduleRef = await Test.createTestingModule({
383
288
 
384
289
  No se realiza ninguna llamada HTTP — el XML se genera y firma normalmente, solo el envío a SUNAT es simulado.
385
290
 
291
+ ## Generación de PDF
292
+
293
+ ```typescript
294
+ import { DocumentPdfService } from 'sunat-engine-nest';
295
+
296
+ @Injectable()
297
+ export class InvoicesService {
298
+ constructor(
299
+ private readonly engine: SunatEngineService,
300
+ private readonly pdf: DocumentPdfService,
301
+ ) {}
302
+
303
+ async getPdf(payload: InvoicePayload): Promise<Buffer> {
304
+ return this.pdf.generateInvoice(payload, 'A4'); // 'A4' | 'TICKET_80MM' | 'STICKER_A6'
305
+ }
306
+ }
307
+ ```
308
+
386
309
  ## Respuesta del motor
387
310
 
388
311
  ```typescript
@@ -426,4 +349,4 @@ Cualquier aporte, por pequeño que sea, ayuda a mantener la librería actualizad
426
349
 
427
350
  ## Licencia
428
351
 
429
- MIT — excepto la generación de PDF (`DocumentPdfService`), que requiere una license key comercial. Ver [Generación de PDF](#generación-de-pdf-función-paga).
352
+ MIT
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { SunatEngineModule, SUNAT_ENGINE_OPTIONS } from './sunat-engine.module';
2
- export type { SunatEngineOptions, SunatEngineAsyncOptions, SunatEngineGreOptions, SunatEngineCredentialsOptions, SunatEngineOseOptions, SunatEnginePdfOptions } from './sunat-engine.module';
2
+ export type { SunatEngineOptions, SunatEngineAsyncOptions, SunatEngineGreOptions, SunatEngineCredentialsOptions, SunatEngineOseOptions } from './sunat-engine.module';
3
3
  export { SunatEngineService } from './sunat-engine.service';
4
4
  export { XmlSignerService } from './signer/xml-signer.service';
5
5
  export { SunatSoapClient } from './soap/sunat-soap.client';
@@ -10,9 +10,7 @@ export { OseClient } from './ose/ose.client';
10
10
  export type { OseClientOptions } from './ose/ose.client';
11
11
  export { CdrParserService } from './cdr/cdr-parser.service';
12
12
  export { DocumentPdfService } from './pdf/document-pdf.service';
13
- export type { PdfFormat, PdfBranding, PdfGenerationOptions } from './pdf/document-pdf.service';
14
- export { PdfLicenseError } from './licensing/pdf-license.service';
15
- export type { PdfLicensePayload } from './licensing/pdf-license.service';
13
+ export type { PdfFormat } from './pdf/document-pdf.service';
16
14
  export { buildInvoiceXml } from './xml/invoice.builder';
17
15
  export { buildNoteXml } from './xml/note.builder';
18
16
  export { buildDespatchXml } from './xml/despatch.builder';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildVoidedXml = exports.buildSummaryXml = exports.buildDespatchXml = exports.buildNoteXml = exports.buildInvoiceXml = exports.PdfLicenseError = exports.DocumentPdfService = exports.CdrParserService = exports.OseClient = exports.SunatGreClient = exports.FakeSunatSoapClient = exports.SunatSoapClient = exports.XmlSignerService = exports.SunatEngineService = exports.SUNAT_ENGINE_OPTIONS = exports.SunatEngineModule = void 0;
3
+ exports.buildVoidedXml = exports.buildSummaryXml = exports.buildDespatchXml = exports.buildNoteXml = exports.buildInvoiceXml = exports.DocumentPdfService = exports.CdrParserService = exports.OseClient = exports.SunatGreClient = exports.FakeSunatSoapClient = exports.SunatSoapClient = exports.XmlSignerService = exports.SunatEngineService = exports.SUNAT_ENGINE_OPTIONS = exports.SunatEngineModule = void 0;
4
4
  var sunat_engine_module_1 = require("./sunat-engine.module");
5
5
  Object.defineProperty(exports, "SunatEngineModule", { enumerable: true, get: function () { return sunat_engine_module_1.SunatEngineModule; } });
6
6
  Object.defineProperty(exports, "SUNAT_ENGINE_OPTIONS", { enumerable: true, get: function () { return sunat_engine_module_1.SUNAT_ENGINE_OPTIONS; } });
@@ -20,8 +20,6 @@ var cdr_parser_service_1 = require("./cdr/cdr-parser.service");
20
20
  Object.defineProperty(exports, "CdrParserService", { enumerable: true, get: function () { return cdr_parser_service_1.CdrParserService; } });
21
21
  var document_pdf_service_1 = require("./pdf/document-pdf.service");
22
22
  Object.defineProperty(exports, "DocumentPdfService", { enumerable: true, get: function () { return document_pdf_service_1.DocumentPdfService; } });
23
- var pdf_license_service_1 = require("./licensing/pdf-license.service");
24
- Object.defineProperty(exports, "PdfLicenseError", { enumerable: true, get: function () { return pdf_license_service_1.PdfLicenseError; } });
25
23
  var invoice_builder_1 = require("./xml/invoice.builder");
26
24
  Object.defineProperty(exports, "buildInvoiceXml", { enumerable: true, get: function () { return invoice_builder_1.buildInvoiceXml; } });
27
25
  var note_builder_1 = require("./xml/note.builder");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,6DAAgF;AAAvE,wHAAA,iBAAiB,OAAA;AAAE,2HAAA,oBAAoB,OAAA;AAIhD,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAG3B,kEAA+D;AAAtD,sHAAA,gBAAgB,OAAA;AACzB,8DAA2D;AAAlD,oHAAA,eAAe,OAAA;AAExB,wEAAoE;AAA3D,6HAAA,mBAAmB,OAAA;AAC5B,2DAAwD;AAA/C,kHAAA,cAAc,OAAA;AACvB,+CAA6C;AAApC,uGAAA,SAAS,OAAA;AAElB,+DAA4D;AAAnD,sHAAA,gBAAgB,OAAA;AACzB,mEAAgE;AAAvD,0HAAA,kBAAkB,OAAA;AAE3B,uEAAkE;AAAzD,sHAAA,eAAe,OAAA;AAIxB,yDAAwD;AAA/C,kHAAA,eAAe,OAAA;AACxB,mDAAkD;AAAzC,4GAAA,YAAY,OAAA;AACrB,2DAA0D;AAAjD,oHAAA,gBAAgB,OAAA;AACzB,yDAAwD;AAA/C,kHAAA,eAAe,OAAA;AACxB,uDAAsD;AAA7C,gHAAA,cAAc,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,6DAAgF;AAAvE,wHAAA,iBAAiB,OAAA;AAAE,2HAAA,oBAAoB,OAAA;AAIhD,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAG3B,kEAA+D;AAAtD,sHAAA,gBAAgB,OAAA;AACzB,8DAA2D;AAAlD,oHAAA,eAAe,OAAA;AAExB,wEAAoE;AAA3D,6HAAA,mBAAmB,OAAA;AAC5B,2DAAwD;AAA/C,kHAAA,cAAc,OAAA;AACvB,+CAA6C;AAApC,uGAAA,SAAS,OAAA;AAElB,+DAA4D;AAAnD,sHAAA,gBAAgB,OAAA;AACzB,mEAAgE;AAAvD,0HAAA,kBAAkB,OAAA;AAI3B,yDAAwD;AAA/C,kHAAA,eAAe,OAAA;AACxB,mDAAkD;AAAzC,4GAAA,YAAY,OAAA;AACrB,2DAA0D;AAAjD,oHAAA,gBAAgB,OAAA;AACzB,yDAAwD;AAA/C,kHAAA,eAAe,OAAA;AACxB,uDAAsD;AAA7C,gHAAA,cAAc,OAAA"}
@@ -1,40 +1,11 @@
1
- import { InvoicePayload, NotePayload, DespatchPayload } from '../types/sunat.types';
2
- import { SunatEngineOptions } from '../sunat-engine.module';
3
- import { PdfLicenseService } from '../licensing/pdf-license.service';
1
+ import { InvoicePayload } from '../types/sunat.types';
4
2
  export type PdfFormat = 'A4' | 'TICKET_80MM' | 'STICKER_A6';
5
- export interface PdfBranding {
6
- logoBase64?: string;
7
- color?: string;
8
- }
9
- export interface PdfGenerationOptions {
10
- licenseKey?: string;
11
- branding?: PdfBranding;
12
- }
13
3
  export declare class DocumentPdfService {
14
- private readonly options;
15
- private readonly license;
16
- constructor(options?: SunatEngineOptions, license?: PdfLicenseService);
17
- generateInvoice(payload: InvoicePayload, format?: PdfFormat, opts?: PdfGenerationOptions): Promise<Buffer>;
18
- private generateInvoiceA4;
19
- private generateInvoiceTicket;
20
- generateNote(payload: NotePayload, format?: PdfFormat, opts?: PdfGenerationOptions): Promise<Buffer>;
21
- private generateNoteA4;
22
- private generateNoteTicket;
23
- generateDespatch(payload: DespatchPayload, opts?: PdfGenerationOptions): Promise<Buffer>;
24
- private buildHeader;
25
- private buildItemsTable;
26
- private buildTotalsQrBlock;
27
- private cardLayout;
28
- private zebraTableLayout;
29
- private baseStyles;
30
- private resolveBranding;
31
- private ticketHeader;
32
- private ticketDivider;
33
- private ticketDetailRow;
4
+ generateInvoice(payload: InvoicePayload, format?: PdfFormat): Promise<Buffer>;
5
+ private generateA4;
6
+ private generateTicket;
34
7
  private totRow;
35
8
  private buildQrContent;
36
- private qr;
37
9
  private fmt;
38
- private lighten;
39
10
  private renderPdf;
40
11
  }