arca-sdk 0.1.0 → 0.1.2
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/dist/index.cjs +93 -21
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +91 -20
- package/package.json +7 -4
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,8 @@ __export(index_exports, {
|
|
|
37
37
|
TipoComprobante: () => TipoComprobante,
|
|
38
38
|
TipoDocumento: () => TipoDocumento,
|
|
39
39
|
WsaaService: () => WsaaService,
|
|
40
|
-
WsfeService: () => WsfeService
|
|
40
|
+
WsfeService: () => WsfeService,
|
|
41
|
+
generarUrlQR: () => generarUrlQR
|
|
41
42
|
});
|
|
42
43
|
module.exports = __toCommonJS(index_exports);
|
|
43
44
|
|
|
@@ -241,6 +242,26 @@ var TicketManager = class {
|
|
|
241
242
|
}
|
|
242
243
|
};
|
|
243
244
|
|
|
245
|
+
// src/utils/network.ts
|
|
246
|
+
var import_https = __toESM(require("https"), 1);
|
|
247
|
+
async function callArcaApi(url, options) {
|
|
248
|
+
const isNode = typeof process !== "undefined" && process.versions && process.versions.node;
|
|
249
|
+
if (isNode) {
|
|
250
|
+
const agent = new import_https.default.Agent({
|
|
251
|
+
// Permitir llaves DH de 1024 bits (AFIP) bajando a Security Level 1
|
|
252
|
+
// solo para esta conexión específica.
|
|
253
|
+
ciphers: "DEFAULT@SECLEVEL=1",
|
|
254
|
+
rejectUnauthorized: true
|
|
255
|
+
// Seguimos validando el certificado
|
|
256
|
+
});
|
|
257
|
+
return fetch(url, {
|
|
258
|
+
...options,
|
|
259
|
+
agent
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return fetch(url, options);
|
|
263
|
+
}
|
|
264
|
+
|
|
244
265
|
// src/auth/wsaa.ts
|
|
245
266
|
var WsaaService = class {
|
|
246
267
|
config;
|
|
@@ -309,7 +330,7 @@ var WsaaService = class {
|
|
|
309
330
|
);
|
|
310
331
|
}
|
|
311
332
|
const endpoint = getWsaaEndpoint(this.config.environment);
|
|
312
|
-
const response = await
|
|
333
|
+
const response = await callArcaApi(endpoint, {
|
|
313
334
|
method: "POST",
|
|
314
335
|
headers: {
|
|
315
336
|
"Content-Type": "text/xml; charset=utf-8",
|
|
@@ -381,21 +402,32 @@ var TipoDocumento = /* @__PURE__ */ ((TipoDocumento2) => {
|
|
|
381
402
|
})(TipoDocumento || {});
|
|
382
403
|
|
|
383
404
|
// src/utils/calculations.ts
|
|
384
|
-
function calcularSubtotal(items) {
|
|
405
|
+
function calcularSubtotal(items, incluyeIva = false) {
|
|
385
406
|
return items.reduce((sum, item) => {
|
|
386
|
-
|
|
407
|
+
let precioNeto = item.precioUnitario;
|
|
408
|
+
if (incluyeIva && item.alicuotaIva) {
|
|
409
|
+
precioNeto = item.precioUnitario / (1 + item.alicuotaIva / 100);
|
|
410
|
+
}
|
|
411
|
+
return sum + item.cantidad * precioNeto;
|
|
387
412
|
}, 0);
|
|
388
413
|
}
|
|
389
|
-
function calcularIVA(items) {
|
|
414
|
+
function calcularIVA(items, incluyeIva = false) {
|
|
390
415
|
return items.reduce((sum, item) => {
|
|
391
|
-
const subtotal = item.cantidad * item.precioUnitario;
|
|
392
416
|
const alicuota = item.alicuotaIva || 0;
|
|
393
|
-
|
|
417
|
+
let precioNeto = item.precioUnitario;
|
|
418
|
+
if (incluyeIva && alicuota) {
|
|
419
|
+
precioNeto = item.precioUnitario / (1 + alicuota / 100);
|
|
420
|
+
}
|
|
421
|
+
const subtotalNeto = item.cantidad * precioNeto;
|
|
422
|
+
return sum + subtotalNeto * alicuota / 100;
|
|
394
423
|
}, 0);
|
|
395
424
|
}
|
|
396
|
-
function calcularTotal(items) {
|
|
397
|
-
|
|
398
|
-
|
|
425
|
+
function calcularTotal(items, incluyeIva = false) {
|
|
426
|
+
if (incluyeIva) {
|
|
427
|
+
return items.reduce((sum, item) => sum + item.cantidad * item.precioUnitario, 0);
|
|
428
|
+
}
|
|
429
|
+
const subtotal = calcularSubtotal(items, false);
|
|
430
|
+
const iva = calcularIVA(items, false);
|
|
399
431
|
return subtotal + iva;
|
|
400
432
|
}
|
|
401
433
|
function redondear(valor) {
|
|
@@ -466,14 +498,16 @@ var WsfeService = class {
|
|
|
466
498
|
*/
|
|
467
499
|
async emitirFacturaB(params) {
|
|
468
500
|
this.validateItemsWithIVA(params.items);
|
|
469
|
-
const
|
|
501
|
+
const incluyeIva = params.incluyeIva || false;
|
|
502
|
+
const ivaData = this.calcularIVAPorAlicuota(params.items, incluyeIva);
|
|
470
503
|
return this.emitirComprobante({
|
|
471
504
|
tipo: 6 /* FACTURA_B */,
|
|
472
505
|
concepto: params.concepto || 1 /* PRODUCTOS */,
|
|
473
506
|
items: params.items,
|
|
474
507
|
comprador: params.comprador,
|
|
475
508
|
fecha: params.fecha,
|
|
476
|
-
ivaData
|
|
509
|
+
ivaData,
|
|
510
|
+
incluyeIva
|
|
477
511
|
});
|
|
478
512
|
}
|
|
479
513
|
/**
|
|
@@ -482,14 +516,16 @@ var WsfeService = class {
|
|
|
482
516
|
*/
|
|
483
517
|
async emitirFacturaA(params) {
|
|
484
518
|
this.validateItemsWithIVA(params.items);
|
|
485
|
-
const
|
|
519
|
+
const incluyeIva = params.incluyeIva || false;
|
|
520
|
+
const ivaData = this.calcularIVAPorAlicuota(params.items, incluyeIva);
|
|
486
521
|
return this.emitirComprobante({
|
|
487
522
|
tipo: 1 /* FACTURA_A */,
|
|
488
523
|
concepto: params.concepto || 1 /* PRODUCTOS */,
|
|
489
524
|
items: params.items,
|
|
490
525
|
comprador: params.comprador,
|
|
491
526
|
fecha: params.fecha,
|
|
492
|
-
ivaData
|
|
527
|
+
ivaData,
|
|
528
|
+
incluyeIva
|
|
493
529
|
});
|
|
494
530
|
}
|
|
495
531
|
/**
|
|
@@ -513,11 +549,15 @@ var WsfeService = class {
|
|
|
513
549
|
* Calcula IVA agrupado por alícuota
|
|
514
550
|
* ARCA requiere esto para Factura B/A
|
|
515
551
|
*/
|
|
516
|
-
calcularIVAPorAlicuota(items) {
|
|
552
|
+
calcularIVAPorAlicuota(items, incluyeIva = false) {
|
|
517
553
|
const porAlicuota = /* @__PURE__ */ new Map();
|
|
518
554
|
items.forEach((item) => {
|
|
519
555
|
const alicuota = item.alicuotaIva || 0;
|
|
520
|
-
|
|
556
|
+
let precioNeto = item.precioUnitario;
|
|
557
|
+
if (incluyeIva && alicuota) {
|
|
558
|
+
precioNeto = item.precioUnitario / (1 + alicuota / 100);
|
|
559
|
+
}
|
|
560
|
+
const base = item.cantidad * precioNeto;
|
|
521
561
|
const importe = base * alicuota / 100;
|
|
522
562
|
const actual = porAlicuota.get(alicuota) || { base: 0, importe: 0 };
|
|
523
563
|
porAlicuota.set(alicuota, {
|
|
@@ -558,9 +598,10 @@ var WsfeService = class {
|
|
|
558
598
|
let subtotal = total;
|
|
559
599
|
let iva = 0;
|
|
560
600
|
if (request.items && request.items.length > 0) {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
601
|
+
const incluyeIva = request.incluyeIva || false;
|
|
602
|
+
subtotal = redondear(calcularSubtotal(request.items, incluyeIva));
|
|
603
|
+
iva = redondear(calcularIVA(request.items, incluyeIva));
|
|
604
|
+
total = redondear(calcularTotal(request.items, incluyeIva));
|
|
564
605
|
}
|
|
565
606
|
if (total <= 0) {
|
|
566
607
|
throw new ArcaValidationError("El monto total debe ser mayor a 0");
|
|
@@ -578,7 +619,7 @@ var WsfeService = class {
|
|
|
578
619
|
ivaData: request.ivaData
|
|
579
620
|
});
|
|
580
621
|
const endpoint = getWsfeEndpoint(this.config.environment);
|
|
581
|
-
const response = await
|
|
622
|
+
const response = await callArcaApi(endpoint, {
|
|
582
623
|
method: "POST",
|
|
583
624
|
headers: {
|
|
584
625
|
"Content-Type": "text/xml; charset=utf-8",
|
|
@@ -756,6 +797,36 @@ var WsfeService = class {
|
|
|
756
797
|
};
|
|
757
798
|
}
|
|
758
799
|
};
|
|
800
|
+
|
|
801
|
+
// src/utils/qr.ts
|
|
802
|
+
function generarUrlQR(caeResponse, cuitEmisor, total, comprador) {
|
|
803
|
+
const fDate = caeResponse.fecha;
|
|
804
|
+
const fechaFormat = fDate.length === 8 ? `${fDate.substring(0, 4)}-${fDate.substring(4, 6)}-${fDate.substring(6, 8)}` : fDate;
|
|
805
|
+
const docTipo = comprador?.tipoDocumento || 99 /* CONSUMIDOR_FINAL */;
|
|
806
|
+
const docNro = comprador?.nroDocumento ? parseInt(comprador.nroDocumento, 10) : 0;
|
|
807
|
+
const qrData = {
|
|
808
|
+
ver: 1,
|
|
809
|
+
// Versión estándar exigida por AFIP
|
|
810
|
+
fecha: fechaFormat,
|
|
811
|
+
cuit: parseInt(cuitEmisor, 10),
|
|
812
|
+
ptoVta: caeResponse.puntoVenta,
|
|
813
|
+
tipoCmp: caeResponse.tipoComprobante,
|
|
814
|
+
nroCmp: caeResponse.nroComprobante,
|
|
815
|
+
importe: parseFloat(total.toFixed(2)),
|
|
816
|
+
moneda: "PES",
|
|
817
|
+
// Por defecto PES (Pesos Argentinos)
|
|
818
|
+
ctz: 1,
|
|
819
|
+
// Cotización (siempre 1 para PES)
|
|
820
|
+
tipoDocRec: docTipo,
|
|
821
|
+
nroDocRec: docNro,
|
|
822
|
+
tipoCodAut: "E",
|
|
823
|
+
// 'E' para comprobantes electrónicos
|
|
824
|
+
codAut: parseInt(caeResponse.cae, 10)
|
|
825
|
+
};
|
|
826
|
+
const jsonString = JSON.stringify(qrData);
|
|
827
|
+
let base64 = typeof Buffer !== "undefined" ? Buffer.from(jsonString).toString("base64") : btoa(jsonString);
|
|
828
|
+
return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;
|
|
829
|
+
}
|
|
759
830
|
// Annotate the CommonJS export names for ESM import in node:
|
|
760
831
|
0 && (module.exports = {
|
|
761
832
|
ArcaAuthError,
|
|
@@ -765,5 +836,6 @@ var WsfeService = class {
|
|
|
765
836
|
TipoComprobante,
|
|
766
837
|
TipoDocumento,
|
|
767
838
|
WsaaService,
|
|
768
|
-
WsfeService
|
|
839
|
+
WsfeService,
|
|
840
|
+
generarUrlQR
|
|
769
841
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -192,6 +192,8 @@ interface EmitirFacturaRequest {
|
|
|
192
192
|
baseImponible: number;
|
|
193
193
|
importe: number;
|
|
194
194
|
}[];
|
|
195
|
+
/** Indica si los preciosUnitarios de los items YA incluyen el IVA (Precio Final). Defecto: false */
|
|
196
|
+
incluyeIva?: boolean;
|
|
195
197
|
/** Fecha del comprobante (default: hoy) */
|
|
196
198
|
fecha?: Date;
|
|
197
199
|
}
|
|
@@ -277,6 +279,7 @@ declare class WsfeService {
|
|
|
277
279
|
comprador: Comprador;
|
|
278
280
|
concepto?: Concepto;
|
|
279
281
|
fecha?: Date;
|
|
282
|
+
incluyeIva?: boolean;
|
|
280
283
|
}): Promise<CAEResponse>;
|
|
281
284
|
/**
|
|
282
285
|
* Emite una Factura A (RI a RI)
|
|
@@ -287,6 +290,7 @@ declare class WsfeService {
|
|
|
287
290
|
comprador: Comprador;
|
|
288
291
|
concepto?: Concepto;
|
|
289
292
|
fecha?: Date;
|
|
293
|
+
incluyeIva?: boolean;
|
|
290
294
|
}): Promise<CAEResponse>;
|
|
291
295
|
/**
|
|
292
296
|
* Valida que todos los items tengan alícuota IVA definida
|
|
@@ -323,4 +327,15 @@ declare class WsfeService {
|
|
|
323
327
|
private parseCAEResponse;
|
|
324
328
|
}
|
|
325
329
|
|
|
326
|
-
|
|
330
|
+
/**
|
|
331
|
+
* Genera la URL completa con el código QR para un comprobante emitido
|
|
332
|
+
*
|
|
333
|
+
* @param caeResponse Respuesta obtenida al emitir la factura (CAEResponse)
|
|
334
|
+
* @param cuitEmisor Tu CUIT (11 dígitos, sin guiones)
|
|
335
|
+
* @param total Importe total del comprobante
|
|
336
|
+
* @param comprador Datos del comprador (opcional, si no se pasa asume Consumidor Final)
|
|
337
|
+
* @returns La URL lista para embeber en un generador de QR
|
|
338
|
+
*/
|
|
339
|
+
declare function generarUrlQR(caeResponse: CAEResponse, cuitEmisor: string, total: number, comprador?: Comprador): string;
|
|
340
|
+
|
|
341
|
+
export { ArcaAuthError, type ArcaConfig, ArcaError, ArcaValidationError, type CAEResponse, type Comprador, Concepto, type EmitirFacturaRequest, type Environment, type FacturaItem, type LoginTicket, TipoComprobante, TipoDocumento, type WsaaConfig, WsaaService, type WsfeConfig, WsfeService, generarUrlQR };
|
package/dist/index.d.ts
CHANGED
|
@@ -192,6 +192,8 @@ interface EmitirFacturaRequest {
|
|
|
192
192
|
baseImponible: number;
|
|
193
193
|
importe: number;
|
|
194
194
|
}[];
|
|
195
|
+
/** Indica si los preciosUnitarios de los items YA incluyen el IVA (Precio Final). Defecto: false */
|
|
196
|
+
incluyeIva?: boolean;
|
|
195
197
|
/** Fecha del comprobante (default: hoy) */
|
|
196
198
|
fecha?: Date;
|
|
197
199
|
}
|
|
@@ -277,6 +279,7 @@ declare class WsfeService {
|
|
|
277
279
|
comprador: Comprador;
|
|
278
280
|
concepto?: Concepto;
|
|
279
281
|
fecha?: Date;
|
|
282
|
+
incluyeIva?: boolean;
|
|
280
283
|
}): Promise<CAEResponse>;
|
|
281
284
|
/**
|
|
282
285
|
* Emite una Factura A (RI a RI)
|
|
@@ -287,6 +290,7 @@ declare class WsfeService {
|
|
|
287
290
|
comprador: Comprador;
|
|
288
291
|
concepto?: Concepto;
|
|
289
292
|
fecha?: Date;
|
|
293
|
+
incluyeIva?: boolean;
|
|
290
294
|
}): Promise<CAEResponse>;
|
|
291
295
|
/**
|
|
292
296
|
* Valida que todos los items tengan alícuota IVA definida
|
|
@@ -323,4 +327,15 @@ declare class WsfeService {
|
|
|
323
327
|
private parseCAEResponse;
|
|
324
328
|
}
|
|
325
329
|
|
|
326
|
-
|
|
330
|
+
/**
|
|
331
|
+
* Genera la URL completa con el código QR para un comprobante emitido
|
|
332
|
+
*
|
|
333
|
+
* @param caeResponse Respuesta obtenida al emitir la factura (CAEResponse)
|
|
334
|
+
* @param cuitEmisor Tu CUIT (11 dígitos, sin guiones)
|
|
335
|
+
* @param total Importe total del comprobante
|
|
336
|
+
* @param comprador Datos del comprador (opcional, si no se pasa asume Consumidor Final)
|
|
337
|
+
* @returns La URL lista para embeber en un generador de QR
|
|
338
|
+
*/
|
|
339
|
+
declare function generarUrlQR(caeResponse: CAEResponse, cuitEmisor: string, total: number, comprador?: Comprador): string;
|
|
340
|
+
|
|
341
|
+
export { ArcaAuthError, type ArcaConfig, ArcaError, ArcaValidationError, type CAEResponse, type Comprador, Concepto, type EmitirFacturaRequest, type Environment, type FacturaItem, type LoginTicket, TipoComprobante, TipoDocumento, type WsaaConfig, WsaaService, type WsfeConfig, WsfeService, generarUrlQR };
|
package/dist/index.js
CHANGED
|
@@ -198,6 +198,26 @@ var TicketManager = class {
|
|
|
198
198
|
}
|
|
199
199
|
};
|
|
200
200
|
|
|
201
|
+
// src/utils/network.ts
|
|
202
|
+
import https from "https";
|
|
203
|
+
async function callArcaApi(url, options) {
|
|
204
|
+
const isNode = typeof process !== "undefined" && process.versions && process.versions.node;
|
|
205
|
+
if (isNode) {
|
|
206
|
+
const agent = new https.Agent({
|
|
207
|
+
// Permitir llaves DH de 1024 bits (AFIP) bajando a Security Level 1
|
|
208
|
+
// solo para esta conexión específica.
|
|
209
|
+
ciphers: "DEFAULT@SECLEVEL=1",
|
|
210
|
+
rejectUnauthorized: true
|
|
211
|
+
// Seguimos validando el certificado
|
|
212
|
+
});
|
|
213
|
+
return fetch(url, {
|
|
214
|
+
...options,
|
|
215
|
+
agent
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
return fetch(url, options);
|
|
219
|
+
}
|
|
220
|
+
|
|
201
221
|
// src/auth/wsaa.ts
|
|
202
222
|
var WsaaService = class {
|
|
203
223
|
config;
|
|
@@ -266,7 +286,7 @@ var WsaaService = class {
|
|
|
266
286
|
);
|
|
267
287
|
}
|
|
268
288
|
const endpoint = getWsaaEndpoint(this.config.environment);
|
|
269
|
-
const response = await
|
|
289
|
+
const response = await callArcaApi(endpoint, {
|
|
270
290
|
method: "POST",
|
|
271
291
|
headers: {
|
|
272
292
|
"Content-Type": "text/xml; charset=utf-8",
|
|
@@ -338,21 +358,32 @@ var TipoDocumento = /* @__PURE__ */ ((TipoDocumento2) => {
|
|
|
338
358
|
})(TipoDocumento || {});
|
|
339
359
|
|
|
340
360
|
// src/utils/calculations.ts
|
|
341
|
-
function calcularSubtotal(items) {
|
|
361
|
+
function calcularSubtotal(items, incluyeIva = false) {
|
|
342
362
|
return items.reduce((sum, item) => {
|
|
343
|
-
|
|
363
|
+
let precioNeto = item.precioUnitario;
|
|
364
|
+
if (incluyeIva && item.alicuotaIva) {
|
|
365
|
+
precioNeto = item.precioUnitario / (1 + item.alicuotaIva / 100);
|
|
366
|
+
}
|
|
367
|
+
return sum + item.cantidad * precioNeto;
|
|
344
368
|
}, 0);
|
|
345
369
|
}
|
|
346
|
-
function calcularIVA(items) {
|
|
370
|
+
function calcularIVA(items, incluyeIva = false) {
|
|
347
371
|
return items.reduce((sum, item) => {
|
|
348
|
-
const subtotal = item.cantidad * item.precioUnitario;
|
|
349
372
|
const alicuota = item.alicuotaIva || 0;
|
|
350
|
-
|
|
373
|
+
let precioNeto = item.precioUnitario;
|
|
374
|
+
if (incluyeIva && alicuota) {
|
|
375
|
+
precioNeto = item.precioUnitario / (1 + alicuota / 100);
|
|
376
|
+
}
|
|
377
|
+
const subtotalNeto = item.cantidad * precioNeto;
|
|
378
|
+
return sum + subtotalNeto * alicuota / 100;
|
|
351
379
|
}, 0);
|
|
352
380
|
}
|
|
353
|
-
function calcularTotal(items) {
|
|
354
|
-
|
|
355
|
-
|
|
381
|
+
function calcularTotal(items, incluyeIva = false) {
|
|
382
|
+
if (incluyeIva) {
|
|
383
|
+
return items.reduce((sum, item) => sum + item.cantidad * item.precioUnitario, 0);
|
|
384
|
+
}
|
|
385
|
+
const subtotal = calcularSubtotal(items, false);
|
|
386
|
+
const iva = calcularIVA(items, false);
|
|
356
387
|
return subtotal + iva;
|
|
357
388
|
}
|
|
358
389
|
function redondear(valor) {
|
|
@@ -423,14 +454,16 @@ var WsfeService = class {
|
|
|
423
454
|
*/
|
|
424
455
|
async emitirFacturaB(params) {
|
|
425
456
|
this.validateItemsWithIVA(params.items);
|
|
426
|
-
const
|
|
457
|
+
const incluyeIva = params.incluyeIva || false;
|
|
458
|
+
const ivaData = this.calcularIVAPorAlicuota(params.items, incluyeIva);
|
|
427
459
|
return this.emitirComprobante({
|
|
428
460
|
tipo: 6 /* FACTURA_B */,
|
|
429
461
|
concepto: params.concepto || 1 /* PRODUCTOS */,
|
|
430
462
|
items: params.items,
|
|
431
463
|
comprador: params.comprador,
|
|
432
464
|
fecha: params.fecha,
|
|
433
|
-
ivaData
|
|
465
|
+
ivaData,
|
|
466
|
+
incluyeIva
|
|
434
467
|
});
|
|
435
468
|
}
|
|
436
469
|
/**
|
|
@@ -439,14 +472,16 @@ var WsfeService = class {
|
|
|
439
472
|
*/
|
|
440
473
|
async emitirFacturaA(params) {
|
|
441
474
|
this.validateItemsWithIVA(params.items);
|
|
442
|
-
const
|
|
475
|
+
const incluyeIva = params.incluyeIva || false;
|
|
476
|
+
const ivaData = this.calcularIVAPorAlicuota(params.items, incluyeIva);
|
|
443
477
|
return this.emitirComprobante({
|
|
444
478
|
tipo: 1 /* FACTURA_A */,
|
|
445
479
|
concepto: params.concepto || 1 /* PRODUCTOS */,
|
|
446
480
|
items: params.items,
|
|
447
481
|
comprador: params.comprador,
|
|
448
482
|
fecha: params.fecha,
|
|
449
|
-
ivaData
|
|
483
|
+
ivaData,
|
|
484
|
+
incluyeIva
|
|
450
485
|
});
|
|
451
486
|
}
|
|
452
487
|
/**
|
|
@@ -470,11 +505,15 @@ var WsfeService = class {
|
|
|
470
505
|
* Calcula IVA agrupado por alícuota
|
|
471
506
|
* ARCA requiere esto para Factura B/A
|
|
472
507
|
*/
|
|
473
|
-
calcularIVAPorAlicuota(items) {
|
|
508
|
+
calcularIVAPorAlicuota(items, incluyeIva = false) {
|
|
474
509
|
const porAlicuota = /* @__PURE__ */ new Map();
|
|
475
510
|
items.forEach((item) => {
|
|
476
511
|
const alicuota = item.alicuotaIva || 0;
|
|
477
|
-
|
|
512
|
+
let precioNeto = item.precioUnitario;
|
|
513
|
+
if (incluyeIva && alicuota) {
|
|
514
|
+
precioNeto = item.precioUnitario / (1 + alicuota / 100);
|
|
515
|
+
}
|
|
516
|
+
const base = item.cantidad * precioNeto;
|
|
478
517
|
const importe = base * alicuota / 100;
|
|
479
518
|
const actual = porAlicuota.get(alicuota) || { base: 0, importe: 0 };
|
|
480
519
|
porAlicuota.set(alicuota, {
|
|
@@ -515,9 +554,10 @@ var WsfeService = class {
|
|
|
515
554
|
let subtotal = total;
|
|
516
555
|
let iva = 0;
|
|
517
556
|
if (request.items && request.items.length > 0) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
557
|
+
const incluyeIva = request.incluyeIva || false;
|
|
558
|
+
subtotal = redondear(calcularSubtotal(request.items, incluyeIva));
|
|
559
|
+
iva = redondear(calcularIVA(request.items, incluyeIva));
|
|
560
|
+
total = redondear(calcularTotal(request.items, incluyeIva));
|
|
521
561
|
}
|
|
522
562
|
if (total <= 0) {
|
|
523
563
|
throw new ArcaValidationError("El monto total debe ser mayor a 0");
|
|
@@ -535,7 +575,7 @@ var WsfeService = class {
|
|
|
535
575
|
ivaData: request.ivaData
|
|
536
576
|
});
|
|
537
577
|
const endpoint = getWsfeEndpoint(this.config.environment);
|
|
538
|
-
const response = await
|
|
578
|
+
const response = await callArcaApi(endpoint, {
|
|
539
579
|
method: "POST",
|
|
540
580
|
headers: {
|
|
541
581
|
"Content-Type": "text/xml; charset=utf-8",
|
|
@@ -713,6 +753,36 @@ var WsfeService = class {
|
|
|
713
753
|
};
|
|
714
754
|
}
|
|
715
755
|
};
|
|
756
|
+
|
|
757
|
+
// src/utils/qr.ts
|
|
758
|
+
function generarUrlQR(caeResponse, cuitEmisor, total, comprador) {
|
|
759
|
+
const fDate = caeResponse.fecha;
|
|
760
|
+
const fechaFormat = fDate.length === 8 ? `${fDate.substring(0, 4)}-${fDate.substring(4, 6)}-${fDate.substring(6, 8)}` : fDate;
|
|
761
|
+
const docTipo = comprador?.tipoDocumento || 99 /* CONSUMIDOR_FINAL */;
|
|
762
|
+
const docNro = comprador?.nroDocumento ? parseInt(comprador.nroDocumento, 10) : 0;
|
|
763
|
+
const qrData = {
|
|
764
|
+
ver: 1,
|
|
765
|
+
// Versión estándar exigida por AFIP
|
|
766
|
+
fecha: fechaFormat,
|
|
767
|
+
cuit: parseInt(cuitEmisor, 10),
|
|
768
|
+
ptoVta: caeResponse.puntoVenta,
|
|
769
|
+
tipoCmp: caeResponse.tipoComprobante,
|
|
770
|
+
nroCmp: caeResponse.nroComprobante,
|
|
771
|
+
importe: parseFloat(total.toFixed(2)),
|
|
772
|
+
moneda: "PES",
|
|
773
|
+
// Por defecto PES (Pesos Argentinos)
|
|
774
|
+
ctz: 1,
|
|
775
|
+
// Cotización (siempre 1 para PES)
|
|
776
|
+
tipoDocRec: docTipo,
|
|
777
|
+
nroDocRec: docNro,
|
|
778
|
+
tipoCodAut: "E",
|
|
779
|
+
// 'E' para comprobantes electrónicos
|
|
780
|
+
codAut: parseInt(caeResponse.cae, 10)
|
|
781
|
+
};
|
|
782
|
+
const jsonString = JSON.stringify(qrData);
|
|
783
|
+
let base64 = typeof Buffer !== "undefined" ? Buffer.from(jsonString).toString("base64") : btoa(jsonString);
|
|
784
|
+
return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;
|
|
785
|
+
}
|
|
716
786
|
export {
|
|
717
787
|
ArcaAuthError,
|
|
718
788
|
ArcaError,
|
|
@@ -721,5 +791,6 @@ export {
|
|
|
721
791
|
TipoComprobante,
|
|
722
792
|
TipoDocumento,
|
|
723
793
|
WsaaService,
|
|
724
|
-
WsfeService
|
|
794
|
+
WsfeService,
|
|
795
|
+
generarUrlQR
|
|
725
796
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arca-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "SDK moderna en TypeScript para ARCA (ex-AFIP)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,9 +8,12 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"types":
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
"types": {
|
|
12
|
+
"import": "./dist/index.d.ts",
|
|
13
|
+
"require": "./dist/index.d.cts"
|
|
14
|
+
},
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
14
17
|
}
|
|
15
18
|
},
|
|
16
19
|
"files": [
|