facturas 0.6.0 → 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.
@@ -6,11 +6,26 @@ declare const ARCA_VOUCHER_TYPES: {
6
6
  readonly FACTURA_B: 6;
7
7
  readonly NOTA_DEBITO_B: 7;
8
8
  readonly NOTA_CREDITO_B: 8;
9
+ readonly FACTURA_C: 11;
10
+ readonly NOTA_DEBITO_C: 12;
11
+ readonly NOTA_CREDITO_C: 13;
9
12
  };
10
13
  /** Common document types accepted by ARCA services. */
11
14
  declare const ARCA_DOCUMENT_TYPES: {
12
15
  readonly CUIT: 80;
13
16
  readonly DNI: 96;
17
+ readonly CONSUMIDOR_FINAL: 99;
18
+ };
19
+ /**
20
+ * Common receiver IVA condition identifiers used by WSFE.
21
+ * Allowed values depend on the voucher class and ARCA's live catalog.
22
+ */
23
+ declare const ARCA_RECEIVER_VAT_CONDITIONS: {
24
+ readonly RESPONSABLE_INSCRIPTO: 1;
25
+ readonly EXENTO: 4;
26
+ readonly CONSUMIDOR_FINAL: 5;
27
+ readonly MONOTRIBUTISTA: 6;
28
+ readonly IVA_NO_ALCANZADO: 15;
14
29
  };
15
30
  /** Supported invoice concept types for WSFE requests. */
16
31
  declare const ARCA_CONCEPT_TYPES: {
@@ -24,6 +39,8 @@ declare const ARCA_VAT_RATES: {
24
39
  readonly IVA_10_5: 4;
25
40
  readonly IVA_21: 5;
26
41
  readonly IVA_27: 6;
42
+ readonly IVA_5: 8;
43
+ readonly IVA_2_5: 9;
27
44
  };
28
45
  /** Common ARCA currency identifiers. */
29
46
  declare const ARCA_CURRENCIES: {
@@ -31,4 +48,4 @@ declare const ARCA_CURRENCIES: {
31
48
  readonly DOL: "DOL";
32
49
  };
33
50
 
34
- export { ARCA_CONCEPT_TYPES, ARCA_CURRENCIES, ARCA_DOCUMENT_TYPES, ARCA_VAT_RATES, ARCA_VOUCHER_TYPES };
51
+ export { ARCA_CONCEPT_TYPES, ARCA_CURRENCIES, ARCA_DOCUMENT_TYPES, ARCA_RECEIVER_VAT_CONDITIONS, ARCA_VAT_RATES, ARCA_VOUCHER_TYPES };
@@ -5,11 +5,22 @@ var ARCA_VOUCHER_TYPES = {
5
5
  NOTA_CREDITO_A: 3,
6
6
  FACTURA_B: 6,
7
7
  NOTA_DEBITO_B: 7,
8
- NOTA_CREDITO_B: 8
8
+ NOTA_CREDITO_B: 8,
9
+ FACTURA_C: 11,
10
+ NOTA_DEBITO_C: 12,
11
+ NOTA_CREDITO_C: 13
9
12
  };
10
13
  var ARCA_DOCUMENT_TYPES = {
11
14
  CUIT: 80,
12
- DNI: 96
15
+ DNI: 96,
16
+ CONSUMIDOR_FINAL: 99
17
+ };
18
+ var ARCA_RECEIVER_VAT_CONDITIONS = {
19
+ RESPONSABLE_INSCRIPTO: 1,
20
+ EXENTO: 4,
21
+ CONSUMIDOR_FINAL: 5,
22
+ MONOTRIBUTISTA: 6,
23
+ IVA_NO_ALCANZADO: 15
13
24
  };
14
25
  var ARCA_CONCEPT_TYPES = {
15
26
  PRODUCTOS: 1,
@@ -20,7 +31,9 @@ var ARCA_VAT_RATES = {
20
31
  IVA_0: 3,
21
32
  IVA_10_5: 4,
22
33
  IVA_21: 5,
23
- IVA_27: 6
34
+ IVA_27: 6,
35
+ IVA_5: 8,
36
+ IVA_2_5: 9
24
37
  };
25
38
  var ARCA_CURRENCIES = {
26
39
  PES: "PES",
@@ -30,6 +43,7 @@ export {
30
43
  ARCA_CONCEPT_TYPES,
31
44
  ARCA_CURRENCIES,
32
45
  ARCA_DOCUMENT_TYPES,
46
+ ARCA_RECEIVER_VAT_CONDITIONS,
33
47
  ARCA_VAT_RATES,
34
48
  ARCA_VOUCHER_TYPES
35
49
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts"],"sourcesContent":["/** Common ARCA reference data for readable userland code and examples. */\nexport const ARCA_VOUCHER_TYPES = {\n FACTURA_A: 1,\n NOTA_DEBITO_A: 2,\n NOTA_CREDITO_A: 3,\n FACTURA_B: 6,\n NOTA_DEBITO_B: 7,\n NOTA_CREDITO_B: 8,\n} as const;\n\n/** Common document types accepted by ARCA services. */\nexport const ARCA_DOCUMENT_TYPES = {\n CUIT: 80,\n DNI: 96,\n} as const;\n\n/** Supported invoice concept types for WSFE requests. */\nexport const ARCA_CONCEPT_TYPES = {\n PRODUCTOS: 1,\n SERVICIOS: 2,\n PRODUCTOS_Y_SERVICIOS: 3,\n} as const;\n\n/** Common IVA rate identifiers used by WSFE. */\nexport const ARCA_VAT_RATES = {\n IVA_0: 3,\n IVA_10_5: 4,\n IVA_21: 5,\n IVA_27: 6,\n} as const;\n\n/** Common ARCA currency identifiers. */\nexport const ARCA_CURRENCIES = {\n PES: \"PES\",\n DOL: \"DOL\",\n} as const;\n"],"mappings":";AACO,IAAM,qBAAqB;AAAA,EAChC,WAAW;AAAA,EACX,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,eAAe;AAAA,EACf,gBAAgB;AAClB;AAGO,IAAM,sBAAsB;AAAA,EACjC,MAAM;AAAA,EACN,KAAK;AACP;AAGO,IAAM,qBAAqB;AAAA,EAChC,WAAW;AAAA,EACX,WAAW;AAAA,EACX,uBAAuB;AACzB;AAGO,IAAM,iBAAiB;AAAA,EAC5B,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AACV;AAGO,IAAM,kBAAkB;AAAA,EAC7B,KAAK;AAAA,EACL,KAAK;AACP;","names":[]}
1
+ {"version":3,"sources":["../src/constants.ts"],"sourcesContent":["/** Common ARCA reference data for readable userland code and examples. */\nexport const ARCA_VOUCHER_TYPES = {\n FACTURA_A: 1,\n NOTA_DEBITO_A: 2,\n NOTA_CREDITO_A: 3,\n FACTURA_B: 6,\n NOTA_DEBITO_B: 7,\n NOTA_CREDITO_B: 8,\n FACTURA_C: 11,\n NOTA_DEBITO_C: 12,\n NOTA_CREDITO_C: 13,\n} as const;\n\n/** Common document types accepted by ARCA services. */\nexport const ARCA_DOCUMENT_TYPES = {\n CUIT: 80,\n DNI: 96,\n CONSUMIDOR_FINAL: 99,\n} as const;\n\n/**\n * Common receiver IVA condition identifiers used by WSFE.\n * Allowed values depend on the voucher class and ARCA's live catalog.\n */\nexport const ARCA_RECEIVER_VAT_CONDITIONS = {\n RESPONSABLE_INSCRIPTO: 1,\n EXENTO: 4,\n CONSUMIDOR_FINAL: 5,\n MONOTRIBUTISTA: 6,\n IVA_NO_ALCANZADO: 15,\n} as const;\n\n/** Supported invoice concept types for WSFE requests. */\nexport const ARCA_CONCEPT_TYPES = {\n PRODUCTOS: 1,\n SERVICIOS: 2,\n PRODUCTOS_Y_SERVICIOS: 3,\n} as const;\n\n/** Common IVA rate identifiers used by WSFE. */\nexport const ARCA_VAT_RATES = {\n IVA_0: 3,\n IVA_10_5: 4,\n IVA_21: 5,\n IVA_27: 6,\n IVA_5: 8,\n IVA_2_5: 9,\n} as const;\n\n/** Common ARCA currency identifiers. */\nexport const ARCA_CURRENCIES = {\n PES: \"PES\",\n DOL: \"DOL\",\n} as const;\n"],"mappings":";AACO,IAAM,qBAAqB;AAAA,EAChC,WAAW;AAAA,EACX,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,eAAe;AAAA,EACf,gBAAgB;AAClB;AAGO,IAAM,sBAAsB;AAAA,EACjC,MAAM;AAAA,EACN,KAAK;AAAA,EACL,kBAAkB;AACpB;AAMO,IAAM,+BAA+B;AAAA,EAC1C,uBAAuB;AAAA,EACvB,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,kBAAkB;AACpB;AAGO,IAAM,qBAAqB;AAAA,EAChC,WAAW;AAAA,EACX,WAAW;AAAA,EACX,uBAAuB;AACzB;AAGO,IAAM,iBAAiB;AAAA,EAC5B,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AACX;AAGO,IAAM,kBAAkB;AAAA,EAC7B,KAAK;AAAA,EACL,KAAK;AACP;","names":[]}
package/dist/index.mjs CHANGED
@@ -100,9 +100,10 @@ var ARCA_ENV_VARIABLES = {
100
100
  };
101
101
  var PRIVATE_KEY_PEM_PREFIXES = [
102
102
  "-----BEGIN PRIVATE KEY-----",
103
- "-----BEGIN RSA PRIVATE KEY-----",
104
- "-----BEGIN ENCRYPTED PRIVATE KEY-----"
103
+ "-----BEGIN RSA PRIVATE KEY-----"
105
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;
106
107
  var VALID_ARCA_LOG_LEVELS = ["debug", "info", "warn", "error"];
107
108
  var DEFAULT_ARCA_TIMEOUT_MS = 3e4;
108
109
  var DEFAULT_ARCA_RETRIES = 0;
@@ -133,6 +134,11 @@ function assertArcaClientConfig(config) {
133
134
  const timeout = normalized.timeout ?? DEFAULT_ARCA_TIMEOUT_MS;
134
135
  const retries = normalized.retries ?? DEFAULT_ARCA_RETRIES;
135
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
+ }
136
142
  if (!/^\d{11}$/.test(normalized.taxId)) {
137
143
  invalidFields.push("taxId");
138
144
  }
@@ -786,12 +792,6 @@ function createWsfeService(options) {
786
792
  };
787
793
  }
788
794
  function mapWsfeVoucherInput(input, voucherNumber) {
789
- const sendsSameForeignCurrencyCancellation = input.currencyId !== "PES" && input.sameCurrencyForeignCancellation === "S";
790
- if (input.exchangeRate === void 0 && !sendsSameForeignCurrencyCancellation) {
791
- throw new ArcaInputError(
792
- "exchangeRate is required unless sameCurrencyForeignCancellation is S for a foreign-currency voucher."
793
- );
794
- }
795
795
  const data = {
796
796
  Concepto: input.concept,
797
797
  DocTipo: input.documentType,
@@ -809,7 +809,7 @@ function mapWsfeVoucherInput(input, voucherNumber) {
809
809
  PtoVta: input.salesPoint,
810
810
  CbteTipo: input.voucherType
811
811
  };
812
- if (!sendsSameForeignCurrencyCancellation) {
812
+ if (input.exchangeRate !== void 0) {
813
813
  data.MonCotiz = input.exchangeRate;
814
814
  }
815
815
  if (input.receiverVatConditionId !== void 0) {
@@ -893,6 +893,7 @@ function mapWsfeVoucherInput(input, voucherNumber) {
893
893
  function normalizeWsfeVoucherInput(input) {
894
894
  const {
895
895
  voucherDate,
896
+ exchangeRate,
896
897
  serviceStartDate,
897
898
  serviceEndDate,
898
899
  paymentDueDate,
@@ -900,9 +901,11 @@ function normalizeWsfeVoucherInput(input) {
900
901
  associatedPeriod,
901
902
  ...rest
902
903
  } = input;
904
+ const normalizedExchangeRate = normalizeWsfeExchangeRate(input, exchangeRate);
903
905
  return {
904
906
  ...rest,
905
907
  voucherDate: normalizeWsfeDateInput(voucherDate, "voucherDate"),
908
+ ...normalizedExchangeRate === void 0 ? {} : { exchangeRate: normalizedExchangeRate },
906
909
  ...serviceStartDate === void 0 ? {} : {
907
910
  serviceStartDate: normalizeWsfeDateInput(
908
911
  serviceStartDate,
@@ -949,6 +952,30 @@ function normalizeWsfeVoucherInput(input) {
949
952
  }
950
953
  };
951
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
+ }
952
979
  function normalizeWsfeDateInput(value, fieldName) {
953
980
  if (typeof value !== "string") {
954
981
  throw new ArcaInputError(
@@ -1380,12 +1407,12 @@ function createWsmtxcaService(options) {
1380
1407
  bodyElementName: `${operation}Request`,
1381
1408
  bodyElementNamespaceMode: "prefix",
1382
1409
  body: {
1410
+ ...body,
1383
1411
  authRequest: createWsmtxcaAuth(
1384
1412
  input.representedTaxId ?? options.config.taxId,
1385
1413
  auth.token,
1386
1414
  auth.sign
1387
- ),
1388
- ...body
1415
+ )
1389
1416
  }
1390
1417
  });
1391
1418
  return unwrapWsmtxcaOperationResponse(response.result, operation);
@@ -1395,6 +1422,11 @@ function createWsmtxcaService(options) {
1395
1422
  data,
1396
1423
  forceRefresh
1397
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
+ }
1398
1430
  try {
1399
1431
  const raw = await executeWsmtxcaAuthenticatedOperation(
1400
1432
  "autorizarComprobante",
@@ -2405,93 +2437,129 @@ function isWsaaCredentialValid(credentials) {
2405
2437
  // src/wsaa/index.ts
2406
2438
  function createWsaaAuthModule(options) {
2407
2439
  const cache = /* @__PURE__ */ new Map();
2408
- const inFlight = /* @__PURE__ */ new Map();
2409
- return {
2410
- async login(service, authOptions = {}) {
2411
- const sessionKey = buildWsaaSessionKey(options.config, service);
2412
- const cacheKey = serializeWsaaSessionKey(sessionKey);
2413
- const running = inFlight.get(cacheKey);
2414
- if (running) {
2415
- return running;
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);
2416
2448
  }
2417
- const loginPromise = (async () => {
2418
- const reuse = await getReusableCredentials({
2419
- config: options.config,
2420
- cache,
2421
- cacheKey,
2422
- sessionKey,
2423
- logger: options.logger,
2424
- service,
2425
- allowStore: !authOptions.forceRefresh,
2426
- allowCache: !authOptions.forceRefresh
2427
- });
2428
- if (reuse) {
2429
- return reuse;
2430
- }
2431
- const refresh = () => refreshWsaaCredentials({
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({
2432
2497
  config: options.config,
2433
2498
  cache,
2434
2499
  cacheKey,
2435
2500
  sessionKey,
2436
2501
  logger: options.logger,
2437
2502
  service,
2438
- forceRefresh: authOptions.forceRefresh === true
2503
+ allowStore: true,
2504
+ allowCache: true
2439
2505
  });
2440
- if (options.config.wsaaSessionStore?.withLock) {
2441
- return await withWsaaSessionStoreLock(
2442
- options.config,
2443
- sessionKey,
2444
- service,
2445
- refresh
2506
+ if (recovered) {
2507
+ options.logger?.warn(
2508
+ "Recovered WSAA coe.alreadyAuthenticated fault",
2509
+ {
2510
+ service,
2511
+ faultCode: error.faultCode
2512
+ }
2446
2513
  );
2514
+ return recovered;
2447
2515
  }
2448
- return await refresh();
2449
- })();
2450
- inFlight.set(cacheKey, loginPromise);
2451
- try {
2452
- return await loginPromise;
2453
- } catch (error) {
2454
- if (error instanceof ArcaSoapFaultError && error.faultCode === "ns1:coe.alreadyAuthenticated") {
2455
- const recovered = await getReusableCredentials({
2456
- config: options.config,
2457
- cache,
2458
- cacheKey,
2459
- sessionKey,
2460
- logger: options.logger,
2461
- service,
2462
- allowStore: true,
2463
- allowCache: true
2464
- });
2465
- if (recovered) {
2466
- options.logger?.warn(
2467
- "Recovered WSAA coe.alreadyAuthenticated fault",
2468
- {
2469
- service,
2470
- faultCode: error.faultCode
2471
- }
2472
- );
2473
- return recovered;
2474
- }
2475
- if (!options.config.wsaaSessionStore) {
2476
- throw new ArcaConfigurationError(
2477
- "WSAA login failed because another process likely owns a valid TA. Configure a durable wsaaSessionStore for multi-process or serverless deployments.",
2478
- { cause: error }
2479
- );
2480
- }
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
+ );
2481
2521
  }
2482
- if (error instanceof ArcaSoapFaultError) {
2483
- options.logger?.error("WSAA SOAP fault response", {
2484
- service,
2485
- operation: "loginCms",
2486
- url: ARCA_WSAA_CONFIG.endpoint[options.config.environment],
2487
- faultCode: error.faultCode,
2488
- error
2489
- });
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;
2490
2543
  }
2491
- throw error;
2492
- } finally {
2493
- inFlight.delete(cacheKey);
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
+ });
2549
+ }
2550
+ const runningOrdinary = ordinaryInFlight.get(cacheKey);
2551
+ if (runningOrdinary) {
2552
+ return runningOrdinary;
2494
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
+ );
2495
2563
  }
2496
2564
  };
2497
2565
  }