sunat-engine-nest 1.1.1 → 2.0.0

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,8 +1,30 @@
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
+
3
6
  Motor de Facturación Electrónica SUNAT UBL 2.1 para NestJS.
4
7
 
5
- Soporta Facturas, Boletas, Notas de Crédito/Débito, Guías de Remisión (GRE), Resúmenes Diarios y Comunicaciones de Baja.
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)
6
28
 
7
29
  ## Instalación
8
30
 
@@ -16,10 +38,11 @@ pnpm add sunat-engine-nest
16
38
 
17
39
  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.
18
40
 
41
+ ### Registro síncrono
42
+
19
43
  ```typescript
20
44
  import { SunatEngineModule } from 'sunat-engine-nest';
21
45
 
22
- // Registro síncrono
23
46
  @Module({
24
47
  imports: [
25
48
  SunatEngineModule.forRoot({
@@ -42,11 +65,14 @@ import { SunatEngineModule } from 'sunat-engine-nest';
42
65
  export class AppModule {}
43
66
  ```
44
67
 
68
+ ### Registro asíncrono
69
+
70
+ Recomendado cuando las credenciales dependen de variables de entorno.
71
+
45
72
  ```typescript
46
73
  import { SunatEngineModule } from 'sunat-engine-nest';
47
74
  import { ConfigModule, ConfigService } from '@nestjs/config';
48
75
 
49
- // Registro asíncrono (recomendado con variables de entorno)
50
76
  @Module({
51
77
  imports: [
52
78
  ConfigModule.forRoot({ isGlobal: true }),
@@ -79,29 +105,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
79
105
  export class AppModule {}
80
106
  ```
81
107
 
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
108
+ ### Proveedor: SUNAT directo vs OSE
105
109
 
106
110
  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.
107
111
 
@@ -128,7 +132,7 @@ SunatEngineModule.forRoot({
128
132
 
129
133
  > 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.
130
134
 
131
- ## Certificado digital
135
+ ### Certificado digital
132
136
 
133
137
  El motor acepta el certificado en tres formatos:
134
138
 
@@ -150,8 +154,32 @@ const credentials: CompanyCredentials = {
150
154
  };
151
155
  ```
152
156
 
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
+
153
179
  ## Uso
154
180
 
181
+ ### Enviar un comprobante
182
+
155
183
  Inyecta `SunatEngineService` en cualquier servicio o controlador. Si configuraste `sunat:{}` en el módulo, **no necesitas pasar credenciales en cada llamada**:
156
184
 
157
185
  ```typescript
@@ -222,20 +250,33 @@ return this.engine.sendInvoice(payload, {
222
250
  });
223
251
  ```
224
252
 
225
- ## Documentos soportados
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 | — |
226
265
 
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 |
266
+ ## Generación de PDF (función paga)
237
267
 
238
- ## Generación de PDF
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
+ ```
239
280
 
240
281
  ```typescript
241
282
  import { DocumentPdfService } from 'sunat-engine-nest';
@@ -253,6 +294,95 @@ export class InvoicesService {
253
294
  }
254
295
  ```
255
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
314
+
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.
332
+
333
+ ## Testing / Modo simulado
334
+
335
+ SUNAT beta rechaza `sendSummary` (RC/RA) con el RUC genérico de prueba `20000000001` — ese RUC solo funciona de forma confiable para `sendBill` (facturas y boletas). Para probar el flujo completo sin depender del entorno beta, el módulo incluye un **cliente SOAP simulado** que devuelve respuestas válidas sin realizar ninguna llamada HTTP.
336
+
337
+ ### Opción 1 — `useFake: true` en el módulo (recomendado)
338
+
339
+ ```typescript
340
+ // app.module.ts (para tests)
341
+ SunatEngineModule.forRoot({
342
+ useFake: true, // ← activa FakeSunatSoapClient automáticamente
343
+ sunat: {
344
+ ruc: '20000000001',
345
+ solUser: 'MODDATOS',
346
+ solPass: 'moddatos',
347
+ certPem: 'BASE64_DEL_P12',
348
+ },
349
+ })
350
+
351
+ // También con forRootAsync:
352
+ SunatEngineModule.forRootAsync({
353
+ imports: [ConfigModule],
354
+ inject: [ConfigService],
355
+ useFactory: (config: ConfigService) => ({
356
+ useFake: config.get('NODE_ENV') === 'test',
357
+ sunat: { ruc: config.get('SUNAT_RUC'), ... },
358
+ }),
359
+ })
360
+ ```
361
+
362
+ ### Opción 2 — `overrideProvider` en NestJS Testing
363
+
364
+ ```typescript
365
+ import { Test } from '@nestjs/testing';
366
+ import { SunatSoapClient, FakeSunatSoapClient } from 'sunat-engine-nest';
367
+
368
+ const moduleRef = await Test.createTestingModule({
369
+ imports: [SunatEngineModule.forRoot({ sunat: { ... } })],
370
+ })
371
+ .overrideProvider(SunatSoapClient)
372
+ .useClass(FakeSunatSoapClient)
373
+ .compile();
374
+ ```
375
+
376
+ ### Comportamiento del cliente simulado
377
+
378
+ | Método | Respuesta simulada |
379
+ |--------|-------------------|
380
+ | `sendBill` | CDR ZIP con `ResponseCode=0` (ACEPTADA) |
381
+ | `sendSummary` | Ticket numérico incremental (`1000000001`, `1000000002`, ...) |
382
+ | `getStatus` | CDR ZIP con `ResponseCode=0` (ACEPTADA) |
383
+
384
+ No se realiza ninguna llamada HTTP — el XML se genera y firma normalmente, solo el envío a SUNAT es simulado.
385
+
256
386
  ## Respuesta del motor
257
387
 
258
388
  ```typescript
@@ -296,4 +426,4 @@ Cualquier aporte, por pequeño que sea, ayuda a mantener la librería actualizad
296
426
 
297
427
  ## Licencia
298
428
 
299
- MIT
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).
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 } from './sunat-engine.module';
2
+ export type { SunatEngineOptions, SunatEngineAsyncOptions, SunatEngineGreOptions, SunatEngineCredentialsOptions, SunatEngineOseOptions, SunatEnginePdfOptions } 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,7 +10,9 @@ 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 } 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';
14
16
  export { buildInvoiceXml } from './xml/invoice.builder';
15
17
  export { buildNoteXml } from './xml/note.builder';
16
18
  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.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.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;
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,6 +20,8 @@ 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; } });
23
25
  var invoice_builder_1 = require("./xml/invoice.builder");
24
26
  Object.defineProperty(exports, "buildInvoiceXml", { enumerable: true, get: function () { return invoice_builder_1.buildInvoiceXml; } });
25
27
  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;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
+ {"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"}
@@ -0,0 +1,11 @@
1
+ export interface PdfLicensePayload {
2
+ sub: string;
3
+ scope: string[];
4
+ iat: number;
5
+ exp?: number;
6
+ }
7
+ export declare class PdfLicenseError extends Error {
8
+ }
9
+ export declare class PdfLicenseService {
10
+ assertValid(licenseKey: string | undefined): PdfLicensePayload;
11
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PdfLicenseService = exports.PdfLicenseError = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const crypto_1 = require("crypto");
12
+ const public_key_1 = require("./public-key");
13
+ class PdfLicenseError extends Error {
14
+ }
15
+ exports.PdfLicenseError = PdfLicenseError;
16
+ const CONTACT = 'https://wa.me/51907596305';
17
+ let PdfLicenseService = class PdfLicenseService {
18
+ assertValid(licenseKey) {
19
+ if (!licenseKey) {
20
+ throw new PdfLicenseError(`La generación de PDF requiere una licencia. Configura "pdf.licenseKey" en SunatEngineModule.forRoot() ` +
21
+ `o adquiere una en ${CONTACT}.`);
22
+ }
23
+ const [payloadB64, sigB64] = licenseKey.split('.');
24
+ if (!payloadB64 || !sigB64) {
25
+ throw new PdfLicenseError('Formato de licencia inválido.');
26
+ }
27
+ let payload;
28
+ try {
29
+ payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString('utf8'));
30
+ }
31
+ catch {
32
+ throw new PdfLicenseError('Licencia inválida: el payload está corrupto.');
33
+ }
34
+ const signatureValid = (0, crypto_1.verify)(null, Buffer.from(payloadB64), public_key_1.PDF_LICENSE_PUBLIC_KEY, Buffer.from(sigB64, 'base64url'));
35
+ if (!signatureValid) {
36
+ throw new PdfLicenseError('Licencia inválida: la firma no coincide.');
37
+ }
38
+ if (!payload.scope?.includes('pdf')) {
39
+ throw new PdfLicenseError('Esta licencia no incluye el módulo de PDF.');
40
+ }
41
+ if (payload.exp && Date.now() / 1000 > payload.exp) {
42
+ throw new PdfLicenseError(`La licencia de PDF expiró. Renueva en ${CONTACT}.`);
43
+ }
44
+ return payload;
45
+ }
46
+ };
47
+ exports.PdfLicenseService = PdfLicenseService;
48
+ exports.PdfLicenseService = PdfLicenseService = __decorate([
49
+ (0, common_1.Injectable)()
50
+ ], PdfLicenseService);
51
+ //# sourceMappingURL=pdf-license.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-license.service.js","sourceRoot":"","sources":["../../src/licensing/pdf-license.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAC5C,mCAAmD;AACnD,6CAAsD;AAatD,MAAa,eAAgB,SAAQ,KAAK;CAAG;AAA7C,0CAA6C;AAE7C,MAAM,OAAO,GAAG,2BAA2B,CAAC;AAGrC,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAM5B,WAAW,CAAC,UAA8B;QACxC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,eAAe,CACvB,wGAAwG;gBACxG,qBAAqB,OAAO,GAAG,CAChC,CAAC;QACJ,CAAC;QAED,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,eAAe,CAAC,+BAA+B,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,OAA0B,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,eAAe,CAAC,8CAA8C,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,cAAc,GAAG,IAAA,eAAe,EACpC,IAAI,EACJ,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EACvB,mCAAsB,EACtB,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CACjC,CAAC;QACF,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,eAAe,CAAC,0CAA0C,CAAC,CAAC;QACxE,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,eAAe,CAAC,4CAA4C,CAAC,CAAC;QAC1E,CAAC;QAED,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YACnD,MAAM,IAAI,eAAe,CAAC,yCAAyC,OAAO,GAAG,CAAC,CAAC;QACjF,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAA;AA9CY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,mBAAU,GAAE;GACA,iBAAiB,CA8C7B"}
@@ -0,0 +1 @@
1
+ export declare const PDF_LICENSE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAD05kwpP38o2RE03c5mS66KDa+KGN3UPUtiAngewbzPI=\n-----END PUBLIC KEY-----\n";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PDF_LICENSE_PUBLIC_KEY = void 0;
4
+ exports.PDF_LICENSE_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
5
+ MCowBQYDK2VwAyEAD05kwpP38o2RE03c5mS66KDa+KGN3UPUtiAngewbzPI=
6
+ -----END PUBLIC KEY-----
7
+ `;
8
+ //# sourceMappingURL=public-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-key.js","sourceRoot":"","sources":["../../src/licensing/public-key.ts"],"names":[],"mappings":";;;AAEa,QAAA,sBAAsB,GAAG;;;CAGrC,CAAC"}
@@ -1,11 +1,40 @@
1
- import { InvoicePayload } from '../types/sunat.types';
1
+ import { InvoicePayload, NotePayload, DespatchPayload } from '../types/sunat.types';
2
+ import { SunatEngineOptions } from '../sunat-engine.module';
3
+ import { PdfLicenseService } from '../licensing/pdf-license.service';
2
4
  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
+ }
3
13
  export declare class DocumentPdfService {
4
- generateInvoice(payload: InvoicePayload, format?: PdfFormat): Promise<Buffer>;
5
- private generateA4;
6
- private generateTicket;
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;
7
34
  private totRow;
8
35
  private buildQrContent;
36
+ private qr;
9
37
  private fmt;
38
+ private lighten;
10
39
  private renderPdf;
11
40
  }