sunat-engine-nest 1.0.0 → 1.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 +217 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# sunat-engine-nest
|
|
2
|
+
|
|
3
|
+
Motor de Facturación Electrónica SUNAT UBL 2.1 para NestJS.
|
|
4
|
+
|
|
5
|
+
Soporta Facturas, Boletas, Notas de Crédito/Débito, Guías de Remisión (GRE), Resúmenes Diarios y Comunicaciones de Baja.
|
|
6
|
+
|
|
7
|
+
## Instalación
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install sunat-engine-nest
|
|
11
|
+
# o
|
|
12
|
+
pnpm add sunat-engine-nest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Configuración
|
|
16
|
+
|
|
17
|
+
Registra el módulo en tu `AppModule`:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { SunatEngineModule } from 'sunat-engine-nest';
|
|
21
|
+
|
|
22
|
+
// Registro síncrono
|
|
23
|
+
@Module({
|
|
24
|
+
imports: [
|
|
25
|
+
SunatEngineModule.forRoot({
|
|
26
|
+
gre: {
|
|
27
|
+
authUrl: 'https://gre-test.nubefact.com/v1',
|
|
28
|
+
apiUrl: 'https://gre-test.nubefact.com/v1',
|
|
29
|
+
clientId: 'TU_CLIENT_ID',
|
|
30
|
+
clientSecret: 'TU_CLIENT_SECRET',
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
})
|
|
35
|
+
export class AppModule {}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { SunatEngineModule } from 'sunat-engine-nest';
|
|
40
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
41
|
+
|
|
42
|
+
// Registro asíncrono (recomendado con variables de entorno)
|
|
43
|
+
@Module({
|
|
44
|
+
imports: [
|
|
45
|
+
ConfigModule.forRoot({ isGlobal: true }),
|
|
46
|
+
SunatEngineModule.forRootAsync({
|
|
47
|
+
imports: [ConfigModule],
|
|
48
|
+
inject: [ConfigService],
|
|
49
|
+
useFactory: (config: ConfigService) => ({
|
|
50
|
+
gre: {
|
|
51
|
+
authUrl: config.get('GRE_AUTH_URL'),
|
|
52
|
+
apiUrl: config.get('GRE_API_URL'),
|
|
53
|
+
clientId: config.get('GRE_CLIENT_ID'),
|
|
54
|
+
clientSecret: config.get('GRE_CLIENT_SECRET'),
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
}),
|
|
58
|
+
],
|
|
59
|
+
})
|
|
60
|
+
export class AppModule {}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Variables de entorno (GRE)
|
|
64
|
+
|
|
65
|
+
```env
|
|
66
|
+
GRE_AUTH_URL=https://gre-test.nubefact.com/v1
|
|
67
|
+
GRE_API_URL=https://gre-test.nubefact.com/v1
|
|
68
|
+
GRE_CLIENT_ID=tu_client_id
|
|
69
|
+
GRE_CLIENT_SECRET=tu_client_secret
|
|
70
|
+
GRE_SCOPE=https://api-cpe.sunat.gob.pe
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Uso
|
|
74
|
+
|
|
75
|
+
Inyecta `SunatEngineService` en cualquier servicio o controlador:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { Injectable } from '@nestjs/common';
|
|
79
|
+
import { SunatEngineService, InvoicePayload, CompanyCredentials } from 'sunat-engine-nest';
|
|
80
|
+
|
|
81
|
+
@Injectable()
|
|
82
|
+
export class InvoicesService {
|
|
83
|
+
constructor(private readonly engine: SunatEngineService) {}
|
|
84
|
+
|
|
85
|
+
async sendInvoice() {
|
|
86
|
+
const credentials: CompanyCredentials = {
|
|
87
|
+
ruc: '20123456789',
|
|
88
|
+
solUser: 'MODDATOS',
|
|
89
|
+
solPass: 'moddatos',
|
|
90
|
+
certPem: 'BASE64_DEL_P12_O_PEM',
|
|
91
|
+
endpointMode: 'beta', // 'beta' | 'produccion'
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const payload: InvoicePayload = {
|
|
95
|
+
tipoOperacion: '0101',
|
|
96
|
+
tipoDoc: '01', // 01=Factura, 03=Boleta
|
|
97
|
+
serie: 'F001',
|
|
98
|
+
correlativo: '00000001',
|
|
99
|
+
fechaEmision: '2026-07-20T00:00:00-05:00',
|
|
100
|
+
tipoMoneda: 'PEN',
|
|
101
|
+
company: {
|
|
102
|
+
ruc: '20123456789',
|
|
103
|
+
razonSocial: 'MI EMPRESA S.A.C.',
|
|
104
|
+
address: { direccion: 'Av. Principal 123, Lima' },
|
|
105
|
+
},
|
|
106
|
+
client: {
|
|
107
|
+
tipoDoc: '6',
|
|
108
|
+
numDoc: '20987654321',
|
|
109
|
+
rznSocial: 'CLIENTE S.A.C.',
|
|
110
|
+
},
|
|
111
|
+
details: [
|
|
112
|
+
{
|
|
113
|
+
unidad: 'NIU',
|
|
114
|
+
cantidad: 2,
|
|
115
|
+
descripcion: 'Producto de prueba',
|
|
116
|
+
mtoValorUnitario: 100,
|
|
117
|
+
mtoValorVenta: 200,
|
|
118
|
+
mtoBaseIgv: 200,
|
|
119
|
+
porcentajeIgv: 18,
|
|
120
|
+
igv: 36,
|
|
121
|
+
tipAfeIgv: '10',
|
|
122
|
+
totalImpuestos: 36,
|
|
123
|
+
mtoPrecioUnitario: 118,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
legends: [{ code: '1000', value: 'DOSCIENTOS TREINTA Y SEIS Y 00/100 SOLES' }],
|
|
127
|
+
mtoOperGravadas: 200,
|
|
128
|
+
mtoIGV: 36,
|
|
129
|
+
totalImpuestos: 36,
|
|
130
|
+
valorVenta: 200,
|
|
131
|
+
subTotal: 236,
|
|
132
|
+
mtoImpVenta: 236,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return this.engine.sendInvoice(payload, credentials);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Documentos soportados
|
|
141
|
+
|
|
142
|
+
| Tipo | Método | Descripción |
|
|
143
|
+
|------|--------|-------------|
|
|
144
|
+
| Factura (01) | `sendInvoice()` | Factura electrónica — SOAP síncrono |
|
|
145
|
+
| Boleta (03) | `sendInvoice()` | Boleta de venta electrónica — SOAP síncrono |
|
|
146
|
+
| Nota de Crédito (07) | `sendNote()` | NC electrónica — SOAP síncrono |
|
|
147
|
+
| Nota de Débito (08) | `sendNote()` | ND electrónica — SOAP síncrono |
|
|
148
|
+
| Guía de Remisión (09) | `sendDespatch()` | GRE 2022 — REST/OAuth asíncrono |
|
|
149
|
+
| Resumen Diario (RC) | `sendSummary()` | Resumen de boletas — SOAP asíncrono |
|
|
150
|
+
| Comunicación de Baja (RA) | `sendVoided()` | Baja de comprobantes — SOAP asíncrono |
|
|
151
|
+
| Consulta de ticket | `getTicketStatus()` | Estado de procesos asíncronos |
|
|
152
|
+
|
|
153
|
+
## Generación de PDF
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { DocumentPdfService } from 'sunat-engine-nest';
|
|
157
|
+
|
|
158
|
+
@Injectable()
|
|
159
|
+
export class InvoicesService {
|
|
160
|
+
constructor(
|
|
161
|
+
private readonly engine: SunatEngineService,
|
|
162
|
+
private readonly pdf: DocumentPdfService,
|
|
163
|
+
) {}
|
|
164
|
+
|
|
165
|
+
async getPdf(payload: InvoicePayload): Promise<Buffer> {
|
|
166
|
+
return this.pdf.generateInvoice(payload, 'A4'); // 'A4' | 'TICKET_80MM' | 'STICKER_A6'
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Certificado digital
|
|
172
|
+
|
|
173
|
+
El motor acepta el certificado en dos formatos:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// Formato 1: archivo .p12 en base64
|
|
177
|
+
const credentials: CompanyCredentials = {
|
|
178
|
+
certPem: 'MIIKJAIBAzCCCd4GCSqGSI...', // .p12 en base64 (sin headers PEM)
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Formato 2: certificado PEM + clave privada PEM por separado
|
|
182
|
+
const credentials: CompanyCredentials = {
|
|
183
|
+
certPem: '-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----',
|
|
184
|
+
certKey: '-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----',
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Respuesta del motor
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
interface EngineResponse {
|
|
192
|
+
xml?: string; // XML firmado en base64
|
|
193
|
+
hash?: string; // SHA256 del XML
|
|
194
|
+
sunatResponse?: {
|
|
195
|
+
success?: boolean;
|
|
196
|
+
ticket?: string; // procesos asíncronos (RC/RA/GRE)
|
|
197
|
+
cdrZip?: string; // ZIP CDR en base64 (procesos síncronos)
|
|
198
|
+
cdrResponse?: {
|
|
199
|
+
code?: string; // 0=aceptado, 2xxx=rechazado, 4xxx=obs
|
|
200
|
+
description?: string;
|
|
201
|
+
notes?: string[];
|
|
202
|
+
};
|
|
203
|
+
error?: { code?: string | number; message?: string };
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Endpoints SUNAT
|
|
209
|
+
|
|
210
|
+
| Modo | Factura/Boleta/NC/ND | GRE |
|
|
211
|
+
|------|----------------------|-----|
|
|
212
|
+
| `beta` | e-beta.sunat.gob.pe | gre-test.nubefact.com |
|
|
213
|
+
| `produccion` | e-factura.sunat.gob.pe | api-cpe.sunat.gob.pe |
|
|
214
|
+
|
|
215
|
+
## Licencia
|
|
216
|
+
|
|
217
|
+
MIT
|