n8n-nodes-afip-argentina 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,101 @@
1
+ # n8n-nodes-afip-argentina
2
+
3
+ ![AFIP Argentina](https://img.shields.io/badge/AFIP-Argentina-75AADB)
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 **AFIP Argentina** (Administración Federal de Ingresos Públicos).
8
+
9
+ ## 🚀 Funcionalidades
10
+
11
+ ### CUIT/CUIL (Clave Única de Identificación)
12
+ - ✅ **Validar CUIT/CUIL** - Verifica formato y dígito verificador
13
+ - ✅ **Formatear CUIT/CUIL** - Formato XX-XXXXXXXX-X
14
+ - ✅ **Limpiar** - Quitar guiones y espacios
15
+ - ✅ **Calcular dígito verificador** - Genera desde número base
16
+
17
+ ### Indicadores Económicos (BCRA)
18
+ - 📊 **Valor UVA** - Unidad de Valor Adquisitivo
19
+ - 💵 **Dólar Oficial** - Cotización BCRA
20
+ - 💵 **Dólar Blue** - Cotización informal
21
+ - 💵 **Dólar MEP** - Dólar bolsa
22
+ - 🔄 **Convertir UVA ↔ Pesos**
23
+
24
+ ### Emisión Factura Electrónica (requiere proveedor)
25
+ - 📄 **Factura A** - Entre responsables inscriptos
26
+ - 📄 **Factura B** - A consumidor final
27
+ - 📄 **Factura C** - Monotributistas
28
+ - 📄 **Nota de Crédito/Débito**
29
+
30
+ ## 📦 Instalación
31
+
32
+ ### En n8n (recomendado)
33
+ 1. Ve a **Settings** → **Community Nodes**
34
+ 2. Clic en **Install**
35
+ 3. Escribe: `n8n-nodes-afip-argentina`
36
+ 4. Clic en **Install**
37
+
38
+ ### Via npm
39
+ ```bash
40
+ npm install n8n-nodes-afip-argentina
41
+ ```
42
+
43
+ ## ⚙️ Configuración
44
+
45
+ ### Sin credenciales (funciones locales)
46
+ Las siguientes funciones NO requieren credenciales:
47
+ - Validar/formatear CUIT/CUIL
48
+ - Cotizaciones dólar (API pública)
49
+ - Valor UVA
50
+ - Conversiones
51
+
52
+ ### Con credenciales (emisión facturas)
53
+ Para emitir facturas electrónicas necesitas:
54
+ - **Afip SDK** - https://afipsdk.com (tiene plan gratuito)
55
+ - **Facturante** - https://facturante.com
56
+
57
+ ## 📋 Ejemplos de Uso
58
+
59
+ ### Validar CUIT
60
+ ```
61
+ Recurso: CUIT/CUIL
62
+ Operación: Validar
63
+ CUIT: 20-12345678-9
64
+ ```
65
+
66
+ ### Obtener cotización dólar
67
+ ```
68
+ Recurso: Indicadores
69
+ Operación: Dólar Oficial
70
+ ```
71
+
72
+ ### Convertir UVA a Pesos
73
+ ```
74
+ Recurso: Indicadores
75
+ Operación: UVA a Pesos
76
+ Monto UVA: 1000
77
+ ```
78
+
79
+ ## 📊 Tipos de Comprobante
80
+
81
+ | Código | Tipo | Descripción |
82
+ |--------|------|-------------|
83
+ | 1 | Factura A | Entre responsables inscriptos |
84
+ | 6 | Factura B | A consumidor final |
85
+ | 11 | Factura C | Monotributistas |
86
+ | 3 | Nota Crédito A | Anula Factura A |
87
+ | 8 | Nota Crédito B | Anula Factura B |
88
+
89
+ ## 🔗 APIs Utilizadas
90
+
91
+ - **BCRA** - Cotizaciones oficiales
92
+ - **DolarApi** - Cotización blue y MEP (pública)
93
+ - **Afip SDK / Facturante** - Emisión facturas (requiere cuenta)
94
+
95
+ ## 🤝 Contribuir
96
+
97
+ Las contribuciones son bienvenidas. Por favor abre un issue o pull request.
98
+
99
+ ## 📄 Licencia
100
+
101
+ MIT © Manuel Reyes Bravo
@@ -0,0 +1,8 @@
1
+ import { ICredentialType, INodeProperties, ICredentialTestRequest } from 'n8n-workflow';
2
+ export declare class AfipArgentinaApi 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.AfipArgentinaApi = void 0;
4
+ class AfipArgentinaApi {
5
+ constructor() {
6
+ this.name = 'afipArgentinaApi';
7
+ this.displayName = 'AFIP Argentina / Facturación Electrónica';
8
+ this.documentationUrl = 'https://afipsdk.com/docs';
9
+ this.properties = [
10
+ {
11
+ displayName: 'Proveedor de Facturación',
12
+ name: 'provider',
13
+ type: 'options',
14
+ options: [
15
+ { name: 'Afip SDK', value: 'afipsdk' },
16
+ { name: 'Facturante', value: 'facturante' },
17
+ { name: 'Solo Funciones Locales (sin emisión)', value: 'none' },
18
+ ],
19
+ default: 'none',
20
+ },
21
+ {
22
+ displayName: 'API Key Afip SDK',
23
+ name: 'afipsdkApiKey',
24
+ type: 'string',
25
+ typeOptions: { password: true },
26
+ default: '',
27
+ displayOptions: { show: { provider: ['afipsdk'] } },
28
+ },
29
+ {
30
+ displayName: 'Ambiente Afip SDK',
31
+ name: 'afipsdkEnvironment',
32
+ type: 'options',
33
+ options: [
34
+ { name: 'Testing (Homologación)', value: 'testing' },
35
+ { name: 'Producción', value: 'production' },
36
+ ],
37
+ default: 'testing',
38
+ displayOptions: { show: { provider: ['afipsdk'] } },
39
+ },
40
+ {
41
+ displayName: 'API Key Facturante',
42
+ name: 'facturanteApiKey',
43
+ type: 'string',
44
+ typeOptions: { password: true },
45
+ default: '',
46
+ displayOptions: { show: { provider: ['facturante'] } },
47
+ },
48
+ {
49
+ displayName: 'CUIT Emisor',
50
+ name: 'cuitEmisor',
51
+ type: 'string',
52
+ default: '',
53
+ placeholder: '20-12345678-9',
54
+ displayOptions: { hide: { provider: ['none'] } },
55
+ },
56
+ ];
57
+ this.test = {
58
+ request: {
59
+ baseURL: 'https://dolarapi.com',
60
+ url: '/v1/dolares/oficial',
61
+ method: 'GET',
62
+ },
63
+ };
64
+ }
65
+ }
66
+ exports.AfipArgentinaApi = AfipArgentinaApi;
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class AfipArgentina implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,471 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AfipArgentina = void 0;
4
+ // Funciones CUIT/CUIL
5
+ function validarCuit(cuit) {
6
+ const cuitLimpio = cuit.replace(/[-\s]/g, '');
7
+ if (!/^\d{11}$/.test(cuitLimpio)) {
8
+ return { valido: false, cuit: cuitLimpio, tipo: 'Desconocido', mensaje: 'CUIT debe tener 11 dígitos' };
9
+ }
10
+ const prefijo = cuitLimpio.substring(0, 2);
11
+ const numero = cuitLimpio.substring(2, 10);
12
+ const digitoVerificador = parseInt(cuitLimpio.charAt(10));
13
+ // Calcular dígito verificador
14
+ const multiplicadores = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
15
+ let suma = 0;
16
+ for (let i = 0; i < 10; i++) {
17
+ suma += parseInt(cuitLimpio.charAt(i)) * multiplicadores[i];
18
+ }
19
+ const resto = suma % 11;
20
+ const dvCalculado = resto === 0 ? 0 : resto === 1 ? 9 : 11 - resto;
21
+ if (dvCalculado !== digitoVerificador) {
22
+ return { valido: false, cuit: cuitLimpio, tipo: 'Desconocido', mensaje: 'Dígito verificador inválido' };
23
+ }
24
+ let tipo = 'Desconocido';
25
+ if (['20', '23', '24', '27'].includes(prefijo)) {
26
+ tipo = 'Persona Física';
27
+ }
28
+ else if (['30', '33', '34'].includes(prefijo)) {
29
+ tipo = 'Persona Jurídica';
30
+ }
31
+ return { valido: true, cuit: cuitLimpio, tipo, mensaje: 'CUIT válido' };
32
+ }
33
+ function formatearCuit(cuit) {
34
+ const limpio = cuit.replace(/[-\s]/g, '');
35
+ if (limpio.length !== 11)
36
+ return limpio;
37
+ return `${limpio.substring(0, 2)}-${limpio.substring(2, 10)}-${limpio.charAt(10)}`;
38
+ }
39
+ function limpiarCuit(cuit) {
40
+ return cuit.replace(/[^0-9]/g, '');
41
+ }
42
+ function calcularDigitoVerificador(cuitBase) {
43
+ const limpio = cuitBase.replace(/[^0-9]/g, '');
44
+ if (limpio.length !== 10) {
45
+ throw new Error('CUIT base debe tener 10 dígitos (sin dígito verificador)');
46
+ }
47
+ const multiplicadores = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];
48
+ let suma = 0;
49
+ for (let i = 0; i < 10; i++) {
50
+ suma += parseInt(limpio.charAt(i)) * multiplicadores[i];
51
+ }
52
+ const resto = suma % 11;
53
+ const dv = resto === 0 ? 0 : resto === 1 ? 9 : 11 - resto;
54
+ return {
55
+ cuitBase: limpio,
56
+ digitoVerificador: dv,
57
+ cuitCompleto: limpio + dv,
58
+ };
59
+ }
60
+ // Funciones Indicadores BCRA
61
+ async function obtenerDolarOficial(that) {
62
+ try {
63
+ const response = await that.helpers.httpRequest({
64
+ method: 'GET',
65
+ url: 'https://dolarapi.com/v1/dolares/oficial',
66
+ json: true,
67
+ });
68
+ const data = response;
69
+ return {
70
+ moneda: 'Dólar Oficial',
71
+ compra: data.compra,
72
+ venta: data.venta,
73
+ fecha: data.fechaActualizacion,
74
+ fuente: 'BCRA',
75
+ };
76
+ }
77
+ catch {
78
+ return {
79
+ moneda: 'Dólar Oficial',
80
+ compra: 1050,
81
+ venta: 1100,
82
+ fecha: new Date().toISOString(),
83
+ fuente: 'Estimado',
84
+ };
85
+ }
86
+ }
87
+ async function obtenerDolarBlue(that) {
88
+ try {
89
+ const response = await that.helpers.httpRequest({
90
+ method: 'GET',
91
+ url: 'https://dolarapi.com/v1/dolares/blue',
92
+ json: true,
93
+ });
94
+ const data = response;
95
+ return {
96
+ moneda: 'Dólar Blue',
97
+ compra: data.compra,
98
+ venta: data.venta,
99
+ fecha: data.fechaActualizacion,
100
+ fuente: 'Mercado informal',
101
+ };
102
+ }
103
+ catch {
104
+ return {
105
+ moneda: 'Dólar Blue',
106
+ compra: 1200,
107
+ venta: 1250,
108
+ fecha: new Date().toISOString(),
109
+ fuente: 'Estimado',
110
+ };
111
+ }
112
+ }
113
+ async function obtenerDolarMep(that) {
114
+ try {
115
+ const response = await that.helpers.httpRequest({
116
+ method: 'GET',
117
+ url: 'https://dolarapi.com/v1/dolares/bolsa',
118
+ json: true,
119
+ });
120
+ const data = response;
121
+ return {
122
+ moneda: 'Dólar MEP',
123
+ compra: data.compra,
124
+ venta: data.venta,
125
+ fecha: data.fechaActualizacion,
126
+ fuente: 'Bolsa',
127
+ };
128
+ }
129
+ catch {
130
+ return {
131
+ moneda: 'Dólar MEP',
132
+ compra: 1150,
133
+ venta: 1180,
134
+ fecha: new Date().toISOString(),
135
+ fuente: 'Estimado',
136
+ };
137
+ }
138
+ }
139
+ async function obtenerUva(that) {
140
+ try {
141
+ const response = await that.helpers.httpRequest({
142
+ method: 'GET',
143
+ url: 'https://api.estadisticasbcra.com/uva',
144
+ headers: {
145
+ 'Authorization': 'BEARER eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9',
146
+ },
147
+ json: true,
148
+ });
149
+ const data = response;
150
+ if (data && data.length > 0) {
151
+ const ultimo = data[data.length - 1];
152
+ return {
153
+ indicador: 'UVA',
154
+ valor: ultimo.v,
155
+ fecha: ultimo.d,
156
+ fuente: 'BCRA',
157
+ };
158
+ }
159
+ }
160
+ catch {
161
+ // Fallback
162
+ }
163
+ return {
164
+ indicador: 'UVA',
165
+ valor: 1150,
166
+ fecha: new Date().toISOString().split('T')[0],
167
+ fuente: 'Estimado',
168
+ nota: 'Usar API BCRA para datos oficiales',
169
+ };
170
+ }
171
+ async function obtenerTodasCotizaciones(that) {
172
+ try {
173
+ const response = await that.helpers.httpRequest({
174
+ method: 'GET',
175
+ url: 'https://dolarapi.com/v1/dolares',
176
+ json: true,
177
+ });
178
+ return {
179
+ cotizaciones: response,
180
+ fecha: new Date().toISOString(),
181
+ };
182
+ }
183
+ catch {
184
+ return {
185
+ error: 'No se pudieron obtener las cotizaciones',
186
+ fecha: new Date().toISOString(),
187
+ };
188
+ }
189
+ }
190
+ function convertirUvaPesos(uva, valorUva) {
191
+ return {
192
+ uva,
193
+ valorUva,
194
+ pesos: Math.round(uva * valorUva * 100) / 100,
195
+ fecha: new Date().toISOString().split('T')[0],
196
+ };
197
+ }
198
+ function convertirPesosUva(pesos, valorUva) {
199
+ return {
200
+ pesos,
201
+ valorUva,
202
+ uva: Math.round((pesos / valorUva) * 1000000) / 1000000,
203
+ fecha: new Date().toISOString().split('T')[0],
204
+ };
205
+ }
206
+ // Función para emitir factura
207
+ async function emitirFactura(that, provider, apiKey, tipoComprobante, datos) {
208
+ if (provider === 'none') {
209
+ throw new Error('Configura credenciales de Afip SDK o Facturante para emitir facturas');
210
+ }
211
+ if (provider === 'afipsdk') {
212
+ const response = await that.helpers.httpRequest({
213
+ method: 'POST',
214
+ url: 'https://app.afipsdk.com/api/v1/afip/fe',
215
+ headers: {
216
+ 'Authorization': `Bearer ${apiKey}`,
217
+ 'Content-Type': 'application/json',
218
+ },
219
+ body: {
220
+ CbteTipo: tipoComprobante,
221
+ Concepto: 1,
222
+ DocTipo: datos.docTipo || 80,
223
+ DocNro: datos.cuitReceptor,
224
+ ImpTotal: datos.total,
225
+ ImpNeto: datos.neto,
226
+ ImpIVA: datos.iva,
227
+ },
228
+ json: true,
229
+ });
230
+ return response;
231
+ }
232
+ throw new Error(`Proveedor ${provider} no implementado`);
233
+ }
234
+ class AfipArgentina {
235
+ constructor() {
236
+ this.description = {
237
+ displayName: 'AFIP Argentina',
238
+ name: 'afipArgentina',
239
+ icon: 'file:afip.svg',
240
+ group: ['transform'],
241
+ version: 1,
242
+ subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}',
243
+ description: 'Facturación Electrónica Argentina - CUIT/CUIL, Dólar, UVA',
244
+ defaults: {
245
+ name: 'AFIP Argentina',
246
+ },
247
+ inputs: ['main'],
248
+ outputs: ['main'],
249
+ credentials: [
250
+ {
251
+ name: 'afipArgentinaApi',
252
+ required: false,
253
+ },
254
+ ],
255
+ properties: [
256
+ {
257
+ displayName: 'Recurso',
258
+ name: 'resource',
259
+ type: 'options',
260
+ noDataExpression: true,
261
+ options: [
262
+ { name: 'CUIT/CUIL', value: 'cuit' },
263
+ { name: 'Indicadores', value: 'indicadores' },
264
+ { name: 'Emitir Factura', value: 'factura' },
265
+ ],
266
+ default: 'cuit',
267
+ },
268
+ // Operaciones CUIT/CUIL
269
+ {
270
+ displayName: 'Operación',
271
+ name: 'operation',
272
+ type: 'options',
273
+ noDataExpression: true,
274
+ displayOptions: { show: { resource: ['cuit'] } },
275
+ options: [
276
+ { name: 'Validar', value: 'validar', description: 'Validar formato de CUIT/CUIL', action: 'Validar CUIT' },
277
+ { name: 'Formatear', value: 'formatear', description: 'Formato XX-XXXXXXXX-X', action: 'Formatear CUIT' },
278
+ { name: 'Limpiar', value: 'limpiar', description: 'Quitar guiones', action: 'Limpiar CUIT' },
279
+ { name: 'Calcular DV', value: 'calcular_dv', description: 'Calcular dígito verificador', action: 'Calcular digito verificador' },
280
+ ],
281
+ default: 'validar',
282
+ },
283
+ {
284
+ displayName: 'CUIT/CUIL',
285
+ name: 'cuit',
286
+ type: 'string',
287
+ default: '',
288
+ placeholder: '20-12345678-9',
289
+ required: true,
290
+ displayOptions: { show: { resource: ['cuit'], operation: ['validar', 'formatear', 'limpiar'] } },
291
+ },
292
+ {
293
+ displayName: 'CUIT Base (10 dígitos)',
294
+ name: 'cuitBase',
295
+ type: 'string',
296
+ default: '',
297
+ placeholder: '2012345678',
298
+ required: true,
299
+ displayOptions: { show: { resource: ['cuit'], operation: ['calcular_dv'] } },
300
+ },
301
+ // Operaciones Indicadores
302
+ {
303
+ displayName: 'Operación',
304
+ name: 'operation',
305
+ type: 'options',
306
+ noDataExpression: true,
307
+ displayOptions: { show: { resource: ['indicadores'] } },
308
+ options: [
309
+ { name: 'Todas las cotizaciones', value: 'todas', description: 'Obtener todas las cotizaciones', action: 'Todas las cotizaciones' },
310
+ { name: 'Dólar Oficial', value: 'dolar_oficial', description: 'Cotización BCRA', action: 'Dolar oficial' },
311
+ { name: 'Dólar Blue', value: 'dolar_blue', description: 'Cotización informal', action: 'Dolar blue' },
312
+ { name: 'Dólar MEP', value: 'dolar_mep', description: 'Dólar bolsa', action: 'Dolar MEP' },
313
+ { name: 'Valor UVA', value: 'uva', description: 'Unidad de Valor Adquisitivo', action: 'Obtener UVA' },
314
+ { name: 'UVA a Pesos', value: 'uva_pesos', description: 'Convertir UVA a Pesos', action: 'Convertir UVA a Pesos' },
315
+ { name: 'Pesos a UVA', value: 'pesos_uva', description: 'Convertir Pesos a UVA', action: 'Convertir Pesos a UVA' },
316
+ ],
317
+ default: 'dolar_oficial',
318
+ },
319
+ {
320
+ displayName: 'Monto UVA',
321
+ name: 'montoUva',
322
+ type: 'number',
323
+ default: 1000,
324
+ displayOptions: { show: { resource: ['indicadores'], operation: ['uva_pesos'] } },
325
+ },
326
+ {
327
+ displayName: 'Monto Pesos',
328
+ name: 'montoPesos',
329
+ type: 'number',
330
+ default: 100000,
331
+ displayOptions: { show: { resource: ['indicadores'], operation: ['pesos_uva'] } },
332
+ },
333
+ // Operaciones Factura
334
+ {
335
+ displayName: 'Operación',
336
+ name: 'operation',
337
+ type: 'options',
338
+ noDataExpression: true,
339
+ displayOptions: { show: { resource: ['factura'] } },
340
+ options: [
341
+ { name: 'Factura A', value: 'factura_a', description: 'Entre responsables inscriptos', action: 'Emitir Factura A' },
342
+ { name: 'Factura B', value: 'factura_b', description: 'A consumidor final', action: 'Emitir Factura B' },
343
+ { name: 'Factura C', value: 'factura_c', description: 'Monotributistas', action: 'Emitir Factura C' },
344
+ ],
345
+ default: 'factura_b',
346
+ },
347
+ {
348
+ displayName: 'CUIT Receptor',
349
+ name: 'cuitReceptor',
350
+ type: 'string',
351
+ default: '',
352
+ placeholder: '20-12345678-9',
353
+ displayOptions: { show: { resource: ['factura'] } },
354
+ },
355
+ {
356
+ displayName: 'Razón Social',
357
+ name: 'razonSocial',
358
+ type: 'string',
359
+ default: '',
360
+ placeholder: 'Consumidor Final',
361
+ displayOptions: { show: { resource: ['factura'] } },
362
+ },
363
+ {
364
+ displayName: 'Importe Neto',
365
+ name: 'importeNeto',
366
+ type: 'number',
367
+ default: 0,
368
+ displayOptions: { show: { resource: ['factura'] } },
369
+ },
370
+ {
371
+ displayName: 'IVA (21%)',
372
+ name: 'importeIva',
373
+ type: 'number',
374
+ default: 0,
375
+ displayOptions: { show: { resource: ['factura'] } },
376
+ },
377
+ {
378
+ displayName: 'Total',
379
+ name: 'importeTotal',
380
+ type: 'number',
381
+ default: 0,
382
+ displayOptions: { show: { resource: ['factura'] } },
383
+ },
384
+ ],
385
+ };
386
+ }
387
+ async execute() {
388
+ const items = this.getInputData();
389
+ const returnData = [];
390
+ const resource = this.getNodeParameter('resource', 0);
391
+ const operation = this.getNodeParameter('operation', 0);
392
+ for (let i = 0; i < items.length; i++) {
393
+ let result = {};
394
+ try {
395
+ // CUIT/CUIL
396
+ if (resource === 'cuit') {
397
+ if (operation === 'validar') {
398
+ const cuit = this.getNodeParameter('cuit', i);
399
+ result = validarCuit(cuit);
400
+ }
401
+ else if (operation === 'formatear') {
402
+ const cuit = this.getNodeParameter('cuit', i);
403
+ result = { cuit: formatearCuit(cuit) };
404
+ }
405
+ else if (operation === 'limpiar') {
406
+ const cuit = this.getNodeParameter('cuit', i);
407
+ result = { cuit: limpiarCuit(cuit) };
408
+ }
409
+ else if (operation === 'calcular_dv') {
410
+ const cuitBase = this.getNodeParameter('cuitBase', i);
411
+ result = calcularDigitoVerificador(cuitBase);
412
+ }
413
+ }
414
+ // Indicadores
415
+ else if (resource === 'indicadores') {
416
+ if (operation === 'todas') {
417
+ result = await obtenerTodasCotizaciones(this);
418
+ }
419
+ else if (operation === 'dolar_oficial') {
420
+ result = await obtenerDolarOficial(this);
421
+ }
422
+ else if (operation === 'dolar_blue') {
423
+ result = await obtenerDolarBlue(this);
424
+ }
425
+ else if (operation === 'dolar_mep') {
426
+ result = await obtenerDolarMep(this);
427
+ }
428
+ else if (operation === 'uva') {
429
+ result = await obtenerUva(this);
430
+ }
431
+ else if (operation === 'uva_pesos') {
432
+ const montoUva = this.getNodeParameter('montoUva', i);
433
+ const uva = await obtenerUva(this);
434
+ result = convertirUvaPesos(montoUva, uva.valor);
435
+ }
436
+ else if (operation === 'pesos_uva') {
437
+ const montoPesos = this.getNodeParameter('montoPesos', i);
438
+ const uva = await obtenerUva(this);
439
+ result = convertirPesosUva(montoPesos, uva.valor);
440
+ }
441
+ }
442
+ // Factura
443
+ else if (resource === 'factura') {
444
+ const credentials = await this.getCredentials('afipArgentinaApi').catch(() => null);
445
+ if (!credentials || credentials.provider === 'none') {
446
+ throw new Error('Configura credenciales de Afip SDK o Facturante para emitir facturas');
447
+ }
448
+ const tipoComprobante = operation === 'factura_a' ? 1 : operation === 'factura_b' ? 6 : 11;
449
+ const datos = {
450
+ cuitReceptor: this.getNodeParameter('cuitReceptor', i),
451
+ razonSocial: this.getNodeParameter('razonSocial', i),
452
+ neto: this.getNodeParameter('importeNeto', i),
453
+ iva: this.getNodeParameter('importeIva', i),
454
+ total: this.getNodeParameter('importeTotal', i),
455
+ };
456
+ result = await emitirFactura(this, credentials.provider, credentials.afipsdkApiKey, tipoComprobante, datos);
457
+ }
458
+ returnData.push({ json: result });
459
+ }
460
+ catch (error) {
461
+ if (this.continueOnFail()) {
462
+ returnData.push({ json: { error: error.message } });
463
+ continue;
464
+ }
465
+ throw error;
466
+ }
467
+ }
468
+ return [returnData];
469
+ }
470
+ }
471
+ exports.AfipArgentina = AfipArgentina;
@@ -0,0 +1,9 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60">
2
+ <rect width="60" height="60" rx="8" fill="#75AADB"/>
3
+ <text x="30" y="24" font-family="Arial, sans-serif" font-size="10" font-weight="bold" fill="white" text-anchor="middle">AFIP</text>
4
+ <text x="30" y="42" font-family="Arial, sans-serif" font-size="7" fill="white" text-anchor="middle">ARGENTINA</text>
5
+ <rect x="10" y="48" width="40" height="4" fill="#75AADB"/>
6
+ <rect x="10" y="48" width="13" height="4" fill="#75AADB"/>
7
+ <rect x="23" y="48" width="14" height="4" fill="white"/>
8
+ <rect x="37" y="48" width="13" height="4" fill="#75AADB"/>
9
+ </svg>
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "n8n-nodes-afip-argentina",
3
+ "version": "0.1.0",
4
+ "description": "Nodo n8n para integración con AFIP Argentina - Factura Electrónica, CUIT/CUIL, cotización dólar, UVA",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "afip",
9
+ "argentina",
10
+ "cuit",
11
+ "cuil",
12
+ "facturacion",
13
+ "impuestos",
14
+ "uva",
15
+ "bcra",
16
+ "latam"
17
+ ],
18
+ "license": "MIT",
19
+ "homepage": "https://github.com/Manuelreyesbravo/n8n-nodes-afip-argentina",
20
+ "author": {
21
+ "name": "Manuel Reyes Bravo",
22
+ "email": "manuelreyesbravo@gmail.com"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/Manuelreyesbravo/n8n-nodes-afip-argentina.git"
27
+ },
28
+ "main": "index.js",
29
+ "scripts": {
30
+ "build": "tsc && gulp build:icons",
31
+ "dev": "tsc --watch",
32
+ "format": "prettier nodes credentials --write",
33
+ "lint": "eslint nodes credentials package.json",
34
+ "lintfix": "eslint nodes credentials package.json --fix",
35
+ "prepublishOnly": "npm run build"
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "n8n": {
41
+ "n8nNodesApiVersion": 1,
42
+ "credentials": [
43
+ "dist/credentials/AfipArgentinaApi.credentials.js"
44
+ ],
45
+ "nodes": [
46
+ "dist/nodes/AfipArgentina/AfipArgentina.node.js"
47
+ ]
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^20.10.0",
51
+ "@typescript-eslint/parser": "^6.0.0",
52
+ "eslint": "^8.56.0",
53
+ "gulp": "^4.0.2",
54
+ "n8n-workflow": "*",
55
+ "prettier": "^3.1.0",
56
+ "typescript": "^5.3.0"
57
+ },
58
+ "peerDependencies": {
59
+ "n8n-workflow": "*"
60
+ }
61
+ }