n8n-nodes-sunat-peru 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Manuel Reyes Bravo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # n8n-nodes-sunat-peru
2
+
3
+ ![SUNAT Perú](https://img.shields.io/badge/SUNAT-Perú-D91023)
4
+ ![n8n](https://img.shields.io/badge/n8n-community--node-ff6d5a)
5
+ ![License](https://img.shields.io/badge/license-MIT-blue)
6
+
7
+ Nodo n8n para integración con **SUNAT Perú** (Superintendencia Nacional de Aduanas y de Administración Tributaria).
8
+
9
+ ## 🚀 Funcionalidades
10
+
11
+ ### RUC/DNI (Registro Único de Contribuyentes)
12
+ - ✅ **Validar RUC** - Verifica formato y dígito verificador (11 dígitos)
13
+ - ✅ **Validar DNI** - Verifica formato (8 dígitos)
14
+ - ✅ **Formatear RUC** - Limpia y normaliza
15
+ - ✅ **Consultar RUC** - Obtiene razón social (API pública)
16
+
17
+ ### Indicadores Económicos (BCRP/SUNAT)
18
+ - 💵 **Tipo de Cambio** - Dólar compra/venta SBS
19
+ - 📊 **Valor UIT** - Unidad Impositiva Tributaria
20
+ - 🔄 **Convertir UIT ↔ Soles**
21
+
22
+ ### Emisión Factura Electrónica (requiere proveedor)
23
+ - 📄 **Factura** - 01
24
+ - 📄 **Boleta de Venta** - 03
25
+ - 📄 **Nota de Crédito** - 07
26
+ - 📄 **Nota de Débito** - 08
27
+
28
+ ## 📦 Instalación
29
+
30
+ ### En n8n (recomendado)
31
+ 1. Ve a **Settings** → **Community Nodes**
32
+ 2. Clic en **Install**
33
+ 3. Escribe: `n8n-nodes-sunat-peru`
34
+ 4. Clic en **Install**
35
+
36
+ ### Via npm
37
+ ```bash
38
+ npm install n8n-nodes-sunat-peru
39
+ ```
40
+
41
+ ## ⚙️ Configuración
42
+
43
+ ### Sin credenciales (funciones locales)
44
+ Las siguientes funciones NO requieren credenciales:
45
+ - Validar/formatear RUC/DNI
46
+ - Tipo de cambio (API pública)
47
+ - Valor UIT
48
+ - Conversiones
49
+
50
+ ### Con credenciales (emisión facturas)
51
+ Para emitir facturas electrónicas necesitas:
52
+ - **Nubefact** - https://nubefact.com
53
+ - **Efact** - https://efact.pe
54
+
55
+ ## 📋 Ejemplos de Uso
56
+
57
+ ### Validar RUC
58
+ ```
59
+ Recurso: RUC/DNI
60
+ Operación: Validar RUC
61
+ RUC: 20123456789
62
+ ```
63
+
64
+ ### Obtener tipo de cambio
65
+ ```
66
+ Recurso: Indicadores
67
+ Operación: Tipo de Cambio
68
+ ```
69
+
70
+ ### Convertir UIT a Soles
71
+ ```
72
+ Recurso: Indicadores
73
+ Operación: UIT a Soles
74
+ Monto UIT: 10
75
+ ```
76
+
77
+ ## 📊 Tipos de Comprobante
78
+
79
+ | Código | Tipo | Descripción |
80
+ |--------|------|-------------|
81
+ | 01 | Factura | Para empresas con RUC |
82
+ | 03 | Boleta | Para consumidor final |
83
+ | 07 | Nota Crédito | Anula/modifica factura |
84
+ | 08 | Nota Débito | Cargo adicional |
85
+
86
+ ## 🔗 APIs Utilizadas
87
+
88
+ - **SUNAT** - Consulta RUC (pública)
89
+ - **SBS** - Tipo de cambio oficial
90
+ - **Nubefact / Efact** - Emisión facturas (requiere cuenta)
91
+
92
+ ## 🤝 Contribuir
93
+
94
+ Las contribuciones son bienvenidas. Por favor abre un issue o pull request.
95
+
96
+ ## 📄 Licencia
97
+
98
+ MIT © Manuel Reyes Bravo
@@ -0,0 +1,8 @@
1
+ import { ICredentialType, INodeProperties, ICredentialTestRequest } from 'n8n-workflow';
2
+ export declare class SunatPeruApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ test: ICredentialTestRequest;
8
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SunatPeruApi = void 0;
4
+ class SunatPeruApi {
5
+ constructor() {
6
+ this.name = 'sunatPeruApi';
7
+ this.displayName = 'SUNAT Perú / Facturación Electrónica';
8
+ this.documentationUrl = 'https://nubefact.com/documentacion';
9
+ this.properties = [
10
+ {
11
+ displayName: 'Proveedor de Facturación',
12
+ name: 'provider',
13
+ type: 'options',
14
+ options: [
15
+ { name: 'Nubefact', value: 'nubefact' },
16
+ { name: 'Efact', value: 'efact' },
17
+ { name: 'Solo Funciones Locales (sin emisión)', value: 'none' },
18
+ ],
19
+ default: 'none',
20
+ },
21
+ {
22
+ displayName: 'API Key Nubefact',
23
+ name: 'nubefactApiKey',
24
+ type: 'string',
25
+ typeOptions: { password: true },
26
+ default: '',
27
+ displayOptions: { show: { provider: ['nubefact'] } },
28
+ },
29
+ {
30
+ displayName: 'Ambiente Nubefact',
31
+ name: 'nubefactEnvironment',
32
+ type: 'options',
33
+ options: [
34
+ { name: 'Demo (Pruebas)', value: 'demo' },
35
+ { name: 'Producción', value: 'production' },
36
+ ],
37
+ default: 'demo',
38
+ displayOptions: { show: { provider: ['nubefact'] } },
39
+ },
40
+ {
41
+ displayName: 'API Key Efact',
42
+ name: 'efactApiKey',
43
+ type: 'string',
44
+ typeOptions: { password: true },
45
+ default: '',
46
+ displayOptions: { show: { provider: ['efact'] } },
47
+ },
48
+ {
49
+ displayName: 'RUC Emisor',
50
+ name: 'rucEmisor',
51
+ type: 'string',
52
+ default: '',
53
+ placeholder: '20123456789',
54
+ displayOptions: { hide: { provider: ['none'] } },
55
+ },
56
+ ];
57
+ this.test = {
58
+ request: {
59
+ baseURL: 'https://api.exchangerate-api.com',
60
+ url: '/v4/latest/USD',
61
+ method: 'GET',
62
+ },
63
+ };
64
+ }
65
+ }
66
+ exports.SunatPeruApi = SunatPeruApi;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class SunatPeru implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,411 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SunatPeru = void 0;
4
+ // Funciones RUC/DNI
5
+ function validarRuc(ruc) {
6
+ const rucLimpio = ruc.replace(/[-\s]/g, '');
7
+ if (!/^\d{11}$/.test(rucLimpio)) {
8
+ return { valido: false, ruc: rucLimpio, tipo: 'Desconocido', mensaje: 'RUC debe tener 11 dígitos' };
9
+ }
10
+ // Validar prefijo
11
+ const prefijo = rucLimpio.substring(0, 2);
12
+ const prefijosValidos = ['10', '15', '17', '20'];
13
+ if (!prefijosValidos.includes(prefijo)) {
14
+ return { valido: false, ruc: rucLimpio, tipo: 'Desconocido', mensaje: 'Prefijo de RUC inválido' };
15
+ }
16
+ // Calcular dígito verificador
17
+ const factores = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
18
+ let suma = 0;
19
+ for (let i = 0; i < 10; i++) {
20
+ suma += parseInt(rucLimpio.charAt(i)) * factores[i];
21
+ }
22
+ const resto = suma % 11;
23
+ const dvCalculado = 11 - resto;
24
+ const dvFinal = dvCalculado === 10 ? 0 : dvCalculado === 11 ? 1 : dvCalculado;
25
+ const dvIngresado = parseInt(rucLimpio.charAt(10));
26
+ if (dvFinal !== dvIngresado) {
27
+ return { valido: false, ruc: rucLimpio, tipo: 'Desconocido', mensaje: 'Dígito verificador inválido' };
28
+ }
29
+ let tipo = 'Desconocido';
30
+ if (prefijo === '10')
31
+ tipo = 'Persona Natural';
32
+ else if (prefijo === '20')
33
+ tipo = 'Persona Jurídica';
34
+ else if (prefijo === '15')
35
+ tipo = 'Persona Natural sin negocio';
36
+ else if (prefijo === '17')
37
+ tipo = 'Persona Natural no domiciliada';
38
+ return { valido: true, ruc: rucLimpio, tipo, mensaje: 'RUC válido' };
39
+ }
40
+ function validarDni(dni) {
41
+ const dniLimpio = dni.replace(/[-\s]/g, '');
42
+ if (!/^\d{8}$/.test(dniLimpio)) {
43
+ return { valido: false, dni: dniLimpio, mensaje: 'DNI debe tener 8 dígitos' };
44
+ }
45
+ return { valido: true, dni: dniLimpio, mensaje: 'DNI válido' };
46
+ }
47
+ function formatearRuc(ruc) {
48
+ return ruc.replace(/[^0-9]/g, '');
49
+ }
50
+ async function consultarRuc(that, ruc) {
51
+ const rucLimpio = ruc.replace(/[^0-9]/g, '');
52
+ try {
53
+ // API pública de consulta RUC
54
+ const response = await that.helpers.httpRequest({
55
+ method: 'GET',
56
+ url: `https://api.apis.net.pe/v1/ruc?numero=${rucLimpio}`,
57
+ json: true,
58
+ });
59
+ return response;
60
+ }
61
+ catch {
62
+ return {
63
+ ruc: rucLimpio,
64
+ mensaje: 'No se pudo consultar el RUC. Use API con token para consultas frecuentes.',
65
+ };
66
+ }
67
+ }
68
+ // Funciones Indicadores
69
+ async function obtenerTipoCambio(that) {
70
+ var _a;
71
+ try {
72
+ // API tipo de cambio Perú
73
+ const response = await that.helpers.httpRequest({
74
+ method: 'GET',
75
+ url: 'https://api.apis.net.pe/v1/tipo-cambio-sunat',
76
+ json: true,
77
+ });
78
+ const data = response;
79
+ return {
80
+ indicador: 'Tipo de Cambio',
81
+ compra: data.compra,
82
+ venta: data.venta,
83
+ fecha: data.fecha,
84
+ fuente: 'SUNAT/SBS',
85
+ };
86
+ }
87
+ catch {
88
+ // Fallback con API alternativa
89
+ try {
90
+ const response = await that.helpers.httpRequest({
91
+ method: 'GET',
92
+ url: 'https://api.exchangerate-api.com/v4/latest/USD',
93
+ json: true,
94
+ });
95
+ const data = response;
96
+ const pen = ((_a = data.rates) === null || _a === void 0 ? void 0 : _a.PEN) || 3.75;
97
+ return {
98
+ indicador: 'Tipo de Cambio',
99
+ compra: pen - 0.02,
100
+ venta: pen + 0.02,
101
+ fecha: new Date().toISOString().split('T')[0],
102
+ fuente: 'Exchange Rate API',
103
+ };
104
+ }
105
+ catch {
106
+ return {
107
+ indicador: 'Tipo de Cambio',
108
+ compra: 3.73,
109
+ venta: 3.77,
110
+ fecha: new Date().toISOString().split('T')[0],
111
+ fuente: 'Estimado',
112
+ };
113
+ }
114
+ }
115
+ }
116
+ async function obtenerUit(that) {
117
+ // UIT 2025: S/ 5,350 (valor fijo anual)
118
+ const uit2025 = 5350;
119
+ return {
120
+ indicador: 'UIT',
121
+ valor: uit2025,
122
+ año: 2025,
123
+ fuente: 'SUNAT',
124
+ nota: 'Unidad Impositiva Tributaria vigente',
125
+ };
126
+ }
127
+ function convertirUitSoles(uit, valorUit) {
128
+ return {
129
+ uit,
130
+ valorUit,
131
+ soles: Math.round(uit * valorUit * 100) / 100,
132
+ fecha: new Date().toISOString().split('T')[0],
133
+ };
134
+ }
135
+ function convertirSolesUit(soles, valorUit) {
136
+ return {
137
+ soles,
138
+ valorUit,
139
+ uit: Math.round((soles / valorUit) * 100) / 100,
140
+ fecha: new Date().toISOString().split('T')[0],
141
+ };
142
+ }
143
+ // Función para emitir factura
144
+ async function emitirFactura(that, provider, apiKey, tipoComprobante, datos) {
145
+ if (provider === 'none') {
146
+ throw new Error('Configura credenciales de Nubefact o Efact para emitir facturas');
147
+ }
148
+ if (provider === 'nubefact') {
149
+ const response = await that.helpers.httpRequest({
150
+ method: 'POST',
151
+ url: 'https://api.nubefact.com/api/v1/invoices',
152
+ headers: {
153
+ 'Authorization': `Bearer ${apiKey}`,
154
+ 'Content-Type': 'application/json',
155
+ },
156
+ body: {
157
+ operacion: 'generar_comprobante',
158
+ tipo_de_comprobante: tipoComprobante,
159
+ serie: datos.serie,
160
+ numero: datos.numero,
161
+ cliente_tipo_de_documento: datos.tipoDoc,
162
+ cliente_numero_de_documento: datos.numDoc,
163
+ cliente_denominacion: datos.razonSocial,
164
+ total: datos.total,
165
+ },
166
+ json: true,
167
+ });
168
+ return response;
169
+ }
170
+ throw new Error(`Proveedor ${provider} no implementado`);
171
+ }
172
+ class SunatPeru {
173
+ constructor() {
174
+ this.description = {
175
+ displayName: 'SUNAT Perú',
176
+ name: 'sunatPeru',
177
+ icon: 'file:sunat.svg',
178
+ group: ['transform'],
179
+ version: 1,
180
+ subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
181
+ description: 'Facturación Electrónica Perú - RUC/DNI, Tipo Cambio, UIT',
182
+ defaults: {
183
+ name: 'SUNAT Perú',
184
+ },
185
+ inputs: ['main'],
186
+ outputs: ['main'],
187
+ credentials: [
188
+ {
189
+ name: 'sunatPeruApi',
190
+ required: false,
191
+ },
192
+ ],
193
+ properties: [
194
+ {
195
+ displayName: 'Recurso',
196
+ name: 'resource',
197
+ type: 'options',
198
+ noDataExpression: true,
199
+ options: [
200
+ { name: 'RUC/DNI', value: 'ruc' },
201
+ { name: 'Indicadores', value: 'indicadores' },
202
+ { name: 'Emitir Factura', value: 'factura' },
203
+ ],
204
+ default: 'ruc',
205
+ },
206
+ // Operaciones RUC/DNI
207
+ {
208
+ displayName: 'Operación',
209
+ name: 'operation',
210
+ type: 'options',
211
+ noDataExpression: true,
212
+ displayOptions: { show: { resource: ['ruc'] } },
213
+ options: [
214
+ { name: 'Validar RUC', value: 'validar_ruc', description: 'Validar formato de RUC', action: 'Validar RUC' },
215
+ { name: 'Validar DNI', value: 'validar_dni', description: 'Validar formato de DNI', action: 'Validar DNI' },
216
+ { name: 'Formatear RUC', value: 'formatear', description: 'Limpiar RUC', action: 'Formatear RUC' },
217
+ { name: 'Consultar RUC', value: 'consultar', description: 'Obtener datos de SUNAT', action: 'Consultar RUC' },
218
+ ],
219
+ default: 'validar_ruc',
220
+ },
221
+ {
222
+ displayName: 'RUC',
223
+ name: 'ruc',
224
+ type: 'string',
225
+ default: '',
226
+ placeholder: '20123456789',
227
+ required: true,
228
+ displayOptions: { show: { resource: ['ruc'], operation: ['validar_ruc', 'formatear', 'consultar'] } },
229
+ },
230
+ {
231
+ displayName: 'DNI',
232
+ name: 'dni',
233
+ type: 'string',
234
+ default: '',
235
+ placeholder: '12345678',
236
+ required: true,
237
+ displayOptions: { show: { resource: ['ruc'], operation: ['validar_dni'] } },
238
+ },
239
+ // Operaciones Indicadores
240
+ {
241
+ displayName: 'Operación',
242
+ name: 'operation',
243
+ type: 'options',
244
+ noDataExpression: true,
245
+ displayOptions: { show: { resource: ['indicadores'] } },
246
+ options: [
247
+ { name: 'Tipo de Cambio', value: 'tipo_cambio', description: 'Dólar compra/venta SBS', action: 'Obtener tipo cambio' },
248
+ { name: 'Valor UIT', value: 'uit', description: 'Unidad Impositiva Tributaria', action: 'Obtener UIT' },
249
+ { name: 'UIT a Soles', value: 'uit_soles', description: 'Convertir UIT a Soles', action: 'Convertir UIT a Soles' },
250
+ { name: 'Soles a UIT', value: 'soles_uit', description: 'Convertir Soles a UIT', action: 'Convertir Soles a UIT' },
251
+ ],
252
+ default: 'tipo_cambio',
253
+ },
254
+ {
255
+ displayName: 'Monto UIT',
256
+ name: 'montoUit',
257
+ type: 'number',
258
+ default: 10,
259
+ displayOptions: { show: { resource: ['indicadores'], operation: ['uit_soles'] } },
260
+ },
261
+ {
262
+ displayName: 'Monto Soles',
263
+ name: 'montoSoles',
264
+ type: 'number',
265
+ default: 50000,
266
+ displayOptions: { show: { resource: ['indicadores'], operation: ['soles_uit'] } },
267
+ },
268
+ // Operaciones Factura
269
+ {
270
+ displayName: 'Operación',
271
+ name: 'operation',
272
+ type: 'options',
273
+ noDataExpression: true,
274
+ displayOptions: { show: { resource: ['factura'] } },
275
+ options: [
276
+ { name: 'Factura', value: 'factura', description: 'Tipo 01', action: 'Emitir Factura' },
277
+ { name: 'Boleta de Venta', value: 'boleta', description: 'Tipo 03', action: 'Emitir Boleta' },
278
+ { name: 'Nota de Crédito', value: 'nota_credito', description: 'Tipo 07', action: 'Emitir Nota Credito' },
279
+ ],
280
+ default: 'factura',
281
+ },
282
+ {
283
+ displayName: 'Tipo Documento Cliente',
284
+ name: 'tipoDocCliente',
285
+ type: 'options',
286
+ options: [
287
+ { name: 'RUC', value: '6' },
288
+ { name: 'DNI', value: '1' },
289
+ { name: 'Carnet Extranjería', value: '4' },
290
+ { name: 'Pasaporte', value: '7' },
291
+ ],
292
+ default: '6',
293
+ displayOptions: { show: { resource: ['factura'] } },
294
+ },
295
+ {
296
+ displayName: 'Número Documento',
297
+ name: 'numDocCliente',
298
+ type: 'string',
299
+ default: '',
300
+ placeholder: '20123456789',
301
+ displayOptions: { show: { resource: ['factura'] } },
302
+ },
303
+ {
304
+ displayName: 'Razón Social',
305
+ name: 'razonSocial',
306
+ type: 'string',
307
+ default: '',
308
+ placeholder: 'Empresa S.A.C.',
309
+ displayOptions: { show: { resource: ['factura'] } },
310
+ },
311
+ {
312
+ displayName: 'Subtotal',
313
+ name: 'subtotal',
314
+ type: 'number',
315
+ default: 0,
316
+ displayOptions: { show: { resource: ['factura'] } },
317
+ },
318
+ {
319
+ displayName: 'IGV (18%)',
320
+ name: 'igv',
321
+ type: 'number',
322
+ default: 0,
323
+ displayOptions: { show: { resource: ['factura'] } },
324
+ },
325
+ {
326
+ displayName: 'Total',
327
+ name: 'total',
328
+ type: 'number',
329
+ default: 0,
330
+ displayOptions: { show: { resource: ['factura'] } },
331
+ },
332
+ ],
333
+ };
334
+ }
335
+ async execute() {
336
+ const items = this.getInputData();
337
+ const returnData = [];
338
+ const resource = this.getNodeParameter('resource', 0);
339
+ const operation = this.getNodeParameter('operation', 0);
340
+ for (let i = 0; i < items.length; i++) {
341
+ let result = {};
342
+ try {
343
+ // RUC/DNI
344
+ if (resource === 'ruc') {
345
+ if (operation === 'validar_ruc') {
346
+ const ruc = this.getNodeParameter('ruc', i);
347
+ result = validarRuc(ruc);
348
+ }
349
+ else if (operation === 'validar_dni') {
350
+ const dni = this.getNodeParameter('dni', i);
351
+ result = validarDni(dni);
352
+ }
353
+ else if (operation === 'formatear') {
354
+ const ruc = this.getNodeParameter('ruc', i);
355
+ result = { ruc: formatearRuc(ruc) };
356
+ }
357
+ else if (operation === 'consultar') {
358
+ const ruc = this.getNodeParameter('ruc', i);
359
+ result = await consultarRuc(this, ruc);
360
+ }
361
+ }
362
+ // Indicadores
363
+ else if (resource === 'indicadores') {
364
+ if (operation === 'tipo_cambio') {
365
+ result = await obtenerTipoCambio(this);
366
+ }
367
+ else if (operation === 'uit') {
368
+ result = await obtenerUit(this);
369
+ }
370
+ else if (operation === 'uit_soles') {
371
+ const montoUit = this.getNodeParameter('montoUit', i);
372
+ const uit = await obtenerUit(this);
373
+ result = convertirUitSoles(montoUit, uit.valor);
374
+ }
375
+ else if (operation === 'soles_uit') {
376
+ const montoSoles = this.getNodeParameter('montoSoles', i);
377
+ const uit = await obtenerUit(this);
378
+ result = convertirSolesUit(montoSoles, uit.valor);
379
+ }
380
+ }
381
+ // Factura
382
+ else if (resource === 'factura') {
383
+ const credentials = await this.getCredentials('sunatPeruApi').catch(() => null);
384
+ if (!credentials || credentials.provider === 'none') {
385
+ throw new Error('Configura credenciales de Nubefact o Efact para emitir facturas');
386
+ }
387
+ const tipoComp = operation === 'factura' ? '01' : operation === 'boleta' ? '03' : '07';
388
+ const datos = {
389
+ tipoDoc: this.getNodeParameter('tipoDocCliente', i),
390
+ numDoc: this.getNodeParameter('numDocCliente', i),
391
+ razonSocial: this.getNodeParameter('razonSocial', i),
392
+ subtotal: this.getNodeParameter('subtotal', i),
393
+ igv: this.getNodeParameter('igv', i),
394
+ total: this.getNodeParameter('total', i),
395
+ };
396
+ result = await emitirFactura(this, credentials.provider, credentials.nubefactApiKey, tipoComp, datos);
397
+ }
398
+ returnData.push({ json: result });
399
+ }
400
+ catch (error) {
401
+ if (this.continueOnFail()) {
402
+ returnData.push({ json: { error: error.message } });
403
+ continue;
404
+ }
405
+ throw error;
406
+ }
407
+ }
408
+ return [returnData];
409
+ }
410
+ }
411
+ exports.SunatPeru = SunatPeru;
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60">
2
+ <rect width="60" height="60" rx="8" fill="#D91023"/>
3
+ <text x="30" y="24" font-family="Arial, sans-serif" font-size="9" font-weight="bold" fill="white" text-anchor="middle">SUNAT</text>
4
+ <text x="30" y="40" font-family="Arial, sans-serif" font-size="7" fill="white" text-anchor="middle">PERÚ</text>
5
+ <rect x="10" y="48" width="13" height="6" fill="#D91023"/>
6
+ <rect x="23" y="48" width="14" height="6" fill="white"/>
7
+ <rect x="37" y="48" width="13" height="6" fill="#D91023"/>
8
+ </svg>
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "n8n-nodes-sunat-peru",
3
+ "version": "0.1.0",
4
+ "description": "Nodo n8n para integración con SUNAT Perú - Factura Electrónica, RUC/DNI, tipo cambio, UIT",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "sunat",
9
+ "peru",
10
+ "ruc",
11
+ "dni",
12
+ "facturacion",
13
+ "impuestos",
14
+ "uit",
15
+ "latam"
16
+ ],
17
+ "license": "MIT",
18
+ "homepage": "https://github.com/Manuelreyesbravo/n8n-nodes-sunat-peru",
19
+ "author": {
20
+ "name": "Manuel Reyes Bravo",
21
+ "email": "manuelreyesbravo@gmail.com"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/Manuelreyesbravo/n8n-nodes-sunat-peru.git"
26
+ },
27
+ "main": "index.js",
28
+ "scripts": {
29
+ "build": "tsc && gulp build:icons",
30
+ "dev": "tsc --watch",
31
+ "format": "prettier nodes credentials --write",
32
+ "lint": "eslint nodes credentials package.json",
33
+ "lintfix": "eslint nodes credentials package.json --fix",
34
+ "prepublishOnly": "npm run build"
35
+ },
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "n8n": {
40
+ "n8nNodesApiVersion": 1,
41
+ "credentials": [
42
+ "dist/credentials/SunatPeruApi.credentials.js"
43
+ ],
44
+ "nodes": [
45
+ "dist/nodes/SunatPeru/SunatPeru.node.js"
46
+ ]
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^20.10.0",
50
+ "@typescript-eslint/parser": "^6.0.0",
51
+ "eslint": "^8.56.0",
52
+ "gulp": "^4.0.2",
53
+ "n8n-workflow": "*",
54
+ "prettier": "^3.1.0",
55
+ "typescript": "^5.3.0"
56
+ },
57
+ "peerDependencies": {
58
+ "n8n-workflow": "*"
59
+ }
60
+ }