arca-sdk 1.0.2 → 1.0.4
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/CHANGELOG.md +9 -0
- package/README.md +261 -115
- package/dist/index.cjs +20 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ Todos los cambios notables de este proyecto se documentan en este archivo.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.0.4] — 2026-02-27
|
|
8
|
+
|
|
9
|
+
### 🐛 Bugfix — Timezone Handling
|
|
10
|
+
|
|
11
|
+
- Se ajustó la generación de fechas para forzar la zona horaria UTC-3 (Argentina) independientemente de la zona horaria del servidor (ej: AWS, Vercel).
|
|
12
|
+
- Se restan 10 minutos al tiempo de generación en los TRA para evitar errores de desincronización con los servidores de ARCA.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
7
16
|
## [1.0.1] — 2026-02-23
|
|
8
17
|
|
|
9
18
|
### 🐛 Bugfix crítico — QR URL
|
package/README.md
CHANGED
|
@@ -1,44 +1,97 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# 🇦🇷 arca-sdk
|
|
2
4
|
|
|
3
|
-
**La SDK
|
|
5
|
+
**La SDK de ARCA (ex-AFIP) que querías que alguien hiciera.**
|
|
6
|
+
|
|
7
|
+
TypeScript nativo · API limpia en inglés · Tokens automáticos · QR oficial · Padrón A13
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- ✅ **Moderno**: ESM + CJS nativo, Node.js 18+, Bun compatible
|
|
9
|
+
[](https://www.npmjs.com/package/arca-sdk)
|
|
10
|
+
[](https://www.npmjs.com/package/arca-sdk)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
[](https://nodejs.org)
|
|
13
|
+
[](https://www.typescriptlang.org/)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
13
16
|
|
|
14
17
|
---
|
|
15
18
|
|
|
16
|
-
##
|
|
19
|
+
## ¿Por qué arca-sdk?
|
|
20
|
+
|
|
21
|
+
La mayoría de las librerías de AFIP/ARCA para Node.js son:
|
|
22
|
+
- Ports de código PHP/Java sin tipos
|
|
23
|
+
- Sin soporte para el Padrón A13
|
|
24
|
+
- Sin manejo de tokens (te obligan a gestionarlos a mano)
|
|
25
|
+
- Sin QR oficial
|
|
26
|
+
- Sin mantenimiento activo
|
|
27
|
+
|
|
28
|
+
`arca-sdk` fue construida desde cero en TypeScript moderno, probada contra producción real, y documenta quirks del spec oficial que ninguna otra librería menciona (como el `encodeURIComponent` que rompe el scanner de ARCA).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Instalación
|
|
33
|
+
|
|
17
34
|
```bash
|
|
35
|
+
# npm
|
|
18
36
|
npm install arca-sdk
|
|
19
|
-
|
|
37
|
+
|
|
38
|
+
# bun
|
|
20
39
|
bun add arca-sdk
|
|
40
|
+
|
|
41
|
+
# pnpm
|
|
42
|
+
pnpm add arca-sdk
|
|
21
43
|
```
|
|
22
44
|
|
|
45
|
+
**Requisitos:** Node.js 18+ · TypeScript 5+ (optional but recommended) · Bun compatible
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 🔐 Security & Responsibility / Seguridad y Responsabilidad
|
|
50
|
+
|
|
51
|
+
### 🇺🇸 English
|
|
52
|
+
|
|
53
|
+
**arca-sdk** is designed to be **stateless and cloud-native**. It does **NOT** persist certificates or private keys to the filesystem.
|
|
54
|
+
|
|
55
|
+
It is the responsibility of the implementing application to:
|
|
56
|
+
1. **Securely store** the Private Key (`.key`) and Certificate (`.crt`). (Recommended: Encrypted Database, AWS KMS, HashiCorp Vault).
|
|
57
|
+
2. **Decrypt** credentials only at runtime.
|
|
58
|
+
3. Pass the raw strings/buffers to the SDK constructors.
|
|
59
|
+
|
|
60
|
+
> [!WARNING]
|
|
61
|
+
> Never commit your `.key` files to Git or expose them in public folders. The SDK operates in-memory to ensure maximum security in Serverless environments (Vercel, AWS Lambda).
|
|
62
|
+
|
|
63
|
+
### 🇦🇷 Español
|
|
64
|
+
|
|
65
|
+
**arca-sdk** está diseñado para ser **stateless** (sin estado) y **cloud-native**. **NO** guarda certificados ni claves privadas en el sistema de archivos.
|
|
66
|
+
|
|
67
|
+
Es responsabilidad de la aplicación que implementa el SDK:
|
|
68
|
+
1. **Almacenar de forma segura** la Clave Privada (`.key`) y el Certificado (`.crt`). (Recomendado: Base de Datos encriptada, AWS KMS, HashiCorp Vault).
|
|
69
|
+
2. **Desencriptar** las credenciales solo en tiempo de ejecución.
|
|
70
|
+
3. Pasar los strings o buffers crudos a los constructores del SDK.
|
|
71
|
+
|
|
72
|
+
> [!CAUTION]
|
|
73
|
+
> Nunca subas tus archivos `.key` a Git ni los expongas en carpetas públicas. El SDK opera en memoria para garantizar la máxima seguridad en entornos Serverless (Vercel, AWS Lambda).
|
|
74
|
+
|
|
23
75
|
---
|
|
24
76
|
|
|
25
|
-
##
|
|
77
|
+
## Quick Start — 5 minutos y estás facturando
|
|
78
|
+
|
|
26
79
|
```typescript
|
|
27
|
-
import { WsaaService, WsfeService } from 'arca-sdk';
|
|
28
80
|
import * as fs from 'fs';
|
|
81
|
+
import { WsaaService, WsfeService } from 'arca-sdk';
|
|
29
82
|
|
|
30
|
-
// 1.
|
|
83
|
+
// 1. Autenticación con WSAA (se renueva automáticamente)
|
|
31
84
|
const wsaa = new WsaaService({
|
|
32
|
-
environment: 'homologacion',
|
|
85
|
+
environment: 'homologacion', // 'produccion' cuando estés listo
|
|
33
86
|
cuit: '20123456789',
|
|
34
87
|
cert: fs.readFileSync('cert.pem', 'utf-8'),
|
|
35
|
-
key:
|
|
88
|
+
key: fs.readFileSync('key.pem', 'utf-8'),
|
|
36
89
|
service: 'wsfe',
|
|
37
90
|
});
|
|
38
91
|
|
|
39
92
|
const ticket = await wsaa.login();
|
|
40
93
|
|
|
41
|
-
// 2.
|
|
94
|
+
// 2. Servicio de facturación
|
|
42
95
|
const wsfe = new WsfeService({
|
|
43
96
|
environment: 'homologacion',
|
|
44
97
|
cuit: '20123456789',
|
|
@@ -46,183 +99,276 @@ const wsfe = new WsfeService({
|
|
|
46
99
|
pointOfSale: 4,
|
|
47
100
|
});
|
|
48
101
|
|
|
49
|
-
// 3. Emitir
|
|
102
|
+
// 3. Emitir Ticket C — una línea
|
|
50
103
|
const result = await wsfe.issueSimpleReceipt({ total: 1500 });
|
|
51
104
|
|
|
52
|
-
console.log('CAE:', result.cae);
|
|
53
|
-
console.log('
|
|
105
|
+
console.log('CAE:', result.cae); // '75157992335329'
|
|
106
|
+
console.log('Vto:', result.caeExpiry); // '20260302'
|
|
107
|
+
console.log('QR:', result.qrUrl); // 'https://www.afip.gob.ar/fe/qr/?p=...'
|
|
54
108
|
```
|
|
55
109
|
|
|
110
|
+
> Los certificados se obtienen en el [portal de ARCA](https://auth.afip.gob.ar/contribuyente_/login.xhtml) (CLAVE FISCAL nivel 3+).
|
|
111
|
+
|
|
56
112
|
---
|
|
57
113
|
|
|
58
|
-
##
|
|
59
|
-
No manejes tokens manualmente. Pasale un `storage` al SDK y se encargará de guardar, recuperar y renovar el TA solo cuando expire.
|
|
114
|
+
## Funcionalidades
|
|
60
115
|
|
|
61
|
-
|
|
62
|
-
const wsaa = new WsaaService({
|
|
63
|
-
...config,
|
|
64
|
-
service: 'wsfe',
|
|
65
|
-
storage: {
|
|
66
|
-
get: async (cuit, env) => await db.token.findUnique({ where: { cuit, env } }),
|
|
67
|
-
save: async (cuit, env, ticket) => await db.token.upsert({ ... }),
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// El SDK chequea el storage antes de pedir un nuevo ticket a ARCA
|
|
72
|
-
const ticket = await wsaa.login();
|
|
73
|
-
```
|
|
116
|
+
### ✅ Servicios soportados
|
|
74
117
|
|
|
75
|
-
|
|
118
|
+
| Servicio | Descripción | Estado |
|
|
119
|
+
|----------|-------------|--------|
|
|
120
|
+
| **WSAA** | Autenticación y Autorización | ✅ Completo |
|
|
121
|
+
| **WSFE v1** | Facturación Electrónica (A, B, C) | ✅ Completo |
|
|
122
|
+
| **Padrón A13** | Consulta de datos de contribuyentes | ✅ Completo |
|
|
76
123
|
|
|
77
|
-
|
|
78
|
-
Obtené los datos de un contribuyente (nombre, domicilio, condición IVA) solo con su CUIT.
|
|
124
|
+
### ✅ Tipos de comprobantes
|
|
79
125
|
|
|
80
|
-
|
|
81
|
-
|
|
126
|
+
| Método | Comprobante | Cuándo usarlo |
|
|
127
|
+
|--------|-------------|---------------|
|
|
128
|
+
| `issueSimpleReceipt()` | Ticket C | Monto total, sin detalle. Ideal para POS simple |
|
|
129
|
+
| `issueReceipt()` | Ticket C + items | Con detalle de productos guardado localmente |
|
|
130
|
+
| `issueInvoiceC()` | Factura C | Monotributistas a consumidor final |
|
|
131
|
+
| `issueInvoiceB()` | Factura B | Responsable Inscripto a consumidor final / Monotributo |
|
|
132
|
+
| `issueInvoiceA()` | Factura A | Responsable Inscripto a Responsable Inscripto |
|
|
82
133
|
|
|
83
|
-
|
|
84
|
-
const { taxpayer, error } = await padron.getTaxpayer('30111111118');
|
|
134
|
+
### ✅ Consultas disponibles
|
|
85
135
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
```
|
|
136
|
+
| Método | Descripción |
|
|
137
|
+
|--------|-------------|
|
|
138
|
+
| `wsfe.getInvoice(type, n)` | Consulta un comprobante ya emitido (FECompConsultar) |
|
|
139
|
+
| `wsfe.getPointsOfSale()` | Lista puntos de venta habilitados (FEParamGetPtosVenta) |
|
|
140
|
+
| `WsfeService.checkStatus()` | Estado de los servidores de ARCA (FEDummy) |
|
|
141
|
+
| `padron.getTaxpayer(cuit)` | Datos del contribuyente — nombre, domicilio, condición IVA |
|
|
94
142
|
|
|
95
143
|
---
|
|
96
144
|
|
|
97
|
-
##
|
|
145
|
+
## Ejemplos
|
|
98
146
|
|
|
99
|
-
|
|
100
|
-
// Ticket C — Consumidor Final (solo total)
|
|
101
|
-
const cae = await wsfe.issueSimpleReceipt({ total: 1500 });
|
|
147
|
+
### Ticket C con detalle de items
|
|
102
148
|
|
|
103
|
-
|
|
104
|
-
const
|
|
149
|
+
```typescript
|
|
150
|
+
const result = await wsfe.issueReceipt({
|
|
105
151
|
items: [
|
|
106
|
-
{ description: 'Café con leche',
|
|
107
|
-
{ description: 'Medialunas
|
|
152
|
+
{ description: 'Café con leche', quantity: 2, unitPrice: 750 },
|
|
153
|
+
{ description: 'Medialunas x4', quantity: 1, unitPrice: 600 },
|
|
108
154
|
],
|
|
109
155
|
});
|
|
110
156
|
|
|
111
|
-
|
|
112
|
-
|
|
157
|
+
console.log('Items en respuesta:', result.items?.length); // 2
|
|
158
|
+
console.log('QR URL:', result.qrUrl);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Factura B con IVA discriminado
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { TaxIdType } from 'arca-sdk';
|
|
113
165
|
|
|
114
|
-
|
|
115
|
-
const cae = await wsfe.issueInvoiceB({
|
|
166
|
+
const result = await wsfe.issueInvoiceB({
|
|
116
167
|
items: [
|
|
117
168
|
{ description: 'Servicio de diseño', quantity: 10, unitPrice: 1000, vatRate: 21 },
|
|
169
|
+
{ description: 'Hosting mensual', quantity: 1, unitPrice: 5000, vatRate: 21 },
|
|
118
170
|
],
|
|
119
|
-
buyer: {
|
|
171
|
+
buyer: {
|
|
172
|
+
docType: TaxIdType.CUIT,
|
|
173
|
+
docNumber: '20987654321',
|
|
174
|
+
},
|
|
120
175
|
});
|
|
121
176
|
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
buyer: { docType: TaxIdType.CUIT, docNumber: '30123456789' },
|
|
177
|
+
// VAT breakdown (required by ARCA for A/B invoices)
|
|
178
|
+
result.vat?.forEach(v => {
|
|
179
|
+
console.log(`IVA ${v.rate}%: base $${v.taxBase} → $${v.amount}`);
|
|
126
180
|
});
|
|
127
181
|
```
|
|
128
182
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
## 🔎 Consultar un comprobante ya emitido
|
|
183
|
+
### Consulta de Padrón A13
|
|
132
184
|
|
|
133
185
|
```typescript
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
186
|
+
import { PadronService } from 'arca-sdk';
|
|
187
|
+
|
|
188
|
+
const padron = new PadronService({
|
|
189
|
+
environment: 'homologacion',
|
|
190
|
+
cuit: '20123456789',
|
|
191
|
+
cert: fs.readFileSync('cert.pem', 'utf-8'),
|
|
192
|
+
key: fs.readFileSync('key.pem', 'utf-8'),
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const { taxpayer, error } = await padron.getTaxpayer('30111111118');
|
|
196
|
+
if (taxpayer) {
|
|
197
|
+
const name = taxpayer.companyName || `${taxpayer.firstName} ${taxpayer.lastName}`;
|
|
198
|
+
console.log('Nombre:', name);
|
|
199
|
+
console.log('Provincia:', taxpayer.addresses[0]?.province);
|
|
200
|
+
console.log('¿IVA?:', taxpayer.isVATRegistered);
|
|
201
|
+
console.log('¿Mono?:', taxpayer.isMonotax);
|
|
202
|
+
}
|
|
137
203
|
```
|
|
138
204
|
|
|
139
|
-
|
|
205
|
+
### God Mode: persistencia automática de tokens
|
|
140
206
|
|
|
141
|
-
|
|
207
|
+
Pasale un adaptador `storage` y el SDK gestiona el ciclo de vida del ticket solo — incluyendo renovación automática al expirar.
|
|
142
208
|
|
|
143
209
|
```typescript
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
210
|
+
const wsaa = new WsaaService({
|
|
211
|
+
...config,
|
|
212
|
+
service: 'wsfe',
|
|
213
|
+
storage: {
|
|
214
|
+
// Leé el ticket guardado (de DB, Redis, filesystem, lo que sea)
|
|
215
|
+
get: async (cuit, env) => {
|
|
216
|
+
const row = await db.token.findUnique({ where: { cuit, env } });
|
|
217
|
+
return row ? { token: row.token, sign: row.sign, ... } : null;
|
|
218
|
+
},
|
|
219
|
+
// Guardá el ticket nuevo
|
|
220
|
+
save: async (cuit, env, ticket) => {
|
|
221
|
+
await db.token.upsert({ ... });
|
|
222
|
+
},
|
|
223
|
+
}
|
|
147
224
|
});
|
|
148
|
-
```
|
|
149
225
|
|
|
150
|
-
|
|
226
|
+
// Desde ahora, .login() va a buscar el token en la DB antes de pedirle uno a ARCA
|
|
227
|
+
const ticket = await wsaa.login();
|
|
228
|
+
```
|
|
151
229
|
|
|
152
|
-
|
|
230
|
+
### QR oficial de ARCA
|
|
153
231
|
|
|
154
232
|
```typescript
|
|
155
|
-
|
|
233
|
+
import { generateQRUrl } from 'arca-sdk';
|
|
234
|
+
|
|
235
|
+
// 1. Ya viene integrado en todos los métodos de emisión:
|
|
156
236
|
const result = await wsfe.issueSimpleReceipt({ total: 1500 });
|
|
157
|
-
console.log(result.qrUrl);
|
|
237
|
+
console.log(result.qrUrl); // listo para embeber en un generador de QR
|
|
158
238
|
|
|
159
|
-
// 2. O generalo
|
|
160
|
-
|
|
161
|
-
const url = generateQRUrl(caeResponse, '20123456789', 1500);
|
|
239
|
+
// 2. O generalo a mano si ya tenés la respuesta:
|
|
240
|
+
const url = generateQRUrl(caeResponse, '20123456789', 1500.00);
|
|
162
241
|
```
|
|
163
242
|
|
|
164
|
-
|
|
243
|
+
> **Nota:** La URL usa base64 crudo sin `encodeURIComponent`. Es un quirk documentado del spec de ARCA — su scanner no acepta caracteres URL-encoded.
|
|
244
|
+
|
|
245
|
+
### Manejo de errores
|
|
165
246
|
|
|
166
|
-
|
|
247
|
+
Todos los errores son instancias tipadas de `ArcaError`, con un campo `hint` que te dice qué hacer:
|
|
167
248
|
|
|
168
249
|
```typescript
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
250
|
+
import { ArcaError, ArcaAuthError, ArcaValidationError, ArcaNetworkError } from 'arca-sdk';
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const result = await wsfe.issueSimpleReceipt({ total: 1500 });
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (error instanceof ArcaAuthError) {
|
|
256
|
+
// Token expirado, certificado inválido, etc.
|
|
257
|
+
console.error('Auth error:', error.message);
|
|
258
|
+
console.log('Hint:', error.hint); // → "El certificado puede haber expirado..."
|
|
259
|
+
} else if (error instanceof ArcaValidationError) {
|
|
260
|
+
// Datos inválidos antes de llamar a ARCA
|
|
261
|
+
console.error('Validation:', error.message, error.details);
|
|
262
|
+
} else if (error instanceof ArcaNetworkError) {
|
|
263
|
+
// Timeout, error HTTP
|
|
264
|
+
console.error('Network:', error.message);
|
|
265
|
+
} else if (error instanceof ArcaError) {
|
|
266
|
+
// Error semántico de ARCA (código de error en la respuesta SOAP)
|
|
267
|
+
console.error(`ARCA Error [${error.code}]:`, error.message);
|
|
268
|
+
console.log('Hint:', error.hint); // Pista específica por código de error
|
|
269
|
+
}
|
|
270
|
+
}
|
|
174
271
|
```
|
|
175
272
|
|
|
176
273
|
---
|
|
177
274
|
|
|
178
|
-
##
|
|
275
|
+
## Compatibilidad
|
|
179
276
|
|
|
180
|
-
|
|
|
181
|
-
|
|
182
|
-
|
|
|
183
|
-
|
|
|
184
|
-
|
|
|
277
|
+
| Runtime | Versión mínima | Estado |
|
|
278
|
+
|---------|---------------|--------|
|
|
279
|
+
| Node.js | 18 LTS | ✅ Soportado |
|
|
280
|
+
| Node.js | 20 LTS | ✅ Soportado |
|
|
281
|
+
| Node.js | 22 LTS | ✅ Soportado |
|
|
282
|
+
| Bun | 1.x | ✅ Soportado |
|
|
283
|
+
| Deno | — | ⚠️ Sin probar |
|
|
284
|
+
| Browser | — | ❌ No soportado (requiere `node:https`) |
|
|
185
285
|
|
|
186
|
-
|
|
286
|
+
> El SDK maneja automáticamente los errores SSL de los servidores de ARCA ("dh key too small") mediante configuración custom del `https.Agent`.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Tipos exportados
|
|
187
291
|
|
|
188
292
|
```typescript
|
|
293
|
+
// Servicios
|
|
294
|
+
import { WsaaService, WsfeService, PadronService } from 'arca-sdk';
|
|
295
|
+
|
|
296
|
+
// Enums
|
|
189
297
|
import { InvoiceType, BillingConcept, TaxIdType } from 'arca-sdk';
|
|
190
298
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
299
|
+
// Tipos de configuración
|
|
300
|
+
import type { WsaaConfig, WsfeConfig, TaxpayerServiceConfig } from 'arca-sdk';
|
|
301
|
+
|
|
302
|
+
// Tipos de respuesta
|
|
303
|
+
import type { CAEResponse, InvoiceDetails, PointOfSale, ServiceStatus } from 'arca-sdk';
|
|
304
|
+
import type { TaxpayerResponse, Taxpayer, Address, Activity, TaxRecord } from 'arca-sdk';
|
|
305
|
+
|
|
306
|
+
// Items de factura
|
|
307
|
+
import type { InvoiceItem, Buyer, IssueInvoiceRequest } from 'arca-sdk';
|
|
308
|
+
|
|
309
|
+
// Storage
|
|
310
|
+
import type { TokenStorage, LoginTicket } from 'arca-sdk';
|
|
195
311
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
BillingConcept.PRODUCTS_AND_SERVICES // 3
|
|
312
|
+
// Errores
|
|
313
|
+
import { ArcaError, ArcaAuthError, ArcaValidationError, ArcaNetworkError } from 'arca-sdk';
|
|
199
314
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
TaxIdType.FINAL_CONSUMER // 99
|
|
315
|
+
// QR
|
|
316
|
+
import { generateQRUrl } from 'arca-sdk';
|
|
203
317
|
```
|
|
204
318
|
|
|
205
319
|
---
|
|
206
320
|
|
|
207
|
-
##
|
|
321
|
+
## Desarrollo
|
|
208
322
|
|
|
209
323
|
```bash
|
|
210
|
-
#
|
|
324
|
+
# Clonar e instalar
|
|
325
|
+
git clone https://github.com/marcelaborgarello/arca-sdk
|
|
326
|
+
cd arca-sdk
|
|
327
|
+
bun install
|
|
328
|
+
|
|
329
|
+
# Tests
|
|
211
330
|
bun test
|
|
212
331
|
|
|
213
|
-
# Verificar tipos
|
|
332
|
+
# Verificar tipos
|
|
214
333
|
bun run lint
|
|
215
334
|
|
|
216
|
-
# Build
|
|
335
|
+
# Build (CJS + ESM + .d.ts)
|
|
217
336
|
bun run build
|
|
218
337
|
```
|
|
219
338
|
|
|
339
|
+
### Tests disponibles
|
|
340
|
+
|
|
341
|
+
| Suite | Archivo | Qué cubre |
|
|
342
|
+
|-------|---------|-----------|
|
|
343
|
+
| Cálculos | `calculations.test.ts` | IVA, subtotales, totales con y sin IVA incluido |
|
|
344
|
+
| QR | `qr.test.ts` | Generación de URL, limpieza de CUIT/CAE, campo comprador |
|
|
345
|
+
| XML | `xml.test.ts` | Construcción de TRA, parsing WSAA, validación de CUIT |
|
|
346
|
+
| Padrón | `padron.test.ts` | Parsing de respuesta, CUIT not found, condición IVA |
|
|
347
|
+
| WSFE | `wsfe.test.ts` | issueSimpleReceipt, issueReceipt, issueInvoiceB, checkStatus |
|
|
348
|
+
|
|
220
349
|
---
|
|
221
350
|
|
|
222
|
-
##
|
|
351
|
+
## Roadmap
|
|
352
|
+
|
|
353
|
+
- [ ] Soporte WSMTXCA (Factura de Crédito Electrónica MiPyME)
|
|
354
|
+
- [ ] Soporte WSCT (Turismo)
|
|
355
|
+
- [ ] Método `consultar()` para servicios adicionales del Padrón
|
|
356
|
+
- [ ] Opción de exportar a PDF (recibo y factura)
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Licencia
|
|
361
|
+
|
|
223
362
|
MIT © [Marcela Borgarello](https://github.com/marcelaborgarello)
|
|
224
363
|
|
|
225
364
|
---
|
|
226
365
|
|
|
366
|
+
<div align="center">
|
|
367
|
+
|
|
227
368
|
**Hecho con ❤️ en Argentina 🇦🇷**
|
|
369
|
+
|
|
228
370
|
*Porque integrar con ARCA no tiene por qué ser un infierno.*
|
|
371
|
+
|
|
372
|
+
[npm](https://www.npmjs.com/package/arca-sdk) · [GitHub](https://github.com/marcelaborgarello/arca-sdk) · [CHANGELOG](CHANGELOG.md)
|
|
373
|
+
|
|
374
|
+
</div>
|
package/dist/index.cjs
CHANGED
|
@@ -98,16 +98,33 @@ var ArcaNetworkError = class extends ArcaError {
|
|
|
98
98
|
|
|
99
99
|
// src/utils/xml.ts
|
|
100
100
|
var import_fast_xml_parser = require("fast-xml-parser");
|
|
101
|
+
|
|
102
|
+
// src/utils/formatArcaDate.ts
|
|
103
|
+
function formatArcaDate(date) {
|
|
104
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
105
|
+
const tzOffset = 3 * 60 * 60 * 1e3;
|
|
106
|
+
const baTime = new Date(date.getTime() - tzOffset);
|
|
107
|
+
const yyyy = baTime.getUTCFullYear();
|
|
108
|
+
const mm = pad(baTime.getUTCMonth() + 1);
|
|
109
|
+
const dd = pad(baTime.getUTCDate());
|
|
110
|
+
const hh = pad(baTime.getUTCHours());
|
|
111
|
+
const min = pad(baTime.getUTCMinutes());
|
|
112
|
+
const ss = pad(baTime.getUTCSeconds());
|
|
113
|
+
return `${yyyy}-${mm}-${dd}T${hh}:${min}:${ss}-03:00`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/utils/xml.ts
|
|
101
117
|
function buildTRA(service, cuit) {
|
|
102
118
|
const now = /* @__PURE__ */ new Date();
|
|
103
|
-
const
|
|
119
|
+
const genTime = new Date(now.getTime() - 10 * 60 * 1e3);
|
|
120
|
+
const expTime = new Date(now.getTime() + 12 * 60 * 60 * 1e3);
|
|
104
121
|
const tra = {
|
|
105
122
|
loginTicketRequest: {
|
|
106
123
|
"@_version": "1.0",
|
|
107
124
|
header: {
|
|
108
125
|
uniqueId: Math.floor(now.getTime() / 1e3),
|
|
109
|
-
generationTime:
|
|
110
|
-
expirationTime:
|
|
126
|
+
generationTime: formatArcaDate(genTime),
|
|
127
|
+
expirationTime: formatArcaDate(expTime)
|
|
111
128
|
},
|
|
112
129
|
service
|
|
113
130
|
}
|