facturas 0.5.2 → 0.6.1
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 +2 -0
- package/dist/constants.d.ts +18 -1
- package/dist/constants.mjs +17 -3
- package/dist/constants.mjs.map +1 -1
- package/dist/errors.d.ts +16 -1
- package/dist/errors.mjs +14 -0
- package/dist/errors.mjs.map +1 -1
- package/dist/fiscal-evidence-DbbFH74x.d.ts +69 -0
- package/dist/{index-CqXVyU0E.d.ts → index-3fdgJ3c2.d.ts} +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.mjs +1070 -348
- package/dist/index.mjs.map +1 -1
- package/dist/padron.d.ts +2 -2
- package/dist/padron.mjs.map +1 -1
- package/dist/{types-CKKe1Oo4.d.ts → types-Cup-oevW.d.ts} +2 -0
- package/dist/types.d.ts +1 -1
- package/dist/wsfe.d.ts +32 -3
- package/dist/wsfe.mjs +505 -115
- package/dist/wsfe.mjs.map +1 -1
- package/dist/wsmtxca.d.ts +64 -8
- package/dist/wsmtxca.mjs +556 -156
- package/dist/wsmtxca.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -68,10 +68,24 @@ var ArcaInvalidSoapResponseError = class extends ArcaError {
|
|
|
68
68
|
var ArcaServiceError = class extends ArcaError {
|
|
69
69
|
name = "ArcaServiceError";
|
|
70
70
|
serviceCode;
|
|
71
|
+
service;
|
|
72
|
+
operation;
|
|
73
|
+
result;
|
|
74
|
+
resultLevel;
|
|
75
|
+
results;
|
|
76
|
+
cae;
|
|
77
|
+
issues;
|
|
71
78
|
detail;
|
|
72
79
|
constructor(message, options) {
|
|
73
80
|
super(message, "ARCA_SERVICE_ERROR", options);
|
|
74
81
|
this.serviceCode = options?.serviceCode;
|
|
82
|
+
this.service = options?.service;
|
|
83
|
+
this.operation = options?.operation;
|
|
84
|
+
this.result = options?.result;
|
|
85
|
+
this.resultLevel = options?.resultLevel;
|
|
86
|
+
this.results = options?.results;
|
|
87
|
+
this.cae = options?.cae;
|
|
88
|
+
this.issues = options?.issues;
|
|
75
89
|
this.detail = options?.detail;
|
|
76
90
|
}
|
|
77
91
|
};
|
|
@@ -86,9 +100,10 @@ var ARCA_ENV_VARIABLES = {
|
|
|
86
100
|
};
|
|
87
101
|
var PRIVATE_KEY_PEM_PREFIXES = [
|
|
88
102
|
"-----BEGIN PRIVATE KEY-----",
|
|
89
|
-
"-----BEGIN RSA PRIVATE KEY-----"
|
|
90
|
-
"-----BEGIN ENCRYPTED PRIVATE KEY-----"
|
|
103
|
+
"-----BEGIN RSA PRIVATE KEY-----"
|
|
91
104
|
];
|
|
105
|
+
var ENCRYPTED_PRIVATE_KEY_PEM_PREFIX = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
|
|
106
|
+
var LEGACY_ENCRYPTED_RSA_PRIVATE_KEY_PATTERN = /^-----BEGIN RSA PRIVATE KEY-----[\s\S]*^Proc-Type:\s*4,\s*ENCRYPTED\s*$/m;
|
|
92
107
|
var VALID_ARCA_LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
93
108
|
var DEFAULT_ARCA_TIMEOUT_MS = 3e4;
|
|
94
109
|
var DEFAULT_ARCA_RETRIES = 0;
|
|
@@ -119,6 +134,11 @@ function assertArcaClientConfig(config) {
|
|
|
119
134
|
const timeout = normalized.timeout ?? DEFAULT_ARCA_TIMEOUT_MS;
|
|
120
135
|
const retries = normalized.retries ?? DEFAULT_ARCA_RETRIES;
|
|
121
136
|
const retryDelay = normalized.retryDelay ?? DEFAULT_ARCA_RETRY_DELAY_MS;
|
|
137
|
+
if (normalized.privateKeyPem.startsWith(ENCRYPTED_PRIVATE_KEY_PEM_PREFIX) || LEGACY_ENCRYPTED_RSA_PRIVATE_KEY_PATTERN.test(normalized.privateKeyPem)) {
|
|
138
|
+
throw new ArcaConfigurationError(
|
|
139
|
+
"Encrypted private keys are not supported. Provide an unencrypted PKCS#8 or RSA private key PEM."
|
|
140
|
+
);
|
|
141
|
+
}
|
|
122
142
|
if (!/^\d{11}$/.test(normalized.taxId)) {
|
|
123
143
|
invalidFields.push("taxId");
|
|
124
144
|
}
|
|
@@ -432,7 +452,7 @@ async function executePadronOperation(options, service, operation, body) {
|
|
|
432
452
|
|
|
433
453
|
// src/services/wsfe.ts
|
|
434
454
|
function createWsfeService(options) {
|
|
435
|
-
async function
|
|
455
|
+
async function executeWsfeAuthenticatedRawOperation(operation, input, body = {}, retries) {
|
|
436
456
|
const auth = await options.auth.login("wsfe", {
|
|
437
457
|
representedTaxId: input.representedTaxId,
|
|
438
458
|
forceRefresh: input.forceRefresh
|
|
@@ -440,6 +460,7 @@ function createWsfeService(options) {
|
|
|
440
460
|
const response = await options.soap.execute({
|
|
441
461
|
service: "wsfe",
|
|
442
462
|
operation,
|
|
463
|
+
...retries === void 0 ? {} : { retries },
|
|
443
464
|
body: {
|
|
444
465
|
Auth: createWsfeAuth(
|
|
445
466
|
input.representedTaxId ?? options.config.taxId,
|
|
@@ -449,7 +470,16 @@ function createWsfeService(options) {
|
|
|
449
470
|
...body
|
|
450
471
|
}
|
|
451
472
|
});
|
|
452
|
-
return
|
|
473
|
+
return unwrapWsfeOperationEnvelope(operation, response.result);
|
|
474
|
+
}
|
|
475
|
+
async function executeWsfeAuthenticatedOperation(operation, input, body = {}) {
|
|
476
|
+
const result = await executeWsfeAuthenticatedRawOperation(
|
|
477
|
+
operation,
|
|
478
|
+
input,
|
|
479
|
+
body
|
|
480
|
+
);
|
|
481
|
+
throwForWsfeOperationErrors(operation, result);
|
|
482
|
+
return result;
|
|
453
483
|
}
|
|
454
484
|
async function executeWsfeOperation(operation, body = {}) {
|
|
455
485
|
const response = await options.soap.execute({
|
|
@@ -457,7 +487,9 @@ function createWsfeService(options) {
|
|
|
457
487
|
operation,
|
|
458
488
|
body
|
|
459
489
|
});
|
|
460
|
-
|
|
490
|
+
const result = unwrapWsfeOperationEnvelope(operation, response.result);
|
|
491
|
+
throwForWsfeOperationErrors(operation, result);
|
|
492
|
+
return result;
|
|
461
493
|
}
|
|
462
494
|
async function getNextVoucherNumber({
|
|
463
495
|
representedTaxId,
|
|
@@ -499,55 +531,148 @@ function createWsfeService(options) {
|
|
|
499
531
|
forceRefresh
|
|
500
532
|
});
|
|
501
533
|
}
|
|
534
|
+
function authorizeVoucherOutcome({
|
|
535
|
+
representedTaxId,
|
|
536
|
+
data,
|
|
537
|
+
voucherNumber,
|
|
538
|
+
forceRefresh
|
|
539
|
+
}) {
|
|
540
|
+
const normalizedInput = normalizeWsfeVoucherInput(data);
|
|
541
|
+
return executeWsfeAuthorization({
|
|
542
|
+
representedTaxId,
|
|
543
|
+
data: normalizedInput,
|
|
544
|
+
voucherNumber,
|
|
545
|
+
forceRefresh
|
|
546
|
+
}).then(({ outcome }) => outcome);
|
|
547
|
+
}
|
|
502
548
|
async function authorizeNormalizedVoucher({
|
|
503
549
|
representedTaxId,
|
|
504
550
|
data: normalizedInput,
|
|
505
551
|
voucherNumber,
|
|
506
552
|
forceRefresh
|
|
507
553
|
}) {
|
|
508
|
-
const
|
|
509
|
-
const auth = await options.auth.login("wsfe", {
|
|
554
|
+
const execution = await executeWsfeAuthorization({
|
|
510
555
|
representedTaxId,
|
|
556
|
+
data: normalizedInput,
|
|
557
|
+
voucherNumber,
|
|
511
558
|
forceRefresh
|
|
512
559
|
});
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
560
|
+
if (execution.error) {
|
|
561
|
+
throw execution.error;
|
|
562
|
+
}
|
|
563
|
+
if (execution.outcome.kind !== "authorized") {
|
|
564
|
+
throw createWsfeOutcomeError(execution.outcome);
|
|
565
|
+
}
|
|
566
|
+
const { cae, caeExpiry, raw } = execution.outcome;
|
|
567
|
+
if (!(caeExpiry && raw)) {
|
|
568
|
+
throw new ArcaServiceError("WSFE did not return CAE authorization data", {
|
|
569
|
+
service: "wsfe",
|
|
570
|
+
operation: "FECAESolicitar",
|
|
571
|
+
result: execution.outcome.result,
|
|
572
|
+
resultLevel: execution.outcome.resultLevel,
|
|
573
|
+
results: execution.outcome.results,
|
|
574
|
+
cae,
|
|
575
|
+
issues: [
|
|
576
|
+
...execution.outcome.errors,
|
|
577
|
+
...execution.outcome.observations
|
|
578
|
+
],
|
|
579
|
+
detail: raw
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
cae,
|
|
584
|
+
caeExpiry,
|
|
585
|
+
voucherNumber,
|
|
586
|
+
raw
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
async function executeWsfeAuthorization({
|
|
590
|
+
representedTaxId,
|
|
591
|
+
data: normalizedInput,
|
|
592
|
+
voucherNumber,
|
|
593
|
+
forceRefresh
|
|
594
|
+
}) {
|
|
595
|
+
const requestData = mapWsfeVoucherInput(normalizedInput, voucherNumber);
|
|
596
|
+
try {
|
|
597
|
+
const result = await executeWsfeAuthenticatedRawOperation(
|
|
598
|
+
"FECAESolicitar",
|
|
599
|
+
{ representedTaxId, forceRefresh },
|
|
600
|
+
{
|
|
601
|
+
FeCAEReq: {
|
|
602
|
+
FeCabReq: {
|
|
603
|
+
CantReg: 1,
|
|
604
|
+
PtoVta: normalizedInput.salesPoint,
|
|
605
|
+
CbteTipo: normalizedInput.voucherType
|
|
606
|
+
},
|
|
607
|
+
FeDetReq: {
|
|
608
|
+
FECAEDetRequest: requestData
|
|
609
|
+
}
|
|
530
610
|
}
|
|
611
|
+
},
|
|
612
|
+
0
|
|
613
|
+
);
|
|
614
|
+
return {
|
|
615
|
+
outcome: classifyWsfeAuthorization(result, voucherNumber)
|
|
616
|
+
};
|
|
617
|
+
} catch (error) {
|
|
618
|
+
return {
|
|
619
|
+
outcome: createWsfeIndeterminateOutcome(error),
|
|
620
|
+
error
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function lookupVoucher({
|
|
625
|
+
representedTaxId,
|
|
626
|
+
number,
|
|
627
|
+
salesPoint,
|
|
628
|
+
voucherType,
|
|
629
|
+
forceRefresh
|
|
630
|
+
}) {
|
|
631
|
+
const operation = "FECompConsultar";
|
|
632
|
+
const result = await executeWsfeAuthenticatedRawOperation(
|
|
633
|
+
operation,
|
|
634
|
+
{ representedTaxId, forceRefresh },
|
|
635
|
+
{
|
|
636
|
+
FeCompConsReq: {
|
|
637
|
+
CbteNro: number,
|
|
638
|
+
PtoVta: salesPoint,
|
|
639
|
+
CbteTipo: voucherType
|
|
531
640
|
}
|
|
532
641
|
}
|
|
533
|
-
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
642
|
+
);
|
|
643
|
+
const errors = extractWsfeGlobalIssues(result, operation);
|
|
644
|
+
if (errors.length > 0 && errors.every((issue) => issue.code === "602")) {
|
|
645
|
+
return {
|
|
646
|
+
kind: "not_found",
|
|
647
|
+
service: "wsfe",
|
|
648
|
+
operation,
|
|
649
|
+
errors,
|
|
650
|
+
observations: [],
|
|
651
|
+
raw: result
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
if (errors.length > 0) {
|
|
655
|
+
throw createWsfeServiceError(operation, result, errors);
|
|
656
|
+
}
|
|
657
|
+
const raw = toWsfeRecord(result.ResultGet);
|
|
658
|
+
if (!raw) {
|
|
659
|
+
throw new ArcaServiceError("WSFE did not return the consulted voucher", {
|
|
660
|
+
service: "wsfe",
|
|
661
|
+
operation,
|
|
540
662
|
detail: result
|
|
541
663
|
});
|
|
542
664
|
}
|
|
543
665
|
return {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
666
|
+
kind: "found",
|
|
667
|
+
service: "wsfe",
|
|
668
|
+
operation,
|
|
669
|
+
voucher: mapWsfeVoucherInfo(raw),
|
|
670
|
+
observations: [],
|
|
547
671
|
raw: result
|
|
548
672
|
};
|
|
549
673
|
}
|
|
550
674
|
return {
|
|
675
|
+
authorizeVoucherOutcome,
|
|
551
676
|
authorizeVoucher,
|
|
552
677
|
async createNextVoucher({ representedTaxId, data, forceRefresh }) {
|
|
553
678
|
const normalizedInput = normalizeWsfeVoucherInput(data);
|
|
@@ -659,42 +784,14 @@ function createWsfeService(options) {
|
|
|
659
784
|
const raw = result.ResultGet ?? {};
|
|
660
785
|
return mapWsfeQuotation(raw);
|
|
661
786
|
},
|
|
662
|
-
async getVoucherInfo({
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
forceRefresh
|
|
668
|
-
}) {
|
|
669
|
-
const result = await executeWsfeAuthenticatedOperation(
|
|
670
|
-
"FECompConsultar",
|
|
671
|
-
{
|
|
672
|
-
representedTaxId,
|
|
673
|
-
forceRefresh
|
|
674
|
-
},
|
|
675
|
-
{
|
|
676
|
-
FeCompConsReq: {
|
|
677
|
-
CbteNro: number,
|
|
678
|
-
PtoVta: salesPoint,
|
|
679
|
-
CbteTipo: voucherType
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
);
|
|
683
|
-
const raw = result.ResultGet ?? null;
|
|
684
|
-
if (!raw) {
|
|
685
|
-
return null;
|
|
686
|
-
}
|
|
687
|
-
return mapWsfeVoucherInfo(raw);
|
|
688
|
-
}
|
|
787
|
+
async getVoucherInfo(input) {
|
|
788
|
+
const lookup = await lookupVoucher(input);
|
|
789
|
+
return lookup.kind === "found" ? lookup.voucher : null;
|
|
790
|
+
},
|
|
791
|
+
lookupVoucher
|
|
689
792
|
};
|
|
690
793
|
}
|
|
691
794
|
function mapWsfeVoucherInput(input, voucherNumber) {
|
|
692
|
-
const sendsSameForeignCurrencyCancellation = input.currencyId !== "PES" && input.sameCurrencyForeignCancellation === "S";
|
|
693
|
-
if (input.exchangeRate === void 0 && !sendsSameForeignCurrencyCancellation) {
|
|
694
|
-
throw new ArcaInputError(
|
|
695
|
-
"exchangeRate is required unless sameCurrencyForeignCancellation is S for a foreign-currency voucher."
|
|
696
|
-
);
|
|
697
|
-
}
|
|
698
795
|
const data = {
|
|
699
796
|
Concepto: input.concept,
|
|
700
797
|
DocTipo: input.documentType,
|
|
@@ -712,7 +809,7 @@ function mapWsfeVoucherInput(input, voucherNumber) {
|
|
|
712
809
|
PtoVta: input.salesPoint,
|
|
713
810
|
CbteTipo: input.voucherType
|
|
714
811
|
};
|
|
715
|
-
if (
|
|
812
|
+
if (input.exchangeRate !== void 0) {
|
|
716
813
|
data.MonCotiz = input.exchangeRate;
|
|
717
814
|
}
|
|
718
815
|
if (input.receiverVatConditionId !== void 0) {
|
|
@@ -796,6 +893,7 @@ function mapWsfeVoucherInput(input, voucherNumber) {
|
|
|
796
893
|
function normalizeWsfeVoucherInput(input) {
|
|
797
894
|
const {
|
|
798
895
|
voucherDate,
|
|
896
|
+
exchangeRate,
|
|
799
897
|
serviceStartDate,
|
|
800
898
|
serviceEndDate,
|
|
801
899
|
paymentDueDate,
|
|
@@ -803,9 +901,11 @@ function normalizeWsfeVoucherInput(input) {
|
|
|
803
901
|
associatedPeriod,
|
|
804
902
|
...rest
|
|
805
903
|
} = input;
|
|
904
|
+
const normalizedExchangeRate = normalizeWsfeExchangeRate(input, exchangeRate);
|
|
806
905
|
return {
|
|
807
906
|
...rest,
|
|
808
907
|
voucherDate: normalizeWsfeDateInput(voucherDate, "voucherDate"),
|
|
908
|
+
...normalizedExchangeRate === void 0 ? {} : { exchangeRate: normalizedExchangeRate },
|
|
809
909
|
...serviceStartDate === void 0 ? {} : {
|
|
810
910
|
serviceStartDate: normalizeWsfeDateInput(
|
|
811
911
|
serviceStartDate,
|
|
@@ -852,6 +952,30 @@ function normalizeWsfeVoucherInput(input) {
|
|
|
852
952
|
}
|
|
853
953
|
};
|
|
854
954
|
}
|
|
955
|
+
function normalizeWsfeExchangeRate(input, exchangeRate) {
|
|
956
|
+
if (input.currencyId === "PES") {
|
|
957
|
+
if (exchangeRate !== void 0 && exchangeRate !== 1) {
|
|
958
|
+
throw new ArcaInputError(
|
|
959
|
+
"exchangeRate must be 1 when currencyId is PES."
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
return 1;
|
|
963
|
+
}
|
|
964
|
+
if (exchangeRate === void 0) {
|
|
965
|
+
if (input.sameCurrencyForeignCancellation === "S") {
|
|
966
|
+
return void 0;
|
|
967
|
+
}
|
|
968
|
+
throw new ArcaInputError(
|
|
969
|
+
"exchangeRate is required unless sameCurrencyForeignCancellation is S for a foreign-currency voucher."
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
if (!(Number.isFinite(exchangeRate) && exchangeRate > 0)) {
|
|
973
|
+
throw new ArcaInputError(
|
|
974
|
+
"exchangeRate must be a positive finite number for a foreign-currency voucher."
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
return exchangeRate;
|
|
978
|
+
}
|
|
855
979
|
function normalizeWsfeDateInput(value, fieldName) {
|
|
856
980
|
if (typeof value !== "string") {
|
|
857
981
|
throw new ArcaInputError(
|
|
@@ -951,17 +1075,45 @@ function mapWsfeQuotation(raw) {
|
|
|
951
1075
|
};
|
|
952
1076
|
}
|
|
953
1077
|
function mapWsfeVoucherInfo(raw) {
|
|
954
|
-
|
|
1078
|
+
const voucher = {
|
|
955
1079
|
voucherNumber: Number(raw.CbteDesde ?? raw.CbteHasta ?? 0),
|
|
956
|
-
...raw.CbteFch === void 0 ? {} : { voucherDate: String(raw.CbteFch) },
|
|
957
|
-
...raw.PtoVta === void 0 ? {} : { salesPoint: Number(raw.PtoVta) },
|
|
958
|
-
...raw.CbteTipo === void 0 ? {} : { voucherType: Number(raw.CbteTipo) },
|
|
959
|
-
...raw.ImpTotal === void 0 ? {} : { totalAmount: Number(raw.ImpTotal) },
|
|
960
|
-
...raw.Resultado === void 0 ? {} : { result: String(raw.Resultado) },
|
|
961
|
-
...raw.CAE === void 0 ? {} : { cae: String(raw.CAE) },
|
|
962
|
-
...raw.CAEFchVto === void 0 ? {} : { caeExpiry: String(raw.CAEFchVto) },
|
|
963
1080
|
raw
|
|
964
1081
|
};
|
|
1082
|
+
assignWsfeValue(voucher, "voucherDate", normalizeWsfeString(raw.CbteFch));
|
|
1083
|
+
assignWsfeValue(voucher, "salesPoint", normalizeWsfeNumber(raw.PtoVta));
|
|
1084
|
+
assignWsfeValue(voucher, "voucherType", normalizeWsfeNumber(raw.CbteTipo));
|
|
1085
|
+
assignWsfeValue(voucher, "concept", normalizeWsfeNumber(raw.Concepto));
|
|
1086
|
+
assignWsfeValue(voucher, "documentType", normalizeWsfeNumber(raw.DocTipo));
|
|
1087
|
+
assignWsfeValue(voucher, "documentNumber", normalizeWsfeString(raw.DocNro));
|
|
1088
|
+
assignWsfeValue(
|
|
1089
|
+
voucher,
|
|
1090
|
+
"receiverVatConditionId",
|
|
1091
|
+
normalizeWsfeNumber(raw.CondicionIVAReceptorId)
|
|
1092
|
+
);
|
|
1093
|
+
assignWsfeValue(voucher, "totalAmount", normalizeWsfeNumber(raw.ImpTotal));
|
|
1094
|
+
assignWsfeValue(
|
|
1095
|
+
voucher,
|
|
1096
|
+
"nonTaxableAmount",
|
|
1097
|
+
normalizeWsfeNumber(raw.ImpTotConc)
|
|
1098
|
+
);
|
|
1099
|
+
assignWsfeValue(voucher, "netAmount", normalizeWsfeNumber(raw.ImpNeto));
|
|
1100
|
+
assignWsfeValue(voucher, "exemptAmount", normalizeWsfeNumber(raw.ImpOpEx));
|
|
1101
|
+
assignWsfeValue(voucher, "taxAmount", normalizeWsfeNumber(raw.ImpTrib));
|
|
1102
|
+
assignWsfeValue(voucher, "vatAmount", normalizeWsfeNumber(raw.ImpIVA));
|
|
1103
|
+
assignWsfeValue(voucher, "currencyId", normalizeWsfeString(raw.MonId));
|
|
1104
|
+
assignWsfeValue(voucher, "exchangeRate", normalizeWsfeNumber(raw.MonCotiz));
|
|
1105
|
+
assignWsfeValue(voucher, "result", normalizeWsfeString(raw.Resultado));
|
|
1106
|
+
assignWsfeValue(
|
|
1107
|
+
voucher,
|
|
1108
|
+
"cae",
|
|
1109
|
+
normalizeWsfeString(raw.CodAutorizacion ?? raw.CAE)
|
|
1110
|
+
);
|
|
1111
|
+
assignWsfeValue(
|
|
1112
|
+
voucher,
|
|
1113
|
+
"caeExpiry",
|
|
1114
|
+
normalizeWsfeString(raw.FchVto ?? raw.CAEFchVto)
|
|
1115
|
+
);
|
|
1116
|
+
return voucher;
|
|
965
1117
|
}
|
|
966
1118
|
function createWsfeAuth(representedTaxId, token, sign) {
|
|
967
1119
|
return {
|
|
@@ -970,47 +1122,16 @@ function createWsfeAuth(representedTaxId, token, sign) {
|
|
|
970
1122
|
Cuit: Number.parseInt(String(representedTaxId), 10)
|
|
971
1123
|
};
|
|
972
1124
|
}
|
|
973
|
-
function
|
|
1125
|
+
function unwrapWsfeOperationEnvelope(operation, response) {
|
|
974
1126
|
const operationResponse = response[`${operation}Response`];
|
|
975
1127
|
const result = operationResponse?.[`${operation}Result`] ?? response[`${operation}Result`] ?? response;
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
const observationsContainer = detailResponse.Observaciones;
|
|
981
|
-
const observations = normalizeWsfeErrors(observationsContainer?.Obs);
|
|
982
|
-
if (observations.length > 0) {
|
|
983
|
-
const firstObservation = observations[0];
|
|
984
|
-
if (!firstObservation) {
|
|
985
|
-
throw new ArcaServiceError(
|
|
986
|
-
"WSFE returned an empty observation list",
|
|
987
|
-
{
|
|
988
|
-
detail: result
|
|
989
|
-
}
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
|
-
throw new ArcaServiceError(firstObservation.message, {
|
|
993
|
-
serviceCode: firstObservation.code,
|
|
994
|
-
detail: result
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
const errorsContainer = result.Errors;
|
|
1000
|
-
const errors = normalizeWsfeErrors(errorsContainer?.Err);
|
|
1128
|
+
return result;
|
|
1129
|
+
}
|
|
1130
|
+
function throwForWsfeOperationErrors(operation, result) {
|
|
1131
|
+
const errors = extractWsfeGlobalIssues(result, operation);
|
|
1001
1132
|
if (errors.length > 0) {
|
|
1002
|
-
|
|
1003
|
-
if (!firstError) {
|
|
1004
|
-
throw new ArcaServiceError("WSFE returned an empty error list", {
|
|
1005
|
-
detail: result
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
1008
|
-
throw new ArcaServiceError(firstError.message, {
|
|
1009
|
-
serviceCode: firstError.code,
|
|
1010
|
-
detail: result
|
|
1011
|
-
});
|
|
1133
|
+
throw createWsfeServiceError(operation, result, errors);
|
|
1012
1134
|
}
|
|
1013
|
-
return result;
|
|
1014
1135
|
}
|
|
1015
1136
|
function normalizeWsfeDetailResponse(result) {
|
|
1016
1137
|
const detailResponse = result.FeDetResp;
|
|
@@ -1020,17 +1141,248 @@ function normalizeWsfeDetailResponse(result) {
|
|
|
1020
1141
|
}
|
|
1021
1142
|
return rawDetail ?? {};
|
|
1022
1143
|
}
|
|
1023
|
-
function
|
|
1144
|
+
function classifyWsfeAuthorization(result, voucherNumber) {
|
|
1145
|
+
const operation = "FECAESolicitar";
|
|
1146
|
+
const header = toWsfeRecord(result.FeCabResp) ?? {};
|
|
1147
|
+
const detail = normalizeWsfeDetailResponse(result);
|
|
1148
|
+
const headerResult = normalizeWsfeResult(header.Resultado);
|
|
1149
|
+
const detailResult = normalizeWsfeResult(detail.Resultado);
|
|
1150
|
+
const resultCode = detailResult ?? headerResult;
|
|
1151
|
+
const resultLevel = getWsfeResultLevel(headerResult, detailResult);
|
|
1152
|
+
const cae = normalizeWsfeString(detail.CAE);
|
|
1153
|
+
const caeExpiry = normalizeWsfeString(detail.CAEFchVto);
|
|
1154
|
+
const errors = extractWsfeGlobalIssues(result, operation, "header");
|
|
1155
|
+
const observations = extractWsfeObservations(
|
|
1156
|
+
detail,
|
|
1157
|
+
detailResult === "R" ? "business" : "observation"
|
|
1158
|
+
);
|
|
1159
|
+
const hasInfrastructureError = errors.some(
|
|
1160
|
+
(issue) => issue.category === "infrastructure"
|
|
1161
|
+
);
|
|
1162
|
+
const base = {
|
|
1163
|
+
service: "wsfe",
|
|
1164
|
+
operation,
|
|
1165
|
+
results: createWsfeResults(headerResult, detailResult),
|
|
1166
|
+
errors,
|
|
1167
|
+
observations,
|
|
1168
|
+
raw: result
|
|
1169
|
+
};
|
|
1170
|
+
const context = {
|
|
1171
|
+
base,
|
|
1172
|
+
headerResult,
|
|
1173
|
+
detailResult,
|
|
1174
|
+
resultCode,
|
|
1175
|
+
resultLevel,
|
|
1176
|
+
cae,
|
|
1177
|
+
caeExpiry
|
|
1178
|
+
};
|
|
1179
|
+
if (hasContradictoryWsfeResults(context)) {
|
|
1180
|
+
return createWsfeStructuredIndeterminate(context, "contradictory_response");
|
|
1181
|
+
}
|
|
1182
|
+
if (hasInfrastructureError) {
|
|
1183
|
+
return createWsfeStructuredIndeterminate(context, "incomplete_response");
|
|
1184
|
+
}
|
|
1185
|
+
if (isAuthorizedWsfeContext(context)) {
|
|
1186
|
+
return {
|
|
1187
|
+
...base,
|
|
1188
|
+
kind: "authorized",
|
|
1189
|
+
result: "A",
|
|
1190
|
+
resultLevel: "detail",
|
|
1191
|
+
cae: context.cae,
|
|
1192
|
+
caeExpiry: context.caeExpiry,
|
|
1193
|
+
voucherNumber
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
if (isRejectedWsfeDetailContext(context)) {
|
|
1197
|
+
return {
|
|
1198
|
+
...base,
|
|
1199
|
+
kind: "rejected",
|
|
1200
|
+
result: "R",
|
|
1201
|
+
resultLevel: "detail"
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
if (isRejectedWsfeHeaderContext(context)) {
|
|
1205
|
+
return {
|
|
1206
|
+
...base,
|
|
1207
|
+
kind: "rejected",
|
|
1208
|
+
result: "R",
|
|
1209
|
+
resultLevel: "header"
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
return createWsfeStructuredIndeterminate(
|
|
1213
|
+
context,
|
|
1214
|
+
hasWsfeCaeContradiction(context) ? "contradictory_response" : "incomplete_response"
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
function getWsfeResultLevel(headerResult, detailResult) {
|
|
1218
|
+
if (detailResult) {
|
|
1219
|
+
return "detail";
|
|
1220
|
+
}
|
|
1221
|
+
return headerResult ? "header" : void 0;
|
|
1222
|
+
}
|
|
1223
|
+
function hasContradictoryWsfeResults(context) {
|
|
1224
|
+
return Boolean(
|
|
1225
|
+
context.headerResult && context.detailResult && context.headerResult !== context.detailResult
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
function isAuthorizedWsfeContext(context) {
|
|
1229
|
+
return Boolean(
|
|
1230
|
+
context.detailResult === "A" && context.headerResult !== "R" && context.base.errors.length === 0 && context.cae && context.caeExpiry
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
function isRejectedWsfeDetailContext(context) {
|
|
1234
|
+
return context.detailResult === "R" && context.headerResult !== "A" && !context.cae;
|
|
1235
|
+
}
|
|
1236
|
+
function isRejectedWsfeHeaderContext(context) {
|
|
1237
|
+
return context.headerResult === "R" && context.detailResult === void 0 && !context.cae && context.base.errors.length > 0 && context.base.errors.every((issue) => issue.category === "business");
|
|
1238
|
+
}
|
|
1239
|
+
function hasWsfeCaeContradiction(context) {
|
|
1240
|
+
return (context.resultCode === "A" || context.resultCode === "R") && Boolean(context.cae);
|
|
1241
|
+
}
|
|
1242
|
+
function createWsfeStructuredIndeterminate(context, reason) {
|
|
1243
|
+
const outcome = {
|
|
1244
|
+
...context.base,
|
|
1245
|
+
kind: "indeterminate",
|
|
1246
|
+
reason
|
|
1247
|
+
};
|
|
1248
|
+
assignWsfeValue(outcome, "result", context.resultCode);
|
|
1249
|
+
assignWsfeValue(outcome, "resultLevel", context.resultLevel);
|
|
1250
|
+
assignWsfeValue(outcome, "cae", context.cae);
|
|
1251
|
+
assignWsfeValue(outcome, "caeExpiry", context.caeExpiry);
|
|
1252
|
+
return outcome;
|
|
1253
|
+
}
|
|
1254
|
+
function createWsfeResults(headerResult, detailResult) {
|
|
1255
|
+
const results = {};
|
|
1256
|
+
assignWsfeValue(results, "header", headerResult);
|
|
1257
|
+
assignWsfeValue(results, "detail", detailResult);
|
|
1258
|
+
return results;
|
|
1259
|
+
}
|
|
1260
|
+
function createWsfeIndeterminateOutcome(error) {
|
|
1261
|
+
return {
|
|
1262
|
+
kind: "indeterminate",
|
|
1263
|
+
service: "wsfe",
|
|
1264
|
+
operation: "FECAESolicitar",
|
|
1265
|
+
results: {},
|
|
1266
|
+
reason: getArcaIndeterminateReason(error),
|
|
1267
|
+
errors: [],
|
|
1268
|
+
observations: []
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
function getArcaIndeterminateReason(error) {
|
|
1272
|
+
if (error instanceof ArcaTransportError) {
|
|
1273
|
+
return "transport_error";
|
|
1274
|
+
}
|
|
1275
|
+
if (error instanceof ArcaSoapFaultError) {
|
|
1276
|
+
return "soap_fault";
|
|
1277
|
+
}
|
|
1278
|
+
if (error instanceof ArcaInvalidSoapResponseError) {
|
|
1279
|
+
return "invalid_response";
|
|
1280
|
+
}
|
|
1281
|
+
return "unexpected_error";
|
|
1282
|
+
}
|
|
1283
|
+
function createWsfeOutcomeError(outcome) {
|
|
1284
|
+
const issues = [...outcome.errors, ...outcome.observations];
|
|
1285
|
+
const firstIssue = issues[0];
|
|
1286
|
+
const message = firstIssue ? formatWsfeIssue(firstIssue) : outcome.kind === "rejected" ? "WSFE rejected the voucher authorization" : outcome.result === "A" ? "WSFE did not return CAE authorization data" : "WSFE did not return conclusive voucher authorization data";
|
|
1287
|
+
return new ArcaServiceError(message, {
|
|
1288
|
+
service: "wsfe",
|
|
1289
|
+
operation: outcome.operation,
|
|
1290
|
+
...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
|
|
1291
|
+
...outcome.result === void 0 ? {} : { result: outcome.result },
|
|
1292
|
+
...outcome.resultLevel === void 0 ? {} : { resultLevel: outcome.resultLevel },
|
|
1293
|
+
results: outcome.results,
|
|
1294
|
+
...outcome.kind === "indeterminate" && outcome.cae ? { cae: outcome.cae } : {},
|
|
1295
|
+
issues,
|
|
1296
|
+
detail: outcome.raw
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
function createWsfeServiceError(operation, result, issues) {
|
|
1300
|
+
const firstIssue = issues[0];
|
|
1301
|
+
return new ArcaServiceError(
|
|
1302
|
+
firstIssue ? formatWsfeIssue(firstIssue) : "WSFE returned a service error",
|
|
1303
|
+
{
|
|
1304
|
+
service: "wsfe",
|
|
1305
|
+
operation,
|
|
1306
|
+
...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
|
|
1307
|
+
issues,
|
|
1308
|
+
detail: result
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
function extractWsfeGlobalIssues(result, operation, resultLevel) {
|
|
1313
|
+
const errorsContainer = toWsfeRecord(result.Errors);
|
|
1314
|
+
return normalizeWsfeIssueEntries(errorsContainer?.Err).map((entry) => ({
|
|
1315
|
+
service: "wsfe",
|
|
1316
|
+
operation,
|
|
1317
|
+
source: "error",
|
|
1318
|
+
category: operation === "FECAESolicitar" && WSFE_AUTHORIZATION_INFRASTRUCTURE_CODES.has(entry.code ?? "") ? "infrastructure" : operation === "FECAESolicitar" ? "business" : "unknown",
|
|
1319
|
+
...entry.code === void 0 ? {} : { code: entry.code },
|
|
1320
|
+
message: entry.message,
|
|
1321
|
+
...resultLevel === void 0 ? {} : { resultLevel }
|
|
1322
|
+
}));
|
|
1323
|
+
}
|
|
1324
|
+
function extractWsfeObservations(detail, category) {
|
|
1325
|
+
const observationsContainer = toWsfeRecord(detail.Observaciones);
|
|
1326
|
+
return normalizeWsfeIssueEntries(observationsContainer?.Obs).map((entry) => ({
|
|
1327
|
+
service: "wsfe",
|
|
1328
|
+
operation: "FECAESolicitar",
|
|
1329
|
+
source: "observation",
|
|
1330
|
+
category,
|
|
1331
|
+
...entry.code === void 0 ? {} : { code: entry.code },
|
|
1332
|
+
message: entry.message,
|
|
1333
|
+
resultLevel: "detail"
|
|
1334
|
+
}));
|
|
1335
|
+
}
|
|
1336
|
+
function normalizeWsfeIssueEntries(rawErrors) {
|
|
1024
1337
|
const entries = Array.isArray(rawErrors) ? rawErrors : rawErrors ? [rawErrors] : [];
|
|
1025
1338
|
return entries.map((entry) => entry).map((entry) => {
|
|
1026
|
-
const code = entry.Code ?? entry.code
|
|
1339
|
+
const code = entry.Code ?? entry.code;
|
|
1027
1340
|
const message = entry.Msg ?? entry.msg ?? "Unknown WSFE error";
|
|
1028
1341
|
return {
|
|
1029
|
-
code: String(code),
|
|
1030
|
-
message:
|
|
1342
|
+
...code === void 0 ? {} : { code: String(code) },
|
|
1343
|
+
message: String(message)
|
|
1031
1344
|
};
|
|
1032
1345
|
});
|
|
1033
1346
|
}
|
|
1347
|
+
function formatWsfeIssue(issue) {
|
|
1348
|
+
return issue.code ? `(${issue.code}) ${issue.message}` : issue.message;
|
|
1349
|
+
}
|
|
1350
|
+
function normalizeWsfeResult(value) {
|
|
1351
|
+
if (typeof value !== "string") {
|
|
1352
|
+
return void 0;
|
|
1353
|
+
}
|
|
1354
|
+
const normalized = value.trim().toUpperCase();
|
|
1355
|
+
return normalized || void 0;
|
|
1356
|
+
}
|
|
1357
|
+
function normalizeWsfeString(value) {
|
|
1358
|
+
if (value === void 0 || value === null) {
|
|
1359
|
+
return void 0;
|
|
1360
|
+
}
|
|
1361
|
+
const normalized = String(value).trim();
|
|
1362
|
+
return normalized || void 0;
|
|
1363
|
+
}
|
|
1364
|
+
function normalizeWsfeNumber(value) {
|
|
1365
|
+
if (value === void 0 || value === null || value === "") {
|
|
1366
|
+
return void 0;
|
|
1367
|
+
}
|
|
1368
|
+
const normalized = Number(value);
|
|
1369
|
+
return Number.isFinite(normalized) ? normalized : void 0;
|
|
1370
|
+
}
|
|
1371
|
+
function assignWsfeValue(target, key, value) {
|
|
1372
|
+
if (value !== void 0) {
|
|
1373
|
+
target[key] = value;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
function toWsfeRecord(value) {
|
|
1377
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1378
|
+
}
|
|
1379
|
+
var WSFE_AUTHORIZATION_INFRASTRUCTURE_CODES = /* @__PURE__ */ new Set([
|
|
1380
|
+
"500",
|
|
1381
|
+
"501",
|
|
1382
|
+
"502",
|
|
1383
|
+
"600",
|
|
1384
|
+
"601"
|
|
1385
|
+
]);
|
|
1034
1386
|
function getWsfeResultEntries(result, key) {
|
|
1035
1387
|
const rawEntries = result.ResultGet?.[key];
|
|
1036
1388
|
if (!rawEntries) {
|
|
@@ -1043,145 +1395,227 @@ function getWsfeResultEntries(result, key) {
|
|
|
1043
1395
|
|
|
1044
1396
|
// src/services/wsmtxca.ts
|
|
1045
1397
|
function createWsmtxcaService(options) {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
}
|
|
1065
|
-
});
|
|
1066
|
-
const raw = unwrapWsmtxcaOperationResponse(
|
|
1067
|
-
response.result,
|
|
1068
|
-
"autorizarComprobante"
|
|
1069
|
-
);
|
|
1070
|
-
const authorizationPayload = extractWsmtxcaAuthorizationPayload(raw);
|
|
1071
|
-
const messages = extractWsmtxcaMessages(raw);
|
|
1072
|
-
const resultado = raw.resultado ?? authorizationPayload.resultado;
|
|
1073
|
-
const caeValue = authorizationPayload.CAE ?? authorizationPayload.codigoAutorizacion ?? raw.codigoAutorizacion;
|
|
1074
|
-
if (resultado === "R" || caeValue == null) {
|
|
1075
|
-
throw new ArcaServiceError(
|
|
1076
|
-
messages.join(" | ") || "WSMTXCA rejected the voucher authorization",
|
|
1077
|
-
{ detail: raw }
|
|
1078
|
-
);
|
|
1398
|
+
async function executeWsmtxcaAuthenticatedOperation(operation, input, body = {}, retries) {
|
|
1399
|
+
const auth = await options.auth.login("wsmtxca", {
|
|
1400
|
+
representedTaxId: input.representedTaxId,
|
|
1401
|
+
forceRefresh: input.forceRefresh
|
|
1402
|
+
});
|
|
1403
|
+
const response = await options.soap.execute({
|
|
1404
|
+
service: "wsmtxca",
|
|
1405
|
+
operation,
|
|
1406
|
+
...retries === void 0 ? {} : { retries },
|
|
1407
|
+
bodyElementName: `${operation}Request`,
|
|
1408
|
+
bodyElementNamespaceMode: "prefix",
|
|
1409
|
+
body: {
|
|
1410
|
+
...body,
|
|
1411
|
+
authRequest: createWsmtxcaAuth(
|
|
1412
|
+
input.representedTaxId ?? options.config.taxId,
|
|
1413
|
+
auth.token,
|
|
1414
|
+
auth.sign
|
|
1415
|
+
)
|
|
1079
1416
|
}
|
|
1417
|
+
});
|
|
1418
|
+
return unwrapWsmtxcaOperationResponse(response.result, operation);
|
|
1419
|
+
}
|
|
1420
|
+
async function executeWsmtxcaAuthorization({
|
|
1421
|
+
representedTaxId,
|
|
1422
|
+
data,
|
|
1423
|
+
forceRefresh
|
|
1424
|
+
}) {
|
|
1425
|
+
if (Object.hasOwn(data, "authRequest")) {
|
|
1426
|
+
throw new ArcaInputError(
|
|
1427
|
+
'WSMTXCA authorization data cannot include the reserved top-level field "authRequest".'
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
try {
|
|
1431
|
+
const raw = await executeWsmtxcaAuthenticatedOperation(
|
|
1432
|
+
"autorizarComprobante",
|
|
1433
|
+
{ representedTaxId, forceRefresh },
|
|
1434
|
+
data,
|
|
1435
|
+
0
|
|
1436
|
+
);
|
|
1437
|
+
return { outcome: classifyWsmtxcaAuthorization(raw) };
|
|
1438
|
+
} catch (error) {
|
|
1080
1439
|
return {
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
authorizationPayload.fechaVencimientoCAE ?? authorizationPayload.fechaVencimiento ?? raw.fechaVencimiento
|
|
1084
|
-
),
|
|
1085
|
-
voucherNumber: parseWsmtxcaVoucherNumber(
|
|
1086
|
-
authorizationPayload.numeroComprobante ?? raw.numeroComprobante,
|
|
1087
|
-
"WSMTXCA did not return the authorized voucher number",
|
|
1088
|
-
raw
|
|
1089
|
-
),
|
|
1090
|
-
messages,
|
|
1091
|
-
raw
|
|
1440
|
+
outcome: createWsmtxcaIndeterminateOutcome(error),
|
|
1441
|
+
error
|
|
1092
1442
|
};
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
async function authorizeVoucherOutcome(input) {
|
|
1446
|
+
return (await executeWsmtxcaAuthorization(input)).outcome;
|
|
1447
|
+
}
|
|
1448
|
+
async function authorizeVoucher(input) {
|
|
1449
|
+
const execution = await executeWsmtxcaAuthorization(input);
|
|
1450
|
+
if (execution.error) {
|
|
1451
|
+
throw execution.error;
|
|
1452
|
+
}
|
|
1453
|
+
if (execution.outcome.kind !== "authorized") {
|
|
1454
|
+
throw createWsmtxcaOutcomeError(execution.outcome);
|
|
1455
|
+
}
|
|
1456
|
+
const { outcome } = execution;
|
|
1457
|
+
return {
|
|
1458
|
+
cae: outcome.cae,
|
|
1459
|
+
...outcome.caeExpiry === void 0 ? {} : { caeExpiry: outcome.caeExpiry },
|
|
1460
|
+
voucherNumber: outcome.voucherNumber,
|
|
1461
|
+
messages: formatWsmtxcaIssues([
|
|
1462
|
+
...outcome.errors,
|
|
1463
|
+
...outcome.observations
|
|
1464
|
+
]),
|
|
1465
|
+
raw: outcome.raw ?? {}
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
async function getLastAuthorizedVoucher({
|
|
1469
|
+
representedTaxId,
|
|
1470
|
+
voucherType,
|
|
1471
|
+
salesPoint,
|
|
1472
|
+
forceRefresh
|
|
1473
|
+
}) {
|
|
1474
|
+
const operation = "consultarUltimoComprobanteAutorizado";
|
|
1475
|
+
const raw = await executeWsmtxcaAuthenticatedOperation(
|
|
1476
|
+
operation,
|
|
1477
|
+
{ representedTaxId, forceRefresh },
|
|
1478
|
+
{
|
|
1479
|
+
consultaUltimoComprobanteAutorizadoRequest: {
|
|
1480
|
+
codigoTipoComprobante: voucherType,
|
|
1481
|
+
numeroPuntoVenta: salesPoint
|
|
1119
1482
|
}
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1483
|
+
}
|
|
1484
|
+
);
|
|
1485
|
+
const errors = extractWsmtxcaIssues(raw, operation, "error");
|
|
1486
|
+
if (errors.length > 0 && errors.every((issue) => issue.code === "1502")) {
|
|
1487
|
+
return { voucherNumber: 0, raw };
|
|
1488
|
+
}
|
|
1489
|
+
if (errors.length > 0) {
|
|
1490
|
+
throw createWsmtxcaServiceError(operation, raw, errors);
|
|
1491
|
+
}
|
|
1492
|
+
return {
|
|
1493
|
+
voucherNumber: parseWsmtxcaVoucherNumber(
|
|
1494
|
+
raw.numeroComprobante ?? raw.cbteNro ?? raw.nroComprobante,
|
|
1495
|
+
"WSMTXCA did not return the last authorized voucher number",
|
|
1496
|
+
raw,
|
|
1497
|
+
true
|
|
1498
|
+
),
|
|
1499
|
+
raw
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
async function getSalesPoints({
|
|
1503
|
+
representedTaxId,
|
|
1504
|
+
forceRefresh
|
|
1505
|
+
}) {
|
|
1506
|
+
const raw = await executeWsmtxcaAuthenticatedOperation(
|
|
1507
|
+
"consultarPuntosVenta",
|
|
1508
|
+
{ representedTaxId, forceRefresh }
|
|
1509
|
+
);
|
|
1510
|
+
const rawSalesPoints = toRecord(raw.arrayPuntosVenta)?.puntoVenta;
|
|
1511
|
+
const entries = Array.isArray(rawSalesPoints) ? rawSalesPoints : rawSalesPoints ? [rawSalesPoints] : [];
|
|
1512
|
+
const salesPoints = entries.flatMap((entry) => {
|
|
1513
|
+
const record = toRecord(entry);
|
|
1514
|
+
const number = parseOptionalPositiveInteger(record?.numeroPuntoVenta);
|
|
1515
|
+
if (number === void 0) {
|
|
1516
|
+
return [];
|
|
1517
|
+
}
|
|
1518
|
+
const deletedAt = normalizeWsmtxcaResponseDate(record?.fechaBaja);
|
|
1519
|
+
return [
|
|
1520
|
+
{
|
|
1521
|
+
number,
|
|
1522
|
+
blocked: String(record?.bloqueado ?? "N").toUpperCase() === "S",
|
|
1523
|
+
...deletedAt === void 0 ? {} : { deletedAt }
|
|
1524
|
+
}
|
|
1525
|
+
];
|
|
1526
|
+
});
|
|
1527
|
+
return { salesPoints, raw };
|
|
1528
|
+
}
|
|
1529
|
+
async function lookupVoucher({
|
|
1530
|
+
representedTaxId,
|
|
1531
|
+
voucherType,
|
|
1532
|
+
salesPoint,
|
|
1533
|
+
voucherNumber,
|
|
1534
|
+
forceRefresh
|
|
1535
|
+
}) {
|
|
1536
|
+
const operation = "consultarComprobante";
|
|
1537
|
+
const raw = await executeWsmtxcaAuthenticatedOperation(
|
|
1538
|
+
operation,
|
|
1539
|
+
{ representedTaxId, forceRefresh },
|
|
1540
|
+
{
|
|
1541
|
+
consultaComprobanteRequest: {
|
|
1542
|
+
codigoTipoComprobante: voucherType,
|
|
1543
|
+
numeroPuntoVenta: salesPoint,
|
|
1544
|
+
numeroComprobante: voucherNumber
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
);
|
|
1548
|
+
const errors = extractWsmtxcaIssues(raw, operation, "error");
|
|
1549
|
+
const observations = extractWsmtxcaIssues(raw, operation, "observation");
|
|
1550
|
+
if (errors.length > 0 && errors.every((issue) => issue.code === "1503")) {
|
|
1125
1551
|
return {
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1552
|
+
kind: "not_found",
|
|
1553
|
+
service: "wsmtxca",
|
|
1554
|
+
operation,
|
|
1555
|
+
errors,
|
|
1556
|
+
observations,
|
|
1131
1557
|
raw
|
|
1132
1558
|
};
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
service: "wsmtxca",
|
|
1147
|
-
operation: "consultarComprobante",
|
|
1148
|
-
bodyElementName: "consultarComprobanteRequest",
|
|
1149
|
-
bodyElementNamespaceMode: "prefix",
|
|
1150
|
-
body: {
|
|
1151
|
-
authRequest: createWsmtxcaAuth(
|
|
1152
|
-
representedTaxId ?? options.config.taxId,
|
|
1153
|
-
auth.token,
|
|
1154
|
-
auth.sign
|
|
1155
|
-
),
|
|
1156
|
-
consultaComprobanteRequest: {
|
|
1157
|
-
codigoTipoComprobante: voucherType,
|
|
1158
|
-
numeroPuntoVenta: salesPoint,
|
|
1159
|
-
numeroComprobante: voucherNumber
|
|
1160
|
-
}
|
|
1559
|
+
}
|
|
1560
|
+
if (errors.length > 0) {
|
|
1561
|
+
throw createWsmtxcaServiceError(operation, raw, errors);
|
|
1562
|
+
}
|
|
1563
|
+
const voucher = extractWsmtxcaVoucherPayload(raw);
|
|
1564
|
+
if (voucher === raw && !toRecord(raw.comprobante)) {
|
|
1565
|
+
throw new ArcaServiceError(
|
|
1566
|
+
"WSMTXCA did not return the voucher issue date",
|
|
1567
|
+
{
|
|
1568
|
+
service: "wsmtxca",
|
|
1569
|
+
operation,
|
|
1570
|
+
issues: observations,
|
|
1571
|
+
detail: raw
|
|
1161
1572
|
}
|
|
1162
|
-
});
|
|
1163
|
-
const raw = unwrapWsmtxcaOperationResponse(
|
|
1164
|
-
response.result,
|
|
1165
|
-
"consultarComprobante"
|
|
1166
1573
|
);
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1574
|
+
}
|
|
1575
|
+
return {
|
|
1576
|
+
kind: "found",
|
|
1577
|
+
service: "wsmtxca",
|
|
1578
|
+
operation,
|
|
1579
|
+
voucher: mapWsmtxcaVoucherInfo(voucher),
|
|
1580
|
+
observations,
|
|
1581
|
+
raw
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
async function getVoucher(input) {
|
|
1585
|
+
const lookup = await lookupVoucher(input);
|
|
1586
|
+
if (lookup.kind === "not_found") {
|
|
1587
|
+
throw createWsmtxcaServiceError(
|
|
1588
|
+
lookup.operation,
|
|
1589
|
+
lookup.raw,
|
|
1590
|
+
lookup.errors
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
const invoiceDate = lookup.voucher.invoiceDate;
|
|
1594
|
+
if (!invoiceDate) {
|
|
1595
|
+
throw new ArcaServiceError(
|
|
1596
|
+
formatWsmtxcaIssues(lookup.observations)[0] ?? "WSMTXCA did not return the voucher issue date",
|
|
1597
|
+
{
|
|
1598
|
+
service: "wsmtxca",
|
|
1599
|
+
operation: lookup.operation,
|
|
1600
|
+
issues: lookup.observations,
|
|
1601
|
+
detail: lookup.raw
|
|
1602
|
+
}
|
|
1171
1603
|
);
|
|
1172
|
-
if (!invoiceDate) {
|
|
1173
|
-
throw new ArcaServiceError(
|
|
1174
|
-
messages[0] ?? "WSMTXCA did not return the voucher issue date",
|
|
1175
|
-
{ detail: raw }
|
|
1176
|
-
);
|
|
1177
|
-
}
|
|
1178
|
-
return {
|
|
1179
|
-
invoiceDate,
|
|
1180
|
-
voucher,
|
|
1181
|
-
messages,
|
|
1182
|
-
raw
|
|
1183
|
-
};
|
|
1184
1604
|
}
|
|
1605
|
+
return {
|
|
1606
|
+
invoiceDate,
|
|
1607
|
+
voucher: lookup.voucher.raw,
|
|
1608
|
+
messages: formatWsmtxcaIssues(lookup.observations),
|
|
1609
|
+
raw: lookup.raw
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
return {
|
|
1613
|
+
authorizeVoucherOutcome,
|
|
1614
|
+
authorizeVoucher,
|
|
1615
|
+
getLastAuthorizedVoucher,
|
|
1616
|
+
getSalesPoints,
|
|
1617
|
+
lookupVoucher,
|
|
1618
|
+
getVoucher
|
|
1185
1619
|
};
|
|
1186
1620
|
}
|
|
1187
1621
|
function createWsmtxcaAuth(representedTaxId, token, sign) {
|
|
@@ -1192,7 +1626,7 @@ function createWsmtxcaAuth(representedTaxId, token, sign) {
|
|
|
1192
1626
|
};
|
|
1193
1627
|
}
|
|
1194
1628
|
function toRecord(value) {
|
|
1195
|
-
return value && typeof value === "object" ? value : void 0;
|
|
1629
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1196
1630
|
}
|
|
1197
1631
|
function unwrapWsmtxcaOperationResponse(response, operation) {
|
|
1198
1632
|
const responseRecord = toRecord(response) ?? {};
|
|
@@ -1202,6 +1636,9 @@ function unwrapWsmtxcaOperationResponse(response, operation) {
|
|
|
1202
1636
|
if (operation === "consultarComprobante") {
|
|
1203
1637
|
return toRecord(responseRecord.consultarComprobanteResponse) ?? toRecord(responseRecord.consultaComprobanteResponse) ?? toRecord(responseRecord.consultarComprobanteResult) ?? responseRecord;
|
|
1204
1638
|
}
|
|
1639
|
+
if (operation === "consultarPuntosVenta") {
|
|
1640
|
+
return toRecord(responseRecord.consultarPuntosVentaResponse) ?? toRecord(responseRecord.consultarPuntosVentaResult) ?? responseRecord;
|
|
1641
|
+
}
|
|
1205
1642
|
return toRecord(responseRecord.consultarUltimoComprobanteAutorizadoResponse) ?? toRecord(responseRecord.consultaUltimoComprobanteAutorizadoResponse) ?? toRecord(responseRecord.consultarUltimoComprobanteAutorizadoResult) ?? responseRecord;
|
|
1206
1643
|
}
|
|
1207
1644
|
function extractWsmtxcaAuthorizationPayload(raw) {
|
|
@@ -1210,42 +1647,291 @@ function extractWsmtxcaAuthorizationPayload(raw) {
|
|
|
1210
1647
|
function extractWsmtxcaVoucherPayload(raw) {
|
|
1211
1648
|
return toRecord(raw.comprobanteResponse) ?? toRecord(raw.comprobante) ?? toRecord(raw.cmp) ?? raw;
|
|
1212
1649
|
}
|
|
1213
|
-
function
|
|
1214
|
-
const
|
|
1215
|
-
const
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1650
|
+
function classifyWsmtxcaAuthorization(raw) {
|
|
1651
|
+
const operation = "autorizarComprobante";
|
|
1652
|
+
const payload = extractWsmtxcaAuthorizationPayload(raw);
|
|
1653
|
+
const result = normalizeWsmtxcaResult(raw.resultado ?? payload.resultado);
|
|
1654
|
+
const cae = normalizeWsmtxcaString(
|
|
1655
|
+
payload.CAE ?? payload.codigoAutorizacion ?? raw.codigoAutorizacion
|
|
1656
|
+
);
|
|
1657
|
+
const caeExpiry = normalizeWsmtxcaResponseDate(
|
|
1658
|
+
payload.fechaVencimientoCAE ?? payload.fechaVencimiento ?? raw.fechaVencimiento
|
|
1659
|
+
);
|
|
1660
|
+
const voucherNumber = parseOptionalPositiveInteger(
|
|
1661
|
+
payload.numeroComprobante ?? raw.numeroComprobante
|
|
1662
|
+
);
|
|
1663
|
+
const errors = extractWsmtxcaIssues(raw, operation, "error");
|
|
1664
|
+
const observations = extractWsmtxcaIssues(raw, operation, "observation");
|
|
1665
|
+
const base = {
|
|
1666
|
+
service: "wsmtxca",
|
|
1667
|
+
operation,
|
|
1668
|
+
results: createWsmtxcaResults(result),
|
|
1669
|
+
errors,
|
|
1670
|
+
observations,
|
|
1671
|
+
raw
|
|
1672
|
+
};
|
|
1673
|
+
if ((result === "A" || result === "O") && cae && voucherNumber !== void 0 && errors.length === 0) {
|
|
1674
|
+
return {
|
|
1675
|
+
...base,
|
|
1676
|
+
kind: "authorized",
|
|
1677
|
+
result,
|
|
1678
|
+
resultLevel: "operation",
|
|
1679
|
+
cae,
|
|
1680
|
+
...caeExpiry === void 0 ? {} : { caeExpiry },
|
|
1681
|
+
voucherNumber
|
|
1682
|
+
};
|
|
1683
|
+
}
|
|
1684
|
+
if (result === "R" && !cae && errors.length > 0) {
|
|
1685
|
+
return {
|
|
1686
|
+
...base,
|
|
1687
|
+
kind: "rejected",
|
|
1688
|
+
result: "R",
|
|
1689
|
+
resultLevel: "operation"
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
const outcome = {
|
|
1693
|
+
...base,
|
|
1694
|
+
kind: "indeterminate",
|
|
1695
|
+
reason: result === "R" && Boolean(cae) || (result === "A" || result === "O") && Boolean(errors.length) ? "contradictory_response" : "incomplete_response",
|
|
1696
|
+
...result === void 0 ? {} : { result },
|
|
1697
|
+
...result === void 0 ? {} : { resultLevel: "operation" }
|
|
1698
|
+
};
|
|
1699
|
+
assignWsmtxcaValue(outcome, "cae", cae);
|
|
1700
|
+
assignWsmtxcaValue(outcome, "caeExpiry", caeExpiry);
|
|
1701
|
+
assignWsmtxcaValue(outcome, "voucherNumber", voucherNumber);
|
|
1702
|
+
return outcome;
|
|
1703
|
+
}
|
|
1704
|
+
function createWsmtxcaIndeterminateOutcome(error) {
|
|
1705
|
+
return {
|
|
1706
|
+
kind: "indeterminate",
|
|
1707
|
+
service: "wsmtxca",
|
|
1708
|
+
operation: "autorizarComprobante",
|
|
1709
|
+
results: {},
|
|
1710
|
+
reason: getWsmtxcaIndeterminateReason(error),
|
|
1711
|
+
errors: [],
|
|
1712
|
+
observations: []
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
function getWsmtxcaIndeterminateReason(error) {
|
|
1716
|
+
if (error instanceof ArcaTransportError) {
|
|
1717
|
+
return "transport_error";
|
|
1718
|
+
}
|
|
1719
|
+
if (error instanceof ArcaSoapFaultError) {
|
|
1720
|
+
return "soap_fault";
|
|
1721
|
+
}
|
|
1722
|
+
if (error instanceof ArcaInvalidSoapResponseError) {
|
|
1723
|
+
return "invalid_response";
|
|
1724
|
+
}
|
|
1725
|
+
return "unexpected_error";
|
|
1726
|
+
}
|
|
1727
|
+
function createWsmtxcaOutcomeError(outcome) {
|
|
1728
|
+
const issues = [...outcome.errors, ...outcome.observations];
|
|
1729
|
+
const messages = formatWsmtxcaIssues(issues);
|
|
1730
|
+
const firstIssue = issues[0];
|
|
1731
|
+
return new ArcaServiceError(
|
|
1732
|
+
messages.join(" | ") || (outcome.kind === "rejected" ? "WSMTXCA rejected the voucher authorization" : "WSMTXCA did not return conclusive voucher authorization data"),
|
|
1733
|
+
{
|
|
1734
|
+
service: "wsmtxca",
|
|
1735
|
+
operation: outcome.operation,
|
|
1736
|
+
...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
|
|
1737
|
+
...outcome.result === void 0 ? {} : { result: outcome.result },
|
|
1738
|
+
...outcome.resultLevel === void 0 ? {} : { resultLevel: outcome.resultLevel },
|
|
1739
|
+
results: outcome.results,
|
|
1740
|
+
...outcome.kind === "indeterminate" && outcome.cae ? { cae: outcome.cae } : {},
|
|
1741
|
+
issues,
|
|
1742
|
+
detail: outcome.raw
|
|
1222
1743
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
function createWsmtxcaResults(operationResult) {
|
|
1747
|
+
const results = {};
|
|
1748
|
+
assignWsmtxcaValue(results, "operation", operationResult);
|
|
1749
|
+
return results;
|
|
1750
|
+
}
|
|
1751
|
+
function createWsmtxcaServiceError(operation, raw, issues) {
|
|
1752
|
+
const firstIssue = issues[0];
|
|
1753
|
+
return new ArcaServiceError(
|
|
1754
|
+
formatWsmtxcaIssues(issues).join(" | ") || "WSMTXCA returned a service error",
|
|
1755
|
+
{
|
|
1756
|
+
service: "wsmtxca",
|
|
1757
|
+
operation,
|
|
1758
|
+
...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
|
|
1759
|
+
issues,
|
|
1760
|
+
detail: raw
|
|
1225
1761
|
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
function extractWsmtxcaIssues(raw, operation, source) {
|
|
1765
|
+
const container = toRecord(
|
|
1766
|
+
source === "error" ? raw.arrayErrores : raw.arrayObservaciones
|
|
1767
|
+
);
|
|
1768
|
+
return normalizeWsmtxcaIssueEntries(container?.codigoDescripcion).map(
|
|
1769
|
+
(entry) => ({
|
|
1770
|
+
service: "wsmtxca",
|
|
1771
|
+
operation,
|
|
1772
|
+
source,
|
|
1773
|
+
category: source === "observation" ? "observation" : operation === "autorizarComprobante" ? "business" : "unknown",
|
|
1774
|
+
...entry.code === void 0 ? {} : { code: entry.code },
|
|
1775
|
+
message: entry.message,
|
|
1776
|
+
...operation === "autorizarComprobante" ? { resultLevel: "operation" } : {}
|
|
1777
|
+
})
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
function normalizeWsmtxcaIssueEntries(value) {
|
|
1781
|
+
const entries = Array.isArray(value) ? value : value ? [value] : [];
|
|
1782
|
+
return entries.map((entry) => {
|
|
1783
|
+
const record = toRecord(entry) ?? {};
|
|
1784
|
+
const code = record.codigo;
|
|
1785
|
+
const description = record.descripcion;
|
|
1786
|
+
return {
|
|
1787
|
+
...code === void 0 || code === null ? {} : { code: String(code) },
|
|
1788
|
+
message: description === void 0 || description === null ? "Unknown WSMTXCA issue" : String(description)
|
|
1789
|
+
};
|
|
1232
1790
|
});
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1791
|
+
}
|
|
1792
|
+
function formatWsmtxcaIssues(issues) {
|
|
1793
|
+
return issues.map((issue) => {
|
|
1794
|
+
const prefix = issue.source === "error" ? "Error" : "Obs";
|
|
1795
|
+
return `${prefix}${issue.code ? ` ${issue.code}` : ""}: ${issue.message}`;
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
function mapWsmtxcaVoucherInfo(raw) {
|
|
1799
|
+
const voucher = { raw };
|
|
1800
|
+
const invoiceDate = normalizeWsmtxcaResponseDate(
|
|
1801
|
+
raw.fechaEmision ?? raw.fecha ?? raw.CbteFch
|
|
1802
|
+
);
|
|
1803
|
+
const cae = normalizeWsmtxcaString(raw.codigoAutorizacion ?? raw.CAE);
|
|
1804
|
+
const caeExpiry = normalizeWsmtxcaResponseDate(
|
|
1805
|
+
raw.fechaVencimiento ?? raw.fechaVencimientoCAE
|
|
1806
|
+
);
|
|
1807
|
+
const vatAmount = sumWsmtxcaVatAmounts(raw.arraySubtotalesIVA);
|
|
1808
|
+
assignWsmtxcaValue(
|
|
1809
|
+
voucher,
|
|
1810
|
+
"voucherNumber",
|
|
1811
|
+
parseOptionalPositiveInteger(raw.numeroComprobante)
|
|
1812
|
+
);
|
|
1813
|
+
assignWsmtxcaValue(voucher, "invoiceDate", invoiceDate);
|
|
1814
|
+
assignWsmtxcaValue(
|
|
1815
|
+
voucher,
|
|
1816
|
+
"salesPoint",
|
|
1817
|
+
parseOptionalPositiveInteger(raw.numeroPuntoVenta)
|
|
1818
|
+
);
|
|
1819
|
+
assignWsmtxcaValue(
|
|
1820
|
+
voucher,
|
|
1821
|
+
"voucherType",
|
|
1822
|
+
parseOptionalPositiveInteger(raw.codigoTipoComprobante)
|
|
1823
|
+
);
|
|
1824
|
+
assignWsmtxcaValue(
|
|
1825
|
+
voucher,
|
|
1826
|
+
"concept",
|
|
1827
|
+
parseOptionalNumber(raw.codigoConcepto)
|
|
1828
|
+
);
|
|
1829
|
+
assignWsmtxcaValue(
|
|
1830
|
+
voucher,
|
|
1831
|
+
"documentType",
|
|
1832
|
+
parseOptionalNumber(raw.codigoTipoDocumento)
|
|
1833
|
+
);
|
|
1834
|
+
assignWsmtxcaValue(
|
|
1835
|
+
voucher,
|
|
1836
|
+
"documentNumber",
|
|
1837
|
+
normalizeWsmtxcaString(raw.numeroDocumento)
|
|
1838
|
+
);
|
|
1839
|
+
assignWsmtxcaValue(
|
|
1840
|
+
voucher,
|
|
1841
|
+
"receiverVatConditionId",
|
|
1842
|
+
parseOptionalNumber(raw.condicionIVAReceptor)
|
|
1843
|
+
);
|
|
1844
|
+
assignWsmtxcaValue(
|
|
1845
|
+
voucher,
|
|
1846
|
+
"totalAmount",
|
|
1847
|
+
parseOptionalNumber(raw.importeTotal)
|
|
1848
|
+
);
|
|
1849
|
+
assignWsmtxcaValue(
|
|
1850
|
+
voucher,
|
|
1851
|
+
"subtotalAmount",
|
|
1852
|
+
parseOptionalNumber(raw.importeSubtotal)
|
|
1853
|
+
);
|
|
1854
|
+
assignWsmtxcaValue(
|
|
1855
|
+
voucher,
|
|
1856
|
+
"taxableAmount",
|
|
1857
|
+
parseOptionalNumber(raw.importeGravado)
|
|
1858
|
+
);
|
|
1859
|
+
assignWsmtxcaValue(
|
|
1860
|
+
voucher,
|
|
1861
|
+
"nonTaxableAmount",
|
|
1862
|
+
parseOptionalNumber(raw.importeNoGravado)
|
|
1239
1863
|
);
|
|
1240
|
-
|
|
1864
|
+
assignWsmtxcaValue(
|
|
1865
|
+
voucher,
|
|
1866
|
+
"exemptAmount",
|
|
1867
|
+
parseOptionalNumber(raw.importeExento)
|
|
1868
|
+
);
|
|
1869
|
+
assignWsmtxcaValue(
|
|
1870
|
+
voucher,
|
|
1871
|
+
"taxAmount",
|
|
1872
|
+
parseOptionalNumber(raw.importeOtrosTributos)
|
|
1873
|
+
);
|
|
1874
|
+
assignWsmtxcaValue(voucher, "vatAmount", vatAmount);
|
|
1875
|
+
assignWsmtxcaValue(
|
|
1876
|
+
voucher,
|
|
1877
|
+
"currencyId",
|
|
1878
|
+
normalizeWsmtxcaString(raw.codigoMoneda)
|
|
1879
|
+
);
|
|
1880
|
+
assignWsmtxcaValue(
|
|
1881
|
+
voucher,
|
|
1882
|
+
"exchangeRate",
|
|
1883
|
+
parseOptionalNumber(raw.cotizacionMoneda)
|
|
1884
|
+
);
|
|
1885
|
+
assignWsmtxcaValue(voucher, "cae", cae);
|
|
1886
|
+
assignWsmtxcaValue(voucher, "caeExpiry", caeExpiry);
|
|
1887
|
+
return voucher;
|
|
1241
1888
|
}
|
|
1242
|
-
function
|
|
1889
|
+
function sumWsmtxcaVatAmounts(value) {
|
|
1890
|
+
const subtotals = toRecord(value)?.subtotalIVA;
|
|
1891
|
+
const entries = Array.isArray(subtotals) ? subtotals : subtotals ? [subtotals] : [];
|
|
1892
|
+
const amounts = entries.map((entry) => parseOptionalNumber(toRecord(entry)?.importe)).filter((amount) => amount !== void 0);
|
|
1893
|
+
return amounts.length > 0 ? amounts.reduce((total, amount) => total + amount, 0) : void 0;
|
|
1894
|
+
}
|
|
1895
|
+
function parseWsmtxcaVoucherNumber(value, message, detail, allowZero = false) {
|
|
1243
1896
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
1244
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
1245
|
-
throw new ArcaServiceError(message, {
|
|
1897
|
+
if (!Number.isFinite(parsed) || (allowZero ? parsed < 0 : parsed <= 0)) {
|
|
1898
|
+
throw new ArcaServiceError(message, {
|
|
1899
|
+
service: "wsmtxca",
|
|
1900
|
+
detail
|
|
1901
|
+
});
|
|
1246
1902
|
}
|
|
1247
1903
|
return parsed;
|
|
1248
1904
|
}
|
|
1905
|
+
function parseOptionalPositiveInteger(value) {
|
|
1906
|
+
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
1907
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
1908
|
+
}
|
|
1909
|
+
function parseOptionalNumber(value) {
|
|
1910
|
+
if (value === void 0 || value === null || value === "") {
|
|
1911
|
+
return void 0;
|
|
1912
|
+
}
|
|
1913
|
+
const parsed = Number(value);
|
|
1914
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
1915
|
+
}
|
|
1916
|
+
function normalizeWsmtxcaResult(value) {
|
|
1917
|
+
if (typeof value !== "string") {
|
|
1918
|
+
return void 0;
|
|
1919
|
+
}
|
|
1920
|
+
const normalized = value.trim().toUpperCase();
|
|
1921
|
+
return normalized || void 0;
|
|
1922
|
+
}
|
|
1923
|
+
function normalizeWsmtxcaString(value) {
|
|
1924
|
+
if (value === void 0 || value === null) {
|
|
1925
|
+
return void 0;
|
|
1926
|
+
}
|
|
1927
|
+
const normalized = String(value).trim();
|
|
1928
|
+
return normalized || void 0;
|
|
1929
|
+
}
|
|
1930
|
+
function assignWsmtxcaValue(target, key, value) {
|
|
1931
|
+
if (value !== void 0) {
|
|
1932
|
+
target[key] = value;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1249
1935
|
function normalizeWsmtxcaResponseDate(value) {
|
|
1250
1936
|
if (typeof value === "number" && Number.isInteger(value)) {
|
|
1251
1937
|
return formatCompactDateToIso(value);
|
|
@@ -1638,7 +2324,7 @@ function createSoapTransport(options) {
|
|
|
1638
2324
|
soapAction: serviceConfig.soapVersion === "1.1" ? soapAction : void 0,
|
|
1639
2325
|
useLegacyTlsSecurityLevel0: options.config.environment === "production" && serviceConfig.useLegacyTlsSecurityLevel0 === true,
|
|
1640
2326
|
timeout: options.config.timeout,
|
|
1641
|
-
retries: options.config.retries,
|
|
2327
|
+
retries: request.retries ?? options.config.retries,
|
|
1642
2328
|
retryDelay: options.config.retryDelay,
|
|
1643
2329
|
logger: options.logger,
|
|
1644
2330
|
service: request.service,
|
|
@@ -1751,93 +2437,129 @@ function isWsaaCredentialValid(credentials) {
|
|
|
1751
2437
|
// src/wsaa/index.ts
|
|
1752
2438
|
function createWsaaAuthModule(options) {
|
|
1753
2439
|
const cache = /* @__PURE__ */ new Map();
|
|
1754
|
-
const
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
if (
|
|
1761
|
-
|
|
2440
|
+
const ordinaryInFlight = /* @__PURE__ */ new Map();
|
|
2441
|
+
const forcedInFlight = /* @__PURE__ */ new Map();
|
|
2442
|
+
function trackLogin(target, cacheKey, login) {
|
|
2443
|
+
const promise = login();
|
|
2444
|
+
target.set(cacheKey, promise);
|
|
2445
|
+
const cleanup = () => {
|
|
2446
|
+
if (target.get(cacheKey) === promise) {
|
|
2447
|
+
target.delete(cacheKey);
|
|
1762
2448
|
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
2449
|
+
};
|
|
2450
|
+
promise.then(cleanup, cleanup);
|
|
2451
|
+
return promise;
|
|
2452
|
+
}
|
|
2453
|
+
async function requestOrReuseWsaaCredentials(service, sessionKey, cacheKey, forceRefresh) {
|
|
2454
|
+
const reuse = await getReusableCredentials({
|
|
2455
|
+
config: options.config,
|
|
2456
|
+
cache,
|
|
2457
|
+
cacheKey,
|
|
2458
|
+
sessionKey,
|
|
2459
|
+
logger: options.logger,
|
|
2460
|
+
service,
|
|
2461
|
+
allowStore: !forceRefresh,
|
|
2462
|
+
allowCache: !forceRefresh
|
|
2463
|
+
});
|
|
2464
|
+
if (reuse) {
|
|
2465
|
+
return reuse;
|
|
2466
|
+
}
|
|
2467
|
+
const refresh = () => refreshWsaaCredentials({
|
|
2468
|
+
config: options.config,
|
|
2469
|
+
cache,
|
|
2470
|
+
cacheKey,
|
|
2471
|
+
sessionKey,
|
|
2472
|
+
logger: options.logger,
|
|
2473
|
+
service,
|
|
2474
|
+
forceRefresh
|
|
2475
|
+
});
|
|
2476
|
+
if (options.config.wsaaSessionStore?.withLock) {
|
|
2477
|
+
return await withWsaaSessionStoreLock(
|
|
2478
|
+
options.config,
|
|
2479
|
+
sessionKey,
|
|
2480
|
+
service,
|
|
2481
|
+
refresh
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
return await refresh();
|
|
2485
|
+
}
|
|
2486
|
+
async function performLogin(service, sessionKey, cacheKey, forceRefresh) {
|
|
2487
|
+
try {
|
|
2488
|
+
return await requestOrReuseWsaaCredentials(
|
|
2489
|
+
service,
|
|
2490
|
+
sessionKey,
|
|
2491
|
+
cacheKey,
|
|
2492
|
+
forceRefresh
|
|
2493
|
+
);
|
|
2494
|
+
} catch (error) {
|
|
2495
|
+
if (error instanceof ArcaSoapFaultError && error.faultCode === "ns1:coe.alreadyAuthenticated") {
|
|
2496
|
+
const recovered = await getReusableCredentials({
|
|
1778
2497
|
config: options.config,
|
|
1779
2498
|
cache,
|
|
1780
2499
|
cacheKey,
|
|
1781
2500
|
sessionKey,
|
|
1782
2501
|
logger: options.logger,
|
|
1783
2502
|
service,
|
|
1784
|
-
|
|
2503
|
+
allowStore: true,
|
|
2504
|
+
allowCache: true
|
|
1785
2505
|
});
|
|
1786
|
-
if (
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2506
|
+
if (recovered) {
|
|
2507
|
+
options.logger?.warn(
|
|
2508
|
+
"Recovered WSAA coe.alreadyAuthenticated fault",
|
|
2509
|
+
{
|
|
2510
|
+
service,
|
|
2511
|
+
faultCode: error.faultCode
|
|
2512
|
+
}
|
|
1792
2513
|
);
|
|
2514
|
+
return recovered;
|
|
1793
2515
|
}
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
} catch (error) {
|
|
1800
|
-
if (error instanceof ArcaSoapFaultError && error.faultCode === "ns1:coe.alreadyAuthenticated") {
|
|
1801
|
-
const recovered = await getReusableCredentials({
|
|
1802
|
-
config: options.config,
|
|
1803
|
-
cache,
|
|
1804
|
-
cacheKey,
|
|
1805
|
-
sessionKey,
|
|
1806
|
-
logger: options.logger,
|
|
1807
|
-
service,
|
|
1808
|
-
allowStore: true,
|
|
1809
|
-
allowCache: true
|
|
1810
|
-
});
|
|
1811
|
-
if (recovered) {
|
|
1812
|
-
options.logger?.warn(
|
|
1813
|
-
"Recovered WSAA coe.alreadyAuthenticated fault",
|
|
1814
|
-
{
|
|
1815
|
-
service,
|
|
1816
|
-
faultCode: error.faultCode
|
|
1817
|
-
}
|
|
1818
|
-
);
|
|
1819
|
-
return recovered;
|
|
1820
|
-
}
|
|
1821
|
-
if (!options.config.wsaaSessionStore) {
|
|
1822
|
-
throw new ArcaConfigurationError(
|
|
1823
|
-
"WSAA login failed because another process likely owns a valid TA. Configure a durable wsaaSessionStore for multi-process or serverless deployments.",
|
|
1824
|
-
{ cause: error }
|
|
1825
|
-
);
|
|
1826
|
-
}
|
|
2516
|
+
if (!options.config.wsaaSessionStore) {
|
|
2517
|
+
throw new ArcaConfigurationError(
|
|
2518
|
+
"WSAA login failed because another process likely owns a valid TA. Configure a durable wsaaSessionStore for multi-process or serverless deployments.",
|
|
2519
|
+
{ cause: error }
|
|
2520
|
+
);
|
|
1827
2521
|
}
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
2522
|
+
}
|
|
2523
|
+
if (error instanceof ArcaSoapFaultError) {
|
|
2524
|
+
options.logger?.error("WSAA SOAP fault response", {
|
|
2525
|
+
service,
|
|
2526
|
+
operation: "loginCms",
|
|
2527
|
+
url: ARCA_WSAA_CONFIG.endpoint[options.config.environment],
|
|
2528
|
+
faultCode: error.faultCode,
|
|
2529
|
+
error
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
throw error;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
return {
|
|
2536
|
+
login(service, authOptions = {}) {
|
|
2537
|
+
const sessionKey = buildWsaaSessionKey(options.config, service);
|
|
2538
|
+
const cacheKey = serializeWsaaSessionKey(sessionKey);
|
|
2539
|
+
if (authOptions.forceRefresh) {
|
|
2540
|
+
const runningForced2 = forcedInFlight.get(cacheKey);
|
|
2541
|
+
if (runningForced2) {
|
|
2542
|
+
return runningForced2;
|
|
1836
2543
|
}
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
2544
|
+
const runningOrdinary2 = ordinaryInFlight.get(cacheKey);
|
|
2545
|
+
return trackLogin(forcedInFlight, cacheKey, async () => {
|
|
2546
|
+
await runningOrdinary2?.catch(() => void 0);
|
|
2547
|
+
return await performLogin(service, sessionKey, cacheKey, true);
|
|
2548
|
+
});
|
|
1840
2549
|
}
|
|
2550
|
+
const runningOrdinary = ordinaryInFlight.get(cacheKey);
|
|
2551
|
+
if (runningOrdinary) {
|
|
2552
|
+
return runningOrdinary;
|
|
2553
|
+
}
|
|
2554
|
+
const runningForced = forcedInFlight.get(cacheKey);
|
|
2555
|
+
if (runningForced) {
|
|
2556
|
+
return runningForced;
|
|
2557
|
+
}
|
|
2558
|
+
return trackLogin(
|
|
2559
|
+
ordinaryInFlight,
|
|
2560
|
+
cacheKey,
|
|
2561
|
+
() => performLogin(service, sessionKey, cacheKey, false)
|
|
2562
|
+
);
|
|
1841
2563
|
}
|
|
1842
2564
|
};
|
|
1843
2565
|
}
|