arca-sdk 0.4.0 → 0.5.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 +70 -224
- package/dist/index.cjs +103 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -13
- package/dist/index.d.ts +32 -13
- package/dist/index.js +103 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
SDK en TypeScript para integración con servicios de ARCA:
|
|
6
6
|
- ✅ **Type-safe**: TypeScript strict mode
|
|
7
7
|
- ✅ **Simple**: No más XML manual
|
|
8
|
-
- ✅ **Automático**: Cache de tokens,
|
|
9
|
-
- ✅ **Fiscal**: Generador de QR oficial AFIP
|
|
8
|
+
- ✅ **Automático**: Cache de tokens, persistencia opcional (God Mode)
|
|
9
|
+
- ✅ **Fiscal**: Generador de QR oficial ARCA/AFIP ultra-robusto
|
|
10
|
+
- ✅ **Padrón**: Consulta de CUIT (A13) para autocompletado de datos
|
|
10
11
|
- ✅ **Resiliente**: Maneja errores SSL ("dh key too small") y timeouts
|
|
11
12
|
- ✅ **Moderno**: ESM + CJS nativo, Node.js 18+
|
|
12
13
|
|
|
@@ -23,283 +24,128 @@ bun add arca-sdk
|
|
|
23
24
|
|
|
24
25
|
## ⚡ Quick Start
|
|
25
26
|
```typescript
|
|
26
|
-
import { WsaaService } from 'arca-sdk';
|
|
27
|
-
import * as fs from 'node:fs';
|
|
28
|
-
|
|
29
|
-
// 1. Crear servicio con tus certificados
|
|
30
|
-
const wsaa = new WsaaService({
|
|
31
|
-
environment: 'homologacion', // 'homologacion' o 'produccion'
|
|
32
|
-
cuit: '20123456789',
|
|
33
|
-
cert: fs.readFileSync('./cert.pem', 'utf-8'),
|
|
34
|
-
key: fs.readFileSync('./key.pem', 'utf-8'),
|
|
35
|
-
service: 'wsfe',
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// 2. Obtener ticket (automático, con cache)
|
|
39
|
-
const ticket = await wsaa.login();
|
|
40
|
-
|
|
41
|
-
// 3. Usar token en otros servicios ARCA
|
|
42
|
-
console.log('Token:', ticket.token);
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**Eso es todo.** No XML. No SOAP. No pain.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## 📖 Servicios Disponibles
|
|
50
|
-
|
|
51
|
-
### WSAA - Autenticación
|
|
52
|
-
```typescript
|
|
53
|
-
import { WsaaService } from 'arca-sdk';
|
|
27
|
+
import { WsaaService, WsfeService } from 'arca-sdk';
|
|
54
28
|
|
|
55
|
-
|
|
29
|
+
// 1. Configuración base
|
|
30
|
+
const config = {
|
|
56
31
|
environment: 'homologacion',
|
|
57
32
|
cuit: '20123456789',
|
|
58
33
|
cert: '...certificado PEM...',
|
|
59
34
|
key: '...clave privada PEM...',
|
|
60
|
-
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const ticket = await wsaa.login();
|
|
64
|
-
// Ticket válido por ~12 horas
|
|
65
|
-
// Se renueva automáticamente
|
|
66
|
-
```
|
|
35
|
+
};
|
|
67
36
|
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
37
|
+
// 2. Emitir un Ticket C en dos líneas
|
|
70
38
|
const wsfe = new WsfeService(config);
|
|
71
|
-
const
|
|
72
|
-
console.log('CAE:', cae.cae);
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
---
|
|
39
|
+
const result = await wsfe.emitirTicketCSimple({ total: 1500 });
|
|
76
40
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Necesitás certificados de ARCA en formato PEM:
|
|
80
|
-
- `cert.pem`: Certificado X.509
|
|
81
|
-
- `key.pem`: Clave privada
|
|
82
|
-
|
|
83
|
-
**Homologación (testing):**
|
|
84
|
-
1. Ir a [ARCA Homologación](https://www.afip.gob.ar/ws/documentacion/certificados.asp)
|
|
85
|
-
2. Generar certificado de prueba
|
|
86
|
-
3. Descargar cert + key
|
|
87
|
-
|
|
88
|
-
**Producción:**
|
|
89
|
-
1. Generar CSR con tu CUIT
|
|
90
|
-
2. Subir a ARCA
|
|
91
|
-
3. Descargar certificado firmado
|
|
92
|
-
|
|
93
|
-
---
|
|
94
|
-
|
|
95
|
-
## 🛠️ Ejemplos
|
|
96
|
-
|
|
97
|
-
Ver carpeta [`/examples`](./examples):
|
|
98
|
-
- [`autenticacion.ts`](./examples/autenticacion.ts) - Obtener ticket WSAA
|
|
99
|
-
- [`quick-start.ts`](./examples/quick-start.ts) - Inicio rápido
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## 🧪 Testing
|
|
104
|
-
```bash
|
|
105
|
-
# Tests unitarios
|
|
106
|
-
bun test
|
|
107
|
-
|
|
108
|
-
# Build
|
|
109
|
-
bun run build
|
|
41
|
+
console.log('CAE:', result.cae);
|
|
42
|
+
console.log('QR URL:', result.urlQr); // ← Ya viene integrado!
|
|
110
43
|
```
|
|
111
44
|
|
|
112
45
|
---
|
|
113
46
|
|
|
114
|
-
##
|
|
115
|
-
|
|
116
|
-
La SDK exporta todos los tipos:
|
|
117
|
-
```typescript
|
|
118
|
-
import type {
|
|
119
|
-
LoginTicket,
|
|
120
|
-
WsaaConfig,
|
|
121
|
-
Environment
|
|
122
|
-
} from 'arca-sdk';
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Autocomplete completo en tu IDE. ✨
|
|
126
|
-
|
|
127
|
-
---
|
|
47
|
+
## 👑 God Mode: Persistencia Automática
|
|
48
|
+
No manejes tickets manualmente. Pasale un `storage` al SDK y se encargará de guardar, recuperar y renovar el token solo cuando expire.
|
|
128
49
|
|
|
129
|
-
## ⚠️ Manejo de Errores
|
|
130
50
|
```typescript
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
const ticket = await wsaa.login();
|
|
135
|
-
} catch (error) {
|
|
136
|
-
if (error instanceof ArcaAuthError) {
|
|
137
|
-
console.error('Error de autenticación:', error.message);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (error instanceof ArcaValidationError) {
|
|
141
|
-
console.error('Configuración inválida:', error.message);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
Los errores incluyen contexto útil en `error.details`.
|
|
147
|
-
|
|
148
|
-
#### Timeouts
|
|
149
|
-
Por defecto, las peticiones tienen un timeout de **15 segundos**. Podés ajustarlo en la configuración:
|
|
150
|
-
```typescript
|
|
151
|
-
const wsfe = new WsfeService({
|
|
51
|
+
const wsaa = new WsaaService({
|
|
152
52
|
...config,
|
|
153
|
-
|
|
53
|
+
service: 'wsfe',
|
|
54
|
+
storage: {
|
|
55
|
+
get: async (key) => await db.token.findUnique({ where: { key } }),
|
|
56
|
+
save: async (key, data) => await db.token.upsert({ ... }),
|
|
57
|
+
}
|
|
154
58
|
});
|
|
59
|
+
|
|
60
|
+
// El SDK chequea el storage antes de pedir un nuevo ticket a ARCA
|
|
61
|
+
const ticket = await wsaa.login();
|
|
155
62
|
```
|
|
156
63
|
|
|
157
64
|
---
|
|
158
65
|
|
|
159
|
-
|
|
66
|
+
## 🔍 Consulta de Padrón (A13)
|
|
67
|
+
Obtené los datos de un cliente (Nombre, Domicilio, IVA) solo con su CUIT. Ideal para POS.
|
|
160
68
|
|
|
161
|
-
#### Ticket C Simple (solo total)
|
|
162
69
|
```typescript
|
|
163
|
-
import {
|
|
70
|
+
import { PadronService } from 'arca-sdk';
|
|
164
71
|
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
const ticket = await wsaa.login();
|
|
72
|
+
const padron = new PadronService(config);
|
|
73
|
+
const { persona, error } = await padron.getPersona('30111111118');
|
|
168
74
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
puntoVenta: 4,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// 3. Emitir ticket (modo simple)
|
|
178
|
-
const cae = await wsfe.emitirTicketCSimple({
|
|
179
|
-
total: 3500
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
console.log('CAE:', cae.cae);
|
|
75
|
+
if (persona) {
|
|
76
|
+
console.log('Razón Social:', persona.razonSocial || `${persona.nombre} ${persona.apellido}`);
|
|
77
|
+
console.log('Provincia:', persona.domicilio[0].descripcionProvincia);
|
|
78
|
+
console.log('¿Es Inscripto?:', persona.esInscriptoIVA);
|
|
79
|
+
}
|
|
183
80
|
```
|
|
184
81
|
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
// Modo completo: con detalle de items
|
|
188
|
-
const cae = await wsfe.emitirTicketC({
|
|
189
|
-
items: [
|
|
190
|
-
{ descripcion: 'Producto 1', cantidad: 2, precioUnitario: 500 },
|
|
191
|
-
{ descripcion: 'Producto 2', cantidad: 1, precioUnitario: 1000 },
|
|
192
|
-
],
|
|
193
|
-
});
|
|
82
|
+
---
|
|
194
83
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
console.log('Items:', cae.items);
|
|
198
|
-
```
|
|
84
|
+
## 📱 Generador de QR Oficial
|
|
85
|
+
AFIP exige que los comprobantes impresos tengan un código QR. El SDK lo genera cumpliendo estrictamente con el formato oficial (JSON ordenado, Base64 URL-safe, etc).
|
|
199
86
|
|
|
200
|
-
#### Factura B (IVA discriminado)
|
|
201
87
|
```typescript
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
items: [
|
|
206
|
-
{
|
|
207
|
-
descripcion: 'Servicio',
|
|
208
|
-
cantidad: 10,
|
|
209
|
-
precioUnitario: 1000,
|
|
210
|
-
alicuotaIva: 21, // ← OBLIGATORIO
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
comprador: {
|
|
214
|
-
tipoDocumento: TipoDocumento.CUIT,
|
|
215
|
-
nroDocumento: '20987654321',
|
|
216
|
-
},
|
|
217
|
-
});
|
|
88
|
+
// 1. Integrado en WsfeService (Recomendado)
|
|
89
|
+
const result = await wsfe.emitirTicketCSimple({ total: 1500 });
|
|
90
|
+
console.log(result.urlQr);
|
|
218
91
|
|
|
219
|
-
|
|
220
|
-
|
|
92
|
+
// 2. O manual si lo necesitás por separado
|
|
93
|
+
import { generarUrlQR } from 'arca-sdk';
|
|
94
|
+
const urlQr = generarUrlQR(caeResponse, '20123456789', 1500);
|
|
221
95
|
```
|
|
222
96
|
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
const cae = await wsfe.emitirFacturaA({
|
|
226
|
-
items: [
|
|
227
|
-
{ descripcion: 'Producto', cantidad: 5, precioUnitario: 2000, alicuotaIva: 21 },
|
|
228
|
-
],
|
|
229
|
-
comprador: {
|
|
230
|
-
tipoDocumento: TipoDocumento.CUIT,
|
|
231
|
-
nroDocumento: '20111111119',
|
|
232
|
-
},
|
|
233
|
-
});
|
|
234
|
-
```
|
|
97
|
+
---
|
|
235
98
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const cae = await wsfe.emitirFacturaB({
|
|
240
|
-
incluyeIva: true, // ← El SDK calculará el neto y el IVA automáticamente
|
|
241
|
-
items: [
|
|
242
|
-
{ descripcion: 'Producto', cantidad: 1, precioUnitario: 1210, alicuotaIva: 21 },
|
|
243
|
-
],
|
|
244
|
-
// ... comprador
|
|
245
|
-
});
|
|
246
|
-
// Internamente enviará: Subtotal: 1000, IVA: 210, Total: 1210
|
|
247
|
-
```
|
|
99
|
+
## 🖨️ Generación de PDF
|
|
100
|
+
Para mantener la SDK ligera, no incluimos generadores de PDF (como `jspdf`) en el core.
|
|
101
|
+
**Tip:** La URL del QR (`urlQr`) apunta a la vista oficial de ARCA que ya es 100% imprimible y legal. Si necesitás PDF local, podés usar los datos de `CAEResponse` con tu librería favorita.
|
|
248
102
|
|
|
249
103
|
---
|
|
250
104
|
|
|
251
|
-
##
|
|
252
|
-
|
|
105
|
+
## 🩺 Chequeo de Salud
|
|
106
|
+
Verificá si los servidores de ARCA están online antes de intentar facturar.
|
|
253
107
|
|
|
254
108
|
```typescript
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
// Usá la respuesta del CAE para generar la URL del QR
|
|
258
|
-
const urlQr = generarUrlQR(cae);
|
|
259
|
-
|
|
260
|
-
console.log('URL para QR:', urlQr);
|
|
261
|
-
// Output: https://www.afip.gob.ar/fe/qr/?p=eyJ2ZXIiOjEsImZlY2hh...
|
|
109
|
+
const status = await wsfe.checkStatus();
|
|
110
|
+
console.log('AppServer:', status.appServer); // 'OK'
|
|
262
111
|
```
|
|
263
112
|
|
|
264
|
-
Esta URL la podés pasar a cualquier librería de generación de imágenes QR.
|
|
265
|
-
|
|
266
|
-
---
|
|
267
|
-
|
|
268
113
|
---
|
|
269
114
|
|
|
270
|
-
##
|
|
115
|
+
## 📝 Servicios y Comprobantes
|
|
271
116
|
|
|
272
|
-
|
|
|
273
|
-
|
|
274
|
-
|
|
|
275
|
-
|
|
|
276
|
-
|
|
|
277
|
-
| **Factura A** | RI → RI | Sí | **Obligatorio** |
|
|
117
|
+
| Clase | Servicio ARCA | Descripción |
|
|
118
|
+
|-------|---------------|-------------|
|
|
119
|
+
| `WsaaService` | `wsaa` | Autenticación y Autorización |
|
|
120
|
+
| `WsfeService` | `wsfev1` | Facturación Electrónica (A, B, C) |
|
|
121
|
+
| `PadronService` | `ws_sr_padron_a13` | Consulta de datos de contribuyentes |
|
|
278
122
|
|
|
279
|
-
|
|
123
|
+
### Comprobantes soportados en `WsfeService`:
|
|
124
|
+
- `emitirTicketCSimple()`: Rápido para Consumidor Final.
|
|
125
|
+
- `emitirTicketC()`: Con detalle de items.
|
|
126
|
+
- `emitirFacturaB()`: Para Responsables Inscriptos o Facturas > $ limite.
|
|
127
|
+
- `emitirFacturaA()`: Con discriminación de IVA.
|
|
280
128
|
|
|
281
129
|
---
|
|
282
130
|
|
|
283
|
-
##
|
|
131
|
+
## 🛠️ Desarrollo y Tests
|
|
132
|
+
```bash
|
|
133
|
+
# Correr tests con mocks de ARCA
|
|
134
|
+
bun test
|
|
135
|
+
|
|
136
|
+
# Verificar tipos
|
|
137
|
+
bun run lint
|
|
284
138
|
|
|
285
|
-
|
|
139
|
+
# Build para producción (CJS + ESM)
|
|
140
|
+
bun run build
|
|
141
|
+
```
|
|
286
142
|
|
|
287
143
|
---
|
|
288
144
|
|
|
289
145
|
## 📄 Licencia
|
|
290
|
-
|
|
291
146
|
MIT © [Marcela Borgarello](https://github.com/marcelaborgarello)
|
|
292
147
|
|
|
293
148
|
---
|
|
294
149
|
|
|
295
|
-
## 🔗 Links
|
|
296
|
-
|
|
297
|
-
- [Documentación ARCA](https://www.afip.gob.ar/ws/)
|
|
298
|
-
- [Issues](https://github.com/marcelaborgarello/arca-sdk/issues)
|
|
299
|
-
- [NPM](https://www.npmjs.com/package/arca-sdk)
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
150
|
**Hecho con ❤️ en Argentina 🇦🇷**
|
|
304
|
-
|
|
305
151
|
*Porque integrar con ARCA no tiene por qué ser un infierno.*
|
package/dist/index.cjs
CHANGED
|
@@ -68,10 +68,11 @@ function getPadronEndpoint(environment) {
|
|
|
68
68
|
|
|
69
69
|
// src/types/common.ts
|
|
70
70
|
var ArcaError = class extends Error {
|
|
71
|
-
constructor(message, code, details) {
|
|
71
|
+
constructor(message, code, details, hint) {
|
|
72
72
|
super(message);
|
|
73
73
|
this.code = code;
|
|
74
74
|
this.details = details;
|
|
75
|
+
this.hint = hint;
|
|
75
76
|
this.name = "ArcaError";
|
|
76
77
|
}
|
|
77
78
|
};
|
|
@@ -549,6 +550,54 @@ function redondear(valor) {
|
|
|
549
550
|
return Math.round(valor * 100) / 100;
|
|
550
551
|
}
|
|
551
552
|
|
|
553
|
+
// src/utils/qr.ts
|
|
554
|
+
function generarUrlQR(caeResponse, cuitEmisor, total, comprador) {
|
|
555
|
+
const cleanCuit = cuitEmisor.replace(/\D/g, "");
|
|
556
|
+
const cleanCae = caeResponse.cae.replace(/\D/g, "");
|
|
557
|
+
const fDate = caeResponse.fecha;
|
|
558
|
+
const fechaFormat = fDate.length === 8 ? `${fDate.substring(0, 4)}-${fDate.substring(4, 6)}-${fDate.substring(6, 8)}` : fDate;
|
|
559
|
+
const docTipo = comprador?.tipoDocumento || 99 /* CONSUMIDOR_FINAL */;
|
|
560
|
+
const docNro = comprador?.nroDocumento ? comprador.nroDocumento.replace(/\D/g, "") : "0";
|
|
561
|
+
const qrObj = {
|
|
562
|
+
ver: 1,
|
|
563
|
+
fecha: fechaFormat,
|
|
564
|
+
cuit: Number(cleanCuit),
|
|
565
|
+
ptoVta: Number(caeResponse.puntoVenta),
|
|
566
|
+
tipoCmp: Number(caeResponse.tipoComprobante),
|
|
567
|
+
nroCmp: Number(caeResponse.nroComprobante),
|
|
568
|
+
importe: Number(parseFloat(total.toFixed(2))),
|
|
569
|
+
moneda: "PES",
|
|
570
|
+
ctz: 1
|
|
571
|
+
};
|
|
572
|
+
if (docTipo !== 99 /* CONSUMIDOR_FINAL */ || Number(docNro) > 0) {
|
|
573
|
+
qrObj.tipoDocRec = Number(docTipo);
|
|
574
|
+
qrObj.nroDocRec = Number(docNro);
|
|
575
|
+
}
|
|
576
|
+
qrObj.tipoCodAut = "E";
|
|
577
|
+
qrObj.codAut = Number(cleanCae);
|
|
578
|
+
const jsonString = JSON.stringify(qrObj);
|
|
579
|
+
let base64 = typeof Buffer !== "undefined" ? Buffer.from(jsonString).toString("base64") : btoa(jsonString);
|
|
580
|
+
return `https://www.afip.gob.ar/fe/qr/?p=${encodeURIComponent(base64)}`;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/constants/errors.ts
|
|
584
|
+
var ARCA_ERROR_HINTS = {
|
|
585
|
+
// Generales / Auth
|
|
586
|
+
501: "Error de autenticaci\xF3n: El certificado puede haber expirado o la relaci\xF3n CUIT/Servicio no est\xE1 dada de alta en la web de AFIP.",
|
|
587
|
+
502: "Error de autenticaci\xF3n: El ticket de acceso (TA) ya no es v\xE1lido o est\xE1 mal formado.",
|
|
588
|
+
1e3: "El CUIT informado no es v\xE1lido o no corresponde al certificado usado.",
|
|
589
|
+
// WSFE (Facturación)
|
|
590
|
+
10015: "Factura B: El importe total es superior al l\xEDmite para consumidores finales an\xF3nimos. Identific\xE1 al comprador.",
|
|
591
|
+
10016: "Factura C: El CUIT informado como receptor no es v\xE1lido.",
|
|
592
|
+
10048: 'Punto de Venta inv\xE1lido: Asegurate de que el punto de venta est\xE9 dado de alta como "Factuweb" o "Webservice" en AFIP.',
|
|
593
|
+
600: "No se pudo autorizar el comprobante. Revis\xE1 las observaciones para m\xE1s detalle.",
|
|
594
|
+
// Padrón
|
|
595
|
+
"PADRON_ERROR": "El servicio de Padr\xF3n suele ser inestable en homologaci\xF3n. Reintent\xE1 en unos minutos."
|
|
596
|
+
};
|
|
597
|
+
function getArcaHint(code) {
|
|
598
|
+
return ARCA_ERROR_HINTS[code];
|
|
599
|
+
}
|
|
600
|
+
|
|
552
601
|
// src/services/wsfe.ts
|
|
553
602
|
var WsfeService = class _WsfeService {
|
|
554
603
|
config;
|
|
@@ -797,10 +846,17 @@ var WsfeService = class _WsfeService {
|
|
|
797
846
|
}
|
|
798
847
|
const responseXml = await response.text();
|
|
799
848
|
const result = await this.parseCAEResponse(responseXml);
|
|
849
|
+
const urlQr = generarUrlQR(
|
|
850
|
+
result,
|
|
851
|
+
this.config.cuit,
|
|
852
|
+
total,
|
|
853
|
+
request.comprador
|
|
854
|
+
);
|
|
800
855
|
return {
|
|
801
856
|
...result,
|
|
802
857
|
items: request.items,
|
|
803
|
-
iva: request.ivaData
|
|
858
|
+
iva: request.ivaData,
|
|
859
|
+
urlQr
|
|
804
860
|
};
|
|
805
861
|
}
|
|
806
862
|
/**
|
|
@@ -826,7 +882,13 @@ var WsfeService = class _WsfeService {
|
|
|
826
882
|
const data = result?.Envelope?.Body?.FECompUltimoAutorizadoResponse?.FECompUltimoAutorizadoResult;
|
|
827
883
|
if (data?.Errors) {
|
|
828
884
|
const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;
|
|
829
|
-
|
|
885
|
+
const code = error?.Code || "UNKNOWN";
|
|
886
|
+
throw new ArcaError(
|
|
887
|
+
`Error ARCA: ${error?.Msg || "Error desconocido"}`,
|
|
888
|
+
"ARCA_ERROR",
|
|
889
|
+
data.Errors,
|
|
890
|
+
getArcaHint(code)
|
|
891
|
+
);
|
|
830
892
|
}
|
|
831
893
|
const nro = data?.CbteNro;
|
|
832
894
|
return typeof nro === "number" ? nro + 1 : 1;
|
|
@@ -935,7 +997,13 @@ var WsfeService = class _WsfeService {
|
|
|
935
997
|
}
|
|
936
998
|
if (data.Errors) {
|
|
937
999
|
const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;
|
|
938
|
-
|
|
1000
|
+
const code = error?.Code || "UNKNOWN";
|
|
1001
|
+
throw new ArcaError(
|
|
1002
|
+
`Error ARCA: ${error?.Msg || "Error desconocido"}`,
|
|
1003
|
+
"ARCA_ERROR",
|
|
1004
|
+
data.Errors,
|
|
1005
|
+
getArcaHint(code)
|
|
1006
|
+
);
|
|
939
1007
|
}
|
|
940
1008
|
const cab = data.FeCabResp;
|
|
941
1009
|
const det = Array.isArray(data.FeDetResp.FECAEDetResponse) ? data.FeDetResp.FECAEDetResponse[0] : data.FeDetResp.FECAEDetResponse;
|
|
@@ -1034,7 +1102,7 @@ var PadronService = class {
|
|
|
1034
1102
|
if (!response) {
|
|
1035
1103
|
const fault = body.Fault;
|
|
1036
1104
|
if (fault) {
|
|
1037
|
-
return { error: fault.faultstring || "Error desconocido en
|
|
1105
|
+
return { error: fault.faultstring || "Error desconocido en ARCA" };
|
|
1038
1106
|
}
|
|
1039
1107
|
return { error: "No se encontraron datos para el CUIT informado" };
|
|
1040
1108
|
}
|
|
@@ -1053,6 +1121,8 @@ var PadronService = class {
|
|
|
1053
1121
|
razonSocial: p.razonSocial,
|
|
1054
1122
|
estadoClave: p.estadoClave,
|
|
1055
1123
|
domicilio: this.mapDomicilios(p.domicilio),
|
|
1124
|
+
actividad: this.mapActividades(p.actividad),
|
|
1125
|
+
impuesto: this.mapImpuestos(p.impuesto),
|
|
1056
1126
|
descripcionActividadPrincipal: p.descripcionActividadPrincipal,
|
|
1057
1127
|
esInscriptoIVA: this.checkImpuesto(p, 30),
|
|
1058
1128
|
// 30 = IVA
|
|
@@ -1065,7 +1135,7 @@ var PadronService = class {
|
|
|
1065
1135
|
}
|
|
1066
1136
|
mapDomicilios(d) {
|
|
1067
1137
|
if (!d) return [];
|
|
1068
|
-
const list =
|
|
1138
|
+
const list = this.ensureArray(d);
|
|
1069
1139
|
return list.map((item) => ({
|
|
1070
1140
|
direccion: item.direccion,
|
|
1071
1141
|
localidad: item.localidad,
|
|
@@ -1075,43 +1145,39 @@ var PadronService = class {
|
|
|
1075
1145
|
tipoDomicilio: item.tipoDomicilio
|
|
1076
1146
|
}));
|
|
1077
1147
|
}
|
|
1148
|
+
mapActividades(a) {
|
|
1149
|
+
if (!a) return [];
|
|
1150
|
+
const list = this.ensureArray(a);
|
|
1151
|
+
return list.map((item) => ({
|
|
1152
|
+
idActividad: Number(item.idActividad),
|
|
1153
|
+
descripcion: item.descripcion,
|
|
1154
|
+
orden: Number(item.orden),
|
|
1155
|
+
periodo: Number(item.periodo)
|
|
1156
|
+
}));
|
|
1157
|
+
}
|
|
1158
|
+
mapImpuestos(i) {
|
|
1159
|
+
if (!i) return [];
|
|
1160
|
+
const list = this.ensureArray(i);
|
|
1161
|
+
return list.map((item) => ({
|
|
1162
|
+
idImpuesto: Number(item.idImpuesto),
|
|
1163
|
+
descripcion: item.descripcion,
|
|
1164
|
+
periodo: Number(item.periodo)
|
|
1165
|
+
}));
|
|
1166
|
+
}
|
|
1078
1167
|
checkImpuesto(p, id) {
|
|
1079
1168
|
const impuestos = p.impuesto;
|
|
1080
1169
|
if (!impuestos) return false;
|
|
1081
|
-
const list =
|
|
1170
|
+
const list = this.ensureArray(impuestos);
|
|
1082
1171
|
return list.some((i) => Number(i.idImpuesto) === id);
|
|
1083
1172
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
const fDate = caeResponse.fecha;
|
|
1091
|
-
const fechaFormat = fDate.length === 8 ? `${fDate.substring(0, 4)}-${fDate.substring(4, 6)}-${fDate.substring(6, 8)}` : fDate;
|
|
1092
|
-
const docTipo = comprador?.tipoDocumento || 99 /* CONSUMIDOR_FINAL */;
|
|
1093
|
-
const docNro = comprador?.nroDocumento ? comprador.nroDocumento.replace(/\D/g, "") : "0";
|
|
1094
|
-
const qrObj = {
|
|
1095
|
-
ver: 1,
|
|
1096
|
-
fecha: fechaFormat,
|
|
1097
|
-
cuit: Number(cleanCuit),
|
|
1098
|
-
ptoVta: Number(caeResponse.puntoVenta),
|
|
1099
|
-
tipoCmp: Number(caeResponse.tipoComprobante),
|
|
1100
|
-
nroCmp: Number(caeResponse.nroComprobante),
|
|
1101
|
-
importe: Number(parseFloat(total.toFixed(2))),
|
|
1102
|
-
moneda: "PES",
|
|
1103
|
-
ctz: 1
|
|
1104
|
-
};
|
|
1105
|
-
if (docTipo !== 99 /* CONSUMIDOR_FINAL */ || Number(docNro) > 0) {
|
|
1106
|
-
qrObj.tipoDocRec = Number(docTipo);
|
|
1107
|
-
qrObj.nroDocRec = Number(docNro);
|
|
1173
|
+
/**
|
|
1174
|
+
* Helper para normalizar la respuesta de XML que puede ser objeto único o array
|
|
1175
|
+
*/
|
|
1176
|
+
ensureArray(data) {
|
|
1177
|
+
if (data === void 0 || data === null) return [];
|
|
1178
|
+
return Array.isArray(data) ? data : [data];
|
|
1108
1179
|
}
|
|
1109
|
-
|
|
1110
|
-
qrObj.codAut = Number(cleanCae);
|
|
1111
|
-
const jsonString = JSON.stringify(qrObj);
|
|
1112
|
-
let base64 = typeof Buffer !== "undefined" ? Buffer.from(jsonString).toString("base64") : btoa(jsonString);
|
|
1113
|
-
return `https://www.afip.gob.ar/fe/qr/?p=${encodeURIComponent(base64)}`;
|
|
1114
|
-
}
|
|
1180
|
+
};
|
|
1115
1181
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1116
1182
|
0 && (module.exports = {
|
|
1117
1183
|
ArcaAuthError,
|