facturas 0.7.0 → 0.8.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/README.md CHANGED
@@ -29,10 +29,22 @@ The package exports:
29
29
  - `facturas/errors`
30
30
  - `facturas/types`
31
31
 
32
- The primary WSFE path uses `buildFacturaB()` or `buildFacturaC()` with integer
33
- minor-unit amounts and ISO `ARS`/`USD` currency input. The builders are exported
34
- from both `facturas` and `facturas/wsfe`. Advanced exact `WsfeVoucherInput`
35
- requests continue to use ARCA currency identifiers such as `PES` and `DOL`.
32
+ The primary invoice path is `client.vouchers.issue()`, using an explicit
33
+ `issuer`, a fiscal `to` receiver, a required `salesPoint`, and integer-minor-unit
34
+ items. It derives A/B/C, VAT and totals, and returns `authorized`, `rejected`,
35
+ `indeterminate`, or `conflict`. Raw provider evidence is opt-in.
36
+
37
+ **Single-writer contract:** serialize per `(representedTaxId, salesPoint,
38
+ voucherType)`. The SDK does not coordinate writers; concurrent calls collide on
39
+ 10016. Servers and queues must persist attempts and use
40
+ `client.wsfe.authorizeVoucherOutcome()` directly. The facade makes one write
41
+ attempt and at most one identity-matched recovery lookup, never a resubmission.
42
+
43
+ `buildFacturaB()` and `buildFacturaC()` retain their v0.7.1 behavior and are
44
+ exported from `facturas` and `facturas/wsfe`. The facade and builders accept ISO
45
+ `ARS`/`USD`; exact `WsfeVoucherInput` uses provider identifiers `PES`/`DOL`.
46
+ The only existing type widening in v0.8 is required `ArcaClient.vouchers`;
47
+ hand-built typed mocks must add that member.
36
48
 
37
49
  `facturas` also exports `createMemoryWsaaSessionStore()` for tests/local single-process coordination and the small `ArcaWsaaSessionStore` interface for applications that need to share WSAA tickets across workers through their own durable store.
38
50
 
@@ -0,0 +1,109 @@
1
+ // src/constants.ts
2
+ var ARCA_VOUCHER_TYPES = {
3
+ FACTURA_A: 1,
4
+ NOTA_DEBITO_A: 2,
5
+ NOTA_CREDITO_A: 3,
6
+ FACTURA_B: 6,
7
+ NOTA_DEBITO_B: 7,
8
+ NOTA_CREDITO_B: 8,
9
+ FACTURA_C: 11,
10
+ NOTA_DEBITO_C: 12,
11
+ NOTA_CREDITO_C: 13
12
+ };
13
+ var ARCA_DOCUMENT_TYPES = {
14
+ CUIT: 80,
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
24
+ };
25
+ var ARCA_CONCEPT_TYPES = {
26
+ PRODUCTOS: 1,
27
+ SERVICIOS: 2,
28
+ PRODUCTOS_Y_SERVICIOS: 3
29
+ };
30
+ var ARCA_VAT_RATES = {
31
+ IVA_0: 3,
32
+ IVA_10_5: 4,
33
+ IVA_21: 5,
34
+ IVA_27: 6,
35
+ IVA_5: 8,
36
+ IVA_2_5: 9
37
+ };
38
+ var ISO_CURRENCIES = {
39
+ ARS: "ARS",
40
+ USD: "USD"
41
+ };
42
+ var ARCA_CURRENCY_IDS = {
43
+ ARS: "PES",
44
+ USD: "DOL"
45
+ };
46
+ var ARCA_CURRENCIES = {
47
+ PES: "PES",
48
+ DOL: "DOL"
49
+ };
50
+ var ARCA_RECEIVER_CONDITION_IDS = {
51
+ responsable_inscripto: ARCA_RECEIVER_VAT_CONDITIONS.RESPONSABLE_INSCRIPTO,
52
+ monotributo: ARCA_RECEIVER_VAT_CONDITIONS.MONOTRIBUTISTA,
53
+ exento: ARCA_RECEIVER_VAT_CONDITIONS.EXENTO,
54
+ consumidor_final: ARCA_RECEIVER_VAT_CONDITIONS.CONSUMIDOR_FINAL,
55
+ no_alcanzado: ARCA_RECEIVER_VAT_CONDITIONS.IVA_NO_ALCANZADO
56
+ };
57
+ var ARCA_ISSUER_CONDITION_IDS = {
58
+ responsable_inscripto: 1,
59
+ monotributo: 6,
60
+ exento: 4,
61
+ no_alcanzado: 15
62
+ };
63
+ var ARCA_FINAL_CONSUMER_IDENTIFICATION_THRESHOLD_MINOR_UNITS = 1000000000n;
64
+ var ARCA_INVOICE_CLASS_BY_ISSUER = {
65
+ responsable_inscripto: {
66
+ responsable_inscripto: "A",
67
+ monotributo: "A",
68
+ exento: "B",
69
+ consumidor_final: "B",
70
+ no_alcanzado: "B"
71
+ },
72
+ monotributo: {
73
+ responsable_inscripto: "C",
74
+ monotributo: "C",
75
+ exento: "C",
76
+ consumidor_final: "C",
77
+ no_alcanzado: "C"
78
+ },
79
+ exento: {
80
+ responsable_inscripto: "C",
81
+ monotributo: "C",
82
+ exento: "C",
83
+ consumidor_final: "C",
84
+ no_alcanzado: "C"
85
+ },
86
+ no_alcanzado: {
87
+ responsable_inscripto: "C",
88
+ monotributo: "C",
89
+ exento: "C",
90
+ consumidor_final: "C",
91
+ no_alcanzado: "C"
92
+ }
93
+ };
94
+
95
+ export {
96
+ ARCA_VOUCHER_TYPES,
97
+ ARCA_DOCUMENT_TYPES,
98
+ ARCA_RECEIVER_VAT_CONDITIONS,
99
+ ARCA_CONCEPT_TYPES,
100
+ ARCA_VAT_RATES,
101
+ ISO_CURRENCIES,
102
+ ARCA_CURRENCY_IDS,
103
+ ARCA_CURRENCIES,
104
+ ARCA_RECEIVER_CONDITION_IDS,
105
+ ARCA_ISSUER_CONDITION_IDS,
106
+ ARCA_FINAL_CONSUMER_IDENTIFICATION_THRESHOLD_MINOR_UNITS,
107
+ ARCA_INVOICE_CLASS_BY_ISSUER
108
+ };
109
+ //# sourceMappingURL=chunk-76WU5BVI.mjs.map
@@ -0,0 +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 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/** ISO currency codes accepted by the high-level WSFE builders. */\nexport const ISO_CURRENCIES = {\n ARS: \"ARS\",\n USD: \"USD\",\n} as const;\n\n/** ARCA currency identifiers keyed by their corresponding ISO currency. */\nexport const ARCA_CURRENCY_IDS = {\n ARS: \"PES\",\n USD: \"DOL\",\n} as const;\n\n/**\n * Common ARCA currency identifiers.\n * @deprecated Use ISO_CURRENCIES for builders or ARCA_CURRENCY_IDS at the exact provider boundary.\n */\nexport const ARCA_CURRENCIES = {\n PES: \"PES\",\n DOL: \"DOL\",\n} as const;\n\n/** Legal assertions supported by the invoice facade; never inferred from Padrón. */\nexport type IssuerCondition =\n | \"responsable_inscripto\"\n | \"monotributo\"\n | \"exento\"\n | \"no_alcanzado\";\nexport type ReceiverCondition = IssuerCondition | \"consumidor_final\";\nexport type VoucherClass = \"A\" | \"B\" | \"C\";\n\nexport const ARCA_RECEIVER_CONDITION_IDS = {\n responsable_inscripto: ARCA_RECEIVER_VAT_CONDITIONS.RESPONSABLE_INSCRIPTO,\n monotributo: ARCA_RECEIVER_VAT_CONDITIONS.MONOTRIBUTISTA,\n exento: ARCA_RECEIVER_VAT_CONDITIONS.EXENTO,\n consumidor_final: ARCA_RECEIVER_VAT_CONDITIONS.CONSUMIDOR_FINAL,\n no_alcanzado: ARCA_RECEIVER_VAT_CONDITIONS.IVA_NO_ALCANZADO,\n} as const satisfies Record<ReceiverCondition, number>;\n\nexport const ARCA_ISSUER_CONDITION_IDS = {\n responsable_inscripto: 1,\n monotributo: 6,\n exento: 4,\n no_alcanzado: 15,\n} as const satisfies Record<IssuerCondition, number>;\n\n// RG 5866/2026, art. 1(f), effective 2026-07-01 (art. 4).\n// https://www.argentina.gob.ar/normativa/nacional/norma-427092/texto\nexport const ARCA_FINAL_CONSUMER_IDENTIFICATION_THRESHOLD_MINOR_UNITS =\n 1_000_000_000n;\n\n// WSFE v4.7, physical PDF p. 203, validations 10243/10246; issuer asserted first.\n// ARCA checks actual issuer eligibility independently at authorization.\nexport const ARCA_INVOICE_CLASS_BY_ISSUER = {\n responsable_inscripto: {\n responsable_inscripto: \"A\",\n monotributo: \"A\",\n exento: \"B\",\n consumidor_final: \"B\",\n no_alcanzado: \"B\",\n },\n monotributo: {\n responsable_inscripto: \"C\",\n monotributo: \"C\",\n exento: \"C\",\n consumidor_final: \"C\",\n no_alcanzado: \"C\",\n },\n exento: {\n responsable_inscripto: \"C\",\n monotributo: \"C\",\n exento: \"C\",\n consumidor_final: \"C\",\n no_alcanzado: \"C\",\n },\n no_alcanzado: {\n responsable_inscripto: \"C\",\n monotributo: \"C\",\n exento: \"C\",\n consumidor_final: \"C\",\n no_alcanzado: \"C\",\n },\n} as const satisfies Record<\n IssuerCondition,\n Record<ReceiverCondition, VoucherClass>\n>;\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,iBAAiB;AAAA,EAC5B,KAAK;AAAA,EACL,KAAK;AACP;AAGO,IAAM,oBAAoB;AAAA,EAC/B,KAAK;AAAA,EACL,KAAK;AACP;AAMO,IAAM,kBAAkB;AAAA,EAC7B,KAAK;AAAA,EACL,KAAK;AACP;AAWO,IAAM,8BAA8B;AAAA,EACzC,uBAAuB,6BAA6B;AAAA,EACpD,aAAa,6BAA6B;AAAA,EAC1C,QAAQ,6BAA6B;AAAA,EACrC,kBAAkB,6BAA6B;AAAA,EAC/C,cAAc,6BAA6B;AAC7C;AAEO,IAAM,4BAA4B;AAAA,EACvC,uBAAuB;AAAA,EACvB,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,cAAc;AAChB;AAIO,IAAM,2DACX;AAIK,IAAM,+BAA+B;AAAA,EAC1C,uBAAuB;AAAA,IACrB,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,cAAc;AAAA,EAChB;AAAA,EACA,aAAa;AAAA,IACX,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,cAAc;AAAA,EAChB;AAAA,EACA,QAAQ;AAAA,IACN,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,cAAc;AAAA,EAChB;AAAA,EACA,cAAc;AAAA,IACZ,uBAAuB;AAAA,IACvB,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,cAAc;AAAA,EAChB;AACF;","names":[]}
@@ -198,6 +198,17 @@ function normalizeProviderCode(providerCode) {
198
198
  }
199
199
  return void 0;
200
200
  }
201
+ function toArcaSafeErrorMetadata(error) {
202
+ if (!(error instanceof Error)) {
203
+ return { name: "UnknownError", message: String(error) };
204
+ }
205
+ return {
206
+ name: error.name,
207
+ message: error.message,
208
+ ...error instanceof ArcaError ? { code: error.code } : {},
209
+ ...error instanceof ArcaTransportError && error.statusCode !== void 0 ? { statusCode: error.statusCode } : {}
210
+ };
211
+ }
201
212
 
202
213
  export {
203
214
  createResponseBodyDiagnostic,
@@ -210,6 +221,7 @@ export {
210
221
  ArcaTransportError,
211
222
  ArcaSoapFaultError,
212
223
  ArcaInvalidSoapResponseError,
213
- ArcaServiceError
224
+ ArcaServiceError,
225
+ toArcaSafeErrorMetadata
214
226
  };
215
- //# sourceMappingURL=chunk-MBWOFO67.mjs.map
227
+ //# sourceMappingURL=chunk-HUT3PFKF.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/redaction.ts","../src/errors.ts"],"sourcesContent":["export const MAX_DIAGNOSTIC_PREVIEW_LENGTH = 4096;\n\nconst MAX_DIAGNOSTIC_SCALAR_LENGTH = 512;\nconst SENSITIVE_XML_ELEMENT_NAME = \"((?:[A-Za-z_][\\\\w.-]*:)?(?:Token|Sign))\";\nconst PAIRED_SENSITIVE_XML_ELEMENT = new RegExp(\n `<${SENSITIVE_XML_ELEMENT_NAME}\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/\\\\1\\\\s*>`,\n \"gi\"\n);\nconst SELF_CLOSING_SENSITIVE_XML_ELEMENT = new RegExp(\n `<${SENSITIVE_XML_ELEMENT_NAME}\\\\b[^>]*\\\\/\\\\s*>`,\n \"gi\"\n);\nconst UNTERMINATED_SENSITIVE_XML_ELEMENT = new RegExp(\n `<${SENSITIVE_XML_ELEMENT_NAME}\\\\b[^>]*>[^<]*`,\n \"gi\"\n);\n\nexport type ResponseBodyDiagnostic = {\n responseBodyLength: number;\n responseBodyPreview: string;\n};\n\nexport type SafeErrorDiagnostic = {\n errorName?: string;\n errorCode?: string;\n statusCode?: number;\n contentType?: string;\n responseBodyLength?: number;\n responseBodyPreview?: string;\n faultCode?: string;\n};\n\n/** Redacts credential-bearing XML elements and applies the global preview bound. */\nexport function redactDiagnosticPreview(\n value: string,\n requestedMaxLength = MAX_DIAGNOSTIC_PREVIEW_LENGTH\n): string {\n const maxLength = normalizePreviewLength(requestedMaxLength);\n\n return value\n .replace(\n PAIRED_SENSITIVE_XML_ELEMENT,\n (_match, tagName: string) => `<${tagName}>[REDACTED]</${tagName}>`\n )\n .replace(\n SELF_CLOSING_SENSITIVE_XML_ELEMENT,\n (_match, tagName: string) => `<${tagName}>[REDACTED]</${tagName}>`\n )\n .replace(\n UNTERMINATED_SENSITIVE_XML_ELEMENT,\n (_match, tagName: string) => `<${tagName}>[REDACTED]`\n )\n .slice(0, maxLength);\n}\n\n/** Produces the only response-body shape allowed in errors and logs. */\nexport function createResponseBodyDiagnostic(\n responseBody: string,\n requestedMaxLength = MAX_DIAGNOSTIC_PREVIEW_LENGTH\n): ResponseBodyDiagnostic {\n return {\n responseBodyLength: responseBody.length,\n responseBodyPreview: redactDiagnosticPreview(\n responseBody,\n requestedMaxLength\n ),\n };\n}\n\n/** Extracts a scalar allowlist from an error without exposing the error or cause. */\nexport function createSafeErrorDiagnostic(error: unknown): SafeErrorDiagnostic {\n if (!(error && typeof error === \"object\")) {\n return {};\n }\n\n const candidate = error as Record<string, unknown>;\n const diagnostic: SafeErrorDiagnostic = {};\n\n assignSafeString(diagnostic, \"errorName\", candidate.name);\n assignSafeString(diagnostic, \"errorCode\", candidate.code);\n assignSafeNumber(diagnostic, \"statusCode\", candidate.statusCode);\n assignSafeString(diagnostic, \"contentType\", candidate.contentType);\n assignSafeNumber(\n diagnostic,\n \"responseBodyLength\",\n candidate.responseBodyLength\n );\n if (typeof candidate.responseBodyPreview === \"string\") {\n diagnostic.responseBodyPreview = redactDiagnosticPreview(\n candidate.responseBodyPreview\n );\n }\n assignSafeString(diagnostic, \"faultCode\", candidate.faultCode);\n\n return diagnostic;\n}\n\nfunction normalizePreviewLength(requestedMaxLength: number): number {\n if (!Number.isFinite(requestedMaxLength)) {\n return MAX_DIAGNOSTIC_PREVIEW_LENGTH;\n }\n\n return Math.max(\n 0,\n Math.min(Math.trunc(requestedMaxLength), MAX_DIAGNOSTIC_PREVIEW_LENGTH)\n );\n}\n\nfunction assignSafeString<\n TKey extends \"errorName\" | \"errorCode\" | \"contentType\" | \"faultCode\",\n>(target: SafeErrorDiagnostic, key: TKey, value: unknown): void {\n if (typeof value === \"string\") {\n target[key] = redactDiagnosticPreview(value, MAX_DIAGNOSTIC_SCALAR_LENGTH);\n }\n}\n\nfunction assignSafeNumber<TKey extends \"statusCode\" | \"responseBodyLength\">(\n target: SafeErrorDiagnostic,\n key: TKey,\n value: unknown\n): void {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n target[key] = value;\n }\n}\n","import { redactDiagnosticPreview } from \"./internal/redaction\";\nimport type { ArcaServiceName } from \"./internal/types\";\nimport type {\n ArcaFiscalIssue,\n ArcaFiscalResultLevel,\n ArcaFiscalResults,\n} from \"./services/fiscal-evidence\";\n\n/** Base error class for all ARCA-related errors. */\nexport class ArcaError extends Error {\n readonly code: string;\n override readonly name: string = \"ArcaError\";\n\n constructor(message: string, code = \"ARCA_ERROR\", options?: ErrorOptions) {\n super(message, options);\n this.code = code;\n }\n}\n\n/** Thrown when the ARCA client configuration is missing or invalid. */\nexport class ArcaConfigurationError extends ArcaError {\n override readonly name: string = \"ArcaConfigurationError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, \"ARCA_CONFIGURATION_ERROR\", options);\n }\n}\n\n/** Stable routing codes for caller-provided input failures. */\nexport type ArcaInputErrorCode =\n | \"ARCA_INPUT_INVALID_DATE\"\n | \"ARCA_INPUT_INVALID_AMOUNT\"\n | \"ARCA_INPUT_AMOUNT_PRECISION\"\n | \"ARCA_INPUT_AMOUNT_MISMATCH\"\n | \"ARCA_INPUT_INVALID_EXCHANGE_RATE\"\n | \"ARCA_INPUT_INVALID_VALUE\"\n | \"ARCA_INPUT_MISSING_FIELD\"\n | \"ARCA_INPUT_RESERVED_FIELD\";\n\nexport type ArcaInputErrorOptions = ErrorOptions & {\n code: ArcaInputErrorCode;\n field?: string;\n expected?: string;\n};\n\n/** Thrown when caller-provided input data is missing or invalid. */\nexport class ArcaInputError extends ArcaError {\n declare readonly code: ArcaInputErrorCode;\n override readonly name: string = \"ArcaInputError\";\n readonly field?: string;\n readonly expected?: string;\n\n constructor(message: string, options: ArcaInputErrorOptions) {\n super(message, options.code, options);\n this.field = options.field;\n this.expected = options.expected;\n }\n}\n\n/** Stable reasons exposed for explicit ARCA authentication rejections. */\nexport type ArcaAuthenticationReason =\n | \"invalid_token\"\n | \"unauthorized_computer\"\n | \"missing_relationship\"\n | \"authentication_rejected\";\n\nexport type ArcaAuthenticationErrorOptions = ErrorOptions & {\n reason: ArcaAuthenticationReason;\n service: ArcaServiceName;\n operation: string;\n providerCode?: string | number;\n};\n\n/** Thrown when ARCA explicitly rejects credentials before an operation runs. */\nexport class ArcaAuthenticationError extends ArcaError {\n declare readonly code: \"ARCA_AUTHENTICATION_ERROR\";\n override readonly name: string = \"ArcaAuthenticationError\";\n readonly reason: ArcaAuthenticationReason;\n readonly service: ArcaServiceName;\n readonly operation: string;\n readonly providerCode?: string | number;\n\n constructor(message: string, options: ArcaAuthenticationErrorOptions) {\n super(\n redactDiagnosticPreview(message),\n \"ARCA_AUTHENTICATION_ERROR\",\n options\n );\n this.reason = options.reason;\n this.service = options.service;\n this.operation = options.operation;\n this.providerCode = normalizeProviderCode(options.providerCode);\n }\n}\n\n/** Narrows unknown failures to the explicit authentication error contract. */\nexport function isArcaAuthenticationError(\n error: unknown\n): error is ArcaAuthenticationError {\n return error instanceof ArcaAuthenticationError;\n}\n\n/** Thrown when an HTTP request to an ARCA endpoint fails at the transport level. */\nexport class ArcaTransportError extends ArcaError {\n override readonly name: string = \"ArcaTransportError\";\n readonly statusCode?: number;\n readonly contentType?: string;\n readonly responseBodyLength?: number;\n readonly responseBodyPreview?: string;\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n statusCode?: number;\n contentType?: string;\n responseBodyLength?: number;\n responseBodyPreview?: string;\n }\n ) {\n super(message, \"ARCA_TRANSPORT_ERROR\", options);\n this.statusCode = options?.statusCode;\n this.contentType = options?.contentType;\n this.responseBodyLength = options?.responseBodyLength;\n this.responseBodyPreview =\n options?.responseBodyPreview === undefined\n ? undefined\n : redactDiagnosticPreview(options.responseBodyPreview);\n }\n}\n\n/** Thrown when the SOAP response contains a Fault element. */\nexport class ArcaSoapFaultError extends ArcaError {\n override readonly name: string = \"ArcaSoapFaultError\";\n readonly faultCode?: string;\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n faultCode?: string;\n }\n ) {\n super(redactDiagnosticPreview(message), \"ARCA_SOAP_FAULT\", options);\n this.faultCode =\n options?.faultCode === undefined\n ? undefined\n : redactDiagnosticPreview(options.faultCode);\n }\n}\n\n/** Thrown when a response cannot be parsed as a valid SOAP envelope. */\nexport class ArcaInvalidSoapResponseError extends ArcaError {\n override readonly name: string = \"ArcaInvalidSoapResponseError\";\n readonly service?: ArcaServiceName;\n readonly operation?: string;\n readonly endpointUrl?: string;\n readonly statusCode?: number;\n readonly contentType?: string;\n readonly responseBodyLength?: number;\n readonly responseBodyPreview?: string;\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n service?: ArcaServiceName;\n operation?: string;\n endpointUrl?: string;\n statusCode?: number;\n contentType?: string;\n responseBodyLength?: number;\n responseBodyPreview?: string;\n }\n ) {\n super(message, \"ARCA_INVALID_SOAP_RESPONSE\", options);\n this.service = options?.service;\n this.operation = options?.operation;\n this.endpointUrl = options?.endpointUrl;\n this.statusCode = options?.statusCode;\n this.contentType = options?.contentType;\n this.responseBodyLength = options?.responseBodyLength;\n this.responseBodyPreview =\n options?.responseBodyPreview === undefined\n ? undefined\n : redactDiagnosticPreview(options.responseBodyPreview);\n }\n}\n\n/** Thrown when an ARCA service (WSFE, WSMTXCA, Padron) returns a domain-level error. */\nexport class ArcaServiceError extends ArcaError {\n override readonly name: string = \"ArcaServiceError\";\n readonly serviceCode?: string | number;\n readonly service?: ArcaServiceName;\n readonly operation?: string;\n readonly result?: string;\n readonly resultLevel?: ArcaFiscalResultLevel;\n readonly results?: ArcaFiscalResults;\n readonly cae?: string;\n readonly issues?: readonly ArcaFiscalIssue[];\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n serviceCode?: string | number;\n service?: ArcaServiceName;\n operation?: string;\n result?: string;\n resultLevel?: ArcaFiscalResultLevel;\n results?: ArcaFiscalResults;\n cae?: string;\n issues?: readonly ArcaFiscalIssue[];\n }\n ) {\n super(message, \"ARCA_SERVICE_ERROR\", options);\n this.serviceCode = options?.serviceCode;\n this.service = options?.service;\n this.operation = options?.operation;\n this.result = options?.result;\n this.resultLevel = options?.resultLevel;\n this.results = options?.results;\n this.cae = options?.cae;\n this.issues = options?.issues;\n }\n}\n\nfunction normalizeProviderCode(\n providerCode: string | number | undefined\n): string | number | undefined {\n if (typeof providerCode === \"number\") {\n return Number.isFinite(providerCode) ? providerCode : undefined;\n }\n if (typeof providerCode === \"string\") {\n return redactDiagnosticPreview(providerCode, 512);\n }\n return undefined;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/internal/redaction.ts","../src/errors.ts"],"sourcesContent":["export const MAX_DIAGNOSTIC_PREVIEW_LENGTH = 4096;\n\nconst MAX_DIAGNOSTIC_SCALAR_LENGTH = 512;\nconst SENSITIVE_XML_ELEMENT_NAME = \"((?:[A-Za-z_][\\\\w.-]*:)?(?:Token|Sign))\";\nconst PAIRED_SENSITIVE_XML_ELEMENT = new RegExp(\n `<${SENSITIVE_XML_ELEMENT_NAME}\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/\\\\1\\\\s*>`,\n \"gi\"\n);\nconst SELF_CLOSING_SENSITIVE_XML_ELEMENT = new RegExp(\n `<${SENSITIVE_XML_ELEMENT_NAME}\\\\b[^>]*\\\\/\\\\s*>`,\n \"gi\"\n);\nconst UNTERMINATED_SENSITIVE_XML_ELEMENT = new RegExp(\n `<${SENSITIVE_XML_ELEMENT_NAME}\\\\b[^>]*>[^<]*`,\n \"gi\"\n);\n\nexport type ResponseBodyDiagnostic = {\n responseBodyLength: number;\n responseBodyPreview: string;\n};\n\nexport type SafeErrorDiagnostic = {\n errorName?: string;\n errorCode?: string;\n statusCode?: number;\n contentType?: string;\n responseBodyLength?: number;\n responseBodyPreview?: string;\n faultCode?: string;\n};\n\n/** Redacts credential-bearing XML elements and applies the global preview bound. */\nexport function redactDiagnosticPreview(\n value: string,\n requestedMaxLength = MAX_DIAGNOSTIC_PREVIEW_LENGTH\n): string {\n const maxLength = normalizePreviewLength(requestedMaxLength);\n\n return value\n .replace(\n PAIRED_SENSITIVE_XML_ELEMENT,\n (_match, tagName: string) => `<${tagName}>[REDACTED]</${tagName}>`\n )\n .replace(\n SELF_CLOSING_SENSITIVE_XML_ELEMENT,\n (_match, tagName: string) => `<${tagName}>[REDACTED]</${tagName}>`\n )\n .replace(\n UNTERMINATED_SENSITIVE_XML_ELEMENT,\n (_match, tagName: string) => `<${tagName}>[REDACTED]`\n )\n .slice(0, maxLength);\n}\n\n/** Produces the only response-body shape allowed in errors and logs. */\nexport function createResponseBodyDiagnostic(\n responseBody: string,\n requestedMaxLength = MAX_DIAGNOSTIC_PREVIEW_LENGTH\n): ResponseBodyDiagnostic {\n return {\n responseBodyLength: responseBody.length,\n responseBodyPreview: redactDiagnosticPreview(\n responseBody,\n requestedMaxLength\n ),\n };\n}\n\n/** Extracts a scalar allowlist from an error without exposing the error or cause. */\nexport function createSafeErrorDiagnostic(error: unknown): SafeErrorDiagnostic {\n if (!(error && typeof error === \"object\")) {\n return {};\n }\n\n const candidate = error as Record<string, unknown>;\n const diagnostic: SafeErrorDiagnostic = {};\n\n assignSafeString(diagnostic, \"errorName\", candidate.name);\n assignSafeString(diagnostic, \"errorCode\", candidate.code);\n assignSafeNumber(diagnostic, \"statusCode\", candidate.statusCode);\n assignSafeString(diagnostic, \"contentType\", candidate.contentType);\n assignSafeNumber(\n diagnostic,\n \"responseBodyLength\",\n candidate.responseBodyLength\n );\n if (typeof candidate.responseBodyPreview === \"string\") {\n diagnostic.responseBodyPreview = redactDiagnosticPreview(\n candidate.responseBodyPreview\n );\n }\n assignSafeString(diagnostic, \"faultCode\", candidate.faultCode);\n\n return diagnostic;\n}\n\nfunction normalizePreviewLength(requestedMaxLength: number): number {\n if (!Number.isFinite(requestedMaxLength)) {\n return MAX_DIAGNOSTIC_PREVIEW_LENGTH;\n }\n\n return Math.max(\n 0,\n Math.min(Math.trunc(requestedMaxLength), MAX_DIAGNOSTIC_PREVIEW_LENGTH)\n );\n}\n\nfunction assignSafeString<\n TKey extends \"errorName\" | \"errorCode\" | \"contentType\" | \"faultCode\",\n>(target: SafeErrorDiagnostic, key: TKey, value: unknown): void {\n if (typeof value === \"string\") {\n target[key] = redactDiagnosticPreview(value, MAX_DIAGNOSTIC_SCALAR_LENGTH);\n }\n}\n\nfunction assignSafeNumber<TKey extends \"statusCode\" | \"responseBodyLength\">(\n target: SafeErrorDiagnostic,\n key: TKey,\n value: unknown\n): void {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n target[key] = value;\n }\n}\n","import { redactDiagnosticPreview } from \"./internal/redaction\";\nimport type { ArcaServiceName } from \"./internal/types\";\nimport type {\n ArcaFiscalIssue,\n ArcaFiscalResultLevel,\n ArcaFiscalResults,\n} from \"./services/fiscal-evidence\";\n\n/** Base error class for all ARCA-related errors. */\nexport class ArcaError extends Error {\n readonly code: string;\n override readonly name: string = \"ArcaError\";\n\n constructor(message: string, code = \"ARCA_ERROR\", options?: ErrorOptions) {\n super(message, options);\n this.code = code;\n }\n}\n\n/** Thrown when the ARCA client configuration is missing or invalid. */\nexport class ArcaConfigurationError extends ArcaError {\n override readonly name: string = \"ArcaConfigurationError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, \"ARCA_CONFIGURATION_ERROR\", options);\n }\n}\n\n/** Stable routing codes for caller-provided input failures. */\nexport type ArcaInputErrorCode =\n | \"ARCA_INPUT_INVALID_DATE\"\n | \"ARCA_INPUT_INVALID_AMOUNT\"\n | \"ARCA_INPUT_AMOUNT_PRECISION\"\n | \"ARCA_INPUT_AMOUNT_MISMATCH\"\n | \"ARCA_INPUT_INVALID_EXCHANGE_RATE\"\n | \"ARCA_INPUT_INVALID_VALUE\"\n | \"ARCA_INPUT_MISSING_FIELD\"\n | \"ARCA_INPUT_RESERVED_FIELD\";\n\nexport type ArcaInputErrorOptions = ErrorOptions & {\n code: ArcaInputErrorCode;\n field?: string;\n expected?: string;\n};\n\n/** Thrown when caller-provided input data is missing or invalid. */\nexport class ArcaInputError extends ArcaError {\n declare readonly code: ArcaInputErrorCode;\n override readonly name: string = \"ArcaInputError\";\n readonly field?: string;\n readonly expected?: string;\n\n constructor(message: string, options: ArcaInputErrorOptions) {\n super(message, options.code, options);\n this.field = options.field;\n this.expected = options.expected;\n }\n}\n\n/** Stable reasons exposed for explicit ARCA authentication rejections. */\nexport type ArcaAuthenticationReason =\n | \"invalid_token\"\n | \"unauthorized_computer\"\n | \"missing_relationship\"\n | \"authentication_rejected\";\n\nexport type ArcaAuthenticationErrorOptions = ErrorOptions & {\n reason: ArcaAuthenticationReason;\n service: ArcaServiceName;\n operation: string;\n providerCode?: string | number;\n};\n\n/** Thrown when ARCA explicitly rejects credentials before an operation runs. */\nexport class ArcaAuthenticationError extends ArcaError {\n declare readonly code: \"ARCA_AUTHENTICATION_ERROR\";\n override readonly name: string = \"ArcaAuthenticationError\";\n readonly reason: ArcaAuthenticationReason;\n readonly service: ArcaServiceName;\n readonly operation: string;\n readonly providerCode?: string | number;\n\n constructor(message: string, options: ArcaAuthenticationErrorOptions) {\n super(\n redactDiagnosticPreview(message),\n \"ARCA_AUTHENTICATION_ERROR\",\n options\n );\n this.reason = options.reason;\n this.service = options.service;\n this.operation = options.operation;\n this.providerCode = normalizeProviderCode(options.providerCode);\n }\n}\n\n/** Narrows unknown failures to the explicit authentication error contract. */\nexport function isArcaAuthenticationError(\n error: unknown\n): error is ArcaAuthenticationError {\n return error instanceof ArcaAuthenticationError;\n}\n\n/** Thrown when an HTTP request to an ARCA endpoint fails at the transport level. */\nexport class ArcaTransportError extends ArcaError {\n override readonly name: string = \"ArcaTransportError\";\n readonly statusCode?: number;\n readonly contentType?: string;\n readonly responseBodyLength?: number;\n readonly responseBodyPreview?: string;\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n statusCode?: number;\n contentType?: string;\n responseBodyLength?: number;\n responseBodyPreview?: string;\n }\n ) {\n super(message, \"ARCA_TRANSPORT_ERROR\", options);\n this.statusCode = options?.statusCode;\n this.contentType = options?.contentType;\n this.responseBodyLength = options?.responseBodyLength;\n this.responseBodyPreview =\n options?.responseBodyPreview === undefined\n ? undefined\n : redactDiagnosticPreview(options.responseBodyPreview);\n }\n}\n\n/** Thrown when the SOAP response contains a Fault element. */\nexport class ArcaSoapFaultError extends ArcaError {\n override readonly name: string = \"ArcaSoapFaultError\";\n readonly faultCode?: string;\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n faultCode?: string;\n }\n ) {\n super(redactDiagnosticPreview(message), \"ARCA_SOAP_FAULT\", options);\n this.faultCode =\n options?.faultCode === undefined\n ? undefined\n : redactDiagnosticPreview(options.faultCode);\n }\n}\n\n/** Thrown when a response cannot be parsed as a valid SOAP envelope. */\nexport class ArcaInvalidSoapResponseError extends ArcaError {\n override readonly name: string = \"ArcaInvalidSoapResponseError\";\n readonly service?: ArcaServiceName;\n readonly operation?: string;\n readonly endpointUrl?: string;\n readonly statusCode?: number;\n readonly contentType?: string;\n readonly responseBodyLength?: number;\n readonly responseBodyPreview?: string;\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n service?: ArcaServiceName;\n operation?: string;\n endpointUrl?: string;\n statusCode?: number;\n contentType?: string;\n responseBodyLength?: number;\n responseBodyPreview?: string;\n }\n ) {\n super(message, \"ARCA_INVALID_SOAP_RESPONSE\", options);\n this.service = options?.service;\n this.operation = options?.operation;\n this.endpointUrl = options?.endpointUrl;\n this.statusCode = options?.statusCode;\n this.contentType = options?.contentType;\n this.responseBodyLength = options?.responseBodyLength;\n this.responseBodyPreview =\n options?.responseBodyPreview === undefined\n ? undefined\n : redactDiagnosticPreview(options.responseBodyPreview);\n }\n}\n\n/** Thrown when an ARCA service (WSFE, WSMTXCA, Padron) returns a domain-level error. */\nexport class ArcaServiceError extends ArcaError {\n override readonly name: string = \"ArcaServiceError\";\n readonly serviceCode?: string | number;\n readonly service?: ArcaServiceName;\n readonly operation?: string;\n readonly result?: string;\n readonly resultLevel?: ArcaFiscalResultLevel;\n readonly results?: ArcaFiscalResults;\n readonly cae?: string;\n readonly issues?: readonly ArcaFiscalIssue[];\n\n constructor(\n message: string,\n options?: ErrorOptions & {\n serviceCode?: string | number;\n service?: ArcaServiceName;\n operation?: string;\n result?: string;\n resultLevel?: ArcaFiscalResultLevel;\n results?: ArcaFiscalResults;\n cae?: string;\n issues?: readonly ArcaFiscalIssue[];\n }\n ) {\n super(message, \"ARCA_SERVICE_ERROR\", options);\n this.serviceCode = options?.serviceCode;\n this.service = options?.service;\n this.operation = options?.operation;\n this.result = options?.result;\n this.resultLevel = options?.resultLevel;\n this.results = options?.results;\n this.cae = options?.cae;\n this.issues = options?.issues;\n }\n}\n\nfunction normalizeProviderCode(\n providerCode: string | number | undefined\n): string | number | undefined {\n if (typeof providerCode === \"number\") {\n return Number.isFinite(providerCode) ? providerCode : undefined;\n }\n if (typeof providerCode === \"string\") {\n return redactDiagnosticPreview(providerCode, 512);\n }\n return undefined;\n}\n\n/** Narrow error evidence: never includes a cause, raw response or stack. */\nexport type ArcaSafeErrorMetadata = {\n name: string;\n message: string;\n code?: string;\n statusCode?: number;\n};\n\nexport function toArcaSafeErrorMetadata(error: unknown): ArcaSafeErrorMetadata {\n if (!(error instanceof Error)) {\n return { name: \"UnknownError\", message: String(error) };\n }\n return {\n name: error.name,\n message: error.message,\n ...(error instanceof ArcaError ? { code: error.code } : {}),\n ...(error instanceof ArcaTransportError && error.statusCode !== undefined\n ? { statusCode: error.statusCode }\n : {}),\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ArcaSoapFaultError
3
- } from "./chunk-MBWOFO67.mjs";
3
+ } from "./chunk-HUT3PFKF.mjs";
4
4
 
5
5
  // src/services/padron.ts
6
6
  function createPadronService(options) {
@@ -103,4 +103,4 @@ async function executePadronOperation(options, service, operation, body) {
103
103
  export {
104
104
  createPadronService
105
105
  };
106
- //# sourceMappingURL=chunk-EDY3PNKJ.mjs.map
106
+ //# sourceMappingURL=chunk-NUV5RZPZ.mjs.map
@@ -3,7 +3,7 @@ import {
3
3
  ArcaServiceError,
4
4
  ArcaSoapFaultError,
5
5
  isArcaAuthenticationError
6
- } from "./chunk-MBWOFO67.mjs";
6
+ } from "./chunk-HUT3PFKF.mjs";
7
7
 
8
8
  // src/internal/authentication.ts
9
9
  var WSFE_AUTHENTICATION_CODES = {
@@ -192,4 +192,4 @@ export {
192
192
  createArcaAuthenticationErrorFromEvidence,
193
193
  executeWithAuthenticationRecovery
194
194
  };
195
- //# sourceMappingURL=chunk-IOKZX6CA.mjs.map
195
+ //# sourceMappingURL=chunk-PPYGVNFA.mjs.map
@@ -2,21 +2,21 @@ import {
2
2
  ARCA_CURRENCY_IDS,
3
3
  ARCA_VAT_RATES,
4
4
  ARCA_VOUCHER_TYPES
5
- } from "./chunk-VVY2LZIZ.mjs";
5
+ } from "./chunk-76WU5BVI.mjs";
6
6
  import {
7
7
  classifyArcaAuthenticationError,
8
8
  classifyArcaAuthenticationIssues,
9
9
  createArcaAuthenticationErrorFromEvidence,
10
10
  createArcaAuthenticationEvidence,
11
11
  executeWithAuthenticationRecovery
12
- } from "./chunk-IOKZX6CA.mjs";
12
+ } from "./chunk-PPYGVNFA.mjs";
13
13
  import {
14
14
  ArcaInputError,
15
15
  ArcaInvalidSoapResponseError,
16
16
  ArcaServiceError,
17
17
  ArcaSoapFaultError,
18
18
  ArcaTransportError
19
- } from "./chunk-MBWOFO67.mjs";
19
+ } from "./chunk-HUT3PFKF.mjs";
20
20
 
21
21
  // src/internal/decimal.ts
22
22
  var AMOUNT_SCALE = 100;
@@ -103,7 +103,23 @@ function calculateVatMinorUnits(taxableMinorUnits, vatRate, field) {
103
103
  expected: "one of 0, 2.5, 5, 10.5, 21, or 27"
104
104
  });
105
105
  }
106
- return (taxableMinorUnits * basisPoints + 5000n) / 10000n;
106
+ return roundHalfEvenRatio(taxableMinorUnits * basisPoints, 10000n);
107
+ }
108
+ function roundHalfEvenRatio(numerator, denominator) {
109
+ if (numerator < 0n || denominator <= 0n) {
110
+ throw new RangeError(
111
+ "roundHalfEvenRatio requires a non-negative numerator and a positive denominator."
112
+ );
113
+ }
114
+ const quotient = numerator / denominator;
115
+ const doubledRemainder = numerator % denominator * 2n;
116
+ if (doubledRemainder > denominator) {
117
+ return quotient + 1n;
118
+ }
119
+ if (doubledRemainder < denominator) {
120
+ return quotient;
121
+ }
122
+ return quotient % 2n === 0n ? quotient : quotient + 1n;
107
123
  }
108
124
  function isWithinArcaTolerance(actualMinorUnits, expectedMinorUnits, absoluteCentAllowance = 1) {
109
125
  const difference = absoluteBigInt(actualMinorUnits - expectedMinorUnits);
@@ -1094,8 +1110,72 @@ function mapWsfeVoucherInfo(raw) {
1094
1110
  "caeExpiry",
1095
1111
  normalizeWsfeString(raw.FchVto ?? raw.CAEFchVto)
1096
1112
  );
1113
+ assignWsfeValue(
1114
+ voucher,
1115
+ "serviceStartDate",
1116
+ normalizeWsfeString(raw.FchServDesde)
1117
+ );
1118
+ assignWsfeValue(
1119
+ voucher,
1120
+ "serviceEndDate",
1121
+ normalizeWsfeString(raw.FchServHasta)
1122
+ );
1123
+ assignWsfeValue(
1124
+ voucher,
1125
+ "paymentDueDate",
1126
+ normalizeWsfeString(raw.FchVtoPago)
1127
+ );
1128
+ assignWsfeValue(
1129
+ voucher,
1130
+ "vatRates",
1131
+ mapWsfeLookupDetails(raw.Iva, "AlicIva", mapWsfeLookupVat)
1132
+ );
1133
+ assignWsfeValue(
1134
+ voucher,
1135
+ "taxes",
1136
+ mapWsfeLookupDetails(raw.Tributos, "Tributo", mapWsfeLookupTax)
1137
+ );
1097
1138
  return voucher;
1098
1139
  }
1140
+ function mapWsfeLookupDetails(container, key, map) {
1141
+ const record = toWsfeRecord(container);
1142
+ if (!record || record[key] === void 0) {
1143
+ return void 0;
1144
+ }
1145
+ const rows = Array.isArray(record[key]) ? record[key] : [record[key]];
1146
+ const result = [];
1147
+ for (const value of rows) {
1148
+ const row = toWsfeRecord(value);
1149
+ const mapped = row ? map(row) : void 0;
1150
+ if (mapped === void 0) {
1151
+ return void 0;
1152
+ }
1153
+ result.push(mapped);
1154
+ }
1155
+ return result;
1156
+ }
1157
+ function mapWsfeLookupVat(row) {
1158
+ const id = normalizeWsfeNumber(row.Id);
1159
+ const baseAmount = normalizeWsfeNumber(row.BaseImp);
1160
+ const amount = normalizeWsfeNumber(row.Importe);
1161
+ if (id === void 0 || baseAmount === void 0 || amount === void 0) {
1162
+ return void 0;
1163
+ }
1164
+ return { id, baseAmount, amount };
1165
+ }
1166
+ function mapWsfeLookupTax(row) {
1167
+ const vat = mapWsfeLookupVat(row);
1168
+ const rate = normalizeWsfeNumber(row.Alic);
1169
+ if (!vat || rate === void 0) {
1170
+ return void 0;
1171
+ }
1172
+ const description = normalizeWsfeString(row.Desc);
1173
+ return {
1174
+ ...vat,
1175
+ rate,
1176
+ ...description === void 0 ? {} : { description }
1177
+ };
1178
+ }
1099
1179
  function createWsfeAuth(representedTaxId, token, sign) {
1100
1180
  return {
1101
1181
  Token: token,
@@ -1402,15 +1482,141 @@ function getWsfeResultEntries(result, key) {
1402
1482
  );
1403
1483
  }
1404
1484
 
1405
- // src/services/wsfe-builders.ts
1406
- var VAT_RATE_IDS = {
1407
- 0: ARCA_VAT_RATES.IVA_0,
1408
- 2.5: ARCA_VAT_RATES.IVA_2_5,
1409
- 5: ARCA_VAT_RATES.IVA_5,
1410
- 10.5: ARCA_VAT_RATES.IVA_10_5,
1411
- 21: ARCA_VAT_RATES.IVA_21,
1412
- 27: ARCA_VAT_RATES.IVA_27
1485
+ // src/services/wsfe-amounts.ts
1486
+ var RATES = {
1487
+ 0: { id: ARCA_VAT_RATES.IVA_0, basisPoints: 0n },
1488
+ 2.5: { id: ARCA_VAT_RATES.IVA_2_5, basisPoints: 250n },
1489
+ 5: { id: ARCA_VAT_RATES.IVA_5, basisPoints: 500n },
1490
+ 10.5: { id: ARCA_VAT_RATES.IVA_10_5, basisPoints: 1050n },
1491
+ 21: { id: ARCA_VAT_RATES.IVA_21, basisPoints: 2100n },
1492
+ 27: { id: ARCA_VAT_RATES.IVA_27, basisPoints: 2700n }
1413
1493
  };
1494
+ function calculateWsfeAmounts(input) {
1495
+ if (!Array.isArray(input.items) || input.items.length === 0) {
1496
+ invalidItem("items", "a non-empty array of items");
1497
+ }
1498
+ const isVat = input.issuer === "responsable_inscripto";
1499
+ if (!(isVat || ["monotributo", "exento", "no_alcanzado"].includes(input.issuer))) {
1500
+ invalidItem("issuer", "a supported issuer condition");
1501
+ }
1502
+ const totals = collectItems(input.items, isVat);
1503
+ let net = totals.net;
1504
+ let vat = 0n;
1505
+ const { exempt, untaxed, groups } = totals;
1506
+ const vatRates = [];
1507
+ for (const [rate, group] of groups) {
1508
+ const { id, basisPoints } = RATES[rate];
1509
+ const netFromGross = roundHalfEvenRatio(
1510
+ group.gross * 10000n,
1511
+ 10000n + basisPoints
1512
+ );
1513
+ const base = group.net + netFromGross;
1514
+ const tax = roundHalfEvenRatio(group.net * basisPoints, 10000n) + group.gross - netFromGross;
1515
+ if (base === 0n) {
1516
+ continue;
1517
+ }
1518
+ net += base;
1519
+ vat += tax;
1520
+ vatRates.push({
1521
+ id,
1522
+ baseAmount: arcaMinorUnitsToNumber(base, "netAmount"),
1523
+ amount: arcaMinorUnitsToNumber(tax, "vatAmount")
1524
+ });
1525
+ }
1526
+ const computed = net + vat + exempt + untaxed;
1527
+ arcaMinorUnitsToNumber(computed, "totalAmount");
1528
+ const sent = input.total === void 0 ? computed : assertArcaMinorUnits(input.total, "total");
1529
+ const adjustment = sent - computed;
1530
+ const allowance = BigInt(vatRates.length);
1531
+ if (adjustment < -allowance || adjustment > allowance || vat + adjustment < 0n) {
1532
+ throw new ArcaInputError(
1533
+ "total does not match the computed amount within the VAT allowance.",
1534
+ {
1535
+ code: "ARCA_INPUT_AMOUNT_MISMATCH",
1536
+ field: "total",
1537
+ expected: `${computed} minor units (at most ${allowance} minor units of VAT adjustment, with non-negative VAT)`
1538
+ }
1539
+ );
1540
+ }
1541
+ return {
1542
+ data: {
1543
+ totalAmount: arcaMinorUnitsToNumber(sent, "totalAmount"),
1544
+ netAmount: arcaMinorUnitsToNumber(net, "netAmount"),
1545
+ vatAmount: arcaMinorUnitsToNumber(vat + adjustment, "vatAmount"),
1546
+ nonTaxableAmount: arcaMinorUnitsToNumber(untaxed, "nonTaxableAmount"),
1547
+ exemptAmount: arcaMinorUnitsToNumber(exempt, "exemptAmount"),
1548
+ taxAmount: 0,
1549
+ ...isVat ? { vatRates } : {}
1550
+ },
1551
+ amounts: {
1552
+ computedTotal: Number(computed),
1553
+ sentTotal: Number(sent),
1554
+ vatAdjustment: Number(adjustment)
1555
+ }
1556
+ };
1557
+ }
1558
+ function collectItems(items, isVat) {
1559
+ let net = 0n;
1560
+ let exempt = 0n;
1561
+ let untaxed = 0n;
1562
+ const groups = /* @__PURE__ */ new Map();
1563
+ for (const [index, item] of items.entries()) {
1564
+ const path = `items[${index}]`;
1565
+ if (item === null || typeof item !== "object" || Array.isArray(item)) {
1566
+ invalidItem(path, "an item object");
1567
+ }
1568
+ if (!isVat) {
1569
+ net += classCAmount(item, path);
1570
+ continue;
1571
+ }
1572
+ const { amount, field, rate } = vatItemAmount(item, path);
1573
+ if (rate === "exempt") {
1574
+ exempt += amount;
1575
+ continue;
1576
+ }
1577
+ if (rate === "untaxed") {
1578
+ untaxed += amount;
1579
+ continue;
1580
+ }
1581
+ const group = groups.get(rate) ?? { net: 0n, gross: 0n };
1582
+ group[field] += amount;
1583
+ groups.set(rate, group);
1584
+ }
1585
+ return { net, exempt, untaxed, groups };
1586
+ }
1587
+ function classCAmount(item, path) {
1588
+ if ("vat" in item || "net" in item || "gross" in item) {
1589
+ invalidItem("items", "amount items for a non-RI issuer");
1590
+ }
1591
+ return assertArcaMinorUnits(item.amount, `${path}.amount`);
1592
+ }
1593
+ function vatItemAmount(item, path) {
1594
+ if ("amount" in item || "net" in item === "gross" in item) {
1595
+ invalidItem(
1596
+ "items",
1597
+ "exactly one of net or gross, and vat, for an RI issuer"
1598
+ );
1599
+ }
1600
+ const field = "net" in item ? "net" : "gross";
1601
+ const amount = assertArcaMinorUnits(
1602
+ item[field],
1603
+ `${path}.${field}`
1604
+ );
1605
+ const rate = item.vat;
1606
+ if (rate !== "exempt" && rate !== "untaxed" && (typeof rate !== "number" || !Object.hasOwn(RATES, rate))) {
1607
+ invalidItem(`${path}.vat`, "0, 2.5, 5, 10.5, 21, 27, exempt, or untaxed");
1608
+ }
1609
+ return { amount, field, rate };
1610
+ }
1611
+ function invalidItem(field, expected) {
1612
+ throw new ArcaInputError(`${field} must be ${expected}.`, {
1613
+ code: "ARCA_INPUT_INVALID_VALUE",
1614
+ field,
1615
+ expected
1616
+ });
1617
+ }
1618
+
1619
+ // src/services/wsfe-builders.ts
1414
1620
  function buildFacturaB(input) {
1415
1621
  const taxableMinorUnits = assertArcaMinorUnits(
1416
1622
  input.taxableAmount,
@@ -1431,15 +1637,6 @@ function buildFacturaB(input) {
1431
1637
  input.vatRate,
1432
1638
  "vatRate"
1433
1639
  );
1434
- const totalMinorUnits = taxableMinorUnits + vatMinorUnits;
1435
- const vatRateId = VAT_RATE_IDS[input.vatRate];
1436
- if (vatRateId === void 0) {
1437
- throw new ArcaInputError("vatRate is not a supported VAT rate.", {
1438
- code: "ARCA_INPUT_INVALID_VALUE",
1439
- field: "vatRate",
1440
- expected: "one of 0, 2.5, 5, 10.5, 21, or 27"
1441
- });
1442
- }
1443
1640
  if (input.vatRate !== 0 && vatMinorUnits === 0n) {
1444
1641
  throw new ArcaInputError(
1445
1642
  "taxableAmount is too small to produce VAT at the selected positive vatRate.",
@@ -1450,39 +1647,30 @@ function buildFacturaB(input) {
1450
1647
  }
1451
1648
  );
1452
1649
  }
1453
- const vatRates = [
1454
- Object.freeze({
1455
- id: vatRateId,
1456
- baseAmount: arcaMinorUnitsToNumber(taxableMinorUnits, "taxableAmount"),
1457
- amount: arcaMinorUnitsToNumber(vatMinorUnits, "vatAmount")
1458
- })
1459
- ];
1460
- Object.freeze(vatRates);
1650
+ const { data } = calculateWsfeAmounts({
1651
+ issuer: "responsable_inscripto",
1652
+ items: [{ net: input.taxableAmount, vat: input.vatRate }]
1653
+ });
1654
+ for (const rate of data.vatRates ?? []) {
1655
+ Object.freeze(rate);
1656
+ }
1657
+ Object.freeze(data.vatRates);
1461
1658
  return Object.freeze({
1462
1659
  ...buildCommonExactInput(input),
1463
1660
  voucherType: ARCA_VOUCHER_TYPES.FACTURA_B,
1464
- totalAmount: arcaMinorUnitsToNumber(totalMinorUnits, "totalAmount"),
1465
- nonTaxableAmount: 0,
1466
- netAmount: arcaMinorUnitsToNumber(taxableMinorUnits, "taxableAmount"),
1467
- exemptAmount: 0,
1468
- taxAmount: 0,
1469
- vatAmount: arcaMinorUnitsToNumber(vatMinorUnits, "vatAmount"),
1470
- vatRates
1661
+ ...data
1471
1662
  });
1472
1663
  }
1473
1664
  function buildFacturaC(input) {
1474
- const amountMinorUnits = assertArcaMinorUnits(input.amount, "amount");
1475
- const amount = arcaMinorUnitsToNumber(amountMinorUnits, "amount");
1665
+ assertArcaMinorUnits(input.amount, "amount");
1666
+ const { data } = calculateWsfeAmounts({
1667
+ issuer: "monotributo",
1668
+ items: [{ amount: input.amount }]
1669
+ });
1476
1670
  return Object.freeze({
1477
1671
  ...buildCommonExactInput(input),
1478
1672
  voucherType: ARCA_VOUCHER_TYPES.FACTURA_C,
1479
- totalAmount: amount,
1480
- nonTaxableAmount: 0,
1481
- // ARCA defines ImpNeto as the subtotal for class C vouchers.
1482
- netAmount: amount,
1483
- exemptAmount: 0,
1484
- taxAmount: 0,
1485
- vatAmount: 0
1673
+ ...data
1486
1674
  });
1487
1675
  }
1488
1676
  function buildCommonExactInput(input) {
@@ -1579,8 +1767,13 @@ function normalizeBuilderCurrency(input) {
1579
1767
  }
1580
1768
 
1581
1769
  export {
1770
+ normalizeArcaAmountToMinorUnits,
1771
+ serializeArcaExchangeRate,
1582
1772
  createWsfeService,
1773
+ normalizeWsfeVoucherInput,
1774
+ normalizeWsfeDateInput,
1775
+ calculateWsfeAmounts,
1583
1776
  buildFacturaB,
1584
1777
  buildFacturaC
1585
1778
  };
1586
- //# sourceMappingURL=chunk-C55KOV5N.mjs.map
1779
+ //# sourceMappingURL=chunk-TOVSOJ3G.mjs.map