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 +21 -0
- package/README.md +101 -0
- package/dist/credentials/Afipargentinaapi.credentials.d.ts +8 -0
- package/dist/credentials/Afipargentinaapi.credentials.js +66 -0
- package/dist/nodes/AfipArgentina/AfipArgentina.node.d.ts +5 -0
- package/dist/nodes/AfipArgentina/AfipArgentina.node.js +471 -0
- package/dist/nodes/AfipArgentina/afip.svg +9 -0
- package/package.json +61 -0
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
|
+

|
|
4
|
+

|
|
5
|
+

|
|
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
|
+
}
|