facturas 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
  };
@@ -432,7 +446,7 @@ async function executePadronOperation(options, service, operation, body) {
432
446
 
433
447
  // src/services/wsfe.ts
434
448
  function createWsfeService(options) {
435
- async function executeWsfeAuthenticatedOperation(operation, input, body = {}) {
449
+ async function executeWsfeAuthenticatedRawOperation(operation, input, body = {}, retries) {
436
450
  const auth = await options.auth.login("wsfe", {
437
451
  representedTaxId: input.representedTaxId,
438
452
  forceRefresh: input.forceRefresh
@@ -440,6 +454,7 @@ function createWsfeService(options) {
440
454
  const response = await options.soap.execute({
441
455
  service: "wsfe",
442
456
  operation,
457
+ ...retries === void 0 ? {} : { retries },
443
458
  body: {
444
459
  Auth: createWsfeAuth(
445
460
  input.representedTaxId ?? options.config.taxId,
@@ -449,7 +464,16 @@ function createWsfeService(options) {
449
464
  ...body
450
465
  }
451
466
  });
452
- return unwrapWsfeOperationResult(operation, response.result);
467
+ return unwrapWsfeOperationEnvelope(operation, response.result);
468
+ }
469
+ async function executeWsfeAuthenticatedOperation(operation, input, body = {}) {
470
+ const result = await executeWsfeAuthenticatedRawOperation(
471
+ operation,
472
+ input,
473
+ body
474
+ );
475
+ throwForWsfeOperationErrors(operation, result);
476
+ return result;
453
477
  }
454
478
  async function executeWsfeOperation(operation, body = {}) {
455
479
  const response = await options.soap.execute({
@@ -457,7 +481,9 @@ function createWsfeService(options) {
457
481
  operation,
458
482
  body
459
483
  });
460
- return unwrapWsfeOperationResult(operation, response.result);
484
+ const result = unwrapWsfeOperationEnvelope(operation, response.result);
485
+ throwForWsfeOperationErrors(operation, result);
486
+ return result;
461
487
  }
462
488
  async function getNextVoucherNumber({
463
489
  representedTaxId,
@@ -499,55 +525,148 @@ function createWsfeService(options) {
499
525
  forceRefresh
500
526
  });
501
527
  }
528
+ function authorizeVoucherOutcome({
529
+ representedTaxId,
530
+ data,
531
+ voucherNumber,
532
+ forceRefresh
533
+ }) {
534
+ const normalizedInput = normalizeWsfeVoucherInput(data);
535
+ return executeWsfeAuthorization({
536
+ representedTaxId,
537
+ data: normalizedInput,
538
+ voucherNumber,
539
+ forceRefresh
540
+ }).then(({ outcome }) => outcome);
541
+ }
502
542
  async function authorizeNormalizedVoucher({
503
543
  representedTaxId,
504
544
  data: normalizedInput,
505
545
  voucherNumber,
506
546
  forceRefresh
507
547
  }) {
508
- const requestData = mapWsfeVoucherInput(normalizedInput, voucherNumber);
509
- const auth = await options.auth.login("wsfe", {
548
+ const execution = await executeWsfeAuthorization({
510
549
  representedTaxId,
550
+ data: normalizedInput,
551
+ voucherNumber,
511
552
  forceRefresh
512
553
  });
513
- const response = await options.soap.execute({
514
- service: "wsfe",
515
- operation: "FECAESolicitar",
516
- body: {
517
- Auth: createWsfeAuth(
518
- representedTaxId ?? options.config.taxId,
519
- auth.token,
520
- auth.sign
521
- ),
522
- FeCAEReq: {
523
- FeCabReq: {
524
- CantReg: 1,
525
- PtoVta: normalizedInput.salesPoint,
526
- CbteTipo: normalizedInput.voucherType
527
- },
528
- FeDetReq: {
529
- FECAEDetRequest: requestData
554
+ if (execution.error) {
555
+ throw execution.error;
556
+ }
557
+ if (execution.outcome.kind !== "authorized") {
558
+ throw createWsfeOutcomeError(execution.outcome);
559
+ }
560
+ const { cae, caeExpiry, raw } = execution.outcome;
561
+ if (!(caeExpiry && raw)) {
562
+ throw new ArcaServiceError("WSFE did not return CAE authorization data", {
563
+ service: "wsfe",
564
+ operation: "FECAESolicitar",
565
+ result: execution.outcome.result,
566
+ resultLevel: execution.outcome.resultLevel,
567
+ results: execution.outcome.results,
568
+ cae,
569
+ issues: [
570
+ ...execution.outcome.errors,
571
+ ...execution.outcome.observations
572
+ ],
573
+ detail: raw
574
+ });
575
+ }
576
+ return {
577
+ cae,
578
+ caeExpiry,
579
+ voucherNumber,
580
+ raw
581
+ };
582
+ }
583
+ async function executeWsfeAuthorization({
584
+ representedTaxId,
585
+ data: normalizedInput,
586
+ voucherNumber,
587
+ forceRefresh
588
+ }) {
589
+ const requestData = mapWsfeVoucherInput(normalizedInput, voucherNumber);
590
+ try {
591
+ const result = await executeWsfeAuthenticatedRawOperation(
592
+ "FECAESolicitar",
593
+ { representedTaxId, forceRefresh },
594
+ {
595
+ FeCAEReq: {
596
+ FeCabReq: {
597
+ CantReg: 1,
598
+ PtoVta: normalizedInput.salesPoint,
599
+ CbteTipo: normalizedInput.voucherType
600
+ },
601
+ FeDetReq: {
602
+ FECAEDetRequest: requestData
603
+ }
530
604
  }
605
+ },
606
+ 0
607
+ );
608
+ return {
609
+ outcome: classifyWsfeAuthorization(result, voucherNumber)
610
+ };
611
+ } catch (error) {
612
+ return {
613
+ outcome: createWsfeIndeterminateOutcome(error),
614
+ error
615
+ };
616
+ }
617
+ }
618
+ async function lookupVoucher({
619
+ representedTaxId,
620
+ number,
621
+ salesPoint,
622
+ voucherType,
623
+ forceRefresh
624
+ }) {
625
+ const operation = "FECompConsultar";
626
+ const result = await executeWsfeAuthenticatedRawOperation(
627
+ operation,
628
+ { representedTaxId, forceRefresh },
629
+ {
630
+ FeCompConsReq: {
631
+ CbteNro: number,
632
+ PtoVta: salesPoint,
633
+ CbteTipo: voucherType
531
634
  }
532
635
  }
533
- });
534
- const result = unwrapWsfeOperationResult("FECAESolicitar", response.result);
535
- const detailResponse = normalizeWsfeDetailResponse(result);
536
- const cae = detailResponse.CAE;
537
- const caeExpiry = detailResponse.CAEFchVto;
538
- if (typeof cae !== "string" || typeof caeExpiry !== "string") {
539
- throw new ArcaServiceError("WSFE did not return CAE authorization data", {
636
+ );
637
+ const errors = extractWsfeGlobalIssues(result, operation);
638
+ if (errors.length > 0 && errors.every((issue) => issue.code === "602")) {
639
+ return {
640
+ kind: "not_found",
641
+ service: "wsfe",
642
+ operation,
643
+ errors,
644
+ observations: [],
645
+ raw: result
646
+ };
647
+ }
648
+ if (errors.length > 0) {
649
+ throw createWsfeServiceError(operation, result, errors);
650
+ }
651
+ const raw = toWsfeRecord(result.ResultGet);
652
+ if (!raw) {
653
+ throw new ArcaServiceError("WSFE did not return the consulted voucher", {
654
+ service: "wsfe",
655
+ operation,
540
656
  detail: result
541
657
  });
542
658
  }
543
659
  return {
544
- cae,
545
- caeExpiry: String(caeExpiry),
546
- voucherNumber,
660
+ kind: "found",
661
+ service: "wsfe",
662
+ operation,
663
+ voucher: mapWsfeVoucherInfo(raw),
664
+ observations: [],
547
665
  raw: result
548
666
  };
549
667
  }
550
668
  return {
669
+ authorizeVoucherOutcome,
551
670
  authorizeVoucher,
552
671
  async createNextVoucher({ representedTaxId, data, forceRefresh }) {
553
672
  const normalizedInput = normalizeWsfeVoucherInput(data);
@@ -659,33 +778,11 @@ function createWsfeService(options) {
659
778
  const raw = result.ResultGet ?? {};
660
779
  return mapWsfeQuotation(raw);
661
780
  },
662
- async getVoucherInfo({
663
- representedTaxId,
664
- number,
665
- salesPoint,
666
- voucherType,
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
- }
781
+ async getVoucherInfo(input) {
782
+ const lookup = await lookupVoucher(input);
783
+ return lookup.kind === "found" ? lookup.voucher : null;
784
+ },
785
+ lookupVoucher
689
786
  };
690
787
  }
691
788
  function mapWsfeVoucherInput(input, voucherNumber) {
@@ -951,17 +1048,45 @@ function mapWsfeQuotation(raw) {
951
1048
  };
952
1049
  }
953
1050
  function mapWsfeVoucherInfo(raw) {
954
- return {
1051
+ const voucher = {
955
1052
  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
1053
  raw
964
1054
  };
1055
+ assignWsfeValue(voucher, "voucherDate", normalizeWsfeString(raw.CbteFch));
1056
+ assignWsfeValue(voucher, "salesPoint", normalizeWsfeNumber(raw.PtoVta));
1057
+ assignWsfeValue(voucher, "voucherType", normalizeWsfeNumber(raw.CbteTipo));
1058
+ assignWsfeValue(voucher, "concept", normalizeWsfeNumber(raw.Concepto));
1059
+ assignWsfeValue(voucher, "documentType", normalizeWsfeNumber(raw.DocTipo));
1060
+ assignWsfeValue(voucher, "documentNumber", normalizeWsfeString(raw.DocNro));
1061
+ assignWsfeValue(
1062
+ voucher,
1063
+ "receiverVatConditionId",
1064
+ normalizeWsfeNumber(raw.CondicionIVAReceptorId)
1065
+ );
1066
+ assignWsfeValue(voucher, "totalAmount", normalizeWsfeNumber(raw.ImpTotal));
1067
+ assignWsfeValue(
1068
+ voucher,
1069
+ "nonTaxableAmount",
1070
+ normalizeWsfeNumber(raw.ImpTotConc)
1071
+ );
1072
+ assignWsfeValue(voucher, "netAmount", normalizeWsfeNumber(raw.ImpNeto));
1073
+ assignWsfeValue(voucher, "exemptAmount", normalizeWsfeNumber(raw.ImpOpEx));
1074
+ assignWsfeValue(voucher, "taxAmount", normalizeWsfeNumber(raw.ImpTrib));
1075
+ assignWsfeValue(voucher, "vatAmount", normalizeWsfeNumber(raw.ImpIVA));
1076
+ assignWsfeValue(voucher, "currencyId", normalizeWsfeString(raw.MonId));
1077
+ assignWsfeValue(voucher, "exchangeRate", normalizeWsfeNumber(raw.MonCotiz));
1078
+ assignWsfeValue(voucher, "result", normalizeWsfeString(raw.Resultado));
1079
+ assignWsfeValue(
1080
+ voucher,
1081
+ "cae",
1082
+ normalizeWsfeString(raw.CodAutorizacion ?? raw.CAE)
1083
+ );
1084
+ assignWsfeValue(
1085
+ voucher,
1086
+ "caeExpiry",
1087
+ normalizeWsfeString(raw.FchVto ?? raw.CAEFchVto)
1088
+ );
1089
+ return voucher;
965
1090
  }
966
1091
  function createWsfeAuth(representedTaxId, token, sign) {
967
1092
  return {
@@ -970,47 +1095,16 @@ function createWsfeAuth(representedTaxId, token, sign) {
970
1095
  Cuit: Number.parseInt(String(representedTaxId), 10)
971
1096
  };
972
1097
  }
973
- function unwrapWsfeOperationResult(operation, response) {
1098
+ function unwrapWsfeOperationEnvelope(operation, response) {
974
1099
  const operationResponse = response[`${operation}Response`];
975
1100
  const result = operationResponse?.[`${operation}Result`] ?? response[`${operation}Result`] ?? response;
976
- if (operation === "FECAESolicitar") {
977
- const detailResponse = normalizeWsfeDetailResponse(result);
978
- const resultCode = detailResponse.Resultado;
979
- if (resultCode && resultCode !== "A") {
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);
1101
+ return result;
1102
+ }
1103
+ function throwForWsfeOperationErrors(operation, result) {
1104
+ const errors = extractWsfeGlobalIssues(result, operation);
1001
1105
  if (errors.length > 0) {
1002
- const firstError = errors[0];
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
- });
1106
+ throw createWsfeServiceError(operation, result, errors);
1012
1107
  }
1013
- return result;
1014
1108
  }
1015
1109
  function normalizeWsfeDetailResponse(result) {
1016
1110
  const detailResponse = result.FeDetResp;
@@ -1020,17 +1114,248 @@ function normalizeWsfeDetailResponse(result) {
1020
1114
  }
1021
1115
  return rawDetail ?? {};
1022
1116
  }
1023
- function normalizeWsfeErrors(rawErrors) {
1117
+ function classifyWsfeAuthorization(result, voucherNumber) {
1118
+ const operation = "FECAESolicitar";
1119
+ const header = toWsfeRecord(result.FeCabResp) ?? {};
1120
+ const detail = normalizeWsfeDetailResponse(result);
1121
+ const headerResult = normalizeWsfeResult(header.Resultado);
1122
+ const detailResult = normalizeWsfeResult(detail.Resultado);
1123
+ const resultCode = detailResult ?? headerResult;
1124
+ const resultLevel = getWsfeResultLevel(headerResult, detailResult);
1125
+ const cae = normalizeWsfeString(detail.CAE);
1126
+ const caeExpiry = normalizeWsfeString(detail.CAEFchVto);
1127
+ const errors = extractWsfeGlobalIssues(result, operation, "header");
1128
+ const observations = extractWsfeObservations(
1129
+ detail,
1130
+ detailResult === "R" ? "business" : "observation"
1131
+ );
1132
+ const hasInfrastructureError = errors.some(
1133
+ (issue) => issue.category === "infrastructure"
1134
+ );
1135
+ const base = {
1136
+ service: "wsfe",
1137
+ operation,
1138
+ results: createWsfeResults(headerResult, detailResult),
1139
+ errors,
1140
+ observations,
1141
+ raw: result
1142
+ };
1143
+ const context = {
1144
+ base,
1145
+ headerResult,
1146
+ detailResult,
1147
+ resultCode,
1148
+ resultLevel,
1149
+ cae,
1150
+ caeExpiry
1151
+ };
1152
+ if (hasContradictoryWsfeResults(context)) {
1153
+ return createWsfeStructuredIndeterminate(context, "contradictory_response");
1154
+ }
1155
+ if (hasInfrastructureError) {
1156
+ return createWsfeStructuredIndeterminate(context, "incomplete_response");
1157
+ }
1158
+ if (isAuthorizedWsfeContext(context)) {
1159
+ return {
1160
+ ...base,
1161
+ kind: "authorized",
1162
+ result: "A",
1163
+ resultLevel: "detail",
1164
+ cae: context.cae,
1165
+ caeExpiry: context.caeExpiry,
1166
+ voucherNumber
1167
+ };
1168
+ }
1169
+ if (isRejectedWsfeDetailContext(context)) {
1170
+ return {
1171
+ ...base,
1172
+ kind: "rejected",
1173
+ result: "R",
1174
+ resultLevel: "detail"
1175
+ };
1176
+ }
1177
+ if (isRejectedWsfeHeaderContext(context)) {
1178
+ return {
1179
+ ...base,
1180
+ kind: "rejected",
1181
+ result: "R",
1182
+ resultLevel: "header"
1183
+ };
1184
+ }
1185
+ return createWsfeStructuredIndeterminate(
1186
+ context,
1187
+ hasWsfeCaeContradiction(context) ? "contradictory_response" : "incomplete_response"
1188
+ );
1189
+ }
1190
+ function getWsfeResultLevel(headerResult, detailResult) {
1191
+ if (detailResult) {
1192
+ return "detail";
1193
+ }
1194
+ return headerResult ? "header" : void 0;
1195
+ }
1196
+ function hasContradictoryWsfeResults(context) {
1197
+ return Boolean(
1198
+ context.headerResult && context.detailResult && context.headerResult !== context.detailResult
1199
+ );
1200
+ }
1201
+ function isAuthorizedWsfeContext(context) {
1202
+ return Boolean(
1203
+ context.detailResult === "A" && context.headerResult !== "R" && context.base.errors.length === 0 && context.cae && context.caeExpiry
1204
+ );
1205
+ }
1206
+ function isRejectedWsfeDetailContext(context) {
1207
+ return context.detailResult === "R" && context.headerResult !== "A" && !context.cae;
1208
+ }
1209
+ function isRejectedWsfeHeaderContext(context) {
1210
+ return context.headerResult === "R" && context.detailResult === void 0 && !context.cae && context.base.errors.length > 0 && context.base.errors.every((issue) => issue.category === "business");
1211
+ }
1212
+ function hasWsfeCaeContradiction(context) {
1213
+ return (context.resultCode === "A" || context.resultCode === "R") && Boolean(context.cae);
1214
+ }
1215
+ function createWsfeStructuredIndeterminate(context, reason) {
1216
+ const outcome = {
1217
+ ...context.base,
1218
+ kind: "indeterminate",
1219
+ reason
1220
+ };
1221
+ assignWsfeValue(outcome, "result", context.resultCode);
1222
+ assignWsfeValue(outcome, "resultLevel", context.resultLevel);
1223
+ assignWsfeValue(outcome, "cae", context.cae);
1224
+ assignWsfeValue(outcome, "caeExpiry", context.caeExpiry);
1225
+ return outcome;
1226
+ }
1227
+ function createWsfeResults(headerResult, detailResult) {
1228
+ const results = {};
1229
+ assignWsfeValue(results, "header", headerResult);
1230
+ assignWsfeValue(results, "detail", detailResult);
1231
+ return results;
1232
+ }
1233
+ function createWsfeIndeterminateOutcome(error) {
1234
+ return {
1235
+ kind: "indeterminate",
1236
+ service: "wsfe",
1237
+ operation: "FECAESolicitar",
1238
+ results: {},
1239
+ reason: getArcaIndeterminateReason(error),
1240
+ errors: [],
1241
+ observations: []
1242
+ };
1243
+ }
1244
+ function getArcaIndeterminateReason(error) {
1245
+ if (error instanceof ArcaTransportError) {
1246
+ return "transport_error";
1247
+ }
1248
+ if (error instanceof ArcaSoapFaultError) {
1249
+ return "soap_fault";
1250
+ }
1251
+ if (error instanceof ArcaInvalidSoapResponseError) {
1252
+ return "invalid_response";
1253
+ }
1254
+ return "unexpected_error";
1255
+ }
1256
+ function createWsfeOutcomeError(outcome) {
1257
+ const issues = [...outcome.errors, ...outcome.observations];
1258
+ const firstIssue = issues[0];
1259
+ 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";
1260
+ return new ArcaServiceError(message, {
1261
+ service: "wsfe",
1262
+ operation: outcome.operation,
1263
+ ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1264
+ ...outcome.result === void 0 ? {} : { result: outcome.result },
1265
+ ...outcome.resultLevel === void 0 ? {} : { resultLevel: outcome.resultLevel },
1266
+ results: outcome.results,
1267
+ ...outcome.kind === "indeterminate" && outcome.cae ? { cae: outcome.cae } : {},
1268
+ issues,
1269
+ detail: outcome.raw
1270
+ });
1271
+ }
1272
+ function createWsfeServiceError(operation, result, issues) {
1273
+ const firstIssue = issues[0];
1274
+ return new ArcaServiceError(
1275
+ firstIssue ? formatWsfeIssue(firstIssue) : "WSFE returned a service error",
1276
+ {
1277
+ service: "wsfe",
1278
+ operation,
1279
+ ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1280
+ issues,
1281
+ detail: result
1282
+ }
1283
+ );
1284
+ }
1285
+ function extractWsfeGlobalIssues(result, operation, resultLevel) {
1286
+ const errorsContainer = toWsfeRecord(result.Errors);
1287
+ return normalizeWsfeIssueEntries(errorsContainer?.Err).map((entry) => ({
1288
+ service: "wsfe",
1289
+ operation,
1290
+ source: "error",
1291
+ category: operation === "FECAESolicitar" && WSFE_AUTHORIZATION_INFRASTRUCTURE_CODES.has(entry.code ?? "") ? "infrastructure" : operation === "FECAESolicitar" ? "business" : "unknown",
1292
+ ...entry.code === void 0 ? {} : { code: entry.code },
1293
+ message: entry.message,
1294
+ ...resultLevel === void 0 ? {} : { resultLevel }
1295
+ }));
1296
+ }
1297
+ function extractWsfeObservations(detail, category) {
1298
+ const observationsContainer = toWsfeRecord(detail.Observaciones);
1299
+ return normalizeWsfeIssueEntries(observationsContainer?.Obs).map((entry) => ({
1300
+ service: "wsfe",
1301
+ operation: "FECAESolicitar",
1302
+ source: "observation",
1303
+ category,
1304
+ ...entry.code === void 0 ? {} : { code: entry.code },
1305
+ message: entry.message,
1306
+ resultLevel: "detail"
1307
+ }));
1308
+ }
1309
+ function normalizeWsfeIssueEntries(rawErrors) {
1024
1310
  const entries = Array.isArray(rawErrors) ? rawErrors : rawErrors ? [rawErrors] : [];
1025
1311
  return entries.map((entry) => entry).map((entry) => {
1026
- const code = entry.Code ?? entry.code ?? "N/A";
1312
+ const code = entry.Code ?? entry.code;
1027
1313
  const message = entry.Msg ?? entry.msg ?? "Unknown WSFE error";
1028
1314
  return {
1029
- code: String(code),
1030
- message: `(${String(code)}) ${String(message)}`
1315
+ ...code === void 0 ? {} : { code: String(code) },
1316
+ message: String(message)
1031
1317
  };
1032
1318
  });
1033
1319
  }
1320
+ function formatWsfeIssue(issue) {
1321
+ return issue.code ? `(${issue.code}) ${issue.message}` : issue.message;
1322
+ }
1323
+ function normalizeWsfeResult(value) {
1324
+ if (typeof value !== "string") {
1325
+ return void 0;
1326
+ }
1327
+ const normalized = value.trim().toUpperCase();
1328
+ return normalized || void 0;
1329
+ }
1330
+ function normalizeWsfeString(value) {
1331
+ if (value === void 0 || value === null) {
1332
+ return void 0;
1333
+ }
1334
+ const normalized = String(value).trim();
1335
+ return normalized || void 0;
1336
+ }
1337
+ function normalizeWsfeNumber(value) {
1338
+ if (value === void 0 || value === null || value === "") {
1339
+ return void 0;
1340
+ }
1341
+ const normalized = Number(value);
1342
+ return Number.isFinite(normalized) ? normalized : void 0;
1343
+ }
1344
+ function assignWsfeValue(target, key, value) {
1345
+ if (value !== void 0) {
1346
+ target[key] = value;
1347
+ }
1348
+ }
1349
+ function toWsfeRecord(value) {
1350
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1351
+ }
1352
+ var WSFE_AUTHORIZATION_INFRASTRUCTURE_CODES = /* @__PURE__ */ new Set([
1353
+ "500",
1354
+ "501",
1355
+ "502",
1356
+ "600",
1357
+ "601"
1358
+ ]);
1034
1359
  function getWsfeResultEntries(result, key) {
1035
1360
  const rawEntries = result.ResultGet?.[key];
1036
1361
  if (!rawEntries) {
@@ -1043,145 +1368,222 @@ function getWsfeResultEntries(result, key) {
1043
1368
 
1044
1369
  // src/services/wsmtxca.ts
1045
1370
  function createWsmtxcaService(options) {
1046
- return {
1047
- async authorizeVoucher({ representedTaxId, data, forceRefresh }) {
1048
- const auth = await options.auth.login("wsmtxca", {
1049
- representedTaxId,
1050
- forceRefresh
1051
- });
1052
- const response = await options.soap.execute({
1053
- service: "wsmtxca",
1054
- operation: "autorizarComprobante",
1055
- bodyElementName: "autorizarComprobanteRequest",
1056
- bodyElementNamespaceMode: "prefix",
1057
- body: {
1058
- authRequest: createWsmtxcaAuth(
1059
- representedTaxId ?? options.config.taxId,
1060
- auth.token,
1061
- auth.sign
1062
- ),
1063
- ...data
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
- );
1371
+ async function executeWsmtxcaAuthenticatedOperation(operation, input, body = {}, retries) {
1372
+ const auth = await options.auth.login("wsmtxca", {
1373
+ representedTaxId: input.representedTaxId,
1374
+ forceRefresh: input.forceRefresh
1375
+ });
1376
+ const response = await options.soap.execute({
1377
+ service: "wsmtxca",
1378
+ operation,
1379
+ ...retries === void 0 ? {} : { retries },
1380
+ bodyElementName: `${operation}Request`,
1381
+ bodyElementNamespaceMode: "prefix",
1382
+ body: {
1383
+ authRequest: createWsmtxcaAuth(
1384
+ input.representedTaxId ?? options.config.taxId,
1385
+ auth.token,
1386
+ auth.sign
1387
+ ),
1388
+ ...body
1079
1389
  }
1390
+ });
1391
+ return unwrapWsmtxcaOperationResponse(response.result, operation);
1392
+ }
1393
+ async function executeWsmtxcaAuthorization({
1394
+ representedTaxId,
1395
+ data,
1396
+ forceRefresh
1397
+ }) {
1398
+ try {
1399
+ const raw = await executeWsmtxcaAuthenticatedOperation(
1400
+ "autorizarComprobante",
1401
+ { representedTaxId, forceRefresh },
1402
+ data,
1403
+ 0
1404
+ );
1405
+ return { outcome: classifyWsmtxcaAuthorization(raw) };
1406
+ } catch (error) {
1080
1407
  return {
1081
- cae: String(caeValue),
1082
- caeExpiry: normalizeWsmtxcaResponseDate(
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
1408
+ outcome: createWsmtxcaIndeterminateOutcome(error),
1409
+ error
1092
1410
  };
1093
- },
1094
- async getLastAuthorizedVoucher({
1095
- representedTaxId,
1096
- voucherType,
1097
- salesPoint,
1098
- forceRefresh
1099
- }) {
1100
- const auth = await options.auth.login("wsmtxca", {
1101
- representedTaxId,
1102
- forceRefresh
1103
- });
1104
- const response = await options.soap.execute({
1105
- service: "wsmtxca",
1106
- operation: "consultarUltimoComprobanteAutorizado",
1107
- bodyElementName: "consultarUltimoComprobanteAutorizadoRequest",
1108
- bodyElementNamespaceMode: "prefix",
1109
- body: {
1110
- authRequest: createWsmtxcaAuth(
1111
- representedTaxId ?? options.config.taxId,
1112
- auth.token,
1113
- auth.sign
1114
- ),
1115
- consultaUltimoComprobanteAutorizadoRequest: {
1116
- codigoTipoComprobante: voucherType,
1117
- numeroPuntoVenta: salesPoint
1118
- }
1411
+ }
1412
+ }
1413
+ async function authorizeVoucherOutcome(input) {
1414
+ return (await executeWsmtxcaAuthorization(input)).outcome;
1415
+ }
1416
+ async function authorizeVoucher(input) {
1417
+ const execution = await executeWsmtxcaAuthorization(input);
1418
+ if (execution.error) {
1419
+ throw execution.error;
1420
+ }
1421
+ if (execution.outcome.kind !== "authorized") {
1422
+ throw createWsmtxcaOutcomeError(execution.outcome);
1423
+ }
1424
+ const { outcome } = execution;
1425
+ return {
1426
+ cae: outcome.cae,
1427
+ ...outcome.caeExpiry === void 0 ? {} : { caeExpiry: outcome.caeExpiry },
1428
+ voucherNumber: outcome.voucherNumber,
1429
+ messages: formatWsmtxcaIssues([
1430
+ ...outcome.errors,
1431
+ ...outcome.observations
1432
+ ]),
1433
+ raw: outcome.raw ?? {}
1434
+ };
1435
+ }
1436
+ async function getLastAuthorizedVoucher({
1437
+ representedTaxId,
1438
+ voucherType,
1439
+ salesPoint,
1440
+ forceRefresh
1441
+ }) {
1442
+ const operation = "consultarUltimoComprobanteAutorizado";
1443
+ const raw = await executeWsmtxcaAuthenticatedOperation(
1444
+ operation,
1445
+ { representedTaxId, forceRefresh },
1446
+ {
1447
+ consultaUltimoComprobanteAutorizadoRequest: {
1448
+ codigoTipoComprobante: voucherType,
1449
+ numeroPuntoVenta: salesPoint
1119
1450
  }
1120
- });
1121
- const raw = unwrapWsmtxcaOperationResponse(
1122
- response.result,
1123
- "consultarUltimoComprobanteAutorizado"
1124
- );
1451
+ }
1452
+ );
1453
+ const errors = extractWsmtxcaIssues(raw, operation, "error");
1454
+ if (errors.length > 0 && errors.every((issue) => issue.code === "1502")) {
1455
+ return { voucherNumber: 0, raw };
1456
+ }
1457
+ if (errors.length > 0) {
1458
+ throw createWsmtxcaServiceError(operation, raw, errors);
1459
+ }
1460
+ return {
1461
+ voucherNumber: parseWsmtxcaVoucherNumber(
1462
+ raw.numeroComprobante ?? raw.cbteNro ?? raw.nroComprobante,
1463
+ "WSMTXCA did not return the last authorized voucher number",
1464
+ raw,
1465
+ true
1466
+ ),
1467
+ raw
1468
+ };
1469
+ }
1470
+ async function getSalesPoints({
1471
+ representedTaxId,
1472
+ forceRefresh
1473
+ }) {
1474
+ const raw = await executeWsmtxcaAuthenticatedOperation(
1475
+ "consultarPuntosVenta",
1476
+ { representedTaxId, forceRefresh }
1477
+ );
1478
+ const rawSalesPoints = toRecord(raw.arrayPuntosVenta)?.puntoVenta;
1479
+ const entries = Array.isArray(rawSalesPoints) ? rawSalesPoints : rawSalesPoints ? [rawSalesPoints] : [];
1480
+ const salesPoints = entries.flatMap((entry) => {
1481
+ const record = toRecord(entry);
1482
+ const number = parseOptionalPositiveInteger(record?.numeroPuntoVenta);
1483
+ if (number === void 0) {
1484
+ return [];
1485
+ }
1486
+ const deletedAt = normalizeWsmtxcaResponseDate(record?.fechaBaja);
1487
+ return [
1488
+ {
1489
+ number,
1490
+ blocked: String(record?.bloqueado ?? "N").toUpperCase() === "S",
1491
+ ...deletedAt === void 0 ? {} : { deletedAt }
1492
+ }
1493
+ ];
1494
+ });
1495
+ return { salesPoints, raw };
1496
+ }
1497
+ async function lookupVoucher({
1498
+ representedTaxId,
1499
+ voucherType,
1500
+ salesPoint,
1501
+ voucherNumber,
1502
+ forceRefresh
1503
+ }) {
1504
+ const operation = "consultarComprobante";
1505
+ const raw = await executeWsmtxcaAuthenticatedOperation(
1506
+ operation,
1507
+ { representedTaxId, forceRefresh },
1508
+ {
1509
+ consultaComprobanteRequest: {
1510
+ codigoTipoComprobante: voucherType,
1511
+ numeroPuntoVenta: salesPoint,
1512
+ numeroComprobante: voucherNumber
1513
+ }
1514
+ }
1515
+ );
1516
+ const errors = extractWsmtxcaIssues(raw, operation, "error");
1517
+ const observations = extractWsmtxcaIssues(raw, operation, "observation");
1518
+ if (errors.length > 0 && errors.every((issue) => issue.code === "1503")) {
1125
1519
  return {
1126
- voucherNumber: parseWsmtxcaVoucherNumber(
1127
- raw.numeroComprobante ?? raw.cbteNro ?? raw.nroComprobante,
1128
- extractWsmtxcaMessages(raw).join(" | ") || "WSMTXCA did not return the last authorized voucher number",
1129
- raw
1130
- ),
1520
+ kind: "not_found",
1521
+ service: "wsmtxca",
1522
+ operation,
1523
+ errors,
1524
+ observations,
1131
1525
  raw
1132
1526
  };
1133
- },
1134
- async getVoucher({
1135
- representedTaxId,
1136
- voucherType,
1137
- salesPoint,
1138
- voucherNumber,
1139
- forceRefresh
1140
- }) {
1141
- const auth = await options.auth.login("wsmtxca", {
1142
- representedTaxId,
1143
- forceRefresh
1144
- });
1145
- const response = await options.soap.execute({
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
- }
1527
+ }
1528
+ if (errors.length > 0) {
1529
+ throw createWsmtxcaServiceError(operation, raw, errors);
1530
+ }
1531
+ const voucher = extractWsmtxcaVoucherPayload(raw);
1532
+ if (voucher === raw && !toRecord(raw.comprobante)) {
1533
+ throw new ArcaServiceError(
1534
+ "WSMTXCA did not return the voucher issue date",
1535
+ {
1536
+ service: "wsmtxca",
1537
+ operation,
1538
+ issues: observations,
1539
+ detail: raw
1161
1540
  }
1162
- });
1163
- const raw = unwrapWsmtxcaOperationResponse(
1164
- response.result,
1165
- "consultarComprobante"
1166
1541
  );
1167
- const voucher = extractWsmtxcaVoucherPayload(raw);
1168
- const messages = extractWsmtxcaMessages(raw);
1169
- const invoiceDate = normalizeWsmtxcaResponseDate(
1170
- voucher.fechaEmision ?? voucher.fecha ?? voucher.CbteFch
1542
+ }
1543
+ return {
1544
+ kind: "found",
1545
+ service: "wsmtxca",
1546
+ operation,
1547
+ voucher: mapWsmtxcaVoucherInfo(voucher),
1548
+ observations,
1549
+ raw
1550
+ };
1551
+ }
1552
+ async function getVoucher(input) {
1553
+ const lookup = await lookupVoucher(input);
1554
+ if (lookup.kind === "not_found") {
1555
+ throw createWsmtxcaServiceError(
1556
+ lookup.operation,
1557
+ lookup.raw,
1558
+ lookup.errors
1559
+ );
1560
+ }
1561
+ const invoiceDate = lookup.voucher.invoiceDate;
1562
+ if (!invoiceDate) {
1563
+ throw new ArcaServiceError(
1564
+ formatWsmtxcaIssues(lookup.observations)[0] ?? "WSMTXCA did not return the voucher issue date",
1565
+ {
1566
+ service: "wsmtxca",
1567
+ operation: lookup.operation,
1568
+ issues: lookup.observations,
1569
+ detail: lookup.raw
1570
+ }
1171
1571
  );
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
1572
  }
1573
+ return {
1574
+ invoiceDate,
1575
+ voucher: lookup.voucher.raw,
1576
+ messages: formatWsmtxcaIssues(lookup.observations),
1577
+ raw: lookup.raw
1578
+ };
1579
+ }
1580
+ return {
1581
+ authorizeVoucherOutcome,
1582
+ authorizeVoucher,
1583
+ getLastAuthorizedVoucher,
1584
+ getSalesPoints,
1585
+ lookupVoucher,
1586
+ getVoucher
1185
1587
  };
1186
1588
  }
1187
1589
  function createWsmtxcaAuth(representedTaxId, token, sign) {
@@ -1192,7 +1594,7 @@ function createWsmtxcaAuth(representedTaxId, token, sign) {
1192
1594
  };
1193
1595
  }
1194
1596
  function toRecord(value) {
1195
- return value && typeof value === "object" ? value : void 0;
1597
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1196
1598
  }
1197
1599
  function unwrapWsmtxcaOperationResponse(response, operation) {
1198
1600
  const responseRecord = toRecord(response) ?? {};
@@ -1202,6 +1604,9 @@ function unwrapWsmtxcaOperationResponse(response, operation) {
1202
1604
  if (operation === "consultarComprobante") {
1203
1605
  return toRecord(responseRecord.consultarComprobanteResponse) ?? toRecord(responseRecord.consultaComprobanteResponse) ?? toRecord(responseRecord.consultarComprobanteResult) ?? responseRecord;
1204
1606
  }
1607
+ if (operation === "consultarPuntosVenta") {
1608
+ return toRecord(responseRecord.consultarPuntosVentaResponse) ?? toRecord(responseRecord.consultarPuntosVentaResult) ?? responseRecord;
1609
+ }
1205
1610
  return toRecord(responseRecord.consultarUltimoComprobanteAutorizadoResponse) ?? toRecord(responseRecord.consultaUltimoComprobanteAutorizadoResponse) ?? toRecord(responseRecord.consultarUltimoComprobanteAutorizadoResult) ?? responseRecord;
1206
1611
  }
1207
1612
  function extractWsmtxcaAuthorizationPayload(raw) {
@@ -1210,42 +1615,291 @@ function extractWsmtxcaAuthorizationPayload(raw) {
1210
1615
  function extractWsmtxcaVoucherPayload(raw) {
1211
1616
  return toRecord(raw.comprobanteResponse) ?? toRecord(raw.comprobante) ?? toRecord(raw.cmp) ?? raw;
1212
1617
  }
1213
- function extractWsmtxcaMessages(raw) {
1214
- const rawErrors = raw.arrayErrores;
1215
- const rawObservations = raw.arrayObservaciones;
1216
- const toEntries = (value) => {
1217
- if (!value) {
1218
- return [];
1219
- }
1220
- if (Array.isArray(value)) {
1221
- return value;
1618
+ function classifyWsmtxcaAuthorization(raw) {
1619
+ const operation = "autorizarComprobante";
1620
+ const payload = extractWsmtxcaAuthorizationPayload(raw);
1621
+ const result = normalizeWsmtxcaResult(raw.resultado ?? payload.resultado);
1622
+ const cae = normalizeWsmtxcaString(
1623
+ payload.CAE ?? payload.codigoAutorizacion ?? raw.codigoAutorizacion
1624
+ );
1625
+ const caeExpiry = normalizeWsmtxcaResponseDate(
1626
+ payload.fechaVencimientoCAE ?? payload.fechaVencimiento ?? raw.fechaVencimiento
1627
+ );
1628
+ const voucherNumber = parseOptionalPositiveInteger(
1629
+ payload.numeroComprobante ?? raw.numeroComprobante
1630
+ );
1631
+ const errors = extractWsmtxcaIssues(raw, operation, "error");
1632
+ const observations = extractWsmtxcaIssues(raw, operation, "observation");
1633
+ const base = {
1634
+ service: "wsmtxca",
1635
+ operation,
1636
+ results: createWsmtxcaResults(result),
1637
+ errors,
1638
+ observations,
1639
+ raw
1640
+ };
1641
+ if ((result === "A" || result === "O") && cae && voucherNumber !== void 0 && errors.length === 0) {
1642
+ return {
1643
+ ...base,
1644
+ kind: "authorized",
1645
+ result,
1646
+ resultLevel: "operation",
1647
+ cae,
1648
+ ...caeExpiry === void 0 ? {} : { caeExpiry },
1649
+ voucherNumber
1650
+ };
1651
+ }
1652
+ if (result === "R" && !cae && errors.length > 0) {
1653
+ return {
1654
+ ...base,
1655
+ kind: "rejected",
1656
+ result: "R",
1657
+ resultLevel: "operation"
1658
+ };
1659
+ }
1660
+ const outcome = {
1661
+ ...base,
1662
+ kind: "indeterminate",
1663
+ reason: result === "R" && Boolean(cae) || (result === "A" || result === "O") && Boolean(errors.length) ? "contradictory_response" : "incomplete_response",
1664
+ ...result === void 0 ? {} : { result },
1665
+ ...result === void 0 ? {} : { resultLevel: "operation" }
1666
+ };
1667
+ assignWsmtxcaValue(outcome, "cae", cae);
1668
+ assignWsmtxcaValue(outcome, "caeExpiry", caeExpiry);
1669
+ assignWsmtxcaValue(outcome, "voucherNumber", voucherNumber);
1670
+ return outcome;
1671
+ }
1672
+ function createWsmtxcaIndeterminateOutcome(error) {
1673
+ return {
1674
+ kind: "indeterminate",
1675
+ service: "wsmtxca",
1676
+ operation: "autorizarComprobante",
1677
+ results: {},
1678
+ reason: getWsmtxcaIndeterminateReason(error),
1679
+ errors: [],
1680
+ observations: []
1681
+ };
1682
+ }
1683
+ function getWsmtxcaIndeterminateReason(error) {
1684
+ if (error instanceof ArcaTransportError) {
1685
+ return "transport_error";
1686
+ }
1687
+ if (error instanceof ArcaSoapFaultError) {
1688
+ return "soap_fault";
1689
+ }
1690
+ if (error instanceof ArcaInvalidSoapResponseError) {
1691
+ return "invalid_response";
1692
+ }
1693
+ return "unexpected_error";
1694
+ }
1695
+ function createWsmtxcaOutcomeError(outcome) {
1696
+ const issues = [...outcome.errors, ...outcome.observations];
1697
+ const messages = formatWsmtxcaIssues(issues);
1698
+ const firstIssue = issues[0];
1699
+ return new ArcaServiceError(
1700
+ messages.join(" | ") || (outcome.kind === "rejected" ? "WSMTXCA rejected the voucher authorization" : "WSMTXCA did not return conclusive voucher authorization data"),
1701
+ {
1702
+ service: "wsmtxca",
1703
+ operation: outcome.operation,
1704
+ ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1705
+ ...outcome.result === void 0 ? {} : { result: outcome.result },
1706
+ ...outcome.resultLevel === void 0 ? {} : { resultLevel: outcome.resultLevel },
1707
+ results: outcome.results,
1708
+ ...outcome.kind === "indeterminate" && outcome.cae ? { cae: outcome.cae } : {},
1709
+ issues,
1710
+ detail: outcome.raw
1222
1711
  }
1223
- if (typeof value === "object") {
1224
- return [value];
1712
+ );
1713
+ }
1714
+ function createWsmtxcaResults(operationResult) {
1715
+ const results = {};
1716
+ assignWsmtxcaValue(results, "operation", operationResult);
1717
+ return results;
1718
+ }
1719
+ function createWsmtxcaServiceError(operation, raw, issues) {
1720
+ const firstIssue = issues[0];
1721
+ return new ArcaServiceError(
1722
+ formatWsmtxcaIssues(issues).join(" | ") || "WSMTXCA returned a service error",
1723
+ {
1724
+ service: "wsmtxca",
1725
+ operation,
1726
+ ...firstIssue?.code === void 0 ? {} : { serviceCode: firstIssue.code },
1727
+ issues,
1728
+ detail: raw
1225
1729
  }
1226
- return [];
1227
- };
1228
- const errors = toEntries(rawErrors?.codigoDescripcion).map((entry) => {
1229
- const code = entry.codigo == null ? "N/A" : String(entry.codigo);
1230
- const description = entry.descripcion == null ? "Unknown WSMTXCA error" : String(entry.descripcion);
1231
- return `Error ${code}: ${description}`;
1730
+ );
1731
+ }
1732
+ function extractWsmtxcaIssues(raw, operation, source) {
1733
+ const container = toRecord(
1734
+ source === "error" ? raw.arrayErrores : raw.arrayObservaciones
1735
+ );
1736
+ return normalizeWsmtxcaIssueEntries(container?.codigoDescripcion).map(
1737
+ (entry) => ({
1738
+ service: "wsmtxca",
1739
+ operation,
1740
+ source,
1741
+ category: source === "observation" ? "observation" : operation === "autorizarComprobante" ? "business" : "unknown",
1742
+ ...entry.code === void 0 ? {} : { code: entry.code },
1743
+ message: entry.message,
1744
+ ...operation === "autorizarComprobante" ? { resultLevel: "operation" } : {}
1745
+ })
1746
+ );
1747
+ }
1748
+ function normalizeWsmtxcaIssueEntries(value) {
1749
+ const entries = Array.isArray(value) ? value : value ? [value] : [];
1750
+ return entries.map((entry) => {
1751
+ const record = toRecord(entry) ?? {};
1752
+ const code = record.codigo;
1753
+ const description = record.descripcion;
1754
+ return {
1755
+ ...code === void 0 || code === null ? {} : { code: String(code) },
1756
+ message: description === void 0 || description === null ? "Unknown WSMTXCA issue" : String(description)
1757
+ };
1232
1758
  });
1233
- const observations = toEntries(rawObservations?.codigoDescripcion).map(
1234
- (entry) => {
1235
- const code = entry.codigo == null ? "N/A" : String(entry.codigo);
1236
- const description = entry.descripcion == null ? "" : String(entry.descripcion);
1237
- return `Obs ${code}: ${description}`.trim();
1238
- }
1759
+ }
1760
+ function formatWsmtxcaIssues(issues) {
1761
+ return issues.map((issue) => {
1762
+ const prefix = issue.source === "error" ? "Error" : "Obs";
1763
+ return `${prefix}${issue.code ? ` ${issue.code}` : ""}: ${issue.message}`;
1764
+ });
1765
+ }
1766
+ function mapWsmtxcaVoucherInfo(raw) {
1767
+ const voucher = { raw };
1768
+ const invoiceDate = normalizeWsmtxcaResponseDate(
1769
+ raw.fechaEmision ?? raw.fecha ?? raw.CbteFch
1770
+ );
1771
+ const cae = normalizeWsmtxcaString(raw.codigoAutorizacion ?? raw.CAE);
1772
+ const caeExpiry = normalizeWsmtxcaResponseDate(
1773
+ raw.fechaVencimiento ?? raw.fechaVencimientoCAE
1774
+ );
1775
+ const vatAmount = sumWsmtxcaVatAmounts(raw.arraySubtotalesIVA);
1776
+ assignWsmtxcaValue(
1777
+ voucher,
1778
+ "voucherNumber",
1779
+ parseOptionalPositiveInteger(raw.numeroComprobante)
1780
+ );
1781
+ assignWsmtxcaValue(voucher, "invoiceDate", invoiceDate);
1782
+ assignWsmtxcaValue(
1783
+ voucher,
1784
+ "salesPoint",
1785
+ parseOptionalPositiveInteger(raw.numeroPuntoVenta)
1786
+ );
1787
+ assignWsmtxcaValue(
1788
+ voucher,
1789
+ "voucherType",
1790
+ parseOptionalPositiveInteger(raw.codigoTipoComprobante)
1791
+ );
1792
+ assignWsmtxcaValue(
1793
+ voucher,
1794
+ "concept",
1795
+ parseOptionalNumber(raw.codigoConcepto)
1796
+ );
1797
+ assignWsmtxcaValue(
1798
+ voucher,
1799
+ "documentType",
1800
+ parseOptionalNumber(raw.codigoTipoDocumento)
1801
+ );
1802
+ assignWsmtxcaValue(
1803
+ voucher,
1804
+ "documentNumber",
1805
+ normalizeWsmtxcaString(raw.numeroDocumento)
1806
+ );
1807
+ assignWsmtxcaValue(
1808
+ voucher,
1809
+ "receiverVatConditionId",
1810
+ parseOptionalNumber(raw.condicionIVAReceptor)
1811
+ );
1812
+ assignWsmtxcaValue(
1813
+ voucher,
1814
+ "totalAmount",
1815
+ parseOptionalNumber(raw.importeTotal)
1816
+ );
1817
+ assignWsmtxcaValue(
1818
+ voucher,
1819
+ "subtotalAmount",
1820
+ parseOptionalNumber(raw.importeSubtotal)
1239
1821
  );
1240
- return [...errors, ...observations];
1822
+ assignWsmtxcaValue(
1823
+ voucher,
1824
+ "taxableAmount",
1825
+ parseOptionalNumber(raw.importeGravado)
1826
+ );
1827
+ assignWsmtxcaValue(
1828
+ voucher,
1829
+ "nonTaxableAmount",
1830
+ parseOptionalNumber(raw.importeNoGravado)
1831
+ );
1832
+ assignWsmtxcaValue(
1833
+ voucher,
1834
+ "exemptAmount",
1835
+ parseOptionalNumber(raw.importeExento)
1836
+ );
1837
+ assignWsmtxcaValue(
1838
+ voucher,
1839
+ "taxAmount",
1840
+ parseOptionalNumber(raw.importeOtrosTributos)
1841
+ );
1842
+ assignWsmtxcaValue(voucher, "vatAmount", vatAmount);
1843
+ assignWsmtxcaValue(
1844
+ voucher,
1845
+ "currencyId",
1846
+ normalizeWsmtxcaString(raw.codigoMoneda)
1847
+ );
1848
+ assignWsmtxcaValue(
1849
+ voucher,
1850
+ "exchangeRate",
1851
+ parseOptionalNumber(raw.cotizacionMoneda)
1852
+ );
1853
+ assignWsmtxcaValue(voucher, "cae", cae);
1854
+ assignWsmtxcaValue(voucher, "caeExpiry", caeExpiry);
1855
+ return voucher;
1241
1856
  }
1242
- function parseWsmtxcaVoucherNumber(value, message, detail) {
1857
+ function sumWsmtxcaVatAmounts(value) {
1858
+ const subtotals = toRecord(value)?.subtotalIVA;
1859
+ const entries = Array.isArray(subtotals) ? subtotals : subtotals ? [subtotals] : [];
1860
+ const amounts = entries.map((entry) => parseOptionalNumber(toRecord(entry)?.importe)).filter((amount) => amount !== void 0);
1861
+ return amounts.length > 0 ? amounts.reduce((total, amount) => total + amount, 0) : void 0;
1862
+ }
1863
+ function parseWsmtxcaVoucherNumber(value, message, detail, allowZero = false) {
1243
1864
  const parsed = Number.parseInt(String(value ?? ""), 10);
1244
- if (!Number.isFinite(parsed) || parsed <= 0) {
1245
- throw new ArcaServiceError(message, { detail });
1865
+ if (!Number.isFinite(parsed) || (allowZero ? parsed < 0 : parsed <= 0)) {
1866
+ throw new ArcaServiceError(message, {
1867
+ service: "wsmtxca",
1868
+ detail
1869
+ });
1246
1870
  }
1247
1871
  return parsed;
1248
1872
  }
1873
+ function parseOptionalPositiveInteger(value) {
1874
+ const parsed = Number.parseInt(String(value ?? ""), 10);
1875
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
1876
+ }
1877
+ function parseOptionalNumber(value) {
1878
+ if (value === void 0 || value === null || value === "") {
1879
+ return void 0;
1880
+ }
1881
+ const parsed = Number(value);
1882
+ return Number.isFinite(parsed) ? parsed : void 0;
1883
+ }
1884
+ function normalizeWsmtxcaResult(value) {
1885
+ if (typeof value !== "string") {
1886
+ return void 0;
1887
+ }
1888
+ const normalized = value.trim().toUpperCase();
1889
+ return normalized || void 0;
1890
+ }
1891
+ function normalizeWsmtxcaString(value) {
1892
+ if (value === void 0 || value === null) {
1893
+ return void 0;
1894
+ }
1895
+ const normalized = String(value).trim();
1896
+ return normalized || void 0;
1897
+ }
1898
+ function assignWsmtxcaValue(target, key, value) {
1899
+ if (value !== void 0) {
1900
+ target[key] = value;
1901
+ }
1902
+ }
1249
1903
  function normalizeWsmtxcaResponseDate(value) {
1250
1904
  if (typeof value === "number" && Number.isInteger(value)) {
1251
1905
  return formatCompactDateToIso(value);
@@ -1638,7 +2292,7 @@ function createSoapTransport(options) {
1638
2292
  soapAction: serviceConfig.soapVersion === "1.1" ? soapAction : void 0,
1639
2293
  useLegacyTlsSecurityLevel0: options.config.environment === "production" && serviceConfig.useLegacyTlsSecurityLevel0 === true,
1640
2294
  timeout: options.config.timeout,
1641
- retries: options.config.retries,
2295
+ retries: request.retries ?? options.config.retries,
1642
2296
  retryDelay: options.config.retryDelay,
1643
2297
  logger: options.logger,
1644
2298
  service: request.service,