arca-sdk 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ Todos los cambios notables de este proyecto se documentan en este archivo.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [1.0.1] — 2026-02-23
|
|
8
|
+
|
|
9
|
+
### 🐛 Bugfix crítico — QR URL
|
|
10
|
+
|
|
11
|
+
`generateQRUrl` usaba `encodeURIComponent` sobre el string base64, convirtiendo:
|
|
12
|
+
- `+` → `%2B`
|
|
13
|
+
- `=` → `%3D`
|
|
14
|
+
- `/` → `%2F`
|
|
15
|
+
|
|
16
|
+
El scanner de ARCA intenta decodificar el parámetro `?p=` como base64 puro. Al recibir `%2B` en lugar de `+`, la decodificación falla parcialmente: el CUIT y el CAE se rescatan por un camino alternativo interno, pero la fecha, punto de venta, número de comprobante e importe llegan vacíos.
|
|
17
|
+
|
|
18
|
+
**Fix:** El base64 ahora se embebe directamente sin URL-encoding, tal como especifica la [documentación oficial de ARCA](https://www.afip.gob.ar/fe/qr/especificaciones.asp).
|
|
19
|
+
|
|
20
|
+
```diff
|
|
21
|
+
- return `https://www.afip.gob.ar/fe/qr/?p=${encodeURIComponent(base64)}`;
|
|
22
|
+
+ return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
7
27
|
## [1.0.0] — 2026-02-23
|
|
8
28
|
|
|
9
29
|
### 🔴 Breaking Changes
|
package/dist/index.cjs
CHANGED
|
@@ -555,7 +555,7 @@ function round(value) {
|
|
|
555
555
|
function generateQRUrl(caeResponse, issuerCUIT, total, buyer) {
|
|
556
556
|
const cleanCUIT = issuerCUIT.replace(/\D/g, "");
|
|
557
557
|
const cleanCAE = caeResponse.cae.replace(/\D/g, "");
|
|
558
|
-
const rawDate = caeResponse.date;
|
|
558
|
+
const rawDate = String(caeResponse.date);
|
|
559
559
|
const formattedDate = rawDate.length === 8 ? `${rawDate.substring(0, 4)}-${rawDate.substring(4, 6)}-${rawDate.substring(6, 8)}` : rawDate;
|
|
560
560
|
const docType = buyer?.docType || 99 /* FINAL_CONSUMER */;
|
|
561
561
|
const docNumber = buyer?.docNumber ? buyer.docNumber.replace(/\D/g, "") : "0";
|
|
@@ -578,7 +578,7 @@ function generateQRUrl(caeResponse, issuerCUIT, total, buyer) {
|
|
|
578
578
|
qrData.codAut = Number(cleanCAE);
|
|
579
579
|
const jsonString = JSON.stringify(qrData);
|
|
580
580
|
const base64 = typeof Buffer !== "undefined" ? Buffer.from(jsonString).toString("base64") : btoa(jsonString);
|
|
581
|
-
return `https://www.afip.gob.ar/fe/qr/?p=${
|
|
581
|
+
return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;
|
|
582
582
|
}
|
|
583
583
|
|
|
584
584
|
// src/constants/errors.ts
|
|
@@ -1156,10 +1156,10 @@ var WsfeService = class _WsfeService {
|
|
|
1156
1156
|
obsArray.forEach((o) => observations.push(o.Msg));
|
|
1157
1157
|
}
|
|
1158
1158
|
return {
|
|
1159
|
-
invoiceType: cab.CbteTipo,
|
|
1160
|
-
pointOfSale: cab.PtoVta,
|
|
1159
|
+
invoiceType: Number(cab.CbteTipo),
|
|
1160
|
+
pointOfSale: Number(cab.PtoVta),
|
|
1161
1161
|
invoiceNumber: Number(det.CbteDesde),
|
|
1162
|
-
date: det.CbteFch,
|
|
1162
|
+
date: String(det.CbteFch),
|
|
1163
1163
|
cae: String(det.CAE),
|
|
1164
1164
|
caeExpiry: String(det.CAEFchVto),
|
|
1165
1165
|
result: det.Resultado,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constants/endpoints.ts","../src/types/common.ts","../src/utils/xml.ts","../src/utils/crypto.ts","../src/auth/ticket.ts","../src/utils/network.ts","../src/auth/wsaa.ts","../src/types/wsfe.ts","../src/utils/calculations.ts","../src/utils/qr.ts","../src/constants/errors.ts","../src/services/wsfe.ts","../src/services/padron.ts"],"sourcesContent":["/**\r\n * arca-sdk — SDK moderna para ARCA (ex-AFIP)\r\n */\r\n\r\n// Servicios principales\r\nexport { WsaaService } from './auth/wsaa';\r\nexport { WsfeService } from './services/wsfe';\r\nexport { PadronService } from './services/padron';\r\n\r\n// Tipos comunes\r\nexport type {\r\n Environment,\r\n ArcaConfig,\r\n} from './types/common';\r\n\r\n// Tipos WSAA\r\nexport type {\r\n WsaaConfig,\r\n LoginTicket,\r\n} from './types/wsaa';\r\nexport type { TokenStorage } from './auth/storage';\r\n\r\n// Tipos Padrón\r\nexport type {\r\n TaxpayerServiceConfig,\r\n Taxpayer,\r\n Address,\r\n Activity,\r\n TaxRecord,\r\n TaxpayerResponse,\r\n} from './types/padron';\r\n\r\n// Tipos WSFE\r\nexport type {\r\n WsfeConfig,\r\n InvoiceItem,\r\n Buyer,\r\n IssueInvoiceRequest,\r\n CAEResponse,\r\n InvoiceDetails,\r\n PointOfSale,\r\n ServiceStatus,\r\n} from './types/wsfe';\r\n\r\n// Enums WSFE\r\nexport {\r\n InvoiceType,\r\n BillingConcept,\r\n TaxIdType,\r\n} from './types/wsfe';\r\n\r\n// Errores\r\nexport {\r\n ArcaError,\r\n ArcaAuthError,\r\n ArcaValidationError,\r\n ArcaNetworkError,\r\n} from './types/common';\r\n\r\n// Utilidades para Frontend/Impresión\r\nexport { generateQRUrl } from './utils/qr';\r\n","import type { Environment } from '../types/common';\r\n\r\n/**\r\n * URLs de los servicios ARCA por ambiente\r\n */\r\nexport const WSAA_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms',\r\n produccion: 'https://wsaa.afip.gov.ar/ws/services/LoginCms',\r\n};\r\n\r\n/**\r\n * URLs del servicio WSFE por ambiente\r\n */\r\nexport const WSFE_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx',\r\n produccion: 'https://servicios1.afip.gov.ar/wsfev1/service.asmx',\r\n};\r\n\r\n/**\r\n * URLs del servicio Padron A13 por ambiente\r\n */\r\nexport const PADRON_A13_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n produccion: 'https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n};\r\n\r\n/**\r\n * Obtener endpoint WSAA según ambiente\r\n */\r\nexport function getWsaaEndpoint(environment: Environment): string {\r\n return WSAA_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint WSFE según ambiente\r\n */\r\nexport function getWsfeEndpoint(environment: Environment): string {\r\n return WSFE_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint Padron A13 según ambiente\r\n */\r\nexport function getPadronEndpoint(environment: Environment): string {\r\n return PADRON_A13_ENDPOINTS[environment];\r\n}\r\n","/**\r\n * Tipos comunes compartidos en toda la SDK\r\n */\r\n\r\n/**\r\n * Ambiente de ejecución ARCA\r\n */\r\nexport type Environment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Configuración base para servicios ARCA\r\n */\r\nexport interface ArcaConfig {\r\n /** Ambiente (homologación o producción) */\r\n environment: Environment;\r\n /** CUIT del contribuyente (11 dígitos sin guiones) */\r\n cuit: string;\r\n /** Tiempo de espera para peticiones (ms). Defecto: 15000 */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Error personalizado de ARCA SDK\r\n */\r\nexport class ArcaError extends Error {\r\n constructor(\r\n message: string,\r\n public code: string,\r\n public details?: unknown,\r\n public hint?: string\r\n ) {\r\n super(message);\r\n this.name = 'ArcaError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de autenticación WSAA\r\n */\r\nexport class ArcaAuthError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'AUTH_ERROR', details);\r\n this.name = 'ArcaAuthError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de validación de input\r\n */\r\nexport class ArcaValidationError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'VALIDATION_ERROR', details);\r\n this.name = 'ArcaValidationError';\r\n }\r\n}\r\n/**\r\n * Error de comunicación/red\r\n */\r\nexport class ArcaNetworkError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'NETWORK_ERROR', details);\r\n this.name = 'ArcaNetworkError';\r\n }\r\n}\r\n","import { XMLBuilder, XMLParser } from 'fast-xml-parser';\r\nimport { ArcaAuthError } from '../types/common';\r\nimport type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Genera el XML TRA (Ticket de Requerimiento de Acceso)\r\n * \r\n * @param service - Servicio ARCA (ej: 'wsfe')\r\n * @param cuit - CUIT del contribuyente\r\n * @returns XML del TRA\r\n */\r\nexport function buildTRA(service: string, cuit: string): string {\r\n const now = new Date();\r\n const expirationTime = new Date(now.getTime() + 12 * 60 * 60 * 1000); // +12 horas\r\n\r\n const tra = {\r\n loginTicketRequest: {\r\n '@_version': '1.0',\r\n header: {\r\n uniqueId: Math.floor(now.getTime() / 1000),\r\n generationTime: now.toISOString(),\r\n expirationTime: expirationTime.toISOString(),\r\n },\r\n service,\r\n },\r\n };\r\n\r\n const builder = new XMLBuilder({\r\n ignoreAttributes: false,\r\n format: true,\r\n });\r\n\r\n const xml = builder.build(tra);\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${xml}`;\r\n}\r\n\r\n/**\r\n * Parsea la respuesta XML de WSAA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Ticket de login\r\n */\r\nexport function parseWsaaResponse(xml: string): LoginTicket {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n\r\n try {\r\n const envelope = parser.parse(xml);\r\n\r\n // El loginCmsReturn contiene el ticket real como un XML escapado (string)\r\n const loginCmsReturn = envelope?.Envelope?.Body?.loginCmsResponse?.loginCmsReturn;\r\n\r\n if (!loginCmsReturn) {\r\n const fault = envelope?.Envelope?.Body?.Fault;\r\n if (fault) {\r\n throw new ArcaAuthError(\r\n `Error ARCA: ${fault.faultstring || 'Error desconocido'}`,\r\n { faultCode: fault.faultcode, detail: fault.detail }\r\n );\r\n }\r\n\r\n throw new ArcaAuthError(\r\n 'Respuesta WSAA inválida: estructura no reconocida',\r\n {\r\n receivedXml: xml.substring(0, 5000),\r\n receivedStructure: JSON.stringify(envelope).substring(0, 500)\r\n }\r\n );\r\n }\r\n\r\n // Segundo nivel de parseo: El XML interno escapado que viene dentro de loginCmsReturn\r\n const ticketResult = parser.parse(loginCmsReturn);\r\n const ticket = ticketResult?.loginTicketResponse;\r\n\r\n if (!ticket || !ticket.header || !ticket.credentials) {\r\n throw new ArcaAuthError('Ticket WSAA inválido o malformado dentro de loginCmsReturn', {\r\n innerStructure: JSON.stringify(ticketResult).substring(0, 500),\r\n receivedXml: xml.substring(0, 5000)\r\n });\r\n }\r\n\r\n return {\r\n token: ticket.credentials.token,\r\n sign: ticket.credentials.sign,\r\n generationTime: new Date(ticket.header.generationTime),\r\n expirationTime: new Date(ticket.header.expirationTime),\r\n };\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al parsear respuesta WSAA (posible XML anidado malformado)',\r\n {\r\n originalError: error instanceof Error ? error.message : String(error),\r\n receivedXml: xml.substring(0, 5000)\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Parsea un XML genérico de ARCA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Objeto parseado\r\n */\r\nexport function parseXml(xml: string): any {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n return parser.parse(xml);\r\n}\r\n\r\n/**\r\n * Valida CUIT (11 dígitos sin guiones)\r\n */\r\nexport function validateCUIT(cuit: string): boolean {\r\n return /^\\d{11}$/.test(cuit);\r\n}\r\n","import * as forge from 'node-forge';\r\nimport { ArcaAuthError } from '../types/common';\r\n\r\n/**\r\n * Firma un XML en formato CMS (PKCS#7) usando certificado y clave privada\r\n * \r\n * @param xml - Contenido XML a firmar (TRA)\r\n * @param certPem - Certificado en formato PEM\r\n * @param keyPem - Clave privada en formato PEM\r\n * @returns CMS firmado en base64\r\n */\r\nexport function signCMS(xml: string, certPem: string, keyPem: string): string {\r\n try {\r\n // 1. Parsear certificado\r\n const cert = forge.pki.certificateFromPem(certPem);\r\n\r\n // 2. Parsear clave privada\r\n const privateKey = forge.pki.privateKeyFromPem(keyPem);\r\n\r\n // 3. Crear contenedor PKCS#7\r\n const p7 = forge.pkcs7.createSignedData();\r\n\r\n // 4. Agregar contenido a firmar\r\n p7.content = forge.util.createBuffer(xml, 'utf8');\r\n\r\n // 5. Agregar certificado\r\n p7.addCertificate(cert);\r\n\r\n // 6. Firmar con SHA256\r\n p7.addSigner({\r\n key: privateKey,\r\n certificate: cert,\r\n digestAlgorithm: forge.pki.oids.sha256,\r\n authenticatedAttributes: [\r\n {\r\n type: forge.pki.oids.contentType,\r\n value: forge.pki.oids.data,\r\n },\r\n {\r\n type: forge.pki.oids.messageDigest,\r\n // El valor será calculado automáticamente\r\n },\r\n {\r\n type: forge.pki.oids.signingTime,\r\n // node-forge expects a Date object, but its typings might be missing or expect string/any\r\n value: new Date() as any,\r\n },\r\n ],\r\n });\r\n\r\n // 7. Firmar\r\n p7.sign();\r\n\r\n // 8. Convertir a DER y luego a base64\r\n const derBytes = forge.asn1.toDer(p7.toAsn1()).getBytes();\r\n const base64 = forge.util.encode64(derBytes);\r\n\r\n return base64;\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al firmar XML con certificado usando PKCS#7',\r\n {\r\n originalError: error,\r\n hint: 'Verificar que el certificado y la clave privada sean válidos y correspondan entre sí'\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Valida formato de certificado PEM\r\n */\r\nexport function validateCertificate(cert: string): boolean {\r\n return cert.includes('-----BEGIN CERTIFICATE-----') &&\r\n cert.includes('-----END CERTIFICATE-----');\r\n}\r\n\r\n/**\r\n * Valida formato de clave privada PEM\r\n */\r\nexport function validatePrivateKey(key: string): boolean {\r\n return (\r\n (key.includes('-----BEGIN PRIVATE KEY-----') &&\r\n key.includes('-----END PRIVATE KEY-----')) ||\r\n (key.includes('-----BEGIN RSA PRIVATE KEY-----') &&\r\n key.includes('-----END RSA PRIVATE KEY-----'))\r\n );\r\n}\r\n","import type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Gestor de tickets de autenticación\r\n * Maneja cache en memoria del ticket WSAA\r\n */\r\nexport class TicketManager {\r\n private ticket: LoginTicket | null = null;\r\n\r\n /**\r\n * Guarda un ticket en cache\r\n */\r\n setTicket(ticket: LoginTicket): void {\r\n this.ticket = ticket;\r\n }\r\n\r\n /**\r\n * Obtiene el ticket actual si es válido\r\n * @returns Ticket válido o null si expiró\r\n */\r\n getTicket(): LoginTicket | null {\r\n if (!this.ticket) return null;\r\n\r\n const now = new Date();\r\n const expiresIn = this.ticket.expirationTime.getTime() - now.getTime();\r\n\r\n // Si expira en menos de 5 minutos, considerarlo inválido\r\n const BUFFER_MS = 5 * 60 * 1000;\r\n\r\n if (expiresIn < BUFFER_MS) {\r\n this.ticket = null;\r\n return null;\r\n }\r\n\r\n return this.ticket;\r\n }\r\n\r\n /**\r\n * Verifica si hay un ticket válido\r\n */\r\n hasValidTicket(): boolean {\r\n return this.getTicket() !== null;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache\r\n */\r\n clearTicket(): void {\r\n this.ticket = null;\r\n }\r\n}\r\n","import https from 'https';\r\nimport { ArcaNetworkError } from '../types/common';\r\n\r\n/**\r\n * Entornos compatibles\r\n */\r\nexport type ArcaEnvironment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Opciones para la llamada API\r\n */\r\nexport interface CallApiOptions {\r\n method: string;\r\n headers: Record<string, string>;\r\n body: string;\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Realiza una llamada a la API de ARCA (WSAA o WSFE)\r\n * Maneja la compatibilidad SSL con los servidores de AFIP (DH key size)\r\n * y añade robustez (timeouts, mejores errores).\r\n */\r\nexport async function callArcaApi(\r\n url: string,\r\n options: CallApiOptions\r\n): Promise<Response> {\r\n const timeout = options.timeout || 15000;\r\n const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\r\n\r\n if (isNode) {\r\n return new Promise((resolve, reject) => {\r\n const parsedUrl = new URL(url);\r\n\r\n const agent = new https.Agent({\r\n // SECLEVEL=0 es el nivel más permisivo de OpenSSL.\r\n // !DH desactiva Diffie-Hellman para forzar RSA o ECDHE si están disponibles,\r\n // evitando el problema de \"dh key too small\" de raíz.\r\n ciphers: 'DEFAULT:!DH@SECLEVEL=0',\r\n // AFIP todavía tiene endpoints que podrían requerir TLS 1.0/1.1\r\n minVersion: 'TLSv1',\r\n // @ts-ignore - Propiedad específica para mitigar \"dh key too small\" en Node 18+\r\n minDHSize: 1024,\r\n rejectUnauthorized: true,\r\n });\r\n\r\n const reqOptions: https.RequestOptions = {\r\n method: options.method,\r\n hostname: parsedUrl.hostname,\r\n path: parsedUrl.pathname + parsedUrl.search,\r\n headers: options.headers,\r\n agent,\r\n timeout,\r\n };\r\n\r\n const req = https.request(reqOptions, (res) => {\r\n res.setEncoding('utf8');\r\n let data = '';\r\n res.on('data', (chunk) => { data += chunk; });\r\n res.on('end', () => {\r\n // Simular objeto Response de fetch\r\n const response = {\r\n ok: (res.statusCode || 0) >= 200 && (res.statusCode || 0) < 300,\r\n status: res.statusCode || 0,\r\n statusText: res.statusMessage || '',\r\n text: async () => data,\r\n json: async () => JSON.parse(data),\r\n };\r\n resolve(response as Response);\r\n });\r\n });\r\n\r\n req.on('error', (error: any) => {\r\n let message = error.message;\r\n if (message.includes('dh key too small')) {\r\n message = 'Error SSL de ARCA (DH Key too small). Verifique su versión de OpenSSL/Node.';\r\n }\r\n reject(new ArcaNetworkError(`Error de red al comunicarse con ARCA (HTTPS): ${message}`, {\r\n url,\r\n originalError: error\r\n }));\r\n });\r\n\r\n req.on('timeout', () => {\r\n req.destroy();\r\n reject(new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`));\r\n });\r\n\r\n req.write(options.body);\r\n req.end();\r\n });\r\n }\r\n\r\n // Navegador o entorno no-Node (utiliza fetch nativo)\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: options.method,\r\n headers: options.headers,\r\n body: options.body,\r\n signal: controller.signal\r\n });\r\n return response;\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n throw new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`);\r\n }\r\n throw new ArcaNetworkError(`Error de red: ${error.message}`, { url, originalError: error });\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n}\r\n","import { getWsaaEndpoint } from '../constants/endpoints';\r\nimport { ArcaAuthError, ArcaValidationError } from '../types/common';\r\nimport type { WsaaConfig, LoginTicket } from '../types/wsaa';\r\nimport { buildTRA, parseWsaaResponse, validateCUIT } from '../utils/xml';\r\nimport { validateCertificate, validatePrivateKey, signCMS } from '../utils/crypto';\r\nimport { TicketManager } from './ticket';\r\nimport { callArcaApi } from '../utils/network';\r\n\r\n/**\r\n * Servicio de autenticación WSAA (Web Service de Autenticación y Autorización)\r\n * \r\n * @example\r\n * ```typescript\r\n * const wsaa = new WsaaService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * service: 'wsfe',\r\n * });\r\n * \r\n * const ticket = await wsaa.login();\r\n * console.log('Token:', ticket.token);\r\n * ```\r\n */\r\nexport class WsaaService {\r\n private config: WsaaConfig;\r\n private ticketManager: TicketManager;\r\n\r\n constructor(config: WsaaConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n this.ticketManager = new TicketManager();\r\n }\r\n\r\n /**\r\n * Valida la configuración\r\n */\r\n private validateConfig(config: WsaaConfig): void {\r\n if (!validateCUIT(config.cuit)) {\r\n throw new ArcaValidationError(\r\n 'CUIT inválido: debe tener 11 dígitos sin guiones',\r\n { cuit: config.cuit }\r\n );\r\n }\r\n\r\n if (!validateCertificate(config.cert)) {\r\n throw new ArcaValidationError(\r\n 'Certificado inválido: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN CERTIFICATE-----' }\r\n );\r\n }\r\n\r\n if (!validatePrivateKey(config.key)) {\r\n throw new ArcaValidationError(\r\n 'Clave privada inválida: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN PRIVATE KEY----- o -----BEGIN RSA PRIVATE KEY-----' }\r\n );\r\n }\r\n\r\n if (!config.service || config.service.trim() === '') {\r\n throw new ArcaValidationError(\r\n 'Servicio ARCA no especificado',\r\n { hint: 'Ejemplos: \"wsfe\", \"wsmtxca\"' }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Obtiene un ticket de acceso válido.\r\n * \r\n * Prioridad de búsqueda:\r\n * 1. Memoria (TicketManager cache)\r\n * 2. Persistencia (si config.storage está definido)\r\n * 3. Nueva solicitud a WSAA\r\n * \r\n * @returns Ticket de acceso\r\n */\r\n async login(): Promise<LoginTicket> {\r\n // 1. Intentar usar ticket en memoria (muy rápido)\r\n const cachedTicket = this.ticketManager.getTicket();\r\n if (cachedTicket) {\r\n return cachedTicket;\r\n }\r\n\r\n // 2. Intentar usar persistencia externa si está disponible\r\n if (this.config.storage) {\r\n try {\r\n const storedTicket = await this.config.storage.get(this.config.cuit, this.config.environment);\r\n if (storedTicket) {\r\n // Validar si el ticket devuelto por el storage no está expirado\r\n // Agrego un margen de 5 minutos\r\n const now = new Date();\r\n if (new Date(storedTicket.expirationTime) > new Date(now.getTime() + 5 * 60000)) {\r\n this.ticketManager.setTicket(storedTicket);\r\n return storedTicket;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.get falló, intentando login directo:', error);\r\n }\r\n }\r\n\r\n // 3. Generar nuevo ticket (llamada a AFIP)\r\n const ticket = await this.requestNewTicket();\r\n\r\n // Guardar en memoria\r\n this.ticketManager.setTicket(ticket);\r\n\r\n // Guardar en persistencia externa\r\n if (this.config.storage) {\r\n try {\r\n await this.config.storage.save(this.config.cuit, this.config.environment, ticket);\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.save falló:', error);\r\n }\r\n }\r\n\r\n return ticket;\r\n }\r\n\r\n /**\r\n * Solicita un nuevo ticket a WSAA\r\n */\r\n private async requestNewTicket(): Promise<LoginTicket> {\r\n // 1. Generar TRA (Ticket de Requerimiento de Acceso)\r\n const tra = buildTRA(this.config.service, this.config.cuit);\r\n\r\n // 2. Firmar TRA con certificado (genera CMS)\r\n let cms: string;\r\n try {\r\n cms = signCMS(tra, this.config.cert, this.config.key);\r\n } catch (error) {\r\n throw new ArcaAuthError(\r\n 'Error al firmar TRA con certificado',\r\n { originalError: error }\r\n );\r\n }\r\n\r\n // 3. Enviar CMS a WSAA\r\n const endpoint = getWsaaEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: this.buildSoapRequest(cms),\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaAuthError(\r\n `Error HTTP al comunicarse con WSAA: ${response.status} ${response.statusText}`,\r\n { status: response.status, statusText: response.statusText }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 4. Parsear respuesta\r\n return parseWsaaResponse(responseXml);\r\n }\r\n\r\n /**\r\n * Construye el SOAP request para WSAA\r\n */\r\n private buildSoapRequest(cms: string): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:wsaa=\"http://wsaa.view.sua.dvadac.desein.afip.gov\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <wsaa:loginCms>\r\n <wsaa:in0>${cms}</wsaa:in0>\r\n </wsaa:loginCms>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache (forzar renovación)\r\n */\r\n clearCache(): void {\r\n this.ticketManager.clearTicket();\r\n }\r\n}","import type { ArcaConfig } from './common';\r\nimport type { LoginTicket } from './wsaa';\r\n\r\n/**\r\n * Configuración para WsfeService\r\n */\r\nexport interface WsfeConfig extends ArcaConfig {\r\n /** Ticket de autenticación WSAA */\r\n ticket: LoginTicket;\r\n /** Punto de venta (1-9999) */\r\n pointOfSale: number;\r\n}\r\n\r\n/**\r\n * Tipo de comprobante ARCA\r\n */\r\nexport enum InvoiceType {\r\n FACTURA_A = 1,\r\n FACTURA_B = 6,\r\n FACTURA_C = 11,\r\n TICKET_A = 81,\r\n TICKET_B = 82,\r\n TICKET_C = 83,\r\n}\r\n\r\n/**\r\n * Concepto de facturación\r\n */\r\nexport enum BillingConcept {\r\n PRODUCTS = 1,\r\n SERVICES = 2,\r\n PRODUCTS_AND_SERVICES = 3,\r\n}\r\n\r\n/**\r\n * Tipo de documento del receptor\r\n */\r\nexport enum TaxIdType {\r\n CUIT = 80,\r\n CUIL = 86,\r\n CDI = 87,\r\n LE = 89,\r\n LC = 90,\r\n FOREIGN_ID = 91,\r\n PASSPORT = 94,\r\n BUENOS_AIRES_ID = 95,\r\n /**\r\n * @note AFIP usa el código 96 para ambos. En la práctica, DNI es el más utilizado.\r\n * Fuente: Tabla 13 del catálogo ARCA — ambos valores son 96 en el catálogo oficial.\r\n */\r\n NATIONAL_POLICE_ID = 96,\r\n DNI = 96,\r\n FINAL_CONSUMER = 99,\r\n}\r\n\r\n/**\r\n * Ítem de factura\r\n */\r\nexport interface InvoiceItem {\r\n /** Descripción del producto/servicio */\r\n description: string;\r\n /** Cantidad */\r\n quantity: number;\r\n /** Precio unitario */\r\n unitPrice: number;\r\n /** Alícuota IVA % (0, 10.5, 21, 27) */\r\n vatRate?: number;\r\n}\r\n\r\n/**\r\n * Datos del comprador\r\n */\r\nexport interface Buyer {\r\n /** Tipo de documento */\r\n docType: TaxIdType;\r\n /** Número de documento (sin guiones) */\r\n docNumber: string;\r\n}\r\n\r\n/**\r\n * Request para emitir comprobante\r\n */\r\nexport interface IssueInvoiceRequest {\r\n /** Tipo de comprobante */\r\n type: InvoiceType;\r\n /** Concepto */\r\n concept: BillingConcept;\r\n /** Comprador (opcional para Factura C consumidor final) */\r\n buyer?: Buyer;\r\n /** Items de la factura */\r\n items?: InvoiceItem[];\r\n /** Monto total (requerido si no hay items) */\r\n total?: number;\r\n /** Desglose de IVA (requerido para Factura A/B) */\r\n vatData?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** Indica si los precios unitarios YA incluyen el IVA. Defecto: false */\r\n includesVAT?: boolean;\r\n /** Fecha del comprobante (default: hoy) */\r\n date?: Date;\r\n}\r\n\r\n/**\r\n * Respuesta CAE (Código de Autorización Electrónico)\r\n */\r\nexport interface CAEResponse {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** CAE asignado */\r\n cae: string;\r\n /** Fecha de vencimiento del CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado (A = Aprobado, R = Rechazado) */\r\n result: 'A' | 'R';\r\n /** Observaciones de ARCA */\r\n observations?: string[];\r\n /** Items (se retornan si fueron proveídos en el request) */\r\n items?: InvoiceItem[];\r\n /** Desglose IVA (solo para Factura A/B) */\r\n vat?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** URL del código QR oficial de ARCA */\r\n qrUrl?: string;\r\n}\r\n\r\n/**\r\n * Detalle de un comprobante consultado (FECompConsultar)\r\n */\r\nexport interface InvoiceDetails {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** Concepto */\r\n concept: number;\r\n /** Tipo de documento del receptor */\r\n docType: number;\r\n /** Número de documento del receptor */\r\n docNumber: number;\r\n /** Importe total */\r\n total: number;\r\n /** Importe neto gravado */\r\n net: number;\r\n /** Importe IVA */\r\n vat: number;\r\n /** CAE */\r\n cae: string;\r\n /** Vencimiento CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado */\r\n result: 'A' | 'R';\r\n}\r\n\r\n/**\r\n * Punto de venta habilitado en ARCA\r\n */\r\nexport interface PointOfSale {\r\n /** Número de punto de venta */\r\n number: number;\r\n /** Tipo (CAI, CAE, CAEA, etc.) */\r\n type: string;\r\n /** Indica si está bloqueado */\r\n isBlocked: boolean;\r\n /** Fecha de bloqueo (si aplica) */\r\n blockedSince?: string;\r\n}\r\n\r\n/**\r\n * Estado de los servidores de ARCA\r\n */\r\nexport interface ServiceStatus {\r\n /** Estado del servidor de aplicaciones */\r\n appServer: string;\r\n /** Estado del servidor de base de datos */\r\n dbServer: string;\r\n /** Estado del servidor de autenticación */\r\n authServer: string;\r\n}\r\n","import type { InvoiceItem } from '../types/wsfe';\r\n\r\n/**\r\n * Calcula el subtotal de items (sin IVA)\r\n */\r\nexport function calculateSubtotal(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && item.vatRate) {\r\n netPrice = item.unitPrice / (1 + (item.vatRate / 100));\r\n }\r\n return sum + (item.quantity * netPrice);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el IVA total de items\r\n */\r\nexport function calculateVAT(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n const netSubtotal = item.quantity * netPrice;\r\n return sum + (netSubtotal * rate / 100);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el total de la factura (subtotal + IVA)\r\n */\r\nexport function calculateTotal(items: InvoiceItem[], includesVAT = false): number {\r\n if (includesVAT) {\r\n return items.reduce((sum, item) => sum + (item.quantity * item.unitPrice), 0);\r\n }\r\n const subtotal = calculateSubtotal(items, false);\r\n const vat = calculateVAT(items, false);\r\n return subtotal + vat;\r\n}\r\n\r\n/**\r\n * Redondea a 2 decimales\r\n */\r\nexport function round(value: number): number {\r\n return Math.round(value * 100) / 100;\r\n}\r\n","import type { CAEResponse, Buyer } from '../types/wsfe';\r\nimport { TaxIdType } from '../types/wsfe';\r\n\r\n/**\r\n * Datos requeridos por ARCA para el QR (estructura oficial)\r\n * @see https://www.afip.gob.ar/fe/qr/especificaciones.asp\r\n */\r\ninterface AFIPQRData {\r\n ver: number;\r\n fecha: string;\r\n cuit: number;\r\n ptoVta: number;\r\n tipoCmp: number;\r\n nroCmp: number;\r\n importe: number;\r\n moneda: string;\r\n ctz: number;\r\n tipoDocRec?: number;\r\n nroDocRec?: number;\r\n tipoCodAut: string;\r\n codAut: number;\r\n}\r\n\r\n/**\r\n * Genera la URL completa con el código QR para un comprobante emitido.\r\n * Implementa la versión oficial con orden estricto de campos según spec de ARCA.\r\n *\r\n * @param caeResponse Respuesta obtenida al emitir la factura (CAEResponse)\r\n * @param issuerCUIT CUIT del emisor (con o sin guiones)\r\n * @param total Importe total del comprobante\r\n * @param buyer Datos del comprador (opcional)\r\n * @returns URL lista para embeber en un generador de QR\r\n */\r\nexport function generateQRUrl(\r\n caeResponse: CAEResponse,\r\n issuerCUIT: string,\r\n total: number,\r\n buyer?: Buyer\r\n): string {\r\n // Clean CUIT and CAE (digits only)\r\n const cleanCUIT = issuerCUIT.replace(/\\D/g, '');\r\n const cleanCAE = caeResponse.cae.replace(/\\D/g, '');\r\n\r\n // Format date to YYYY-MM-DD (ARCA returns YYYYMMDD)\r\n const rawDate = caeResponse.date;\r\n const formattedDate = rawDate.length === 8\r\n ? `${rawDate.substring(0, 4)}-${rawDate.substring(4, 6)}-${rawDate.substring(6, 8)}`\r\n : rawDate;\r\n\r\n // Buyer document info\r\n const docType = buyer?.docType || TaxIdType.FINAL_CONSUMER;\r\n const docNumber = buyer?.docNumber ? buyer.docNumber.replace(/\\D/g, '') : '0';\r\n\r\n // Build QR object with STRICT field order (required by ARCA spec)\r\n const qrData: any = {\r\n ver: 1,\r\n fecha: formattedDate,\r\n cuit: Number(cleanCUIT),\r\n ptoVta: Number(caeResponse.pointOfSale),\r\n tipoCmp: Number(caeResponse.invoiceType),\r\n nroCmp: Number(caeResponse.invoiceNumber),\r\n importe: Number(parseFloat(total.toFixed(2))),\r\n moneda: 'PES',\r\n ctz: 1,\r\n };\r\n\r\n // Omit buyer fields for anonymous final consumers\r\n if (docType !== TaxIdType.FINAL_CONSUMER || Number(docNumber) > 0) {\r\n qrData.tipoDocRec = Number(docType);\r\n qrData.nroDocRec = Number(docNumber);\r\n }\r\n\r\n qrData.tipoCodAut = 'E';\r\n qrData.codAut = Number(cleanCAE);\r\n\r\n // Encode to Base64 (Buffer for Node.js, btoa fallback for browsers)\r\n const jsonString = JSON.stringify(qrData);\r\n const base64 = typeof Buffer !== 'undefined'\r\n ? Buffer.from(jsonString).toString('base64')\r\n : btoa(jsonString);\r\n\r\n return `https://www.afip.gob.ar/fe/qr/?p=${encodeURIComponent(base64)}`;\r\n}\r\n","/**\r\n * Diccionario de errores comunes de ARCA/AFIP y sus soluciones.\r\n * Clave: código de error numérico o string retornado por ARCA.\r\n * Valor: sugerencia clara para el desarrollador.\r\n */\r\nexport const ARCA_ERROR_HINTS: Record<string | number, string> = {\r\n // === Autenticación WSAA ===\r\n 501: 'El certificado puede haber expirado o la relación CUIT/Servicio no está habilitada en el portal de ARCA.',\r\n 502: 'El ticket de acceso (TA) es inválido o ya expiró. Hacé wsaa.login() nuevamente.',\r\n 503: 'Error interno del servidor de autenticación de ARCA. Reintentá en unos minutos.',\r\n 1000: 'El CUIT informado no es válido o no corresponde al certificado usado.',\r\n 1001: 'El servicio solicitado no existe o el certificado no tiene autorización para usarlo.',\r\n 1003: 'El TRA (Ticket de Requerimiento de Acceso) tiene un formato inválido.',\r\n 1005: 'El TRA ya expiró antes de ser presentado. Verificá la hora del sistema.',\r\n\r\n // === WSFE — Puntos de venta y configuración ===\r\n 10048: 'El punto de venta no está dado de alta en ARCA. Dalo de alta como Webservice en el portal.',\r\n 10049: 'El punto de venta no está activo o está bloqueado.',\r\n\r\n // === WSFE — Comprobantes y montos ===\r\n 10015: 'Factura B: El importe supera el límite para consumidores finales anónimos. Identificá al comprador con CUIT/DNI.',\r\n 10016: 'El CUIT informado como receptor no es válido o no existe en el Padrón.',\r\n 600: 'No se pudo autorizar el comprobante. Revisá el campo `observations` en la respuesta para más detalle.',\r\n 601: 'El comprobante ya fue autorizado anteriormente. No emitas dos veces el mismo número.',\r\n 602: 'El número de comprobante es inválido o no es el correcto según el último autorizado.',\r\n\r\n // === WSFE — IVA ===\r\n 10043: 'La alícuota de IVA informada no existe o es incorrecta. Usá 3 (0%), 4 (10.5%), 5 (21%) o 6 (27%).',\r\n 10044: 'El importe de IVA no cuadra con la base imponible × alícuota.',\r\n\r\n // === Padrón ===\r\n PADRON_ERROR: 'El servicio de Padrón suele ser inestable en homologación. Reintentá en unos minutos.',\r\n CUIT_NOT_FOUND: 'El CUIT consultado no existe en el Padrón de ARCA.',\r\n};\r\n\r\n/**\r\n * Busca un hint para un código de error dado.\r\n * Retorna undefined si no hay sugerencia conocida para ese código.\r\n */\r\nexport function getArcaHint(code: string | number): string | undefined {\r\n return ARCA_ERROR_HINTS[code];\r\n}\r\n","import { getWsfeEndpoint } from '../constants/endpoints';\r\nimport { ArcaError, ArcaValidationError } from '../types/common';\r\nimport type {\r\n WsfeConfig,\r\n IssueInvoiceRequest,\r\n CAEResponse,\r\n InvoiceItem,\r\n Buyer,\r\n ServiceStatus,\r\n InvoiceDetails,\r\n PointOfSale,\r\n} from '../types/wsfe';\r\nimport {\r\n InvoiceType,\r\n BillingConcept,\r\n TaxIdType,\r\n} from '../types/wsfe';\r\nimport {\r\n calculateSubtotal,\r\n calculateVAT,\r\n calculateTotal,\r\n round,\r\n} from '../utils/calculations';\r\nimport { parseXml } from '../utils/xml';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { generateQRUrl } from '../utils/qr';\r\nimport { getArcaHint } from '../constants/errors';\r\n\r\n/**\r\n * Servicio de Facturación Electrónica WSFE v1\r\n *\r\n * @example\r\n * ```typescript\r\n * const wsfe = new WsfeService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * ticket: await wsaa.login(),\r\n * pointOfSale: 4,\r\n * });\r\n *\r\n * // Ticket C rápido\r\n * const cae = await wsfe.issueSimpleReceipt({ total: 1500 });\r\n * console.log('CAE:', cae.cae);\r\n * console.log('QR:', cae.qrUrl);\r\n *\r\n * // Factura A/B con IVA discriminado\r\n * const cae = await wsfe.issueInvoiceB({\r\n * items: [{ description: 'Servicio', quantity: 1, unitPrice: 1000, vatRate: 21 }],\r\n * buyer: { docType: TaxIdType.CUIT, docNumber: '20987654321' },\r\n * });\r\n * ```\r\n */\r\nexport class WsfeService {\r\n private config: WsfeConfig;\r\n\r\n constructor(config: WsfeConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n }\r\n\r\n private validateConfig(config: WsfeConfig): void {\r\n if (!config.ticket || !config.ticket.token) {\r\n throw new ArcaValidationError(\r\n 'Ticket WSAA requerido. Ejecutá wsaa.login() primero.',\r\n { hint: 'El ticket se obtiene del servicio WsaaService' }\r\n );\r\n }\r\n\r\n if (!config.pointOfSale || config.pointOfSale < 1 || config.pointOfSale > 9999) {\r\n throw new ArcaValidationError(\r\n 'Punto de venta inválido: debe ser un número entre 1 y 9999',\r\n { pointOfSale: config.pointOfSale }\r\n );\r\n }\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Estado de los servidores\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA (FEDummy).\r\n * No requiere autenticación. Útil para health checks.\r\n *\r\n * @param environment Ambiente a consultar (default: 'homologacion')\r\n */\r\n static async checkStatus(environment: 'homologacion' | 'produccion' = 'homologacion'): Promise<ServiceStatus> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEDummy/>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEDummy',\r\n },\r\n body: soapRequest,\r\n timeout: 10000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar estado: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEDummyResponse?.FEDummyResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEDummy inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n return {\r\n appServer: data.AppServer,\r\n dbServer: data.DbServer,\r\n authServer: data.AuthServer,\r\n };\r\n }\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA.\r\n * Versión de instancia — usa el ambiente configurado.\r\n */\r\n async checkStatus(): Promise<ServiceStatus> {\r\n return WsfeService.checkStatus(this.config.environment);\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Emisión de comprobantes\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Emite un Ticket C simple (solo monto total, sin detalle de items).\r\n * Ideal para registros mínimos, como una app móvil de punto de venta.\r\n */\r\n async issueSimpleReceipt(params: {\r\n total: number;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n return this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total: params.total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Emite un Ticket C con detalle de items.\r\n * Los items se guardan en la respuesta pero no se envían a ARCA.\r\n */\r\n async issueReceipt(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n const cae = await this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n\r\n return { ...cae, items: params.items };\r\n }\r\n\r\n /**\r\n * Emite una Factura C (consumidor final, sin discriminación de IVA).\r\n */\r\n async issueInvoiceC(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n items: params.items,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura B (con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceB(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_B,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura A (Responsable Inscripto a Responsable Inscripto, con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceA(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_A,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Consultas\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Consulta un comprobante ya emitido (FECompConsultar).\r\n *\r\n * @param type Tipo de comprobante\r\n * @param invoiceNumber Número de comprobante\r\n */\r\n async getInvoice(type: InvoiceType, invoiceNumber: number): Promise<InvoiceDetails> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompConsultar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCompConsReq>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n <ar:CbteNro>${invoiceNumber}</ar:CbteNro>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n </ar:FeCompConsReq>\r\n </ar:FECompConsultar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompConsultar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompConsultarResponse?.FECompConsultarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FECompConsultar inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const det = data.ResultGet;\r\n return {\r\n invoiceType: Number(det.CbteTipo),\r\n pointOfSale: Number(det.PtoVta),\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: String(det.CbteFch),\r\n concept: Number(det.Concepto),\r\n docType: Number(det.DocTipo),\r\n docNumber: Number(det.DocNro),\r\n total: Number(det.ImpTotal),\r\n net: Number(det.ImpNeto),\r\n vat: Number(det.ImpIVA),\r\n cae: String(det.CodAutorizacion),\r\n caeExpiry: String(det.FchVto),\r\n result: det.Resultado as 'A' | 'R',\r\n };\r\n }\r\n\r\n /**\r\n * Lista los puntos de venta habilitados para el CUIT autenticado (FEParamGetPtosVenta).\r\n */\r\n async getPointsOfSale(): Promise<PointOfSale[]> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEParamGetPtosVenta>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n </ar:FEParamGetPtosVenta>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEParamGetPtosVenta',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar puntos de venta: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEParamGetPtosVentaResponse?.FEParamGetPtosVentaResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEParamGetPtosVenta inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n throw new ArcaError(`Error ARCA: ${error?.Msg || 'Error desconocido'}`, 'ARCA_ERROR', data.Errors);\r\n }\r\n\r\n const raw = data.ResultGet?.PtoVenta;\r\n if (!raw) return [];\r\n\r\n const list = Array.isArray(raw) ? raw : [raw];\r\n return list.map((pv: Record<string, unknown>) => ({\r\n number: Number(pv.Nro),\r\n type: String(pv.EmisionTipo),\r\n isBlocked: pv.Bloqueado === 'S',\r\n blockedSince: pv.FchBaja ? String(pv.FchBaja) : undefined,\r\n }));\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Métodos internos\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Método genérico interno para emitir cualquier tipo de comprobante.\r\n */\r\n private async issueDocument(request: IssueInvoiceRequest): Promise<CAEResponse> {\r\n // 1. Get next invoice number\r\n const invoiceNumber = await this.getNextInvoiceNumber(request.type);\r\n\r\n // 2. Calculate totals\r\n let total = request.total || 0;\r\n let net = total;\r\n let vat = 0;\r\n\r\n if (request.items && request.items.length > 0) {\r\n const includesVAT = request.includesVAT || false;\r\n net = round(calculateSubtotal(request.items, includesVAT));\r\n vat = round(calculateVAT(request.items, includesVAT));\r\n total = round(calculateTotal(request.items, includesVAT));\r\n }\r\n\r\n if (total <= 0) {\r\n throw new ArcaValidationError('El monto total debe ser mayor a 0');\r\n }\r\n\r\n // 3. Build SOAP request\r\n const soapRequest = this.buildCAERequest({\r\n type: request.type,\r\n pointOfSale: this.config.pointOfSale,\r\n invoiceNumber,\r\n concept: request.concept,\r\n date: request.date || new Date(),\r\n buyer: request.buyer,\r\n net,\r\n vat,\r\n total,\r\n vatData: request.vatData,\r\n });\r\n\r\n // 4. Send to ARCA\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECAESolicitar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(\r\n `Error HTTP al comunicarse con WSFE: ${response.status}`,\r\n 'HTTP_ERROR',\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 5. Parse CAE response\r\n const result = await this.parseCAEResponse(responseXml);\r\n\r\n // 6. Generate QR URL\r\n const qrUrl = generateQRUrl(result, this.config.cuit, total, request.buyer);\r\n\r\n return {\r\n ...result,\r\n items: request.items,\r\n vat: request.vatData,\r\n qrUrl,\r\n };\r\n }\r\n\r\n /**\r\n * Obtiene el próximo número de comprobante disponible (FECompUltimoAutorizado + 1)\r\n */\r\n private async getNextInvoiceNumber(type: InvoiceType): Promise<number> {\r\n const soapRequest = this.buildLastInvoiceRequest(type);\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompUltimoAutorizado',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar último comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompUltimoAutorizadoResponse?.FECompUltimoAutorizadoResult;\r\n\r\n if (data?.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const lastNumber = data?.CbteNro;\r\n return typeof lastNumber === 'number' ? lastNumber + 1 : 1;\r\n }\r\n\r\n /**\r\n * Valida que todos los items tengan alícuota IVA definida\r\n */\r\n private validateItemsWithVAT(items: InvoiceItem[]): void {\r\n const missingVAT = items.filter(item =>\r\n item.vatRate === undefined || item.vatRate === null\r\n );\r\n\r\n if (missingVAT.length > 0) {\r\n throw new ArcaValidationError(\r\n 'Esta operación requiere `vatRate` en todos los items',\r\n {\r\n itemsMissingVAT: missingVAT.map(i => i.description),\r\n hint: 'Agregá vatRate a cada item (21, 10.5, 27, o 0)'\r\n }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Calcula el IVA agrupado por alícuota (requerido por ARCA para Factura A/B)\r\n */\r\n private calculateVATByRate(items: InvoiceItem[], includesVAT = false): {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[] {\r\n const byRate = new Map<number, { base: number; amount: number }>();\r\n\r\n items.forEach(item => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n\r\n const base = item.quantity * netPrice;\r\n const amount = base * rate / 100;\r\n\r\n const current = byRate.get(rate) || { base: 0, amount: 0 };\r\n byRate.set(rate, {\r\n base: current.base + base,\r\n amount: current.amount + amount,\r\n });\r\n });\r\n\r\n return Array.from(byRate.entries()).map(([rate, values]) => ({\r\n rate,\r\n taxBase: round(values.base),\r\n amount: round(values.amount),\r\n }));\r\n }\r\n\r\n /**\r\n * Mapea alícuota % al código interno de ARCA\r\n */\r\n private getVATCode(percentage: number): number {\r\n const map: Record<number, number> = {\r\n 0: 3,\r\n 10.5: 4,\r\n 21: 5,\r\n 27: 6,\r\n };\r\n\r\n const code = map[percentage];\r\n if (code === undefined) {\r\n throw new ArcaValidationError(\r\n `Alícuota IVA inválida: ${percentage}%`,\r\n {\r\n validRates: [0, 10.5, 21, 27],\r\n hint: 'Usá una de las alícuotas oficiales de Argentina'\r\n }\r\n );\r\n }\r\n\r\n return code;\r\n }\r\n\r\n private buildCAERequest(params: {\r\n type: InvoiceType;\r\n pointOfSale: number;\r\n invoiceNumber: number;\r\n concept: BillingConcept;\r\n date: Date;\r\n buyer?: IssueInvoiceRequest['buyer'];\r\n net: number;\r\n vat: number;\r\n total: number;\r\n vatData?: IssueInvoiceRequest['vatData'];\r\n }): string {\r\n const dateStr = params.date.toISOString().split('T')[0].replace(/-/g, '');\r\n\r\n let vatXml = '';\r\n if (params.vatData && params.vatData.length > 0) {\r\n vatXml = '<ar:Iva>';\r\n params.vatData.forEach(entry => {\r\n vatXml += `\r\n <ar:AlicIva>\r\n <ar:Id>${this.getVATCode(entry.rate)}</ar:Id>\r\n <ar:BaseImp>${entry.taxBase.toFixed(2)}</ar:BaseImp>\r\n <ar:Importe>${entry.amount.toFixed(2)}</ar:Importe>\r\n </ar:AlicIva>`;\r\n });\r\n vatXml += '\\n </ar:Iva>';\r\n }\r\n\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECAESolicitar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCAEReq>\r\n <ar:FeCabReq>\r\n <ar:CantReg>1</ar:CantReg>\r\n <ar:PtoVta>${params.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${params.type}</ar:CbteTipo>\r\n </ar:FeCabReq>\r\n <ar:FeDetReq>\r\n <ar:FECAEDetRequest>\r\n <ar:Concepto>${params.concept}</ar:Concepto>\r\n <ar:DocTipo>${params.buyer?.docType || 99}</ar:DocTipo>\r\n <ar:DocNro>${params.buyer?.docNumber || 0}</ar:DocNro>\r\n <ar:CbteDesde>${params.invoiceNumber}</ar:CbteDesde>\r\n <ar:CbteHasta>${params.invoiceNumber}</ar:CbteHasta>\r\n <ar:CbteFch>${dateStr}</ar:CbteFch>\r\n <ar:ImpTotal>${params.total.toFixed(2)}</ar:ImpTotal>\r\n <ar:ImpTotConc>0.00</ar:ImpTotConc>\r\n <ar:ImpNeto>${params.net.toFixed(2)}</ar:ImpNeto>\r\n <ar:ImpOpEx>0.00</ar:ImpOpEx>\r\n <ar:ImpIVA>${params.vat.toFixed(2)}</ar:ImpIVA>\r\n <ar:ImpTrib>0.00</ar:ImpTrib>\r\n <ar:MonId>PES</ar:MonId>\r\n <ar:MonCotiz>1</ar:MonCotiz>\r\n ${vatXml}\r\n </ar:FECAEDetRequest>\r\n </ar:FeDetReq>\r\n </ar:FeCAEReq>\r\n </ar:FECAESolicitar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private buildLastInvoiceRequest(type: InvoiceType): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompUltimoAutorizado>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n </ar:FECompUltimoAutorizado>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private async parseCAEResponse(xml: string): Promise<CAEResponse> {\r\n const result = parseXml(xml);\r\n const data = result?.Envelope?.Body?.FECAESolicitarResponse?.FECAESolicitarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta WSFE inválida: estructura no reconocida', 'PARSE_ERROR', { xml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const cab = data.FeCabResp;\r\n const det = Array.isArray(data.FeDetResp.FECAEDetResponse)\r\n ? data.FeDetResp.FECAEDetResponse[0]\r\n : data.FeDetResp.FECAEDetResponse;\r\n\r\n if (!det) {\r\n throw new ArcaError('Respuesta WSFE incompleta: falta detalle del comprobante', 'PARSE_ERROR');\r\n }\r\n\r\n const observations: string[] = [];\r\n if (det.Observaciones) {\r\n const obsArray = Array.isArray(det.Observaciones.Obs)\r\n ? det.Observaciones.Obs\r\n : [det.Observaciones.Obs];\r\n obsArray.forEach((o: { Msg: string }) => observations.push(o.Msg));\r\n }\r\n\r\n return {\r\n invoiceType: cab.CbteTipo,\r\n pointOfSale: cab.PtoVta,\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: det.CbteFch,\r\n cae: String(det.CAE),\r\n caeExpiry: String(det.CAEFchVto),\r\n result: det.Resultado,\r\n observations: observations.length > 0 ? observations : undefined,\r\n };\r\n }\r\n}\r\n","import { WsaaService } from '../auth/wsaa';\r\nimport { getPadronEndpoint } from '../constants/endpoints';\r\nimport { ArcaNetworkError, ArcaError } from '../types/common';\r\nimport type {\r\n TaxpayerServiceConfig,\r\n Taxpayer,\r\n TaxpayerResponse,\r\n Address,\r\n Activity,\r\n TaxRecord,\r\n} from '../types/padron';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\n/**\r\n * Servicio para consultar el Padrón de AFIP (ws_sr_padron_a13)\r\n *\r\n * @example\r\n * ```typescript\r\n * const padron = new PadronService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * });\r\n *\r\n * const { taxpayer, error } = await padron.getTaxpayer('30111111118');\r\n * if (taxpayer) {\r\n * console.log(taxpayer.companyName || `${taxpayer.firstName} ${taxpayer.lastName}`);\r\n * console.log('¿Inscripto IVA?:', taxpayer.isVATRegistered);\r\n * }\r\n * ```\r\n */\r\nexport class PadronService {\r\n private wsaa: WsaaService;\r\n private config: TaxpayerServiceConfig;\r\n\r\n constructor(config: TaxpayerServiceConfig) {\r\n this.config = config;\r\n this.wsaa = new WsaaService({\r\n environment: config.environment,\r\n cuit: config.cuit,\r\n cert: config.cert,\r\n key: config.key,\r\n service: 'ws_sr_padron_a13',\r\n storage: config.storage,\r\n });\r\n }\r\n\r\n /**\r\n * Consulta los datos de un contribuyente por CUIT\r\n *\r\n * @param taxId CUIT a consultar (11 dígitos sin guiones)\r\n * @returns Datos del contribuyente o mensaje de error\r\n */\r\n async getTaxpayer(taxId: string): Promise<TaxpayerResponse> {\r\n const ticket = await this.wsaa.login();\r\n\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:a13=\"http://a13.soap.ws.server.puc.sr/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <a13:getPersona>\r\n <token>${ticket.token}</token>\r\n <sign>${ticket.sign}</sign>\r\n <cuitRepresentada>${this.config.cuit}</cuitRepresentada>\r\n <idPersona>${taxId}</idPersona>\r\n </a13:getPersona>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getPadronEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout || 15000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaNetworkError(\r\n `Error HTTP al comunicarse con Padrón A13: ${response.status}`,\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const xml = await response.text();\r\n return this.parseResponse(xml);\r\n }\r\n\r\n /**\r\n * Parsea la respuesta XML de getPersona\r\n */\r\n private parseResponse(xml: string): TaxpayerResponse {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n removeNSPrefix: true,\r\n });\r\n const result = parser.parse(xml);\r\n\r\n const body = result.Envelope?.Body;\r\n if (!body) {\r\n throw new ArcaError('Respuesta del Padrón inválida: Body no encontrado', 'PADRON_ERROR');\r\n }\r\n\r\n const response = body.getPersonaResponse?.personaReturn;\r\n if (!response) {\r\n const fault = body.Fault;\r\n if (fault) {\r\n return { error: fault.faultstring || 'Error desconocido en ARCA' };\r\n }\r\n return { error: 'No se encontraron datos para el CUIT informado' };\r\n }\r\n\r\n if (response.errorConstancia) {\r\n return { error: response.errorConstancia };\r\n }\r\n\r\n const p = response.persona;\r\n if (!p) {\r\n return { error: 'CUIT no encontrado' };\r\n }\r\n\r\n const taxpayer: Taxpayer = {\r\n taxId: Number(p.idPersona),\r\n personType: p.tipoPersona as 'FISICA' | 'JURIDICA',\r\n firstName: p.nombre,\r\n lastName: p.apellido,\r\n companyName: p.razonSocial,\r\n status: p.estadoClave,\r\n addresses: this.mapAddresses(p.domicilio),\r\n activities: this.mapActivities(p.actividad),\r\n taxes: this.mapTaxRecords(p.impuesto),\r\n mainActivity: p.descripcionActividadPrincipal,\r\n isVATRegistered: this.hasTaxId(p, 30), // 30 = IVA\r\n isMonotax: this.hasTaxId(p, 20), // 20 = Monotributo\r\n isVATExempt: this.hasTaxId(p, 32), // 32 = IVA Exento\r\n };\r\n\r\n return { taxpayer };\r\n }\r\n\r\n private mapAddresses(raw: unknown): Address[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n street: item.direccion as string,\r\n city: item.localidad as string | undefined,\r\n postalCode: item.codPostal as string | undefined,\r\n provinceId: Number(item.idProvincia),\r\n province: item.descripcionProvincia as string,\r\n type: item.tipoDomicilio as string,\r\n }));\r\n }\r\n\r\n private mapActivities(raw: unknown): Activity[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idActividad),\r\n description: item.descripcion as string,\r\n order: Number(item.orden),\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private mapTaxRecords(raw: unknown): TaxRecord[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idImpuesto),\r\n description: item.descripcion as string,\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private hasTaxId(p: Record<string, unknown>, id: number): boolean {\r\n const taxes = p.impuesto;\r\n if (!taxes) return false;\r\n return this.toArray(taxes).some((i: Record<string, unknown>) => Number(i.idImpuesto) === id);\r\n }\r\n\r\n /**\r\n * Normaliza un valor que puede ser un objeto único o un array (comportamiento de fast-xml-parser)\r\n */\r\n private toArray(data: unknown): Record<string, unknown>[] {\r\n if (data === undefined || data === null) return [];\r\n if (Array.isArray(data)) return data as Record<string, unknown>[];\r\n return [data as Record<string, unknown>];\r\n }\r\n}\r\n"],"mappings":"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","names":["https","InvoiceType","BillingConcept","TaxIdType","import_fast_xml_parser"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants/endpoints.ts","../src/types/common.ts","../src/utils/xml.ts","../src/utils/crypto.ts","../src/auth/ticket.ts","../src/utils/network.ts","../src/auth/wsaa.ts","../src/types/wsfe.ts","../src/utils/calculations.ts","../src/utils/qr.ts","../src/constants/errors.ts","../src/services/wsfe.ts","../src/services/padron.ts"],"sourcesContent":["/**\r\n * arca-sdk — SDK moderna para ARCA (ex-AFIP)\r\n */\r\n\r\n// Servicios principales\r\nexport { WsaaService } from './auth/wsaa';\r\nexport { WsfeService } from './services/wsfe';\r\nexport { PadronService } from './services/padron';\r\n\r\n// Tipos comunes\r\nexport type {\r\n Environment,\r\n ArcaConfig,\r\n} from './types/common';\r\n\r\n// Tipos WSAA\r\nexport type {\r\n WsaaConfig,\r\n LoginTicket,\r\n} from './types/wsaa';\r\nexport type { TokenStorage } from './auth/storage';\r\n\r\n// Tipos Padrón\r\nexport type {\r\n TaxpayerServiceConfig,\r\n Taxpayer,\r\n Address,\r\n Activity,\r\n TaxRecord,\r\n TaxpayerResponse,\r\n} from './types/padron';\r\n\r\n// Tipos WSFE\r\nexport type {\r\n WsfeConfig,\r\n InvoiceItem,\r\n Buyer,\r\n IssueInvoiceRequest,\r\n CAEResponse,\r\n InvoiceDetails,\r\n PointOfSale,\r\n ServiceStatus,\r\n} from './types/wsfe';\r\n\r\n// Enums WSFE\r\nexport {\r\n InvoiceType,\r\n BillingConcept,\r\n TaxIdType,\r\n} from './types/wsfe';\r\n\r\n// Errores\r\nexport {\r\n ArcaError,\r\n ArcaAuthError,\r\n ArcaValidationError,\r\n ArcaNetworkError,\r\n} from './types/common';\r\n\r\n// Utilidades para Frontend/Impresión\r\nexport { generateQRUrl } from './utils/qr';\r\n","import type { Environment } from '../types/common';\r\n\r\n/**\r\n * URLs de los servicios ARCA por ambiente\r\n */\r\nexport const WSAA_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms',\r\n produccion: 'https://wsaa.afip.gov.ar/ws/services/LoginCms',\r\n};\r\n\r\n/**\r\n * URLs del servicio WSFE por ambiente\r\n */\r\nexport const WSFE_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx',\r\n produccion: 'https://servicios1.afip.gov.ar/wsfev1/service.asmx',\r\n};\r\n\r\n/**\r\n * URLs del servicio Padron A13 por ambiente\r\n */\r\nexport const PADRON_A13_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n produccion: 'https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n};\r\n\r\n/**\r\n * Obtener endpoint WSAA según ambiente\r\n */\r\nexport function getWsaaEndpoint(environment: Environment): string {\r\n return WSAA_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint WSFE según ambiente\r\n */\r\nexport function getWsfeEndpoint(environment: Environment): string {\r\n return WSFE_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint Padron A13 según ambiente\r\n */\r\nexport function getPadronEndpoint(environment: Environment): string {\r\n return PADRON_A13_ENDPOINTS[environment];\r\n}\r\n","/**\r\n * Tipos comunes compartidos en toda la SDK\r\n */\r\n\r\n/**\r\n * Ambiente de ejecución ARCA\r\n */\r\nexport type Environment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Configuración base para servicios ARCA\r\n */\r\nexport interface ArcaConfig {\r\n /** Ambiente (homologación o producción) */\r\n environment: Environment;\r\n /** CUIT del contribuyente (11 dígitos sin guiones) */\r\n cuit: string;\r\n /** Tiempo de espera para peticiones (ms). Defecto: 15000 */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Error personalizado de ARCA SDK\r\n */\r\nexport class ArcaError extends Error {\r\n constructor(\r\n message: string,\r\n public code: string,\r\n public details?: unknown,\r\n public hint?: string\r\n ) {\r\n super(message);\r\n this.name = 'ArcaError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de autenticación WSAA\r\n */\r\nexport class ArcaAuthError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'AUTH_ERROR', details);\r\n this.name = 'ArcaAuthError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de validación de input\r\n */\r\nexport class ArcaValidationError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'VALIDATION_ERROR', details);\r\n this.name = 'ArcaValidationError';\r\n }\r\n}\r\n/**\r\n * Error de comunicación/red\r\n */\r\nexport class ArcaNetworkError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'NETWORK_ERROR', details);\r\n this.name = 'ArcaNetworkError';\r\n }\r\n}\r\n","import { XMLBuilder, XMLParser } from 'fast-xml-parser';\r\nimport { ArcaAuthError } from '../types/common';\r\nimport type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Genera el XML TRA (Ticket de Requerimiento de Acceso)\r\n * \r\n * @param service - Servicio ARCA (ej: 'wsfe')\r\n * @param cuit - CUIT del contribuyente\r\n * @returns XML del TRA\r\n */\r\nexport function buildTRA(service: string, cuit: string): string {\r\n const now = new Date();\r\n const expirationTime = new Date(now.getTime() + 12 * 60 * 60 * 1000); // +12 horas\r\n\r\n const tra = {\r\n loginTicketRequest: {\r\n '@_version': '1.0',\r\n header: {\r\n uniqueId: Math.floor(now.getTime() / 1000),\r\n generationTime: now.toISOString(),\r\n expirationTime: expirationTime.toISOString(),\r\n },\r\n service,\r\n },\r\n };\r\n\r\n const builder = new XMLBuilder({\r\n ignoreAttributes: false,\r\n format: true,\r\n });\r\n\r\n const xml = builder.build(tra);\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${xml}`;\r\n}\r\n\r\n/**\r\n * Parsea la respuesta XML de WSAA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Ticket de login\r\n */\r\nexport function parseWsaaResponse(xml: string): LoginTicket {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n\r\n try {\r\n const envelope = parser.parse(xml);\r\n\r\n // El loginCmsReturn contiene el ticket real como un XML escapado (string)\r\n const loginCmsReturn = envelope?.Envelope?.Body?.loginCmsResponse?.loginCmsReturn;\r\n\r\n if (!loginCmsReturn) {\r\n const fault = envelope?.Envelope?.Body?.Fault;\r\n if (fault) {\r\n throw new ArcaAuthError(\r\n `Error ARCA: ${fault.faultstring || 'Error desconocido'}`,\r\n { faultCode: fault.faultcode, detail: fault.detail }\r\n );\r\n }\r\n\r\n throw new ArcaAuthError(\r\n 'Respuesta WSAA inválida: estructura no reconocida',\r\n {\r\n receivedXml: xml.substring(0, 5000),\r\n receivedStructure: JSON.stringify(envelope).substring(0, 500)\r\n }\r\n );\r\n }\r\n\r\n // Segundo nivel de parseo: El XML interno escapado que viene dentro de loginCmsReturn\r\n const ticketResult = parser.parse(loginCmsReturn);\r\n const ticket = ticketResult?.loginTicketResponse;\r\n\r\n if (!ticket || !ticket.header || !ticket.credentials) {\r\n throw new ArcaAuthError('Ticket WSAA inválido o malformado dentro de loginCmsReturn', {\r\n innerStructure: JSON.stringify(ticketResult).substring(0, 500),\r\n receivedXml: xml.substring(0, 5000)\r\n });\r\n }\r\n\r\n return {\r\n token: ticket.credentials.token,\r\n sign: ticket.credentials.sign,\r\n generationTime: new Date(ticket.header.generationTime),\r\n expirationTime: new Date(ticket.header.expirationTime),\r\n };\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al parsear respuesta WSAA (posible XML anidado malformado)',\r\n {\r\n originalError: error instanceof Error ? error.message : String(error),\r\n receivedXml: xml.substring(0, 5000)\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Parsea un XML genérico de ARCA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Objeto parseado\r\n */\r\nexport function parseXml(xml: string): any {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n return parser.parse(xml);\r\n}\r\n\r\n/**\r\n * Valida CUIT (11 dígitos sin guiones)\r\n */\r\nexport function validateCUIT(cuit: string): boolean {\r\n return /^\\d{11}$/.test(cuit);\r\n}\r\n","import * as forge from 'node-forge';\r\nimport { ArcaAuthError } from '../types/common';\r\n\r\n/**\r\n * Firma un XML en formato CMS (PKCS#7) usando certificado y clave privada\r\n * \r\n * @param xml - Contenido XML a firmar (TRA)\r\n * @param certPem - Certificado en formato PEM\r\n * @param keyPem - Clave privada en formato PEM\r\n * @returns CMS firmado en base64\r\n */\r\nexport function signCMS(xml: string, certPem: string, keyPem: string): string {\r\n try {\r\n // 1. Parsear certificado\r\n const cert = forge.pki.certificateFromPem(certPem);\r\n\r\n // 2. Parsear clave privada\r\n const privateKey = forge.pki.privateKeyFromPem(keyPem);\r\n\r\n // 3. Crear contenedor PKCS#7\r\n const p7 = forge.pkcs7.createSignedData();\r\n\r\n // 4. Agregar contenido a firmar\r\n p7.content = forge.util.createBuffer(xml, 'utf8');\r\n\r\n // 5. Agregar certificado\r\n p7.addCertificate(cert);\r\n\r\n // 6. Firmar con SHA256\r\n p7.addSigner({\r\n key: privateKey,\r\n certificate: cert,\r\n digestAlgorithm: forge.pki.oids.sha256,\r\n authenticatedAttributes: [\r\n {\r\n type: forge.pki.oids.contentType,\r\n value: forge.pki.oids.data,\r\n },\r\n {\r\n type: forge.pki.oids.messageDigest,\r\n // El valor será calculado automáticamente\r\n },\r\n {\r\n type: forge.pki.oids.signingTime,\r\n // node-forge expects a Date object, but its typings might be missing or expect string/any\r\n value: new Date() as any,\r\n },\r\n ],\r\n });\r\n\r\n // 7. Firmar\r\n p7.sign();\r\n\r\n // 8. Convertir a DER y luego a base64\r\n const derBytes = forge.asn1.toDer(p7.toAsn1()).getBytes();\r\n const base64 = forge.util.encode64(derBytes);\r\n\r\n return base64;\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al firmar XML con certificado usando PKCS#7',\r\n {\r\n originalError: error,\r\n hint: 'Verificar que el certificado y la clave privada sean válidos y correspondan entre sí'\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Valida formato de certificado PEM\r\n */\r\nexport function validateCertificate(cert: string): boolean {\r\n return cert.includes('-----BEGIN CERTIFICATE-----') &&\r\n cert.includes('-----END CERTIFICATE-----');\r\n}\r\n\r\n/**\r\n * Valida formato de clave privada PEM\r\n */\r\nexport function validatePrivateKey(key: string): boolean {\r\n return (\r\n (key.includes('-----BEGIN PRIVATE KEY-----') &&\r\n key.includes('-----END PRIVATE KEY-----')) ||\r\n (key.includes('-----BEGIN RSA PRIVATE KEY-----') &&\r\n key.includes('-----END RSA PRIVATE KEY-----'))\r\n );\r\n}\r\n","import type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Gestor de tickets de autenticación\r\n * Maneja cache en memoria del ticket WSAA\r\n */\r\nexport class TicketManager {\r\n private ticket: LoginTicket | null = null;\r\n\r\n /**\r\n * Guarda un ticket en cache\r\n */\r\n setTicket(ticket: LoginTicket): void {\r\n this.ticket = ticket;\r\n }\r\n\r\n /**\r\n * Obtiene el ticket actual si es válido\r\n * @returns Ticket válido o null si expiró\r\n */\r\n getTicket(): LoginTicket | null {\r\n if (!this.ticket) return null;\r\n\r\n const now = new Date();\r\n const expiresIn = this.ticket.expirationTime.getTime() - now.getTime();\r\n\r\n // Si expira en menos de 5 minutos, considerarlo inválido\r\n const BUFFER_MS = 5 * 60 * 1000;\r\n\r\n if (expiresIn < BUFFER_MS) {\r\n this.ticket = null;\r\n return null;\r\n }\r\n\r\n return this.ticket;\r\n }\r\n\r\n /**\r\n * Verifica si hay un ticket válido\r\n */\r\n hasValidTicket(): boolean {\r\n return this.getTicket() !== null;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache\r\n */\r\n clearTicket(): void {\r\n this.ticket = null;\r\n }\r\n}\r\n","import https from 'https';\r\nimport { ArcaNetworkError } from '../types/common';\r\n\r\n/**\r\n * Entornos compatibles\r\n */\r\nexport type ArcaEnvironment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Opciones para la llamada API\r\n */\r\nexport interface CallApiOptions {\r\n method: string;\r\n headers: Record<string, string>;\r\n body: string;\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Realiza una llamada a la API de ARCA (WSAA o WSFE)\r\n * Maneja la compatibilidad SSL con los servidores de AFIP (DH key size)\r\n * y añade robustez (timeouts, mejores errores).\r\n */\r\nexport async function callArcaApi(\r\n url: string,\r\n options: CallApiOptions\r\n): Promise<Response> {\r\n const timeout = options.timeout || 15000;\r\n const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\r\n\r\n if (isNode) {\r\n return new Promise((resolve, reject) => {\r\n const parsedUrl = new URL(url);\r\n\r\n const agent = new https.Agent({\r\n // SECLEVEL=0 es el nivel más permisivo de OpenSSL.\r\n // !DH desactiva Diffie-Hellman para forzar RSA o ECDHE si están disponibles,\r\n // evitando el problema de \"dh key too small\" de raíz.\r\n ciphers: 'DEFAULT:!DH@SECLEVEL=0',\r\n // AFIP todavía tiene endpoints que podrían requerir TLS 1.0/1.1\r\n minVersion: 'TLSv1',\r\n // @ts-ignore - Propiedad específica para mitigar \"dh key too small\" en Node 18+\r\n minDHSize: 1024,\r\n rejectUnauthorized: true,\r\n });\r\n\r\n const reqOptions: https.RequestOptions = {\r\n method: options.method,\r\n hostname: parsedUrl.hostname,\r\n path: parsedUrl.pathname + parsedUrl.search,\r\n headers: options.headers,\r\n agent,\r\n timeout,\r\n };\r\n\r\n const req = https.request(reqOptions, (res) => {\r\n res.setEncoding('utf8');\r\n let data = '';\r\n res.on('data', (chunk) => { data += chunk; });\r\n res.on('end', () => {\r\n // Simular objeto Response de fetch\r\n const response = {\r\n ok: (res.statusCode || 0) >= 200 && (res.statusCode || 0) < 300,\r\n status: res.statusCode || 0,\r\n statusText: res.statusMessage || '',\r\n text: async () => data,\r\n json: async () => JSON.parse(data),\r\n };\r\n resolve(response as Response);\r\n });\r\n });\r\n\r\n req.on('error', (error: any) => {\r\n let message = error.message;\r\n if (message.includes('dh key too small')) {\r\n message = 'Error SSL de ARCA (DH Key too small). Verifique su versión de OpenSSL/Node.';\r\n }\r\n reject(new ArcaNetworkError(`Error de red al comunicarse con ARCA (HTTPS): ${message}`, {\r\n url,\r\n originalError: error\r\n }));\r\n });\r\n\r\n req.on('timeout', () => {\r\n req.destroy();\r\n reject(new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`));\r\n });\r\n\r\n req.write(options.body);\r\n req.end();\r\n });\r\n }\r\n\r\n // Navegador o entorno no-Node (utiliza fetch nativo)\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: options.method,\r\n headers: options.headers,\r\n body: options.body,\r\n signal: controller.signal\r\n });\r\n return response;\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n throw new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`);\r\n }\r\n throw new ArcaNetworkError(`Error de red: ${error.message}`, { url, originalError: error });\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n}\r\n","import { getWsaaEndpoint } from '../constants/endpoints';\r\nimport { ArcaAuthError, ArcaValidationError } from '../types/common';\r\nimport type { WsaaConfig, LoginTicket } from '../types/wsaa';\r\nimport { buildTRA, parseWsaaResponse, validateCUIT } from '../utils/xml';\r\nimport { validateCertificate, validatePrivateKey, signCMS } from '../utils/crypto';\r\nimport { TicketManager } from './ticket';\r\nimport { callArcaApi } from '../utils/network';\r\n\r\n/**\r\n * Servicio de autenticación WSAA (Web Service de Autenticación y Autorización)\r\n * \r\n * @example\r\n * ```typescript\r\n * const wsaa = new WsaaService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * service: 'wsfe',\r\n * });\r\n * \r\n * const ticket = await wsaa.login();\r\n * console.log('Token:', ticket.token);\r\n * ```\r\n */\r\nexport class WsaaService {\r\n private config: WsaaConfig;\r\n private ticketManager: TicketManager;\r\n\r\n constructor(config: WsaaConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n this.ticketManager = new TicketManager();\r\n }\r\n\r\n /**\r\n * Valida la configuración\r\n */\r\n private validateConfig(config: WsaaConfig): void {\r\n if (!validateCUIT(config.cuit)) {\r\n throw new ArcaValidationError(\r\n 'CUIT inválido: debe tener 11 dígitos sin guiones',\r\n { cuit: config.cuit }\r\n );\r\n }\r\n\r\n if (!validateCertificate(config.cert)) {\r\n throw new ArcaValidationError(\r\n 'Certificado inválido: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN CERTIFICATE-----' }\r\n );\r\n }\r\n\r\n if (!validatePrivateKey(config.key)) {\r\n throw new ArcaValidationError(\r\n 'Clave privada inválida: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN PRIVATE KEY----- o -----BEGIN RSA PRIVATE KEY-----' }\r\n );\r\n }\r\n\r\n if (!config.service || config.service.trim() === '') {\r\n throw new ArcaValidationError(\r\n 'Servicio ARCA no especificado',\r\n { hint: 'Ejemplos: \"wsfe\", \"wsmtxca\"' }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Obtiene un ticket de acceso válido.\r\n * \r\n * Prioridad de búsqueda:\r\n * 1. Memoria (TicketManager cache)\r\n * 2. Persistencia (si config.storage está definido)\r\n * 3. Nueva solicitud a WSAA\r\n * \r\n * @returns Ticket de acceso\r\n */\r\n async login(): Promise<LoginTicket> {\r\n // 1. Intentar usar ticket en memoria (muy rápido)\r\n const cachedTicket = this.ticketManager.getTicket();\r\n if (cachedTicket) {\r\n return cachedTicket;\r\n }\r\n\r\n // 2. Intentar usar persistencia externa si está disponible\r\n if (this.config.storage) {\r\n try {\r\n const storedTicket = await this.config.storage.get(this.config.cuit, this.config.environment);\r\n if (storedTicket) {\r\n // Validar si el ticket devuelto por el storage no está expirado\r\n // Agrego un margen de 5 minutos\r\n const now = new Date();\r\n if (new Date(storedTicket.expirationTime) > new Date(now.getTime() + 5 * 60000)) {\r\n this.ticketManager.setTicket(storedTicket);\r\n return storedTicket;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.get falló, intentando login directo:', error);\r\n }\r\n }\r\n\r\n // 3. Generar nuevo ticket (llamada a AFIP)\r\n const ticket = await this.requestNewTicket();\r\n\r\n // Guardar en memoria\r\n this.ticketManager.setTicket(ticket);\r\n\r\n // Guardar en persistencia externa\r\n if (this.config.storage) {\r\n try {\r\n await this.config.storage.save(this.config.cuit, this.config.environment, ticket);\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.save falló:', error);\r\n }\r\n }\r\n\r\n return ticket;\r\n }\r\n\r\n /**\r\n * Solicita un nuevo ticket a WSAA\r\n */\r\n private async requestNewTicket(): Promise<LoginTicket> {\r\n // 1. Generar TRA (Ticket de Requerimiento de Acceso)\r\n const tra = buildTRA(this.config.service, this.config.cuit);\r\n\r\n // 2. Firmar TRA con certificado (genera CMS)\r\n let cms: string;\r\n try {\r\n cms = signCMS(tra, this.config.cert, this.config.key);\r\n } catch (error) {\r\n throw new ArcaAuthError(\r\n 'Error al firmar TRA con certificado',\r\n { originalError: error }\r\n );\r\n }\r\n\r\n // 3. Enviar CMS a WSAA\r\n const endpoint = getWsaaEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: this.buildSoapRequest(cms),\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaAuthError(\r\n `Error HTTP al comunicarse con WSAA: ${response.status} ${response.statusText}`,\r\n { status: response.status, statusText: response.statusText }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 4. Parsear respuesta\r\n return parseWsaaResponse(responseXml);\r\n }\r\n\r\n /**\r\n * Construye el SOAP request para WSAA\r\n */\r\n private buildSoapRequest(cms: string): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:wsaa=\"http://wsaa.view.sua.dvadac.desein.afip.gov\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <wsaa:loginCms>\r\n <wsaa:in0>${cms}</wsaa:in0>\r\n </wsaa:loginCms>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache (forzar renovación)\r\n */\r\n clearCache(): void {\r\n this.ticketManager.clearTicket();\r\n }\r\n}","import type { ArcaConfig } from './common';\r\nimport type { LoginTicket } from './wsaa';\r\n\r\n/**\r\n * Configuración para WsfeService\r\n */\r\nexport interface WsfeConfig extends ArcaConfig {\r\n /** Ticket de autenticación WSAA */\r\n ticket: LoginTicket;\r\n /** Punto de venta (1-9999) */\r\n pointOfSale: number;\r\n}\r\n\r\n/**\r\n * Tipo de comprobante ARCA\r\n */\r\nexport enum InvoiceType {\r\n FACTURA_A = 1,\r\n FACTURA_B = 6,\r\n FACTURA_C = 11,\r\n TICKET_A = 81,\r\n TICKET_B = 82,\r\n TICKET_C = 83,\r\n}\r\n\r\n/**\r\n * Concepto de facturación\r\n */\r\nexport enum BillingConcept {\r\n PRODUCTS = 1,\r\n SERVICES = 2,\r\n PRODUCTS_AND_SERVICES = 3,\r\n}\r\n\r\n/**\r\n * Tipo de documento del receptor\r\n */\r\nexport enum TaxIdType {\r\n CUIT = 80,\r\n CUIL = 86,\r\n CDI = 87,\r\n LE = 89,\r\n LC = 90,\r\n FOREIGN_ID = 91,\r\n PASSPORT = 94,\r\n BUENOS_AIRES_ID = 95,\r\n /**\r\n * @note AFIP usa el código 96 para ambos. En la práctica, DNI es el más utilizado.\r\n * Fuente: Tabla 13 del catálogo ARCA — ambos valores son 96 en el catálogo oficial.\r\n */\r\n NATIONAL_POLICE_ID = 96,\r\n DNI = 96,\r\n FINAL_CONSUMER = 99,\r\n}\r\n\r\n/**\r\n * Ítem de factura\r\n */\r\nexport interface InvoiceItem {\r\n /** Descripción del producto/servicio */\r\n description: string;\r\n /** Cantidad */\r\n quantity: number;\r\n /** Precio unitario */\r\n unitPrice: number;\r\n /** Alícuota IVA % (0, 10.5, 21, 27) */\r\n vatRate?: number;\r\n}\r\n\r\n/**\r\n * Datos del comprador\r\n */\r\nexport interface Buyer {\r\n /** Tipo de documento */\r\n docType: TaxIdType;\r\n /** Número de documento (sin guiones) */\r\n docNumber: string;\r\n}\r\n\r\n/**\r\n * Request para emitir comprobante\r\n */\r\nexport interface IssueInvoiceRequest {\r\n /** Tipo de comprobante */\r\n type: InvoiceType;\r\n /** Concepto */\r\n concept: BillingConcept;\r\n /** Comprador (opcional para Factura C consumidor final) */\r\n buyer?: Buyer;\r\n /** Items de la factura */\r\n items?: InvoiceItem[];\r\n /** Monto total (requerido si no hay items) */\r\n total?: number;\r\n /** Desglose de IVA (requerido para Factura A/B) */\r\n vatData?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** Indica si los precios unitarios YA incluyen el IVA. Defecto: false */\r\n includesVAT?: boolean;\r\n /** Fecha del comprobante (default: hoy) */\r\n date?: Date;\r\n}\r\n\r\n/**\r\n * Respuesta CAE (Código de Autorización Electrónico)\r\n */\r\nexport interface CAEResponse {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** CAE asignado */\r\n cae: string;\r\n /** Fecha de vencimiento del CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado (A = Aprobado, R = Rechazado) */\r\n result: 'A' | 'R';\r\n /** Observaciones de ARCA */\r\n observations?: string[];\r\n /** Items (se retornan si fueron proveídos en el request) */\r\n items?: InvoiceItem[];\r\n /** Desglose IVA (solo para Factura A/B) */\r\n vat?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** URL del código QR oficial de ARCA */\r\n qrUrl?: string;\r\n}\r\n\r\n/**\r\n * Detalle de un comprobante consultado (FECompConsultar)\r\n */\r\nexport interface InvoiceDetails {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** Concepto */\r\n concept: number;\r\n /** Tipo de documento del receptor */\r\n docType: number;\r\n /** Número de documento del receptor */\r\n docNumber: number;\r\n /** Importe total */\r\n total: number;\r\n /** Importe neto gravado */\r\n net: number;\r\n /** Importe IVA */\r\n vat: number;\r\n /** CAE */\r\n cae: string;\r\n /** Vencimiento CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado */\r\n result: 'A' | 'R';\r\n}\r\n\r\n/**\r\n * Punto de venta habilitado en ARCA\r\n */\r\nexport interface PointOfSale {\r\n /** Número de punto de venta */\r\n number: number;\r\n /** Tipo (CAI, CAE, CAEA, etc.) */\r\n type: string;\r\n /** Indica si está bloqueado */\r\n isBlocked: boolean;\r\n /** Fecha de bloqueo (si aplica) */\r\n blockedSince?: string;\r\n}\r\n\r\n/**\r\n * Estado de los servidores de ARCA\r\n */\r\nexport interface ServiceStatus {\r\n /** Estado del servidor de aplicaciones */\r\n appServer: string;\r\n /** Estado del servidor de base de datos */\r\n dbServer: string;\r\n /** Estado del servidor de autenticación */\r\n authServer: string;\r\n}\r\n","import type { InvoiceItem } from '../types/wsfe';\r\n\r\n/**\r\n * Calcula el subtotal de items (sin IVA)\r\n */\r\nexport function calculateSubtotal(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && item.vatRate) {\r\n netPrice = item.unitPrice / (1 + (item.vatRate / 100));\r\n }\r\n return sum + (item.quantity * netPrice);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el IVA total de items\r\n */\r\nexport function calculateVAT(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n const netSubtotal = item.quantity * netPrice;\r\n return sum + (netSubtotal * rate / 100);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el total de la factura (subtotal + IVA)\r\n */\r\nexport function calculateTotal(items: InvoiceItem[], includesVAT = false): number {\r\n if (includesVAT) {\r\n return items.reduce((sum, item) => sum + (item.quantity * item.unitPrice), 0);\r\n }\r\n const subtotal = calculateSubtotal(items, false);\r\n const vat = calculateVAT(items, false);\r\n return subtotal + vat;\r\n}\r\n\r\n/**\r\n * Redondea a 2 decimales\r\n */\r\nexport function round(value: number): number {\r\n return Math.round(value * 100) / 100;\r\n}\r\n","import type { CAEResponse, Buyer } from '../types/wsfe';\r\nimport { TaxIdType } from '../types/wsfe';\r\n\r\n/**\r\n * Datos requeridos por ARCA para el QR (estructura oficial)\r\n * @see https://www.afip.gob.ar/fe/qr/especificaciones.asp\r\n */\r\ninterface AFIPQRData {\r\n ver: number;\r\n fecha: string;\r\n cuit: number;\r\n ptoVta: number;\r\n tipoCmp: number;\r\n nroCmp: number;\r\n importe: number;\r\n moneda: string;\r\n ctz: number;\r\n tipoDocRec?: number;\r\n nroDocRec?: number;\r\n tipoCodAut: string;\r\n codAut: number;\r\n}\r\n\r\n/**\r\n * Genera la URL completa con el código QR para un comprobante emitido.\r\n * Implementa la versión oficial con orden estricto de campos según spec de ARCA.\r\n *\r\n * @param caeResponse Respuesta obtenida al emitir la factura (CAEResponse)\r\n * @param issuerCUIT CUIT del emisor (con o sin guiones)\r\n * @param total Importe total del comprobante\r\n * @param buyer Datos del comprador (opcional)\r\n * @returns URL lista para embeber en un generador de QR\r\n */\r\nexport function generateQRUrl(\r\n caeResponse: CAEResponse,\r\n issuerCUIT: string,\r\n total: number,\r\n buyer?: Buyer\r\n): string {\r\n // Clean CUIT and CAE (digits only)\r\n const cleanCUIT = issuerCUIT.replace(/\\D/g, '');\r\n const cleanCAE = caeResponse.cae.replace(/\\D/g, '');\r\n\r\n // Format date to YYYY-MM-DD (ARCA returns YYYYMMDD as string or number)\r\n const rawDate = String(caeResponse.date); // Ensure string — fast-xml-parser may return number\r\n const formattedDate = rawDate.length === 8\r\n ? `${rawDate.substring(0, 4)}-${rawDate.substring(4, 6)}-${rawDate.substring(6, 8)}`\r\n : rawDate;\r\n\r\n // Buyer document info\r\n const docType = buyer?.docType || TaxIdType.FINAL_CONSUMER;\r\n const docNumber = buyer?.docNumber ? buyer.docNumber.replace(/\\D/g, '') : '0';\r\n\r\n // Build QR object with STRICT field order (required by ARCA spec)\r\n const qrData: any = {\r\n ver: 1,\r\n fecha: formattedDate,\r\n cuit: Number(cleanCUIT),\r\n ptoVta: Number(caeResponse.pointOfSale),\r\n tipoCmp: Number(caeResponse.invoiceType),\r\n nroCmp: Number(caeResponse.invoiceNumber),\r\n importe: Number(parseFloat(total.toFixed(2))),\r\n moneda: 'PES',\r\n ctz: 1,\r\n };\r\n\r\n // Omit buyer fields for anonymous final consumers\r\n if (docType !== TaxIdType.FINAL_CONSUMER || Number(docNumber) > 0) {\r\n qrData.tipoDocRec = Number(docType);\r\n qrData.nroDocRec = Number(docNumber);\r\n }\r\n\r\n qrData.tipoCodAut = 'E';\r\n qrData.codAut = Number(cleanCAE);\r\n\r\n // IMPORTANT: ARCA's scanner decodes raw base64, NOT URL-encoded base64.\r\n // Using encodeURIComponent here converts + to %2B and = to %3D, which\r\n // breaks ARCA's QR scanner. The raw base64 string must be used as-is.\r\n const jsonString = JSON.stringify(qrData);\r\n const base64 = typeof Buffer !== 'undefined'\r\n ? Buffer.from(jsonString).toString('base64')\r\n : btoa(jsonString);\r\n\r\n return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;\r\n}\r\n","/**\r\n * Diccionario de errores comunes de ARCA/AFIP y sus soluciones.\r\n * Clave: código de error numérico o string retornado por ARCA.\r\n * Valor: sugerencia clara para el desarrollador.\r\n */\r\nexport const ARCA_ERROR_HINTS: Record<string | number, string> = {\r\n // === Autenticación WSAA ===\r\n 501: 'El certificado puede haber expirado o la relación CUIT/Servicio no está habilitada en el portal de ARCA.',\r\n 502: 'El ticket de acceso (TA) es inválido o ya expiró. Hacé wsaa.login() nuevamente.',\r\n 503: 'Error interno del servidor de autenticación de ARCA. Reintentá en unos minutos.',\r\n 1000: 'El CUIT informado no es válido o no corresponde al certificado usado.',\r\n 1001: 'El servicio solicitado no existe o el certificado no tiene autorización para usarlo.',\r\n 1003: 'El TRA (Ticket de Requerimiento de Acceso) tiene un formato inválido.',\r\n 1005: 'El TRA ya expiró antes de ser presentado. Verificá la hora del sistema.',\r\n\r\n // === WSFE — Puntos de venta y configuración ===\r\n 10048: 'El punto de venta no está dado de alta en ARCA. Dalo de alta como Webservice en el portal.',\r\n 10049: 'El punto de venta no está activo o está bloqueado.',\r\n\r\n // === WSFE — Comprobantes y montos ===\r\n 10015: 'Factura B: El importe supera el límite para consumidores finales anónimos. Identificá al comprador con CUIT/DNI.',\r\n 10016: 'El CUIT informado como receptor no es válido o no existe en el Padrón.',\r\n 600: 'No se pudo autorizar el comprobante. Revisá el campo `observations` en la respuesta para más detalle.',\r\n 601: 'El comprobante ya fue autorizado anteriormente. No emitas dos veces el mismo número.',\r\n 602: 'El número de comprobante es inválido o no es el correcto según el último autorizado.',\r\n\r\n // === WSFE — IVA ===\r\n 10043: 'La alícuota de IVA informada no existe o es incorrecta. Usá 3 (0%), 4 (10.5%), 5 (21%) o 6 (27%).',\r\n 10044: 'El importe de IVA no cuadra con la base imponible × alícuota.',\r\n\r\n // === Padrón ===\r\n PADRON_ERROR: 'El servicio de Padrón suele ser inestable en homologación. Reintentá en unos minutos.',\r\n CUIT_NOT_FOUND: 'El CUIT consultado no existe en el Padrón de ARCA.',\r\n};\r\n\r\n/**\r\n * Busca un hint para un código de error dado.\r\n * Retorna undefined si no hay sugerencia conocida para ese código.\r\n */\r\nexport function getArcaHint(code: string | number): string | undefined {\r\n return ARCA_ERROR_HINTS[code];\r\n}\r\n","import { getWsfeEndpoint } from '../constants/endpoints';\r\nimport { ArcaError, ArcaValidationError } from '../types/common';\r\nimport type {\r\n WsfeConfig,\r\n IssueInvoiceRequest,\r\n CAEResponse,\r\n InvoiceItem,\r\n Buyer,\r\n ServiceStatus,\r\n InvoiceDetails,\r\n PointOfSale,\r\n} from '../types/wsfe';\r\nimport {\r\n InvoiceType,\r\n BillingConcept,\r\n TaxIdType,\r\n} from '../types/wsfe';\r\nimport {\r\n calculateSubtotal,\r\n calculateVAT,\r\n calculateTotal,\r\n round,\r\n} from '../utils/calculations';\r\nimport { parseXml } from '../utils/xml';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { generateQRUrl } from '../utils/qr';\r\nimport { getArcaHint } from '../constants/errors';\r\n\r\n/**\r\n * Servicio de Facturación Electrónica WSFE v1\r\n *\r\n * @example\r\n * ```typescript\r\n * const wsfe = new WsfeService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * ticket: await wsaa.login(),\r\n * pointOfSale: 4,\r\n * });\r\n *\r\n * // Ticket C rápido\r\n * const cae = await wsfe.issueSimpleReceipt({ total: 1500 });\r\n * console.log('CAE:', cae.cae);\r\n * console.log('QR:', cae.qrUrl);\r\n *\r\n * // Factura A/B con IVA discriminado\r\n * const cae = await wsfe.issueInvoiceB({\r\n * items: [{ description: 'Servicio', quantity: 1, unitPrice: 1000, vatRate: 21 }],\r\n * buyer: { docType: TaxIdType.CUIT, docNumber: '20987654321' },\r\n * });\r\n * ```\r\n */\r\nexport class WsfeService {\r\n private config: WsfeConfig;\r\n\r\n constructor(config: WsfeConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n }\r\n\r\n private validateConfig(config: WsfeConfig): void {\r\n if (!config.ticket || !config.ticket.token) {\r\n throw new ArcaValidationError(\r\n 'Ticket WSAA requerido. Ejecutá wsaa.login() primero.',\r\n { hint: 'El ticket se obtiene del servicio WsaaService' }\r\n );\r\n }\r\n\r\n if (!config.pointOfSale || config.pointOfSale < 1 || config.pointOfSale > 9999) {\r\n throw new ArcaValidationError(\r\n 'Punto de venta inválido: debe ser un número entre 1 y 9999',\r\n { pointOfSale: config.pointOfSale }\r\n );\r\n }\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Estado de los servidores\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA (FEDummy).\r\n * No requiere autenticación. Útil para health checks.\r\n *\r\n * @param environment Ambiente a consultar (default: 'homologacion')\r\n */\r\n static async checkStatus(environment: 'homologacion' | 'produccion' = 'homologacion'): Promise<ServiceStatus> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEDummy/>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEDummy',\r\n },\r\n body: soapRequest,\r\n timeout: 10000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar estado: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEDummyResponse?.FEDummyResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEDummy inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n return {\r\n appServer: data.AppServer,\r\n dbServer: data.DbServer,\r\n authServer: data.AuthServer,\r\n };\r\n }\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA.\r\n * Versión de instancia — usa el ambiente configurado.\r\n */\r\n async checkStatus(): Promise<ServiceStatus> {\r\n return WsfeService.checkStatus(this.config.environment);\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Emisión de comprobantes\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Emite un Ticket C simple (solo monto total, sin detalle de items).\r\n * Ideal para registros mínimos, como una app móvil de punto de venta.\r\n */\r\n async issueSimpleReceipt(params: {\r\n total: number;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n return this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total: params.total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Emite un Ticket C con detalle de items.\r\n * Los items se guardan en la respuesta pero no se envían a ARCA.\r\n */\r\n async issueReceipt(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n const cae = await this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n\r\n return { ...cae, items: params.items };\r\n }\r\n\r\n /**\r\n * Emite una Factura C (consumidor final, sin discriminación de IVA).\r\n */\r\n async issueInvoiceC(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n items: params.items,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura B (con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceB(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_B,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura A (Responsable Inscripto a Responsable Inscripto, con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceA(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_A,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Consultas\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Consulta un comprobante ya emitido (FECompConsultar).\r\n *\r\n * @param type Tipo de comprobante\r\n * @param invoiceNumber Número de comprobante\r\n */\r\n async getInvoice(type: InvoiceType, invoiceNumber: number): Promise<InvoiceDetails> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompConsultar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCompConsReq>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n <ar:CbteNro>${invoiceNumber}</ar:CbteNro>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n </ar:FeCompConsReq>\r\n </ar:FECompConsultar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompConsultar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompConsultarResponse?.FECompConsultarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FECompConsultar inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const det = data.ResultGet;\r\n return {\r\n invoiceType: Number(det.CbteTipo),\r\n pointOfSale: Number(det.PtoVta),\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: String(det.CbteFch),\r\n concept: Number(det.Concepto),\r\n docType: Number(det.DocTipo),\r\n docNumber: Number(det.DocNro),\r\n total: Number(det.ImpTotal),\r\n net: Number(det.ImpNeto),\r\n vat: Number(det.ImpIVA),\r\n cae: String(det.CodAutorizacion),\r\n caeExpiry: String(det.FchVto),\r\n result: det.Resultado as 'A' | 'R',\r\n };\r\n }\r\n\r\n /**\r\n * Lista los puntos de venta habilitados para el CUIT autenticado (FEParamGetPtosVenta).\r\n */\r\n async getPointsOfSale(): Promise<PointOfSale[]> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEParamGetPtosVenta>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n </ar:FEParamGetPtosVenta>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEParamGetPtosVenta',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar puntos de venta: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEParamGetPtosVentaResponse?.FEParamGetPtosVentaResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEParamGetPtosVenta inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n throw new ArcaError(`Error ARCA: ${error?.Msg || 'Error desconocido'}`, 'ARCA_ERROR', data.Errors);\r\n }\r\n\r\n const raw = data.ResultGet?.PtoVenta;\r\n if (!raw) return [];\r\n\r\n const list = Array.isArray(raw) ? raw : [raw];\r\n return list.map((pv: Record<string, unknown>) => ({\r\n number: Number(pv.Nro),\r\n type: String(pv.EmisionTipo),\r\n isBlocked: pv.Bloqueado === 'S',\r\n blockedSince: pv.FchBaja ? String(pv.FchBaja) : undefined,\r\n }));\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Métodos internos\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Método genérico interno para emitir cualquier tipo de comprobante.\r\n */\r\n private async issueDocument(request: IssueInvoiceRequest): Promise<CAEResponse> {\r\n // 1. Get next invoice number\r\n const invoiceNumber = await this.getNextInvoiceNumber(request.type);\r\n\r\n // 2. Calculate totals\r\n let total = request.total || 0;\r\n let net = total;\r\n let vat = 0;\r\n\r\n if (request.items && request.items.length > 0) {\r\n const includesVAT = request.includesVAT || false;\r\n net = round(calculateSubtotal(request.items, includesVAT));\r\n vat = round(calculateVAT(request.items, includesVAT));\r\n total = round(calculateTotal(request.items, includesVAT));\r\n }\r\n\r\n if (total <= 0) {\r\n throw new ArcaValidationError('El monto total debe ser mayor a 0');\r\n }\r\n\r\n // 3. Build SOAP request\r\n const soapRequest = this.buildCAERequest({\r\n type: request.type,\r\n pointOfSale: this.config.pointOfSale,\r\n invoiceNumber,\r\n concept: request.concept,\r\n date: request.date || new Date(),\r\n buyer: request.buyer,\r\n net,\r\n vat,\r\n total,\r\n vatData: request.vatData,\r\n });\r\n\r\n // 4. Send to ARCA\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECAESolicitar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(\r\n `Error HTTP al comunicarse con WSFE: ${response.status}`,\r\n 'HTTP_ERROR',\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 5. Parse CAE response\r\n const result = await this.parseCAEResponse(responseXml);\r\n\r\n // 6. Generate QR URL\r\n const qrUrl = generateQRUrl(result, this.config.cuit, total, request.buyer);\r\n\r\n return {\r\n ...result,\r\n items: request.items,\r\n vat: request.vatData,\r\n qrUrl,\r\n };\r\n }\r\n\r\n /**\r\n * Obtiene el próximo número de comprobante disponible (FECompUltimoAutorizado + 1)\r\n */\r\n private async getNextInvoiceNumber(type: InvoiceType): Promise<number> {\r\n const soapRequest = this.buildLastInvoiceRequest(type);\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompUltimoAutorizado',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar último comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompUltimoAutorizadoResponse?.FECompUltimoAutorizadoResult;\r\n\r\n if (data?.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const lastNumber = data?.CbteNro;\r\n return typeof lastNumber === 'number' ? lastNumber + 1 : 1;\r\n }\r\n\r\n /**\r\n * Valida que todos los items tengan alícuota IVA definida\r\n */\r\n private validateItemsWithVAT(items: InvoiceItem[]): void {\r\n const missingVAT = items.filter(item =>\r\n item.vatRate === undefined || item.vatRate === null\r\n );\r\n\r\n if (missingVAT.length > 0) {\r\n throw new ArcaValidationError(\r\n 'Esta operación requiere `vatRate` en todos los items',\r\n {\r\n itemsMissingVAT: missingVAT.map(i => i.description),\r\n hint: 'Agregá vatRate a cada item (21, 10.5, 27, o 0)'\r\n }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Calcula el IVA agrupado por alícuota (requerido por ARCA para Factura A/B)\r\n */\r\n private calculateVATByRate(items: InvoiceItem[], includesVAT = false): {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[] {\r\n const byRate = new Map<number, { base: number; amount: number }>();\r\n\r\n items.forEach(item => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n\r\n const base = item.quantity * netPrice;\r\n const amount = base * rate / 100;\r\n\r\n const current = byRate.get(rate) || { base: 0, amount: 0 };\r\n byRate.set(rate, {\r\n base: current.base + base,\r\n amount: current.amount + amount,\r\n });\r\n });\r\n\r\n return Array.from(byRate.entries()).map(([rate, values]) => ({\r\n rate,\r\n taxBase: round(values.base),\r\n amount: round(values.amount),\r\n }));\r\n }\r\n\r\n /**\r\n * Mapea alícuota % al código interno de ARCA\r\n */\r\n private getVATCode(percentage: number): number {\r\n const map: Record<number, number> = {\r\n 0: 3,\r\n 10.5: 4,\r\n 21: 5,\r\n 27: 6,\r\n };\r\n\r\n const code = map[percentage];\r\n if (code === undefined) {\r\n throw new ArcaValidationError(\r\n `Alícuota IVA inválida: ${percentage}%`,\r\n {\r\n validRates: [0, 10.5, 21, 27],\r\n hint: 'Usá una de las alícuotas oficiales de Argentina'\r\n }\r\n );\r\n }\r\n\r\n return code;\r\n }\r\n\r\n private buildCAERequest(params: {\r\n type: InvoiceType;\r\n pointOfSale: number;\r\n invoiceNumber: number;\r\n concept: BillingConcept;\r\n date: Date;\r\n buyer?: IssueInvoiceRequest['buyer'];\r\n net: number;\r\n vat: number;\r\n total: number;\r\n vatData?: IssueInvoiceRequest['vatData'];\r\n }): string {\r\n const dateStr = params.date.toISOString().split('T')[0].replace(/-/g, '');\r\n\r\n let vatXml = '';\r\n if (params.vatData && params.vatData.length > 0) {\r\n vatXml = '<ar:Iva>';\r\n params.vatData.forEach(entry => {\r\n vatXml += `\r\n <ar:AlicIva>\r\n <ar:Id>${this.getVATCode(entry.rate)}</ar:Id>\r\n <ar:BaseImp>${entry.taxBase.toFixed(2)}</ar:BaseImp>\r\n <ar:Importe>${entry.amount.toFixed(2)}</ar:Importe>\r\n </ar:AlicIva>`;\r\n });\r\n vatXml += '\\n </ar:Iva>';\r\n }\r\n\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECAESolicitar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCAEReq>\r\n <ar:FeCabReq>\r\n <ar:CantReg>1</ar:CantReg>\r\n <ar:PtoVta>${params.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${params.type}</ar:CbteTipo>\r\n </ar:FeCabReq>\r\n <ar:FeDetReq>\r\n <ar:FECAEDetRequest>\r\n <ar:Concepto>${params.concept}</ar:Concepto>\r\n <ar:DocTipo>${params.buyer?.docType || 99}</ar:DocTipo>\r\n <ar:DocNro>${params.buyer?.docNumber || 0}</ar:DocNro>\r\n <ar:CbteDesde>${params.invoiceNumber}</ar:CbteDesde>\r\n <ar:CbteHasta>${params.invoiceNumber}</ar:CbteHasta>\r\n <ar:CbteFch>${dateStr}</ar:CbteFch>\r\n <ar:ImpTotal>${params.total.toFixed(2)}</ar:ImpTotal>\r\n <ar:ImpTotConc>0.00</ar:ImpTotConc>\r\n <ar:ImpNeto>${params.net.toFixed(2)}</ar:ImpNeto>\r\n <ar:ImpOpEx>0.00</ar:ImpOpEx>\r\n <ar:ImpIVA>${params.vat.toFixed(2)}</ar:ImpIVA>\r\n <ar:ImpTrib>0.00</ar:ImpTrib>\r\n <ar:MonId>PES</ar:MonId>\r\n <ar:MonCotiz>1</ar:MonCotiz>\r\n ${vatXml}\r\n </ar:FECAEDetRequest>\r\n </ar:FeDetReq>\r\n </ar:FeCAEReq>\r\n </ar:FECAESolicitar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private buildLastInvoiceRequest(type: InvoiceType): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompUltimoAutorizado>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n </ar:FECompUltimoAutorizado>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private async parseCAEResponse(xml: string): Promise<CAEResponse> {\r\n const result = parseXml(xml);\r\n const data = result?.Envelope?.Body?.FECAESolicitarResponse?.FECAESolicitarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta WSFE inválida: estructura no reconocida', 'PARSE_ERROR', { xml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const cab = data.FeCabResp;\r\n const det = Array.isArray(data.FeDetResp.FECAEDetResponse)\r\n ? data.FeDetResp.FECAEDetResponse[0]\r\n : data.FeDetResp.FECAEDetResponse;\r\n\r\n if (!det) {\r\n throw new ArcaError('Respuesta WSFE incompleta: falta detalle del comprobante', 'PARSE_ERROR');\r\n }\r\n\r\n const observations: string[] = [];\r\n if (det.Observaciones) {\r\n const obsArray = Array.isArray(det.Observaciones.Obs)\r\n ? det.Observaciones.Obs\r\n : [det.Observaciones.Obs];\r\n obsArray.forEach((o: { Msg: string }) => observations.push(o.Msg));\r\n }\r\n\r\n return {\r\n invoiceType: Number(cab.CbteTipo),\r\n pointOfSale: Number(cab.PtoVta),\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: String(det.CbteFch),\r\n cae: String(det.CAE),\r\n caeExpiry: String(det.CAEFchVto),\r\n result: det.Resultado,\r\n observations: observations.length > 0 ? observations : undefined,\r\n };\r\n }\r\n}\r\n","import { WsaaService } from '../auth/wsaa';\r\nimport { getPadronEndpoint } from '../constants/endpoints';\r\nimport { ArcaNetworkError, ArcaError } from '../types/common';\r\nimport type {\r\n TaxpayerServiceConfig,\r\n Taxpayer,\r\n TaxpayerResponse,\r\n Address,\r\n Activity,\r\n TaxRecord,\r\n} from '../types/padron';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\n/**\r\n * Servicio para consultar el Padrón de AFIP (ws_sr_padron_a13)\r\n *\r\n * @example\r\n * ```typescript\r\n * const padron = new PadronService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * });\r\n *\r\n * const { taxpayer, error } = await padron.getTaxpayer('30111111118');\r\n * if (taxpayer) {\r\n * console.log(taxpayer.companyName || `${taxpayer.firstName} ${taxpayer.lastName}`);\r\n * console.log('¿Inscripto IVA?:', taxpayer.isVATRegistered);\r\n * }\r\n * ```\r\n */\r\nexport class PadronService {\r\n private wsaa: WsaaService;\r\n private config: TaxpayerServiceConfig;\r\n\r\n constructor(config: TaxpayerServiceConfig) {\r\n this.config = config;\r\n this.wsaa = new WsaaService({\r\n environment: config.environment,\r\n cuit: config.cuit,\r\n cert: config.cert,\r\n key: config.key,\r\n service: 'ws_sr_padron_a13',\r\n storage: config.storage,\r\n });\r\n }\r\n\r\n /**\r\n * Consulta los datos de un contribuyente por CUIT\r\n *\r\n * @param taxId CUIT a consultar (11 dígitos sin guiones)\r\n * @returns Datos del contribuyente o mensaje de error\r\n */\r\n async getTaxpayer(taxId: string): Promise<TaxpayerResponse> {\r\n const ticket = await this.wsaa.login();\r\n\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:a13=\"http://a13.soap.ws.server.puc.sr/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <a13:getPersona>\r\n <token>${ticket.token}</token>\r\n <sign>${ticket.sign}</sign>\r\n <cuitRepresentada>${this.config.cuit}</cuitRepresentada>\r\n <idPersona>${taxId}</idPersona>\r\n </a13:getPersona>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getPadronEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout || 15000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaNetworkError(\r\n `Error HTTP al comunicarse con Padrón A13: ${response.status}`,\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const xml = await response.text();\r\n return this.parseResponse(xml);\r\n }\r\n\r\n /**\r\n * Parsea la respuesta XML de getPersona\r\n */\r\n private parseResponse(xml: string): TaxpayerResponse {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n removeNSPrefix: true,\r\n });\r\n const result = parser.parse(xml);\r\n\r\n const body = result.Envelope?.Body;\r\n if (!body) {\r\n throw new ArcaError('Respuesta del Padrón inválida: Body no encontrado', 'PADRON_ERROR');\r\n }\r\n\r\n const response = body.getPersonaResponse?.personaReturn;\r\n if (!response) {\r\n const fault = body.Fault;\r\n if (fault) {\r\n return { error: fault.faultstring || 'Error desconocido en ARCA' };\r\n }\r\n return { error: 'No se encontraron datos para el CUIT informado' };\r\n }\r\n\r\n if (response.errorConstancia) {\r\n return { error: response.errorConstancia };\r\n }\r\n\r\n const p = response.persona;\r\n if (!p) {\r\n return { error: 'CUIT no encontrado' };\r\n }\r\n\r\n const taxpayer: Taxpayer = {\r\n taxId: Number(p.idPersona),\r\n personType: p.tipoPersona as 'FISICA' | 'JURIDICA',\r\n firstName: p.nombre,\r\n lastName: p.apellido,\r\n companyName: p.razonSocial,\r\n status: p.estadoClave,\r\n addresses: this.mapAddresses(p.domicilio),\r\n activities: this.mapActivities(p.actividad),\r\n taxes: this.mapTaxRecords(p.impuesto),\r\n mainActivity: p.descripcionActividadPrincipal,\r\n isVATRegistered: this.hasTaxId(p, 30), // 30 = IVA\r\n isMonotax: this.hasTaxId(p, 20), // 20 = Monotributo\r\n isVATExempt: this.hasTaxId(p, 32), // 32 = IVA Exento\r\n };\r\n\r\n return { taxpayer };\r\n }\r\n\r\n private mapAddresses(raw: unknown): Address[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n street: item.direccion as string,\r\n city: item.localidad as string | undefined,\r\n postalCode: item.codPostal as string | undefined,\r\n provinceId: Number(item.idProvincia),\r\n province: item.descripcionProvincia as string,\r\n type: item.tipoDomicilio as string,\r\n }));\r\n }\r\n\r\n private mapActivities(raw: unknown): Activity[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idActividad),\r\n description: item.descripcion as string,\r\n order: Number(item.orden),\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private mapTaxRecords(raw: unknown): TaxRecord[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idImpuesto),\r\n description: item.descripcion as string,\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private hasTaxId(p: Record<string, unknown>, id: number): boolean {\r\n const taxes = p.impuesto;\r\n if (!taxes) return false;\r\n return this.toArray(taxes).some((i: Record<string, unknown>) => Number(i.idImpuesto) === id);\r\n }\r\n\r\n /**\r\n * Normaliza un valor que puede ser un objeto único o un array (comportamiento de fast-xml-parser)\r\n */\r\n private toArray(data: unknown): Record<string, unknown>[] {\r\n if (data === undefined || data === null) return [];\r\n if (Array.isArray(data)) return data as Record<string, unknown>[];\r\n return [data as Record<string, unknown>];\r\n }\r\n}\r\n"],"mappings":"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","names":["https","InvoiceType","BillingConcept","TaxIdType","import_fast_xml_parser"]}
|
package/dist/index.js
CHANGED
|
@@ -509,7 +509,7 @@ function round(value) {
|
|
|
509
509
|
function generateQRUrl(caeResponse, issuerCUIT, total, buyer) {
|
|
510
510
|
const cleanCUIT = issuerCUIT.replace(/\D/g, "");
|
|
511
511
|
const cleanCAE = caeResponse.cae.replace(/\D/g, "");
|
|
512
|
-
const rawDate = caeResponse.date;
|
|
512
|
+
const rawDate = String(caeResponse.date);
|
|
513
513
|
const formattedDate = rawDate.length === 8 ? `${rawDate.substring(0, 4)}-${rawDate.substring(4, 6)}-${rawDate.substring(6, 8)}` : rawDate;
|
|
514
514
|
const docType = buyer?.docType || 99 /* FINAL_CONSUMER */;
|
|
515
515
|
const docNumber = buyer?.docNumber ? buyer.docNumber.replace(/\D/g, "") : "0";
|
|
@@ -532,7 +532,7 @@ function generateQRUrl(caeResponse, issuerCUIT, total, buyer) {
|
|
|
532
532
|
qrData.codAut = Number(cleanCAE);
|
|
533
533
|
const jsonString = JSON.stringify(qrData);
|
|
534
534
|
const base64 = typeof Buffer !== "undefined" ? Buffer.from(jsonString).toString("base64") : btoa(jsonString);
|
|
535
|
-
return `https://www.afip.gob.ar/fe/qr/?p=${
|
|
535
|
+
return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;
|
|
536
536
|
}
|
|
537
537
|
|
|
538
538
|
// src/constants/errors.ts
|
|
@@ -1110,10 +1110,10 @@ var WsfeService = class _WsfeService {
|
|
|
1110
1110
|
obsArray.forEach((o) => observations.push(o.Msg));
|
|
1111
1111
|
}
|
|
1112
1112
|
return {
|
|
1113
|
-
invoiceType: cab.CbteTipo,
|
|
1114
|
-
pointOfSale: cab.PtoVta,
|
|
1113
|
+
invoiceType: Number(cab.CbteTipo),
|
|
1114
|
+
pointOfSale: Number(cab.PtoVta),
|
|
1115
1115
|
invoiceNumber: Number(det.CbteDesde),
|
|
1116
|
-
date: det.CbteFch,
|
|
1116
|
+
date: String(det.CbteFch),
|
|
1117
1117
|
cae: String(det.CAE),
|
|
1118
1118
|
caeExpiry: String(det.CAEFchVto),
|
|
1119
1119
|
result: det.Resultado,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants/endpoints.ts","../src/types/common.ts","../src/utils/xml.ts","../src/utils/crypto.ts","../src/auth/ticket.ts","../src/utils/network.ts","../src/auth/wsaa.ts","../src/types/wsfe.ts","../src/utils/calculations.ts","../src/utils/qr.ts","../src/constants/errors.ts","../src/services/wsfe.ts","../src/services/padron.ts"],"sourcesContent":["import type { Environment } from '../types/common';\r\n\r\n/**\r\n * URLs de los servicios ARCA por ambiente\r\n */\r\nexport const WSAA_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms',\r\n produccion: 'https://wsaa.afip.gov.ar/ws/services/LoginCms',\r\n};\r\n\r\n/**\r\n * URLs del servicio WSFE por ambiente\r\n */\r\nexport const WSFE_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx',\r\n produccion: 'https://servicios1.afip.gov.ar/wsfev1/service.asmx',\r\n};\r\n\r\n/**\r\n * URLs del servicio Padron A13 por ambiente\r\n */\r\nexport const PADRON_A13_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n produccion: 'https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n};\r\n\r\n/**\r\n * Obtener endpoint WSAA según ambiente\r\n */\r\nexport function getWsaaEndpoint(environment: Environment): string {\r\n return WSAA_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint WSFE según ambiente\r\n */\r\nexport function getWsfeEndpoint(environment: Environment): string {\r\n return WSFE_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint Padron A13 según ambiente\r\n */\r\nexport function getPadronEndpoint(environment: Environment): string {\r\n return PADRON_A13_ENDPOINTS[environment];\r\n}\r\n","/**\r\n * Tipos comunes compartidos en toda la SDK\r\n */\r\n\r\n/**\r\n * Ambiente de ejecución ARCA\r\n */\r\nexport type Environment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Configuración base para servicios ARCA\r\n */\r\nexport interface ArcaConfig {\r\n /** Ambiente (homologación o producción) */\r\n environment: Environment;\r\n /** CUIT del contribuyente (11 dígitos sin guiones) */\r\n cuit: string;\r\n /** Tiempo de espera para peticiones (ms). Defecto: 15000 */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Error personalizado de ARCA SDK\r\n */\r\nexport class ArcaError extends Error {\r\n constructor(\r\n message: string,\r\n public code: string,\r\n public details?: unknown,\r\n public hint?: string\r\n ) {\r\n super(message);\r\n this.name = 'ArcaError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de autenticación WSAA\r\n */\r\nexport class ArcaAuthError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'AUTH_ERROR', details);\r\n this.name = 'ArcaAuthError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de validación de input\r\n */\r\nexport class ArcaValidationError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'VALIDATION_ERROR', details);\r\n this.name = 'ArcaValidationError';\r\n }\r\n}\r\n/**\r\n * Error de comunicación/red\r\n */\r\nexport class ArcaNetworkError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'NETWORK_ERROR', details);\r\n this.name = 'ArcaNetworkError';\r\n }\r\n}\r\n","import { XMLBuilder, XMLParser } from 'fast-xml-parser';\r\nimport { ArcaAuthError } from '../types/common';\r\nimport type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Genera el XML TRA (Ticket de Requerimiento de Acceso)\r\n * \r\n * @param service - Servicio ARCA (ej: 'wsfe')\r\n * @param cuit - CUIT del contribuyente\r\n * @returns XML del TRA\r\n */\r\nexport function buildTRA(service: string, cuit: string): string {\r\n const now = new Date();\r\n const expirationTime = new Date(now.getTime() + 12 * 60 * 60 * 1000); // +12 horas\r\n\r\n const tra = {\r\n loginTicketRequest: {\r\n '@_version': '1.0',\r\n header: {\r\n uniqueId: Math.floor(now.getTime() / 1000),\r\n generationTime: now.toISOString(),\r\n expirationTime: expirationTime.toISOString(),\r\n },\r\n service,\r\n },\r\n };\r\n\r\n const builder = new XMLBuilder({\r\n ignoreAttributes: false,\r\n format: true,\r\n });\r\n\r\n const xml = builder.build(tra);\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${xml}`;\r\n}\r\n\r\n/**\r\n * Parsea la respuesta XML de WSAA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Ticket de login\r\n */\r\nexport function parseWsaaResponse(xml: string): LoginTicket {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n\r\n try {\r\n const envelope = parser.parse(xml);\r\n\r\n // El loginCmsReturn contiene el ticket real como un XML escapado (string)\r\n const loginCmsReturn = envelope?.Envelope?.Body?.loginCmsResponse?.loginCmsReturn;\r\n\r\n if (!loginCmsReturn) {\r\n const fault = envelope?.Envelope?.Body?.Fault;\r\n if (fault) {\r\n throw new ArcaAuthError(\r\n `Error ARCA: ${fault.faultstring || 'Error desconocido'}`,\r\n { faultCode: fault.faultcode, detail: fault.detail }\r\n );\r\n }\r\n\r\n throw new ArcaAuthError(\r\n 'Respuesta WSAA inválida: estructura no reconocida',\r\n {\r\n receivedXml: xml.substring(0, 5000),\r\n receivedStructure: JSON.stringify(envelope).substring(0, 500)\r\n }\r\n );\r\n }\r\n\r\n // Segundo nivel de parseo: El XML interno escapado que viene dentro de loginCmsReturn\r\n const ticketResult = parser.parse(loginCmsReturn);\r\n const ticket = ticketResult?.loginTicketResponse;\r\n\r\n if (!ticket || !ticket.header || !ticket.credentials) {\r\n throw new ArcaAuthError('Ticket WSAA inválido o malformado dentro de loginCmsReturn', {\r\n innerStructure: JSON.stringify(ticketResult).substring(0, 500),\r\n receivedXml: xml.substring(0, 5000)\r\n });\r\n }\r\n\r\n return {\r\n token: ticket.credentials.token,\r\n sign: ticket.credentials.sign,\r\n generationTime: new Date(ticket.header.generationTime),\r\n expirationTime: new Date(ticket.header.expirationTime),\r\n };\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al parsear respuesta WSAA (posible XML anidado malformado)',\r\n {\r\n originalError: error instanceof Error ? error.message : String(error),\r\n receivedXml: xml.substring(0, 5000)\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Parsea un XML genérico de ARCA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Objeto parseado\r\n */\r\nexport function parseXml(xml: string): any {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n return parser.parse(xml);\r\n}\r\n\r\n/**\r\n * Valida CUIT (11 dígitos sin guiones)\r\n */\r\nexport function validateCUIT(cuit: string): boolean {\r\n return /^\\d{11}$/.test(cuit);\r\n}\r\n","import * as forge from 'node-forge';\r\nimport { ArcaAuthError } from '../types/common';\r\n\r\n/**\r\n * Firma un XML en formato CMS (PKCS#7) usando certificado y clave privada\r\n * \r\n * @param xml - Contenido XML a firmar (TRA)\r\n * @param certPem - Certificado en formato PEM\r\n * @param keyPem - Clave privada en formato PEM\r\n * @returns CMS firmado en base64\r\n */\r\nexport function signCMS(xml: string, certPem: string, keyPem: string): string {\r\n try {\r\n // 1. Parsear certificado\r\n const cert = forge.pki.certificateFromPem(certPem);\r\n\r\n // 2. Parsear clave privada\r\n const privateKey = forge.pki.privateKeyFromPem(keyPem);\r\n\r\n // 3. Crear contenedor PKCS#7\r\n const p7 = forge.pkcs7.createSignedData();\r\n\r\n // 4. Agregar contenido a firmar\r\n p7.content = forge.util.createBuffer(xml, 'utf8');\r\n\r\n // 5. Agregar certificado\r\n p7.addCertificate(cert);\r\n\r\n // 6. Firmar con SHA256\r\n p7.addSigner({\r\n key: privateKey,\r\n certificate: cert,\r\n digestAlgorithm: forge.pki.oids.sha256,\r\n authenticatedAttributes: [\r\n {\r\n type: forge.pki.oids.contentType,\r\n value: forge.pki.oids.data,\r\n },\r\n {\r\n type: forge.pki.oids.messageDigest,\r\n // El valor será calculado automáticamente\r\n },\r\n {\r\n type: forge.pki.oids.signingTime,\r\n // node-forge expects a Date object, but its typings might be missing or expect string/any\r\n value: new Date() as any,\r\n },\r\n ],\r\n });\r\n\r\n // 7. Firmar\r\n p7.sign();\r\n\r\n // 8. Convertir a DER y luego a base64\r\n const derBytes = forge.asn1.toDer(p7.toAsn1()).getBytes();\r\n const base64 = forge.util.encode64(derBytes);\r\n\r\n return base64;\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al firmar XML con certificado usando PKCS#7',\r\n {\r\n originalError: error,\r\n hint: 'Verificar que el certificado y la clave privada sean válidos y correspondan entre sí'\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Valida formato de certificado PEM\r\n */\r\nexport function validateCertificate(cert: string): boolean {\r\n return cert.includes('-----BEGIN CERTIFICATE-----') &&\r\n cert.includes('-----END CERTIFICATE-----');\r\n}\r\n\r\n/**\r\n * Valida formato de clave privada PEM\r\n */\r\nexport function validatePrivateKey(key: string): boolean {\r\n return (\r\n (key.includes('-----BEGIN PRIVATE KEY-----') &&\r\n key.includes('-----END PRIVATE KEY-----')) ||\r\n (key.includes('-----BEGIN RSA PRIVATE KEY-----') &&\r\n key.includes('-----END RSA PRIVATE KEY-----'))\r\n );\r\n}\r\n","import type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Gestor de tickets de autenticación\r\n * Maneja cache en memoria del ticket WSAA\r\n */\r\nexport class TicketManager {\r\n private ticket: LoginTicket | null = null;\r\n\r\n /**\r\n * Guarda un ticket en cache\r\n */\r\n setTicket(ticket: LoginTicket): void {\r\n this.ticket = ticket;\r\n }\r\n\r\n /**\r\n * Obtiene el ticket actual si es válido\r\n * @returns Ticket válido o null si expiró\r\n */\r\n getTicket(): LoginTicket | null {\r\n if (!this.ticket) return null;\r\n\r\n const now = new Date();\r\n const expiresIn = this.ticket.expirationTime.getTime() - now.getTime();\r\n\r\n // Si expira en menos de 5 minutos, considerarlo inválido\r\n const BUFFER_MS = 5 * 60 * 1000;\r\n\r\n if (expiresIn < BUFFER_MS) {\r\n this.ticket = null;\r\n return null;\r\n }\r\n\r\n return this.ticket;\r\n }\r\n\r\n /**\r\n * Verifica si hay un ticket válido\r\n */\r\n hasValidTicket(): boolean {\r\n return this.getTicket() !== null;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache\r\n */\r\n clearTicket(): void {\r\n this.ticket = null;\r\n }\r\n}\r\n","import https from 'https';\r\nimport { ArcaNetworkError } from '../types/common';\r\n\r\n/**\r\n * Entornos compatibles\r\n */\r\nexport type ArcaEnvironment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Opciones para la llamada API\r\n */\r\nexport interface CallApiOptions {\r\n method: string;\r\n headers: Record<string, string>;\r\n body: string;\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Realiza una llamada a la API de ARCA (WSAA o WSFE)\r\n * Maneja la compatibilidad SSL con los servidores de AFIP (DH key size)\r\n * y añade robustez (timeouts, mejores errores).\r\n */\r\nexport async function callArcaApi(\r\n url: string,\r\n options: CallApiOptions\r\n): Promise<Response> {\r\n const timeout = options.timeout || 15000;\r\n const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\r\n\r\n if (isNode) {\r\n return new Promise((resolve, reject) => {\r\n const parsedUrl = new URL(url);\r\n\r\n const agent = new https.Agent({\r\n // SECLEVEL=0 es el nivel más permisivo de OpenSSL.\r\n // !DH desactiva Diffie-Hellman para forzar RSA o ECDHE si están disponibles,\r\n // evitando el problema de \"dh key too small\" de raíz.\r\n ciphers: 'DEFAULT:!DH@SECLEVEL=0',\r\n // AFIP todavía tiene endpoints que podrían requerir TLS 1.0/1.1\r\n minVersion: 'TLSv1',\r\n // @ts-ignore - Propiedad específica para mitigar \"dh key too small\" en Node 18+\r\n minDHSize: 1024,\r\n rejectUnauthorized: true,\r\n });\r\n\r\n const reqOptions: https.RequestOptions = {\r\n method: options.method,\r\n hostname: parsedUrl.hostname,\r\n path: parsedUrl.pathname + parsedUrl.search,\r\n headers: options.headers,\r\n agent,\r\n timeout,\r\n };\r\n\r\n const req = https.request(reqOptions, (res) => {\r\n res.setEncoding('utf8');\r\n let data = '';\r\n res.on('data', (chunk) => { data += chunk; });\r\n res.on('end', () => {\r\n // Simular objeto Response de fetch\r\n const response = {\r\n ok: (res.statusCode || 0) >= 200 && (res.statusCode || 0) < 300,\r\n status: res.statusCode || 0,\r\n statusText: res.statusMessage || '',\r\n text: async () => data,\r\n json: async () => JSON.parse(data),\r\n };\r\n resolve(response as Response);\r\n });\r\n });\r\n\r\n req.on('error', (error: any) => {\r\n let message = error.message;\r\n if (message.includes('dh key too small')) {\r\n message = 'Error SSL de ARCA (DH Key too small). Verifique su versión de OpenSSL/Node.';\r\n }\r\n reject(new ArcaNetworkError(`Error de red al comunicarse con ARCA (HTTPS): ${message}`, {\r\n url,\r\n originalError: error\r\n }));\r\n });\r\n\r\n req.on('timeout', () => {\r\n req.destroy();\r\n reject(new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`));\r\n });\r\n\r\n req.write(options.body);\r\n req.end();\r\n });\r\n }\r\n\r\n // Navegador o entorno no-Node (utiliza fetch nativo)\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: options.method,\r\n headers: options.headers,\r\n body: options.body,\r\n signal: controller.signal\r\n });\r\n return response;\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n throw new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`);\r\n }\r\n throw new ArcaNetworkError(`Error de red: ${error.message}`, { url, originalError: error });\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n}\r\n","import { getWsaaEndpoint } from '../constants/endpoints';\r\nimport { ArcaAuthError, ArcaValidationError } from '../types/common';\r\nimport type { WsaaConfig, LoginTicket } from '../types/wsaa';\r\nimport { buildTRA, parseWsaaResponse, validateCUIT } from '../utils/xml';\r\nimport { validateCertificate, validatePrivateKey, signCMS } from '../utils/crypto';\r\nimport { TicketManager } from './ticket';\r\nimport { callArcaApi } from '../utils/network';\r\n\r\n/**\r\n * Servicio de autenticación WSAA (Web Service de Autenticación y Autorización)\r\n * \r\n * @example\r\n * ```typescript\r\n * const wsaa = new WsaaService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * service: 'wsfe',\r\n * });\r\n * \r\n * const ticket = await wsaa.login();\r\n * console.log('Token:', ticket.token);\r\n * ```\r\n */\r\nexport class WsaaService {\r\n private config: WsaaConfig;\r\n private ticketManager: TicketManager;\r\n\r\n constructor(config: WsaaConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n this.ticketManager = new TicketManager();\r\n }\r\n\r\n /**\r\n * Valida la configuración\r\n */\r\n private validateConfig(config: WsaaConfig): void {\r\n if (!validateCUIT(config.cuit)) {\r\n throw new ArcaValidationError(\r\n 'CUIT inválido: debe tener 11 dígitos sin guiones',\r\n { cuit: config.cuit }\r\n );\r\n }\r\n\r\n if (!validateCertificate(config.cert)) {\r\n throw new ArcaValidationError(\r\n 'Certificado inválido: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN CERTIFICATE-----' }\r\n );\r\n }\r\n\r\n if (!validatePrivateKey(config.key)) {\r\n throw new ArcaValidationError(\r\n 'Clave privada inválida: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN PRIVATE KEY----- o -----BEGIN RSA PRIVATE KEY-----' }\r\n );\r\n }\r\n\r\n if (!config.service || config.service.trim() === '') {\r\n throw new ArcaValidationError(\r\n 'Servicio ARCA no especificado',\r\n { hint: 'Ejemplos: \"wsfe\", \"wsmtxca\"' }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Obtiene un ticket de acceso válido.\r\n * \r\n * Prioridad de búsqueda:\r\n * 1. Memoria (TicketManager cache)\r\n * 2. Persistencia (si config.storage está definido)\r\n * 3. Nueva solicitud a WSAA\r\n * \r\n * @returns Ticket de acceso\r\n */\r\n async login(): Promise<LoginTicket> {\r\n // 1. Intentar usar ticket en memoria (muy rápido)\r\n const cachedTicket = this.ticketManager.getTicket();\r\n if (cachedTicket) {\r\n return cachedTicket;\r\n }\r\n\r\n // 2. Intentar usar persistencia externa si está disponible\r\n if (this.config.storage) {\r\n try {\r\n const storedTicket = await this.config.storage.get(this.config.cuit, this.config.environment);\r\n if (storedTicket) {\r\n // Validar si el ticket devuelto por el storage no está expirado\r\n // Agrego un margen de 5 minutos\r\n const now = new Date();\r\n if (new Date(storedTicket.expirationTime) > new Date(now.getTime() + 5 * 60000)) {\r\n this.ticketManager.setTicket(storedTicket);\r\n return storedTicket;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.get falló, intentando login directo:', error);\r\n }\r\n }\r\n\r\n // 3. Generar nuevo ticket (llamada a AFIP)\r\n const ticket = await this.requestNewTicket();\r\n\r\n // Guardar en memoria\r\n this.ticketManager.setTicket(ticket);\r\n\r\n // Guardar en persistencia externa\r\n if (this.config.storage) {\r\n try {\r\n await this.config.storage.save(this.config.cuit, this.config.environment, ticket);\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.save falló:', error);\r\n }\r\n }\r\n\r\n return ticket;\r\n }\r\n\r\n /**\r\n * Solicita un nuevo ticket a WSAA\r\n */\r\n private async requestNewTicket(): Promise<LoginTicket> {\r\n // 1. Generar TRA (Ticket de Requerimiento de Acceso)\r\n const tra = buildTRA(this.config.service, this.config.cuit);\r\n\r\n // 2. Firmar TRA con certificado (genera CMS)\r\n let cms: string;\r\n try {\r\n cms = signCMS(tra, this.config.cert, this.config.key);\r\n } catch (error) {\r\n throw new ArcaAuthError(\r\n 'Error al firmar TRA con certificado',\r\n { originalError: error }\r\n );\r\n }\r\n\r\n // 3. Enviar CMS a WSAA\r\n const endpoint = getWsaaEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: this.buildSoapRequest(cms),\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaAuthError(\r\n `Error HTTP al comunicarse con WSAA: ${response.status} ${response.statusText}`,\r\n { status: response.status, statusText: response.statusText }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 4. Parsear respuesta\r\n return parseWsaaResponse(responseXml);\r\n }\r\n\r\n /**\r\n * Construye el SOAP request para WSAA\r\n */\r\n private buildSoapRequest(cms: string): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:wsaa=\"http://wsaa.view.sua.dvadac.desein.afip.gov\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <wsaa:loginCms>\r\n <wsaa:in0>${cms}</wsaa:in0>\r\n </wsaa:loginCms>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache (forzar renovación)\r\n */\r\n clearCache(): void {\r\n this.ticketManager.clearTicket();\r\n }\r\n}","import type { ArcaConfig } from './common';\r\nimport type { LoginTicket } from './wsaa';\r\n\r\n/**\r\n * Configuración para WsfeService\r\n */\r\nexport interface WsfeConfig extends ArcaConfig {\r\n /** Ticket de autenticación WSAA */\r\n ticket: LoginTicket;\r\n /** Punto de venta (1-9999) */\r\n pointOfSale: number;\r\n}\r\n\r\n/**\r\n * Tipo de comprobante ARCA\r\n */\r\nexport enum InvoiceType {\r\n FACTURA_A = 1,\r\n FACTURA_B = 6,\r\n FACTURA_C = 11,\r\n TICKET_A = 81,\r\n TICKET_B = 82,\r\n TICKET_C = 83,\r\n}\r\n\r\n/**\r\n * Concepto de facturación\r\n */\r\nexport enum BillingConcept {\r\n PRODUCTS = 1,\r\n SERVICES = 2,\r\n PRODUCTS_AND_SERVICES = 3,\r\n}\r\n\r\n/**\r\n * Tipo de documento del receptor\r\n */\r\nexport enum TaxIdType {\r\n CUIT = 80,\r\n CUIL = 86,\r\n CDI = 87,\r\n LE = 89,\r\n LC = 90,\r\n FOREIGN_ID = 91,\r\n PASSPORT = 94,\r\n BUENOS_AIRES_ID = 95,\r\n /**\r\n * @note AFIP usa el código 96 para ambos. En la práctica, DNI es el más utilizado.\r\n * Fuente: Tabla 13 del catálogo ARCA — ambos valores son 96 en el catálogo oficial.\r\n */\r\n NATIONAL_POLICE_ID = 96,\r\n DNI = 96,\r\n FINAL_CONSUMER = 99,\r\n}\r\n\r\n/**\r\n * Ítem de factura\r\n */\r\nexport interface InvoiceItem {\r\n /** Descripción del producto/servicio */\r\n description: string;\r\n /** Cantidad */\r\n quantity: number;\r\n /** Precio unitario */\r\n unitPrice: number;\r\n /** Alícuota IVA % (0, 10.5, 21, 27) */\r\n vatRate?: number;\r\n}\r\n\r\n/**\r\n * Datos del comprador\r\n */\r\nexport interface Buyer {\r\n /** Tipo de documento */\r\n docType: TaxIdType;\r\n /** Número de documento (sin guiones) */\r\n docNumber: string;\r\n}\r\n\r\n/**\r\n * Request para emitir comprobante\r\n */\r\nexport interface IssueInvoiceRequest {\r\n /** Tipo de comprobante */\r\n type: InvoiceType;\r\n /** Concepto */\r\n concept: BillingConcept;\r\n /** Comprador (opcional para Factura C consumidor final) */\r\n buyer?: Buyer;\r\n /** Items de la factura */\r\n items?: InvoiceItem[];\r\n /** Monto total (requerido si no hay items) */\r\n total?: number;\r\n /** Desglose de IVA (requerido para Factura A/B) */\r\n vatData?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** Indica si los precios unitarios YA incluyen el IVA. Defecto: false */\r\n includesVAT?: boolean;\r\n /** Fecha del comprobante (default: hoy) */\r\n date?: Date;\r\n}\r\n\r\n/**\r\n * Respuesta CAE (Código de Autorización Electrónico)\r\n */\r\nexport interface CAEResponse {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** CAE asignado */\r\n cae: string;\r\n /** Fecha de vencimiento del CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado (A = Aprobado, R = Rechazado) */\r\n result: 'A' | 'R';\r\n /** Observaciones de ARCA */\r\n observations?: string[];\r\n /** Items (se retornan si fueron proveídos en el request) */\r\n items?: InvoiceItem[];\r\n /** Desglose IVA (solo para Factura A/B) */\r\n vat?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** URL del código QR oficial de ARCA */\r\n qrUrl?: string;\r\n}\r\n\r\n/**\r\n * Detalle de un comprobante consultado (FECompConsultar)\r\n */\r\nexport interface InvoiceDetails {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** Concepto */\r\n concept: number;\r\n /** Tipo de documento del receptor */\r\n docType: number;\r\n /** Número de documento del receptor */\r\n docNumber: number;\r\n /** Importe total */\r\n total: number;\r\n /** Importe neto gravado */\r\n net: number;\r\n /** Importe IVA */\r\n vat: number;\r\n /** CAE */\r\n cae: string;\r\n /** Vencimiento CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado */\r\n result: 'A' | 'R';\r\n}\r\n\r\n/**\r\n * Punto de venta habilitado en ARCA\r\n */\r\nexport interface PointOfSale {\r\n /** Número de punto de venta */\r\n number: number;\r\n /** Tipo (CAI, CAE, CAEA, etc.) */\r\n type: string;\r\n /** Indica si está bloqueado */\r\n isBlocked: boolean;\r\n /** Fecha de bloqueo (si aplica) */\r\n blockedSince?: string;\r\n}\r\n\r\n/**\r\n * Estado de los servidores de ARCA\r\n */\r\nexport interface ServiceStatus {\r\n /** Estado del servidor de aplicaciones */\r\n appServer: string;\r\n /** Estado del servidor de base de datos */\r\n dbServer: string;\r\n /** Estado del servidor de autenticación */\r\n authServer: string;\r\n}\r\n","import type { InvoiceItem } from '../types/wsfe';\r\n\r\n/**\r\n * Calcula el subtotal de items (sin IVA)\r\n */\r\nexport function calculateSubtotal(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && item.vatRate) {\r\n netPrice = item.unitPrice / (1 + (item.vatRate / 100));\r\n }\r\n return sum + (item.quantity * netPrice);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el IVA total de items\r\n */\r\nexport function calculateVAT(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n const netSubtotal = item.quantity * netPrice;\r\n return sum + (netSubtotal * rate / 100);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el total de la factura (subtotal + IVA)\r\n */\r\nexport function calculateTotal(items: InvoiceItem[], includesVAT = false): number {\r\n if (includesVAT) {\r\n return items.reduce((sum, item) => sum + (item.quantity * item.unitPrice), 0);\r\n }\r\n const subtotal = calculateSubtotal(items, false);\r\n const vat = calculateVAT(items, false);\r\n return subtotal + vat;\r\n}\r\n\r\n/**\r\n * Redondea a 2 decimales\r\n */\r\nexport function round(value: number): number {\r\n return Math.round(value * 100) / 100;\r\n}\r\n","import type { CAEResponse, Buyer } from '../types/wsfe';\r\nimport { TaxIdType } from '../types/wsfe';\r\n\r\n/**\r\n * Datos requeridos por ARCA para el QR (estructura oficial)\r\n * @see https://www.afip.gob.ar/fe/qr/especificaciones.asp\r\n */\r\ninterface AFIPQRData {\r\n ver: number;\r\n fecha: string;\r\n cuit: number;\r\n ptoVta: number;\r\n tipoCmp: number;\r\n nroCmp: number;\r\n importe: number;\r\n moneda: string;\r\n ctz: number;\r\n tipoDocRec?: number;\r\n nroDocRec?: number;\r\n tipoCodAut: string;\r\n codAut: number;\r\n}\r\n\r\n/**\r\n * Genera la URL completa con el código QR para un comprobante emitido.\r\n * Implementa la versión oficial con orden estricto de campos según spec de ARCA.\r\n *\r\n * @param caeResponse Respuesta obtenida al emitir la factura (CAEResponse)\r\n * @param issuerCUIT CUIT del emisor (con o sin guiones)\r\n * @param total Importe total del comprobante\r\n * @param buyer Datos del comprador (opcional)\r\n * @returns URL lista para embeber en un generador de QR\r\n */\r\nexport function generateQRUrl(\r\n caeResponse: CAEResponse,\r\n issuerCUIT: string,\r\n total: number,\r\n buyer?: Buyer\r\n): string {\r\n // Clean CUIT and CAE (digits only)\r\n const cleanCUIT = issuerCUIT.replace(/\\D/g, '');\r\n const cleanCAE = caeResponse.cae.replace(/\\D/g, '');\r\n\r\n // Format date to YYYY-MM-DD (ARCA returns YYYYMMDD)\r\n const rawDate = caeResponse.date;\r\n const formattedDate = rawDate.length === 8\r\n ? `${rawDate.substring(0, 4)}-${rawDate.substring(4, 6)}-${rawDate.substring(6, 8)}`\r\n : rawDate;\r\n\r\n // Buyer document info\r\n const docType = buyer?.docType || TaxIdType.FINAL_CONSUMER;\r\n const docNumber = buyer?.docNumber ? buyer.docNumber.replace(/\\D/g, '') : '0';\r\n\r\n // Build QR object with STRICT field order (required by ARCA spec)\r\n const qrData: any = {\r\n ver: 1,\r\n fecha: formattedDate,\r\n cuit: Number(cleanCUIT),\r\n ptoVta: Number(caeResponse.pointOfSale),\r\n tipoCmp: Number(caeResponse.invoiceType),\r\n nroCmp: Number(caeResponse.invoiceNumber),\r\n importe: Number(parseFloat(total.toFixed(2))),\r\n moneda: 'PES',\r\n ctz: 1,\r\n };\r\n\r\n // Omit buyer fields for anonymous final consumers\r\n if (docType !== TaxIdType.FINAL_CONSUMER || Number(docNumber) > 0) {\r\n qrData.tipoDocRec = Number(docType);\r\n qrData.nroDocRec = Number(docNumber);\r\n }\r\n\r\n qrData.tipoCodAut = 'E';\r\n qrData.codAut = Number(cleanCAE);\r\n\r\n // Encode to Base64 (Buffer for Node.js, btoa fallback for browsers)\r\n const jsonString = JSON.stringify(qrData);\r\n const base64 = typeof Buffer !== 'undefined'\r\n ? Buffer.from(jsonString).toString('base64')\r\n : btoa(jsonString);\r\n\r\n return `https://www.afip.gob.ar/fe/qr/?p=${encodeURIComponent(base64)}`;\r\n}\r\n","/**\r\n * Diccionario de errores comunes de ARCA/AFIP y sus soluciones.\r\n * Clave: código de error numérico o string retornado por ARCA.\r\n * Valor: sugerencia clara para el desarrollador.\r\n */\r\nexport const ARCA_ERROR_HINTS: Record<string | number, string> = {\r\n // === Autenticación WSAA ===\r\n 501: 'El certificado puede haber expirado o la relación CUIT/Servicio no está habilitada en el portal de ARCA.',\r\n 502: 'El ticket de acceso (TA) es inválido o ya expiró. Hacé wsaa.login() nuevamente.',\r\n 503: 'Error interno del servidor de autenticación de ARCA. Reintentá en unos minutos.',\r\n 1000: 'El CUIT informado no es válido o no corresponde al certificado usado.',\r\n 1001: 'El servicio solicitado no existe o el certificado no tiene autorización para usarlo.',\r\n 1003: 'El TRA (Ticket de Requerimiento de Acceso) tiene un formato inválido.',\r\n 1005: 'El TRA ya expiró antes de ser presentado. Verificá la hora del sistema.',\r\n\r\n // === WSFE — Puntos de venta y configuración ===\r\n 10048: 'El punto de venta no está dado de alta en ARCA. Dalo de alta como Webservice en el portal.',\r\n 10049: 'El punto de venta no está activo o está bloqueado.',\r\n\r\n // === WSFE — Comprobantes y montos ===\r\n 10015: 'Factura B: El importe supera el límite para consumidores finales anónimos. Identificá al comprador con CUIT/DNI.',\r\n 10016: 'El CUIT informado como receptor no es válido o no existe en el Padrón.',\r\n 600: 'No se pudo autorizar el comprobante. Revisá el campo `observations` en la respuesta para más detalle.',\r\n 601: 'El comprobante ya fue autorizado anteriormente. No emitas dos veces el mismo número.',\r\n 602: 'El número de comprobante es inválido o no es el correcto según el último autorizado.',\r\n\r\n // === WSFE — IVA ===\r\n 10043: 'La alícuota de IVA informada no existe o es incorrecta. Usá 3 (0%), 4 (10.5%), 5 (21%) o 6 (27%).',\r\n 10044: 'El importe de IVA no cuadra con la base imponible × alícuota.',\r\n\r\n // === Padrón ===\r\n PADRON_ERROR: 'El servicio de Padrón suele ser inestable en homologación. Reintentá en unos minutos.',\r\n CUIT_NOT_FOUND: 'El CUIT consultado no existe en el Padrón de ARCA.',\r\n};\r\n\r\n/**\r\n * Busca un hint para un código de error dado.\r\n * Retorna undefined si no hay sugerencia conocida para ese código.\r\n */\r\nexport function getArcaHint(code: string | number): string | undefined {\r\n return ARCA_ERROR_HINTS[code];\r\n}\r\n","import { getWsfeEndpoint } from '../constants/endpoints';\r\nimport { ArcaError, ArcaValidationError } from '../types/common';\r\nimport type {\r\n WsfeConfig,\r\n IssueInvoiceRequest,\r\n CAEResponse,\r\n InvoiceItem,\r\n Buyer,\r\n ServiceStatus,\r\n InvoiceDetails,\r\n PointOfSale,\r\n} from '../types/wsfe';\r\nimport {\r\n InvoiceType,\r\n BillingConcept,\r\n TaxIdType,\r\n} from '../types/wsfe';\r\nimport {\r\n calculateSubtotal,\r\n calculateVAT,\r\n calculateTotal,\r\n round,\r\n} from '../utils/calculations';\r\nimport { parseXml } from '../utils/xml';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { generateQRUrl } from '../utils/qr';\r\nimport { getArcaHint } from '../constants/errors';\r\n\r\n/**\r\n * Servicio de Facturación Electrónica WSFE v1\r\n *\r\n * @example\r\n * ```typescript\r\n * const wsfe = new WsfeService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * ticket: await wsaa.login(),\r\n * pointOfSale: 4,\r\n * });\r\n *\r\n * // Ticket C rápido\r\n * const cae = await wsfe.issueSimpleReceipt({ total: 1500 });\r\n * console.log('CAE:', cae.cae);\r\n * console.log('QR:', cae.qrUrl);\r\n *\r\n * // Factura A/B con IVA discriminado\r\n * const cae = await wsfe.issueInvoiceB({\r\n * items: [{ description: 'Servicio', quantity: 1, unitPrice: 1000, vatRate: 21 }],\r\n * buyer: { docType: TaxIdType.CUIT, docNumber: '20987654321' },\r\n * });\r\n * ```\r\n */\r\nexport class WsfeService {\r\n private config: WsfeConfig;\r\n\r\n constructor(config: WsfeConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n }\r\n\r\n private validateConfig(config: WsfeConfig): void {\r\n if (!config.ticket || !config.ticket.token) {\r\n throw new ArcaValidationError(\r\n 'Ticket WSAA requerido. Ejecutá wsaa.login() primero.',\r\n { hint: 'El ticket se obtiene del servicio WsaaService' }\r\n );\r\n }\r\n\r\n if (!config.pointOfSale || config.pointOfSale < 1 || config.pointOfSale > 9999) {\r\n throw new ArcaValidationError(\r\n 'Punto de venta inválido: debe ser un número entre 1 y 9999',\r\n { pointOfSale: config.pointOfSale }\r\n );\r\n }\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Estado de los servidores\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA (FEDummy).\r\n * No requiere autenticación. Útil para health checks.\r\n *\r\n * @param environment Ambiente a consultar (default: 'homologacion')\r\n */\r\n static async checkStatus(environment: 'homologacion' | 'produccion' = 'homologacion'): Promise<ServiceStatus> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEDummy/>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEDummy',\r\n },\r\n body: soapRequest,\r\n timeout: 10000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar estado: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEDummyResponse?.FEDummyResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEDummy inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n return {\r\n appServer: data.AppServer,\r\n dbServer: data.DbServer,\r\n authServer: data.AuthServer,\r\n };\r\n }\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA.\r\n * Versión de instancia — usa el ambiente configurado.\r\n */\r\n async checkStatus(): Promise<ServiceStatus> {\r\n return WsfeService.checkStatus(this.config.environment);\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Emisión de comprobantes\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Emite un Ticket C simple (solo monto total, sin detalle de items).\r\n * Ideal para registros mínimos, como una app móvil de punto de venta.\r\n */\r\n async issueSimpleReceipt(params: {\r\n total: number;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n return this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total: params.total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Emite un Ticket C con detalle de items.\r\n * Los items se guardan en la respuesta pero no se envían a ARCA.\r\n */\r\n async issueReceipt(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n const cae = await this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n\r\n return { ...cae, items: params.items };\r\n }\r\n\r\n /**\r\n * Emite una Factura C (consumidor final, sin discriminación de IVA).\r\n */\r\n async issueInvoiceC(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n items: params.items,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura B (con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceB(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_B,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura A (Responsable Inscripto a Responsable Inscripto, con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceA(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_A,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Consultas\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Consulta un comprobante ya emitido (FECompConsultar).\r\n *\r\n * @param type Tipo de comprobante\r\n * @param invoiceNumber Número de comprobante\r\n */\r\n async getInvoice(type: InvoiceType, invoiceNumber: number): Promise<InvoiceDetails> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompConsultar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCompConsReq>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n <ar:CbteNro>${invoiceNumber}</ar:CbteNro>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n </ar:FeCompConsReq>\r\n </ar:FECompConsultar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompConsultar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompConsultarResponse?.FECompConsultarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FECompConsultar inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const det = data.ResultGet;\r\n return {\r\n invoiceType: Number(det.CbteTipo),\r\n pointOfSale: Number(det.PtoVta),\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: String(det.CbteFch),\r\n concept: Number(det.Concepto),\r\n docType: Number(det.DocTipo),\r\n docNumber: Number(det.DocNro),\r\n total: Number(det.ImpTotal),\r\n net: Number(det.ImpNeto),\r\n vat: Number(det.ImpIVA),\r\n cae: String(det.CodAutorizacion),\r\n caeExpiry: String(det.FchVto),\r\n result: det.Resultado as 'A' | 'R',\r\n };\r\n }\r\n\r\n /**\r\n * Lista los puntos de venta habilitados para el CUIT autenticado (FEParamGetPtosVenta).\r\n */\r\n async getPointsOfSale(): Promise<PointOfSale[]> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEParamGetPtosVenta>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n </ar:FEParamGetPtosVenta>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEParamGetPtosVenta',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar puntos de venta: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEParamGetPtosVentaResponse?.FEParamGetPtosVentaResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEParamGetPtosVenta inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n throw new ArcaError(`Error ARCA: ${error?.Msg || 'Error desconocido'}`, 'ARCA_ERROR', data.Errors);\r\n }\r\n\r\n const raw = data.ResultGet?.PtoVenta;\r\n if (!raw) return [];\r\n\r\n const list = Array.isArray(raw) ? raw : [raw];\r\n return list.map((pv: Record<string, unknown>) => ({\r\n number: Number(pv.Nro),\r\n type: String(pv.EmisionTipo),\r\n isBlocked: pv.Bloqueado === 'S',\r\n blockedSince: pv.FchBaja ? String(pv.FchBaja) : undefined,\r\n }));\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Métodos internos\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Método genérico interno para emitir cualquier tipo de comprobante.\r\n */\r\n private async issueDocument(request: IssueInvoiceRequest): Promise<CAEResponse> {\r\n // 1. Get next invoice number\r\n const invoiceNumber = await this.getNextInvoiceNumber(request.type);\r\n\r\n // 2. Calculate totals\r\n let total = request.total || 0;\r\n let net = total;\r\n let vat = 0;\r\n\r\n if (request.items && request.items.length > 0) {\r\n const includesVAT = request.includesVAT || false;\r\n net = round(calculateSubtotal(request.items, includesVAT));\r\n vat = round(calculateVAT(request.items, includesVAT));\r\n total = round(calculateTotal(request.items, includesVAT));\r\n }\r\n\r\n if (total <= 0) {\r\n throw new ArcaValidationError('El monto total debe ser mayor a 0');\r\n }\r\n\r\n // 3. Build SOAP request\r\n const soapRequest = this.buildCAERequest({\r\n type: request.type,\r\n pointOfSale: this.config.pointOfSale,\r\n invoiceNumber,\r\n concept: request.concept,\r\n date: request.date || new Date(),\r\n buyer: request.buyer,\r\n net,\r\n vat,\r\n total,\r\n vatData: request.vatData,\r\n });\r\n\r\n // 4. Send to ARCA\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECAESolicitar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(\r\n `Error HTTP al comunicarse con WSFE: ${response.status}`,\r\n 'HTTP_ERROR',\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 5. Parse CAE response\r\n const result = await this.parseCAEResponse(responseXml);\r\n\r\n // 6. Generate QR URL\r\n const qrUrl = generateQRUrl(result, this.config.cuit, total, request.buyer);\r\n\r\n return {\r\n ...result,\r\n items: request.items,\r\n vat: request.vatData,\r\n qrUrl,\r\n };\r\n }\r\n\r\n /**\r\n * Obtiene el próximo número de comprobante disponible (FECompUltimoAutorizado + 1)\r\n */\r\n private async getNextInvoiceNumber(type: InvoiceType): Promise<number> {\r\n const soapRequest = this.buildLastInvoiceRequest(type);\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompUltimoAutorizado',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar último comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompUltimoAutorizadoResponse?.FECompUltimoAutorizadoResult;\r\n\r\n if (data?.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const lastNumber = data?.CbteNro;\r\n return typeof lastNumber === 'number' ? lastNumber + 1 : 1;\r\n }\r\n\r\n /**\r\n * Valida que todos los items tengan alícuota IVA definida\r\n */\r\n private validateItemsWithVAT(items: InvoiceItem[]): void {\r\n const missingVAT = items.filter(item =>\r\n item.vatRate === undefined || item.vatRate === null\r\n );\r\n\r\n if (missingVAT.length > 0) {\r\n throw new ArcaValidationError(\r\n 'Esta operación requiere `vatRate` en todos los items',\r\n {\r\n itemsMissingVAT: missingVAT.map(i => i.description),\r\n hint: 'Agregá vatRate a cada item (21, 10.5, 27, o 0)'\r\n }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Calcula el IVA agrupado por alícuota (requerido por ARCA para Factura A/B)\r\n */\r\n private calculateVATByRate(items: InvoiceItem[], includesVAT = false): {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[] {\r\n const byRate = new Map<number, { base: number; amount: number }>();\r\n\r\n items.forEach(item => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n\r\n const base = item.quantity * netPrice;\r\n const amount = base * rate / 100;\r\n\r\n const current = byRate.get(rate) || { base: 0, amount: 0 };\r\n byRate.set(rate, {\r\n base: current.base + base,\r\n amount: current.amount + amount,\r\n });\r\n });\r\n\r\n return Array.from(byRate.entries()).map(([rate, values]) => ({\r\n rate,\r\n taxBase: round(values.base),\r\n amount: round(values.amount),\r\n }));\r\n }\r\n\r\n /**\r\n * Mapea alícuota % al código interno de ARCA\r\n */\r\n private getVATCode(percentage: number): number {\r\n const map: Record<number, number> = {\r\n 0: 3,\r\n 10.5: 4,\r\n 21: 5,\r\n 27: 6,\r\n };\r\n\r\n const code = map[percentage];\r\n if (code === undefined) {\r\n throw new ArcaValidationError(\r\n `Alícuota IVA inválida: ${percentage}%`,\r\n {\r\n validRates: [0, 10.5, 21, 27],\r\n hint: 'Usá una de las alícuotas oficiales de Argentina'\r\n }\r\n );\r\n }\r\n\r\n return code;\r\n }\r\n\r\n private buildCAERequest(params: {\r\n type: InvoiceType;\r\n pointOfSale: number;\r\n invoiceNumber: number;\r\n concept: BillingConcept;\r\n date: Date;\r\n buyer?: IssueInvoiceRequest['buyer'];\r\n net: number;\r\n vat: number;\r\n total: number;\r\n vatData?: IssueInvoiceRequest['vatData'];\r\n }): string {\r\n const dateStr = params.date.toISOString().split('T')[0].replace(/-/g, '');\r\n\r\n let vatXml = '';\r\n if (params.vatData && params.vatData.length > 0) {\r\n vatXml = '<ar:Iva>';\r\n params.vatData.forEach(entry => {\r\n vatXml += `\r\n <ar:AlicIva>\r\n <ar:Id>${this.getVATCode(entry.rate)}</ar:Id>\r\n <ar:BaseImp>${entry.taxBase.toFixed(2)}</ar:BaseImp>\r\n <ar:Importe>${entry.amount.toFixed(2)}</ar:Importe>\r\n </ar:AlicIva>`;\r\n });\r\n vatXml += '\\n </ar:Iva>';\r\n }\r\n\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECAESolicitar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCAEReq>\r\n <ar:FeCabReq>\r\n <ar:CantReg>1</ar:CantReg>\r\n <ar:PtoVta>${params.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${params.type}</ar:CbteTipo>\r\n </ar:FeCabReq>\r\n <ar:FeDetReq>\r\n <ar:FECAEDetRequest>\r\n <ar:Concepto>${params.concept}</ar:Concepto>\r\n <ar:DocTipo>${params.buyer?.docType || 99}</ar:DocTipo>\r\n <ar:DocNro>${params.buyer?.docNumber || 0}</ar:DocNro>\r\n <ar:CbteDesde>${params.invoiceNumber}</ar:CbteDesde>\r\n <ar:CbteHasta>${params.invoiceNumber}</ar:CbteHasta>\r\n <ar:CbteFch>${dateStr}</ar:CbteFch>\r\n <ar:ImpTotal>${params.total.toFixed(2)}</ar:ImpTotal>\r\n <ar:ImpTotConc>0.00</ar:ImpTotConc>\r\n <ar:ImpNeto>${params.net.toFixed(2)}</ar:ImpNeto>\r\n <ar:ImpOpEx>0.00</ar:ImpOpEx>\r\n <ar:ImpIVA>${params.vat.toFixed(2)}</ar:ImpIVA>\r\n <ar:ImpTrib>0.00</ar:ImpTrib>\r\n <ar:MonId>PES</ar:MonId>\r\n <ar:MonCotiz>1</ar:MonCotiz>\r\n ${vatXml}\r\n </ar:FECAEDetRequest>\r\n </ar:FeDetReq>\r\n </ar:FeCAEReq>\r\n </ar:FECAESolicitar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private buildLastInvoiceRequest(type: InvoiceType): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompUltimoAutorizado>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n </ar:FECompUltimoAutorizado>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private async parseCAEResponse(xml: string): Promise<CAEResponse> {\r\n const result = parseXml(xml);\r\n const data = result?.Envelope?.Body?.FECAESolicitarResponse?.FECAESolicitarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta WSFE inválida: estructura no reconocida', 'PARSE_ERROR', { xml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const cab = data.FeCabResp;\r\n const det = Array.isArray(data.FeDetResp.FECAEDetResponse)\r\n ? data.FeDetResp.FECAEDetResponse[0]\r\n : data.FeDetResp.FECAEDetResponse;\r\n\r\n if (!det) {\r\n throw new ArcaError('Respuesta WSFE incompleta: falta detalle del comprobante', 'PARSE_ERROR');\r\n }\r\n\r\n const observations: string[] = [];\r\n if (det.Observaciones) {\r\n const obsArray = Array.isArray(det.Observaciones.Obs)\r\n ? det.Observaciones.Obs\r\n : [det.Observaciones.Obs];\r\n obsArray.forEach((o: { Msg: string }) => observations.push(o.Msg));\r\n }\r\n\r\n return {\r\n invoiceType: cab.CbteTipo,\r\n pointOfSale: cab.PtoVta,\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: det.CbteFch,\r\n cae: String(det.CAE),\r\n caeExpiry: String(det.CAEFchVto),\r\n result: det.Resultado,\r\n observations: observations.length > 0 ? observations : undefined,\r\n };\r\n }\r\n}\r\n","import { WsaaService } from '../auth/wsaa';\r\nimport { getPadronEndpoint } from '../constants/endpoints';\r\nimport { ArcaNetworkError, ArcaError } from '../types/common';\r\nimport type {\r\n TaxpayerServiceConfig,\r\n Taxpayer,\r\n TaxpayerResponse,\r\n Address,\r\n Activity,\r\n TaxRecord,\r\n} from '../types/padron';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\n/**\r\n * Servicio para consultar el Padrón de AFIP (ws_sr_padron_a13)\r\n *\r\n * @example\r\n * ```typescript\r\n * const padron = new PadronService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * });\r\n *\r\n * const { taxpayer, error } = await padron.getTaxpayer('30111111118');\r\n * if (taxpayer) {\r\n * console.log(taxpayer.companyName || `${taxpayer.firstName} ${taxpayer.lastName}`);\r\n * console.log('¿Inscripto IVA?:', taxpayer.isVATRegistered);\r\n * }\r\n * ```\r\n */\r\nexport class PadronService {\r\n private wsaa: WsaaService;\r\n private config: TaxpayerServiceConfig;\r\n\r\n constructor(config: TaxpayerServiceConfig) {\r\n this.config = config;\r\n this.wsaa = new WsaaService({\r\n environment: config.environment,\r\n cuit: config.cuit,\r\n cert: config.cert,\r\n key: config.key,\r\n service: 'ws_sr_padron_a13',\r\n storage: config.storage,\r\n });\r\n }\r\n\r\n /**\r\n * Consulta los datos de un contribuyente por CUIT\r\n *\r\n * @param taxId CUIT a consultar (11 dígitos sin guiones)\r\n * @returns Datos del contribuyente o mensaje de error\r\n */\r\n async getTaxpayer(taxId: string): Promise<TaxpayerResponse> {\r\n const ticket = await this.wsaa.login();\r\n\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:a13=\"http://a13.soap.ws.server.puc.sr/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <a13:getPersona>\r\n <token>${ticket.token}</token>\r\n <sign>${ticket.sign}</sign>\r\n <cuitRepresentada>${this.config.cuit}</cuitRepresentada>\r\n <idPersona>${taxId}</idPersona>\r\n </a13:getPersona>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getPadronEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout || 15000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaNetworkError(\r\n `Error HTTP al comunicarse con Padrón A13: ${response.status}`,\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const xml = await response.text();\r\n return this.parseResponse(xml);\r\n }\r\n\r\n /**\r\n * Parsea la respuesta XML de getPersona\r\n */\r\n private parseResponse(xml: string): TaxpayerResponse {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n removeNSPrefix: true,\r\n });\r\n const result = parser.parse(xml);\r\n\r\n const body = result.Envelope?.Body;\r\n if (!body) {\r\n throw new ArcaError('Respuesta del Padrón inválida: Body no encontrado', 'PADRON_ERROR');\r\n }\r\n\r\n const response = body.getPersonaResponse?.personaReturn;\r\n if (!response) {\r\n const fault = body.Fault;\r\n if (fault) {\r\n return { error: fault.faultstring || 'Error desconocido en ARCA' };\r\n }\r\n return { error: 'No se encontraron datos para el CUIT informado' };\r\n }\r\n\r\n if (response.errorConstancia) {\r\n return { error: response.errorConstancia };\r\n }\r\n\r\n const p = response.persona;\r\n if (!p) {\r\n return { error: 'CUIT no encontrado' };\r\n }\r\n\r\n const taxpayer: Taxpayer = {\r\n taxId: Number(p.idPersona),\r\n personType: p.tipoPersona as 'FISICA' | 'JURIDICA',\r\n firstName: p.nombre,\r\n lastName: p.apellido,\r\n companyName: p.razonSocial,\r\n status: p.estadoClave,\r\n addresses: this.mapAddresses(p.domicilio),\r\n activities: this.mapActivities(p.actividad),\r\n taxes: this.mapTaxRecords(p.impuesto),\r\n mainActivity: p.descripcionActividadPrincipal,\r\n isVATRegistered: this.hasTaxId(p, 30), // 30 = IVA\r\n isMonotax: this.hasTaxId(p, 20), // 20 = Monotributo\r\n isVATExempt: this.hasTaxId(p, 32), // 32 = IVA Exento\r\n };\r\n\r\n return { taxpayer };\r\n }\r\n\r\n private mapAddresses(raw: unknown): Address[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n street: item.direccion as string,\r\n city: item.localidad as string | undefined,\r\n postalCode: item.codPostal as string | undefined,\r\n provinceId: Number(item.idProvincia),\r\n province: item.descripcionProvincia as string,\r\n type: item.tipoDomicilio as string,\r\n }));\r\n }\r\n\r\n private mapActivities(raw: unknown): Activity[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idActividad),\r\n description: item.descripcion as string,\r\n order: Number(item.orden),\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private mapTaxRecords(raw: unknown): TaxRecord[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idImpuesto),\r\n description: item.descripcion as string,\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private hasTaxId(p: Record<string, unknown>, id: number): boolean {\r\n const taxes = p.impuesto;\r\n if (!taxes) return false;\r\n return this.toArray(taxes).some((i: Record<string, unknown>) => Number(i.idImpuesto) === id);\r\n }\r\n\r\n /**\r\n * Normaliza un valor que puede ser un objeto único o un array (comportamiento de fast-xml-parser)\r\n */\r\n private toArray(data: unknown): Record<string, unknown>[] {\r\n if (data === undefined || data === null) return [];\r\n if (Array.isArray(data)) return data as Record<string, unknown>[];\r\n return [data as Record<string, unknown>];\r\n }\r\n}\r\n"],"mappings":"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","names":["InvoiceType","BillingConcept","TaxIdType","XMLParser"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants/endpoints.ts","../src/types/common.ts","../src/utils/xml.ts","../src/utils/crypto.ts","../src/auth/ticket.ts","../src/utils/network.ts","../src/auth/wsaa.ts","../src/types/wsfe.ts","../src/utils/calculations.ts","../src/utils/qr.ts","../src/constants/errors.ts","../src/services/wsfe.ts","../src/services/padron.ts"],"sourcesContent":["import type { Environment } from '../types/common';\r\n\r\n/**\r\n * URLs de los servicios ARCA por ambiente\r\n */\r\nexport const WSAA_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms',\r\n produccion: 'https://wsaa.afip.gov.ar/ws/services/LoginCms',\r\n};\r\n\r\n/**\r\n * URLs del servicio WSFE por ambiente\r\n */\r\nexport const WSFE_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx',\r\n produccion: 'https://servicios1.afip.gov.ar/wsfev1/service.asmx',\r\n};\r\n\r\n/**\r\n * URLs del servicio Padron A13 por ambiente\r\n */\r\nexport const PADRON_A13_ENDPOINTS: Record<Environment, string> = {\r\n homologacion: 'https://awshomo.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n produccion: 'https://aws.afip.gov.ar/sr-padron/webservices/personaServiceA13',\r\n};\r\n\r\n/**\r\n * Obtener endpoint WSAA según ambiente\r\n */\r\nexport function getWsaaEndpoint(environment: Environment): string {\r\n return WSAA_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint WSFE según ambiente\r\n */\r\nexport function getWsfeEndpoint(environment: Environment): string {\r\n return WSFE_ENDPOINTS[environment];\r\n}\r\n\r\n/**\r\n * Obtener endpoint Padron A13 según ambiente\r\n */\r\nexport function getPadronEndpoint(environment: Environment): string {\r\n return PADRON_A13_ENDPOINTS[environment];\r\n}\r\n","/**\r\n * Tipos comunes compartidos en toda la SDK\r\n */\r\n\r\n/**\r\n * Ambiente de ejecución ARCA\r\n */\r\nexport type Environment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Configuración base para servicios ARCA\r\n */\r\nexport interface ArcaConfig {\r\n /** Ambiente (homologación o producción) */\r\n environment: Environment;\r\n /** CUIT del contribuyente (11 dígitos sin guiones) */\r\n cuit: string;\r\n /** Tiempo de espera para peticiones (ms). Defecto: 15000 */\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Error personalizado de ARCA SDK\r\n */\r\nexport class ArcaError extends Error {\r\n constructor(\r\n message: string,\r\n public code: string,\r\n public details?: unknown,\r\n public hint?: string\r\n ) {\r\n super(message);\r\n this.name = 'ArcaError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de autenticación WSAA\r\n */\r\nexport class ArcaAuthError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'AUTH_ERROR', details);\r\n this.name = 'ArcaAuthError';\r\n }\r\n}\r\n\r\n/**\r\n * Error de validación de input\r\n */\r\nexport class ArcaValidationError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'VALIDATION_ERROR', details);\r\n this.name = 'ArcaValidationError';\r\n }\r\n}\r\n/**\r\n * Error de comunicación/red\r\n */\r\nexport class ArcaNetworkError extends ArcaError {\r\n constructor(message: string, details?: unknown) {\r\n super(message, 'NETWORK_ERROR', details);\r\n this.name = 'ArcaNetworkError';\r\n }\r\n}\r\n","import { XMLBuilder, XMLParser } from 'fast-xml-parser';\r\nimport { ArcaAuthError } from '../types/common';\r\nimport type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Genera el XML TRA (Ticket de Requerimiento de Acceso)\r\n * \r\n * @param service - Servicio ARCA (ej: 'wsfe')\r\n * @param cuit - CUIT del contribuyente\r\n * @returns XML del TRA\r\n */\r\nexport function buildTRA(service: string, cuit: string): string {\r\n const now = new Date();\r\n const expirationTime = new Date(now.getTime() + 12 * 60 * 60 * 1000); // +12 horas\r\n\r\n const tra = {\r\n loginTicketRequest: {\r\n '@_version': '1.0',\r\n header: {\r\n uniqueId: Math.floor(now.getTime() / 1000),\r\n generationTime: now.toISOString(),\r\n expirationTime: expirationTime.toISOString(),\r\n },\r\n service,\r\n },\r\n };\r\n\r\n const builder = new XMLBuilder({\r\n ignoreAttributes: false,\r\n format: true,\r\n });\r\n\r\n const xml = builder.build(tra);\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n${xml}`;\r\n}\r\n\r\n/**\r\n * Parsea la respuesta XML de WSAA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Ticket de login\r\n */\r\nexport function parseWsaaResponse(xml: string): LoginTicket {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n\r\n try {\r\n const envelope = parser.parse(xml);\r\n\r\n // El loginCmsReturn contiene el ticket real como un XML escapado (string)\r\n const loginCmsReturn = envelope?.Envelope?.Body?.loginCmsResponse?.loginCmsReturn;\r\n\r\n if (!loginCmsReturn) {\r\n const fault = envelope?.Envelope?.Body?.Fault;\r\n if (fault) {\r\n throw new ArcaAuthError(\r\n `Error ARCA: ${fault.faultstring || 'Error desconocido'}`,\r\n { faultCode: fault.faultcode, detail: fault.detail }\r\n );\r\n }\r\n\r\n throw new ArcaAuthError(\r\n 'Respuesta WSAA inválida: estructura no reconocida',\r\n {\r\n receivedXml: xml.substring(0, 5000),\r\n receivedStructure: JSON.stringify(envelope).substring(0, 500)\r\n }\r\n );\r\n }\r\n\r\n // Segundo nivel de parseo: El XML interno escapado que viene dentro de loginCmsReturn\r\n const ticketResult = parser.parse(loginCmsReturn);\r\n const ticket = ticketResult?.loginTicketResponse;\r\n\r\n if (!ticket || !ticket.header || !ticket.credentials) {\r\n throw new ArcaAuthError('Ticket WSAA inválido o malformado dentro de loginCmsReturn', {\r\n innerStructure: JSON.stringify(ticketResult).substring(0, 500),\r\n receivedXml: xml.substring(0, 5000)\r\n });\r\n }\r\n\r\n return {\r\n token: ticket.credentials.token,\r\n sign: ticket.credentials.sign,\r\n generationTime: new Date(ticket.header.generationTime),\r\n expirationTime: new Date(ticket.header.expirationTime),\r\n };\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al parsear respuesta WSAA (posible XML anidado malformado)',\r\n {\r\n originalError: error instanceof Error ? error.message : String(error),\r\n receivedXml: xml.substring(0, 5000)\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Parsea un XML genérico de ARCA\r\n * \r\n * @param xml - XML de respuesta\r\n * @returns Objeto parseado\r\n */\r\nexport function parseXml(xml: string): any {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n parseAttributeValue: true,\r\n removeNSPrefix: true,\r\n });\r\n return parser.parse(xml);\r\n}\r\n\r\n/**\r\n * Valida CUIT (11 dígitos sin guiones)\r\n */\r\nexport function validateCUIT(cuit: string): boolean {\r\n return /^\\d{11}$/.test(cuit);\r\n}\r\n","import * as forge from 'node-forge';\r\nimport { ArcaAuthError } from '../types/common';\r\n\r\n/**\r\n * Firma un XML en formato CMS (PKCS#7) usando certificado y clave privada\r\n * \r\n * @param xml - Contenido XML a firmar (TRA)\r\n * @param certPem - Certificado en formato PEM\r\n * @param keyPem - Clave privada en formato PEM\r\n * @returns CMS firmado en base64\r\n */\r\nexport function signCMS(xml: string, certPem: string, keyPem: string): string {\r\n try {\r\n // 1. Parsear certificado\r\n const cert = forge.pki.certificateFromPem(certPem);\r\n\r\n // 2. Parsear clave privada\r\n const privateKey = forge.pki.privateKeyFromPem(keyPem);\r\n\r\n // 3. Crear contenedor PKCS#7\r\n const p7 = forge.pkcs7.createSignedData();\r\n\r\n // 4. Agregar contenido a firmar\r\n p7.content = forge.util.createBuffer(xml, 'utf8');\r\n\r\n // 5. Agregar certificado\r\n p7.addCertificate(cert);\r\n\r\n // 6. Firmar con SHA256\r\n p7.addSigner({\r\n key: privateKey,\r\n certificate: cert,\r\n digestAlgorithm: forge.pki.oids.sha256,\r\n authenticatedAttributes: [\r\n {\r\n type: forge.pki.oids.contentType,\r\n value: forge.pki.oids.data,\r\n },\r\n {\r\n type: forge.pki.oids.messageDigest,\r\n // El valor será calculado automáticamente\r\n },\r\n {\r\n type: forge.pki.oids.signingTime,\r\n // node-forge expects a Date object, but its typings might be missing or expect string/any\r\n value: new Date() as any,\r\n },\r\n ],\r\n });\r\n\r\n // 7. Firmar\r\n p7.sign();\r\n\r\n // 8. Convertir a DER y luego a base64\r\n const derBytes = forge.asn1.toDer(p7.toAsn1()).getBytes();\r\n const base64 = forge.util.encode64(derBytes);\r\n\r\n return base64;\r\n } catch (error) {\r\n if (error instanceof ArcaAuthError) throw error;\r\n throw new ArcaAuthError(\r\n 'Error al firmar XML con certificado usando PKCS#7',\r\n {\r\n originalError: error,\r\n hint: 'Verificar que el certificado y la clave privada sean válidos y correspondan entre sí'\r\n }\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Valida formato de certificado PEM\r\n */\r\nexport function validateCertificate(cert: string): boolean {\r\n return cert.includes('-----BEGIN CERTIFICATE-----') &&\r\n cert.includes('-----END CERTIFICATE-----');\r\n}\r\n\r\n/**\r\n * Valida formato de clave privada PEM\r\n */\r\nexport function validatePrivateKey(key: string): boolean {\r\n return (\r\n (key.includes('-----BEGIN PRIVATE KEY-----') &&\r\n key.includes('-----END PRIVATE KEY-----')) ||\r\n (key.includes('-----BEGIN RSA PRIVATE KEY-----') &&\r\n key.includes('-----END RSA PRIVATE KEY-----'))\r\n );\r\n}\r\n","import type { LoginTicket } from '../types/wsaa';\r\n\r\n/**\r\n * Gestor de tickets de autenticación\r\n * Maneja cache en memoria del ticket WSAA\r\n */\r\nexport class TicketManager {\r\n private ticket: LoginTicket | null = null;\r\n\r\n /**\r\n * Guarda un ticket en cache\r\n */\r\n setTicket(ticket: LoginTicket): void {\r\n this.ticket = ticket;\r\n }\r\n\r\n /**\r\n * Obtiene el ticket actual si es válido\r\n * @returns Ticket válido o null si expiró\r\n */\r\n getTicket(): LoginTicket | null {\r\n if (!this.ticket) return null;\r\n\r\n const now = new Date();\r\n const expiresIn = this.ticket.expirationTime.getTime() - now.getTime();\r\n\r\n // Si expira en menos de 5 minutos, considerarlo inválido\r\n const BUFFER_MS = 5 * 60 * 1000;\r\n\r\n if (expiresIn < BUFFER_MS) {\r\n this.ticket = null;\r\n return null;\r\n }\r\n\r\n return this.ticket;\r\n }\r\n\r\n /**\r\n * Verifica si hay un ticket válido\r\n */\r\n hasValidTicket(): boolean {\r\n return this.getTicket() !== null;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache\r\n */\r\n clearTicket(): void {\r\n this.ticket = null;\r\n }\r\n}\r\n","import https from 'https';\r\nimport { ArcaNetworkError } from '../types/common';\r\n\r\n/**\r\n * Entornos compatibles\r\n */\r\nexport type ArcaEnvironment = 'homologacion' | 'produccion';\r\n\r\n/**\r\n * Opciones para la llamada API\r\n */\r\nexport interface CallApiOptions {\r\n method: string;\r\n headers: Record<string, string>;\r\n body: string;\r\n timeout?: number;\r\n}\r\n\r\n/**\r\n * Realiza una llamada a la API de ARCA (WSAA o WSFE)\r\n * Maneja la compatibilidad SSL con los servidores de AFIP (DH key size)\r\n * y añade robustez (timeouts, mejores errores).\r\n */\r\nexport async function callArcaApi(\r\n url: string,\r\n options: CallApiOptions\r\n): Promise<Response> {\r\n const timeout = options.timeout || 15000;\r\n const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;\r\n\r\n if (isNode) {\r\n return new Promise((resolve, reject) => {\r\n const parsedUrl = new URL(url);\r\n\r\n const agent = new https.Agent({\r\n // SECLEVEL=0 es el nivel más permisivo de OpenSSL.\r\n // !DH desactiva Diffie-Hellman para forzar RSA o ECDHE si están disponibles,\r\n // evitando el problema de \"dh key too small\" de raíz.\r\n ciphers: 'DEFAULT:!DH@SECLEVEL=0',\r\n // AFIP todavía tiene endpoints que podrían requerir TLS 1.0/1.1\r\n minVersion: 'TLSv1',\r\n // @ts-ignore - Propiedad específica para mitigar \"dh key too small\" en Node 18+\r\n minDHSize: 1024,\r\n rejectUnauthorized: true,\r\n });\r\n\r\n const reqOptions: https.RequestOptions = {\r\n method: options.method,\r\n hostname: parsedUrl.hostname,\r\n path: parsedUrl.pathname + parsedUrl.search,\r\n headers: options.headers,\r\n agent,\r\n timeout,\r\n };\r\n\r\n const req = https.request(reqOptions, (res) => {\r\n res.setEncoding('utf8');\r\n let data = '';\r\n res.on('data', (chunk) => { data += chunk; });\r\n res.on('end', () => {\r\n // Simular objeto Response de fetch\r\n const response = {\r\n ok: (res.statusCode || 0) >= 200 && (res.statusCode || 0) < 300,\r\n status: res.statusCode || 0,\r\n statusText: res.statusMessage || '',\r\n text: async () => data,\r\n json: async () => JSON.parse(data),\r\n };\r\n resolve(response as Response);\r\n });\r\n });\r\n\r\n req.on('error', (error: any) => {\r\n let message = error.message;\r\n if (message.includes('dh key too small')) {\r\n message = 'Error SSL de ARCA (DH Key too small). Verifique su versión de OpenSSL/Node.';\r\n }\r\n reject(new ArcaNetworkError(`Error de red al comunicarse con ARCA (HTTPS): ${message}`, {\r\n url,\r\n originalError: error\r\n }));\r\n });\r\n\r\n req.on('timeout', () => {\r\n req.destroy();\r\n reject(new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`));\r\n });\r\n\r\n req.write(options.body);\r\n req.end();\r\n });\r\n }\r\n\r\n // Navegador o entorno no-Node (utiliza fetch nativo)\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n method: options.method,\r\n headers: options.headers,\r\n body: options.body,\r\n signal: controller.signal\r\n });\r\n return response;\r\n } catch (error: any) {\r\n if (error.name === 'AbortError') {\r\n throw new ArcaNetworkError(`Tiempo de espera agotado (${timeout}ms) al conectar con ARCA: ${url}`);\r\n }\r\n throw new ArcaNetworkError(`Error de red: ${error.message}`, { url, originalError: error });\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n}\r\n","import { getWsaaEndpoint } from '../constants/endpoints';\r\nimport { ArcaAuthError, ArcaValidationError } from '../types/common';\r\nimport type { WsaaConfig, LoginTicket } from '../types/wsaa';\r\nimport { buildTRA, parseWsaaResponse, validateCUIT } from '../utils/xml';\r\nimport { validateCertificate, validatePrivateKey, signCMS } from '../utils/crypto';\r\nimport { TicketManager } from './ticket';\r\nimport { callArcaApi } from '../utils/network';\r\n\r\n/**\r\n * Servicio de autenticación WSAA (Web Service de Autenticación y Autorización)\r\n * \r\n * @example\r\n * ```typescript\r\n * const wsaa = new WsaaService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * service: 'wsfe',\r\n * });\r\n * \r\n * const ticket = await wsaa.login();\r\n * console.log('Token:', ticket.token);\r\n * ```\r\n */\r\nexport class WsaaService {\r\n private config: WsaaConfig;\r\n private ticketManager: TicketManager;\r\n\r\n constructor(config: WsaaConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n this.ticketManager = new TicketManager();\r\n }\r\n\r\n /**\r\n * Valida la configuración\r\n */\r\n private validateConfig(config: WsaaConfig): void {\r\n if (!validateCUIT(config.cuit)) {\r\n throw new ArcaValidationError(\r\n 'CUIT inválido: debe tener 11 dígitos sin guiones',\r\n { cuit: config.cuit }\r\n );\r\n }\r\n\r\n if (!validateCertificate(config.cert)) {\r\n throw new ArcaValidationError(\r\n 'Certificado inválido: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN CERTIFICATE-----' }\r\n );\r\n }\r\n\r\n if (!validatePrivateKey(config.key)) {\r\n throw new ArcaValidationError(\r\n 'Clave privada inválida: debe estar en formato PEM',\r\n { hint: 'Debe contener -----BEGIN PRIVATE KEY----- o -----BEGIN RSA PRIVATE KEY-----' }\r\n );\r\n }\r\n\r\n if (!config.service || config.service.trim() === '') {\r\n throw new ArcaValidationError(\r\n 'Servicio ARCA no especificado',\r\n { hint: 'Ejemplos: \"wsfe\", \"wsmtxca\"' }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Obtiene un ticket de acceso válido.\r\n * \r\n * Prioridad de búsqueda:\r\n * 1. Memoria (TicketManager cache)\r\n * 2. Persistencia (si config.storage está definido)\r\n * 3. Nueva solicitud a WSAA\r\n * \r\n * @returns Ticket de acceso\r\n */\r\n async login(): Promise<LoginTicket> {\r\n // 1. Intentar usar ticket en memoria (muy rápido)\r\n const cachedTicket = this.ticketManager.getTicket();\r\n if (cachedTicket) {\r\n return cachedTicket;\r\n }\r\n\r\n // 2. Intentar usar persistencia externa si está disponible\r\n if (this.config.storage) {\r\n try {\r\n const storedTicket = await this.config.storage.get(this.config.cuit, this.config.environment);\r\n if (storedTicket) {\r\n // Validar si el ticket devuelto por el storage no está expirado\r\n // Agrego un margen de 5 minutos\r\n const now = new Date();\r\n if (new Date(storedTicket.expirationTime) > new Date(now.getTime() + 5 * 60000)) {\r\n this.ticketManager.setTicket(storedTicket);\r\n return storedTicket;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.get falló, intentando login directo:', error);\r\n }\r\n }\r\n\r\n // 3. Generar nuevo ticket (llamada a AFIP)\r\n const ticket = await this.requestNewTicket();\r\n\r\n // Guardar en memoria\r\n this.ticketManager.setTicket(ticket);\r\n\r\n // Guardar en persistencia externa\r\n if (this.config.storage) {\r\n try {\r\n await this.config.storage.save(this.config.cuit, this.config.environment, ticket);\r\n } catch (error) {\r\n console.warn('[ARCA-SDK] TokenStorage.save falló:', error);\r\n }\r\n }\r\n\r\n return ticket;\r\n }\r\n\r\n /**\r\n * Solicita un nuevo ticket a WSAA\r\n */\r\n private async requestNewTicket(): Promise<LoginTicket> {\r\n // 1. Generar TRA (Ticket de Requerimiento de Acceso)\r\n const tra = buildTRA(this.config.service, this.config.cuit);\r\n\r\n // 2. Firmar TRA con certificado (genera CMS)\r\n let cms: string;\r\n try {\r\n cms = signCMS(tra, this.config.cert, this.config.key);\r\n } catch (error) {\r\n throw new ArcaAuthError(\r\n 'Error al firmar TRA con certificado',\r\n { originalError: error }\r\n );\r\n }\r\n\r\n // 3. Enviar CMS a WSAA\r\n const endpoint = getWsaaEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: this.buildSoapRequest(cms),\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaAuthError(\r\n `Error HTTP al comunicarse con WSAA: ${response.status} ${response.statusText}`,\r\n { status: response.status, statusText: response.statusText }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 4. Parsear respuesta\r\n return parseWsaaResponse(responseXml);\r\n }\r\n\r\n /**\r\n * Construye el SOAP request para WSAA\r\n */\r\n private buildSoapRequest(cms: string): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:wsaa=\"http://wsaa.view.sua.dvadac.desein.afip.gov\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <wsaa:loginCms>\r\n <wsaa:in0>${cms}</wsaa:in0>\r\n </wsaa:loginCms>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n /**\r\n * Limpia el ticket en cache (forzar renovación)\r\n */\r\n clearCache(): void {\r\n this.ticketManager.clearTicket();\r\n }\r\n}","import type { ArcaConfig } from './common';\r\nimport type { LoginTicket } from './wsaa';\r\n\r\n/**\r\n * Configuración para WsfeService\r\n */\r\nexport interface WsfeConfig extends ArcaConfig {\r\n /** Ticket de autenticación WSAA */\r\n ticket: LoginTicket;\r\n /** Punto de venta (1-9999) */\r\n pointOfSale: number;\r\n}\r\n\r\n/**\r\n * Tipo de comprobante ARCA\r\n */\r\nexport enum InvoiceType {\r\n FACTURA_A = 1,\r\n FACTURA_B = 6,\r\n FACTURA_C = 11,\r\n TICKET_A = 81,\r\n TICKET_B = 82,\r\n TICKET_C = 83,\r\n}\r\n\r\n/**\r\n * Concepto de facturación\r\n */\r\nexport enum BillingConcept {\r\n PRODUCTS = 1,\r\n SERVICES = 2,\r\n PRODUCTS_AND_SERVICES = 3,\r\n}\r\n\r\n/**\r\n * Tipo de documento del receptor\r\n */\r\nexport enum TaxIdType {\r\n CUIT = 80,\r\n CUIL = 86,\r\n CDI = 87,\r\n LE = 89,\r\n LC = 90,\r\n FOREIGN_ID = 91,\r\n PASSPORT = 94,\r\n BUENOS_AIRES_ID = 95,\r\n /**\r\n * @note AFIP usa el código 96 para ambos. En la práctica, DNI es el más utilizado.\r\n * Fuente: Tabla 13 del catálogo ARCA — ambos valores son 96 en el catálogo oficial.\r\n */\r\n NATIONAL_POLICE_ID = 96,\r\n DNI = 96,\r\n FINAL_CONSUMER = 99,\r\n}\r\n\r\n/**\r\n * Ítem de factura\r\n */\r\nexport interface InvoiceItem {\r\n /** Descripción del producto/servicio */\r\n description: string;\r\n /** Cantidad */\r\n quantity: number;\r\n /** Precio unitario */\r\n unitPrice: number;\r\n /** Alícuota IVA % (0, 10.5, 21, 27) */\r\n vatRate?: number;\r\n}\r\n\r\n/**\r\n * Datos del comprador\r\n */\r\nexport interface Buyer {\r\n /** Tipo de documento */\r\n docType: TaxIdType;\r\n /** Número de documento (sin guiones) */\r\n docNumber: string;\r\n}\r\n\r\n/**\r\n * Request para emitir comprobante\r\n */\r\nexport interface IssueInvoiceRequest {\r\n /** Tipo de comprobante */\r\n type: InvoiceType;\r\n /** Concepto */\r\n concept: BillingConcept;\r\n /** Comprador (opcional para Factura C consumidor final) */\r\n buyer?: Buyer;\r\n /** Items de la factura */\r\n items?: InvoiceItem[];\r\n /** Monto total (requerido si no hay items) */\r\n total?: number;\r\n /** Desglose de IVA (requerido para Factura A/B) */\r\n vatData?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** Indica si los precios unitarios YA incluyen el IVA. Defecto: false */\r\n includesVAT?: boolean;\r\n /** Fecha del comprobante (default: hoy) */\r\n date?: Date;\r\n}\r\n\r\n/**\r\n * Respuesta CAE (Código de Autorización Electrónico)\r\n */\r\nexport interface CAEResponse {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** CAE asignado */\r\n cae: string;\r\n /** Fecha de vencimiento del CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado (A = Aprobado, R = Rechazado) */\r\n result: 'A' | 'R';\r\n /** Observaciones de ARCA */\r\n observations?: string[];\r\n /** Items (se retornan si fueron proveídos en el request) */\r\n items?: InvoiceItem[];\r\n /** Desglose IVA (solo para Factura A/B) */\r\n vat?: {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[];\r\n /** URL del código QR oficial de ARCA */\r\n qrUrl?: string;\r\n}\r\n\r\n/**\r\n * Detalle de un comprobante consultado (FECompConsultar)\r\n */\r\nexport interface InvoiceDetails {\r\n /** Tipo de comprobante */\r\n invoiceType: number;\r\n /** Punto de venta */\r\n pointOfSale: number;\r\n /** Número de comprobante */\r\n invoiceNumber: number;\r\n /** Fecha de emisión (YYYYMMDD) */\r\n date: string;\r\n /** Concepto */\r\n concept: number;\r\n /** Tipo de documento del receptor */\r\n docType: number;\r\n /** Número de documento del receptor */\r\n docNumber: number;\r\n /** Importe total */\r\n total: number;\r\n /** Importe neto gravado */\r\n net: number;\r\n /** Importe IVA */\r\n vat: number;\r\n /** CAE */\r\n cae: string;\r\n /** Vencimiento CAE (YYYYMMDD) */\r\n caeExpiry: string;\r\n /** Resultado */\r\n result: 'A' | 'R';\r\n}\r\n\r\n/**\r\n * Punto de venta habilitado en ARCA\r\n */\r\nexport interface PointOfSale {\r\n /** Número de punto de venta */\r\n number: number;\r\n /** Tipo (CAI, CAE, CAEA, etc.) */\r\n type: string;\r\n /** Indica si está bloqueado */\r\n isBlocked: boolean;\r\n /** Fecha de bloqueo (si aplica) */\r\n blockedSince?: string;\r\n}\r\n\r\n/**\r\n * Estado de los servidores de ARCA\r\n */\r\nexport interface ServiceStatus {\r\n /** Estado del servidor de aplicaciones */\r\n appServer: string;\r\n /** Estado del servidor de base de datos */\r\n dbServer: string;\r\n /** Estado del servidor de autenticación */\r\n authServer: string;\r\n}\r\n","import type { InvoiceItem } from '../types/wsfe';\r\n\r\n/**\r\n * Calcula el subtotal de items (sin IVA)\r\n */\r\nexport function calculateSubtotal(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && item.vatRate) {\r\n netPrice = item.unitPrice / (1 + (item.vatRate / 100));\r\n }\r\n return sum + (item.quantity * netPrice);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el IVA total de items\r\n */\r\nexport function calculateVAT(items: InvoiceItem[], includesVAT = false): number {\r\n return items.reduce((sum, item) => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n const netSubtotal = item.quantity * netPrice;\r\n return sum + (netSubtotal * rate / 100);\r\n }, 0);\r\n}\r\n\r\n/**\r\n * Calcula el total de la factura (subtotal + IVA)\r\n */\r\nexport function calculateTotal(items: InvoiceItem[], includesVAT = false): number {\r\n if (includesVAT) {\r\n return items.reduce((sum, item) => sum + (item.quantity * item.unitPrice), 0);\r\n }\r\n const subtotal = calculateSubtotal(items, false);\r\n const vat = calculateVAT(items, false);\r\n return subtotal + vat;\r\n}\r\n\r\n/**\r\n * Redondea a 2 decimales\r\n */\r\nexport function round(value: number): number {\r\n return Math.round(value * 100) / 100;\r\n}\r\n","import type { CAEResponse, Buyer } from '../types/wsfe';\r\nimport { TaxIdType } from '../types/wsfe';\r\n\r\n/**\r\n * Datos requeridos por ARCA para el QR (estructura oficial)\r\n * @see https://www.afip.gob.ar/fe/qr/especificaciones.asp\r\n */\r\ninterface AFIPQRData {\r\n ver: number;\r\n fecha: string;\r\n cuit: number;\r\n ptoVta: number;\r\n tipoCmp: number;\r\n nroCmp: number;\r\n importe: number;\r\n moneda: string;\r\n ctz: number;\r\n tipoDocRec?: number;\r\n nroDocRec?: number;\r\n tipoCodAut: string;\r\n codAut: number;\r\n}\r\n\r\n/**\r\n * Genera la URL completa con el código QR para un comprobante emitido.\r\n * Implementa la versión oficial con orden estricto de campos según spec de ARCA.\r\n *\r\n * @param caeResponse Respuesta obtenida al emitir la factura (CAEResponse)\r\n * @param issuerCUIT CUIT del emisor (con o sin guiones)\r\n * @param total Importe total del comprobante\r\n * @param buyer Datos del comprador (opcional)\r\n * @returns URL lista para embeber en un generador de QR\r\n */\r\nexport function generateQRUrl(\r\n caeResponse: CAEResponse,\r\n issuerCUIT: string,\r\n total: number,\r\n buyer?: Buyer\r\n): string {\r\n // Clean CUIT and CAE (digits only)\r\n const cleanCUIT = issuerCUIT.replace(/\\D/g, '');\r\n const cleanCAE = caeResponse.cae.replace(/\\D/g, '');\r\n\r\n // Format date to YYYY-MM-DD (ARCA returns YYYYMMDD as string or number)\r\n const rawDate = String(caeResponse.date); // Ensure string — fast-xml-parser may return number\r\n const formattedDate = rawDate.length === 8\r\n ? `${rawDate.substring(0, 4)}-${rawDate.substring(4, 6)}-${rawDate.substring(6, 8)}`\r\n : rawDate;\r\n\r\n // Buyer document info\r\n const docType = buyer?.docType || TaxIdType.FINAL_CONSUMER;\r\n const docNumber = buyer?.docNumber ? buyer.docNumber.replace(/\\D/g, '') : '0';\r\n\r\n // Build QR object with STRICT field order (required by ARCA spec)\r\n const qrData: any = {\r\n ver: 1,\r\n fecha: formattedDate,\r\n cuit: Number(cleanCUIT),\r\n ptoVta: Number(caeResponse.pointOfSale),\r\n tipoCmp: Number(caeResponse.invoiceType),\r\n nroCmp: Number(caeResponse.invoiceNumber),\r\n importe: Number(parseFloat(total.toFixed(2))),\r\n moneda: 'PES',\r\n ctz: 1,\r\n };\r\n\r\n // Omit buyer fields for anonymous final consumers\r\n if (docType !== TaxIdType.FINAL_CONSUMER || Number(docNumber) > 0) {\r\n qrData.tipoDocRec = Number(docType);\r\n qrData.nroDocRec = Number(docNumber);\r\n }\r\n\r\n qrData.tipoCodAut = 'E';\r\n qrData.codAut = Number(cleanCAE);\r\n\r\n // IMPORTANT: ARCA's scanner decodes raw base64, NOT URL-encoded base64.\r\n // Using encodeURIComponent here converts + to %2B and = to %3D, which\r\n // breaks ARCA's QR scanner. The raw base64 string must be used as-is.\r\n const jsonString = JSON.stringify(qrData);\r\n const base64 = typeof Buffer !== 'undefined'\r\n ? Buffer.from(jsonString).toString('base64')\r\n : btoa(jsonString);\r\n\r\n return `https://www.afip.gob.ar/fe/qr/?p=${base64}`;\r\n}\r\n","/**\r\n * Diccionario de errores comunes de ARCA/AFIP y sus soluciones.\r\n * Clave: código de error numérico o string retornado por ARCA.\r\n * Valor: sugerencia clara para el desarrollador.\r\n */\r\nexport const ARCA_ERROR_HINTS: Record<string | number, string> = {\r\n // === Autenticación WSAA ===\r\n 501: 'El certificado puede haber expirado o la relación CUIT/Servicio no está habilitada en el portal de ARCA.',\r\n 502: 'El ticket de acceso (TA) es inválido o ya expiró. Hacé wsaa.login() nuevamente.',\r\n 503: 'Error interno del servidor de autenticación de ARCA. Reintentá en unos minutos.',\r\n 1000: 'El CUIT informado no es válido o no corresponde al certificado usado.',\r\n 1001: 'El servicio solicitado no existe o el certificado no tiene autorización para usarlo.',\r\n 1003: 'El TRA (Ticket de Requerimiento de Acceso) tiene un formato inválido.',\r\n 1005: 'El TRA ya expiró antes de ser presentado. Verificá la hora del sistema.',\r\n\r\n // === WSFE — Puntos de venta y configuración ===\r\n 10048: 'El punto de venta no está dado de alta en ARCA. Dalo de alta como Webservice en el portal.',\r\n 10049: 'El punto de venta no está activo o está bloqueado.',\r\n\r\n // === WSFE — Comprobantes y montos ===\r\n 10015: 'Factura B: El importe supera el límite para consumidores finales anónimos. Identificá al comprador con CUIT/DNI.',\r\n 10016: 'El CUIT informado como receptor no es válido o no existe en el Padrón.',\r\n 600: 'No se pudo autorizar el comprobante. Revisá el campo `observations` en la respuesta para más detalle.',\r\n 601: 'El comprobante ya fue autorizado anteriormente. No emitas dos veces el mismo número.',\r\n 602: 'El número de comprobante es inválido o no es el correcto según el último autorizado.',\r\n\r\n // === WSFE — IVA ===\r\n 10043: 'La alícuota de IVA informada no existe o es incorrecta. Usá 3 (0%), 4 (10.5%), 5 (21%) o 6 (27%).',\r\n 10044: 'El importe de IVA no cuadra con la base imponible × alícuota.',\r\n\r\n // === Padrón ===\r\n PADRON_ERROR: 'El servicio de Padrón suele ser inestable en homologación. Reintentá en unos minutos.',\r\n CUIT_NOT_FOUND: 'El CUIT consultado no existe en el Padrón de ARCA.',\r\n};\r\n\r\n/**\r\n * Busca un hint para un código de error dado.\r\n * Retorna undefined si no hay sugerencia conocida para ese código.\r\n */\r\nexport function getArcaHint(code: string | number): string | undefined {\r\n return ARCA_ERROR_HINTS[code];\r\n}\r\n","import { getWsfeEndpoint } from '../constants/endpoints';\r\nimport { ArcaError, ArcaValidationError } from '../types/common';\r\nimport type {\r\n WsfeConfig,\r\n IssueInvoiceRequest,\r\n CAEResponse,\r\n InvoiceItem,\r\n Buyer,\r\n ServiceStatus,\r\n InvoiceDetails,\r\n PointOfSale,\r\n} from '../types/wsfe';\r\nimport {\r\n InvoiceType,\r\n BillingConcept,\r\n TaxIdType,\r\n} from '../types/wsfe';\r\nimport {\r\n calculateSubtotal,\r\n calculateVAT,\r\n calculateTotal,\r\n round,\r\n} from '../utils/calculations';\r\nimport { parseXml } from '../utils/xml';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { generateQRUrl } from '../utils/qr';\r\nimport { getArcaHint } from '../constants/errors';\r\n\r\n/**\r\n * Servicio de Facturación Electrónica WSFE v1\r\n *\r\n * @example\r\n * ```typescript\r\n * const wsfe = new WsfeService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * ticket: await wsaa.login(),\r\n * pointOfSale: 4,\r\n * });\r\n *\r\n * // Ticket C rápido\r\n * const cae = await wsfe.issueSimpleReceipt({ total: 1500 });\r\n * console.log('CAE:', cae.cae);\r\n * console.log('QR:', cae.qrUrl);\r\n *\r\n * // Factura A/B con IVA discriminado\r\n * const cae = await wsfe.issueInvoiceB({\r\n * items: [{ description: 'Servicio', quantity: 1, unitPrice: 1000, vatRate: 21 }],\r\n * buyer: { docType: TaxIdType.CUIT, docNumber: '20987654321' },\r\n * });\r\n * ```\r\n */\r\nexport class WsfeService {\r\n private config: WsfeConfig;\r\n\r\n constructor(config: WsfeConfig) {\r\n this.validateConfig(config);\r\n this.config = config;\r\n }\r\n\r\n private validateConfig(config: WsfeConfig): void {\r\n if (!config.ticket || !config.ticket.token) {\r\n throw new ArcaValidationError(\r\n 'Ticket WSAA requerido. Ejecutá wsaa.login() primero.',\r\n { hint: 'El ticket se obtiene del servicio WsaaService' }\r\n );\r\n }\r\n\r\n if (!config.pointOfSale || config.pointOfSale < 1 || config.pointOfSale > 9999) {\r\n throw new ArcaValidationError(\r\n 'Punto de venta inválido: debe ser un número entre 1 y 9999',\r\n { pointOfSale: config.pointOfSale }\r\n );\r\n }\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Estado de los servidores\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA (FEDummy).\r\n * No requiere autenticación. Útil para health checks.\r\n *\r\n * @param environment Ambiente a consultar (default: 'homologacion')\r\n */\r\n static async checkStatus(environment: 'homologacion' | 'produccion' = 'homologacion'): Promise<ServiceStatus> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEDummy/>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEDummy',\r\n },\r\n body: soapRequest,\r\n timeout: 10000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar estado: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEDummyResponse?.FEDummyResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEDummy inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n return {\r\n appServer: data.AppServer,\r\n dbServer: data.DbServer,\r\n authServer: data.AuthServer,\r\n };\r\n }\r\n\r\n /**\r\n * Verifica el estado de los servidores de ARCA.\r\n * Versión de instancia — usa el ambiente configurado.\r\n */\r\n async checkStatus(): Promise<ServiceStatus> {\r\n return WsfeService.checkStatus(this.config.environment);\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Emisión de comprobantes\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Emite un Ticket C simple (solo monto total, sin detalle de items).\r\n * Ideal para registros mínimos, como una app móvil de punto de venta.\r\n */\r\n async issueSimpleReceipt(params: {\r\n total: number;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n return this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total: params.total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * Emite un Ticket C con detalle de items.\r\n * Los items se guardan en la respuesta pero no se envían a ARCA.\r\n */\r\n async issueReceipt(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n const cae = await this.issueDocument({\r\n type: InvoiceType.TICKET_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n });\r\n\r\n return { ...cae, items: params.items };\r\n }\r\n\r\n /**\r\n * Emite una Factura C (consumidor final, sin discriminación de IVA).\r\n */\r\n async issueInvoiceC(params: {\r\n items: InvoiceItem[];\r\n concept?: BillingConcept;\r\n date?: Date;\r\n }): Promise<CAEResponse> {\r\n const total = round(calculateTotal(params.items));\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_C,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n total,\r\n date: params.date,\r\n buyer: {\r\n docType: TaxIdType.FINAL_CONSUMER,\r\n docNumber: '0',\r\n },\r\n items: params.items,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura B (con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceB(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_B,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n /**\r\n * Emite una Factura A (Responsable Inscripto a Responsable Inscripto, con IVA discriminado).\r\n * REQUIERE `vatRate` en todos los items.\r\n */\r\n async issueInvoiceA(params: {\r\n items: InvoiceItem[];\r\n buyer: Buyer;\r\n concept?: BillingConcept;\r\n date?: Date;\r\n includesVAT?: boolean;\r\n }): Promise<CAEResponse> {\r\n this.validateItemsWithVAT(params.items);\r\n const includesVAT = params.includesVAT || false;\r\n const vatData = this.calculateVATByRate(params.items, includesVAT);\r\n\r\n return this.issueDocument({\r\n type: InvoiceType.FACTURA_A,\r\n concept: params.concept || BillingConcept.PRODUCTS,\r\n items: params.items,\r\n buyer: params.buyer,\r\n date: params.date,\r\n vatData,\r\n includesVAT,\r\n });\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Consultas\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Consulta un comprobante ya emitido (FECompConsultar).\r\n *\r\n * @param type Tipo de comprobante\r\n * @param invoiceNumber Número de comprobante\r\n */\r\n async getInvoice(type: InvoiceType, invoiceNumber: number): Promise<InvoiceDetails> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompConsultar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCompConsReq>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n <ar:CbteNro>${invoiceNumber}</ar:CbteNro>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n </ar:FeCompConsReq>\r\n </ar:FECompConsultar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompConsultar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompConsultarResponse?.FECompConsultarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FECompConsultar inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const det = data.ResultGet;\r\n return {\r\n invoiceType: Number(det.CbteTipo),\r\n pointOfSale: Number(det.PtoVta),\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: String(det.CbteFch),\r\n concept: Number(det.Concepto),\r\n docType: Number(det.DocTipo),\r\n docNumber: Number(det.DocNro),\r\n total: Number(det.ImpTotal),\r\n net: Number(det.ImpNeto),\r\n vat: Number(det.ImpIVA),\r\n cae: String(det.CodAutorizacion),\r\n caeExpiry: String(det.FchVto),\r\n result: det.Resultado as 'A' | 'R',\r\n };\r\n }\r\n\r\n /**\r\n * Lista los puntos de venta habilitados para el CUIT autenticado (FEParamGetPtosVenta).\r\n */\r\n async getPointsOfSale(): Promise<PointOfSale[]> {\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FEParamGetPtosVenta>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n </ar:FEParamGetPtosVenta>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FEParamGetPtosVenta',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar puntos de venta: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FEParamGetPtosVentaResponse?.FEParamGetPtosVentaResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta FEParamGetPtosVenta inválida', 'PARSE_ERROR', { xml: responseXml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n throw new ArcaError(`Error ARCA: ${error?.Msg || 'Error desconocido'}`, 'ARCA_ERROR', data.Errors);\r\n }\r\n\r\n const raw = data.ResultGet?.PtoVenta;\r\n if (!raw) return [];\r\n\r\n const list = Array.isArray(raw) ? raw : [raw];\r\n return list.map((pv: Record<string, unknown>) => ({\r\n number: Number(pv.Nro),\r\n type: String(pv.EmisionTipo),\r\n isBlocked: pv.Bloqueado === 'S',\r\n blockedSince: pv.FchBaja ? String(pv.FchBaja) : undefined,\r\n }));\r\n }\r\n\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n // Métodos internos\r\n // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\r\n\r\n /**\r\n * Método genérico interno para emitir cualquier tipo de comprobante.\r\n */\r\n private async issueDocument(request: IssueInvoiceRequest): Promise<CAEResponse> {\r\n // 1. Get next invoice number\r\n const invoiceNumber = await this.getNextInvoiceNumber(request.type);\r\n\r\n // 2. Calculate totals\r\n let total = request.total || 0;\r\n let net = total;\r\n let vat = 0;\r\n\r\n if (request.items && request.items.length > 0) {\r\n const includesVAT = request.includesVAT || false;\r\n net = round(calculateSubtotal(request.items, includesVAT));\r\n vat = round(calculateVAT(request.items, includesVAT));\r\n total = round(calculateTotal(request.items, includesVAT));\r\n }\r\n\r\n if (total <= 0) {\r\n throw new ArcaValidationError('El monto total debe ser mayor a 0');\r\n }\r\n\r\n // 3. Build SOAP request\r\n const soapRequest = this.buildCAERequest({\r\n type: request.type,\r\n pointOfSale: this.config.pointOfSale,\r\n invoiceNumber,\r\n concept: request.concept,\r\n date: request.date || new Date(),\r\n buyer: request.buyer,\r\n net,\r\n vat,\r\n total,\r\n vatData: request.vatData,\r\n });\r\n\r\n // 4. Send to ARCA\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECAESolicitar',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(\r\n `Error HTTP al comunicarse con WSFE: ${response.status}`,\r\n 'HTTP_ERROR',\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const responseXml = await response.text();\r\n\r\n // 5. Parse CAE response\r\n const result = await this.parseCAEResponse(responseXml);\r\n\r\n // 6. Generate QR URL\r\n const qrUrl = generateQRUrl(result, this.config.cuit, total, request.buyer);\r\n\r\n return {\r\n ...result,\r\n items: request.items,\r\n vat: request.vatData,\r\n qrUrl,\r\n };\r\n }\r\n\r\n /**\r\n * Obtiene el próximo número de comprobante disponible (FECompUltimoAutorizado + 1)\r\n */\r\n private async getNextInvoiceNumber(type: InvoiceType): Promise<number> {\r\n const soapRequest = this.buildLastInvoiceRequest(type);\r\n const endpoint = getWsfeEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': 'http://ar.gov.afip.dif.FEV1/FECompUltimoAutorizado',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaError(`Error HTTP al consultar último comprobante: ${response.status}`, 'HTTP_ERROR');\r\n }\r\n\r\n const responseXml = await response.text();\r\n const result = parseXml(responseXml);\r\n const data = result?.Envelope?.Body?.FECompUltimoAutorizadoResponse?.FECompUltimoAutorizadoResult;\r\n\r\n if (data?.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const lastNumber = data?.CbteNro;\r\n return typeof lastNumber === 'number' ? lastNumber + 1 : 1;\r\n }\r\n\r\n /**\r\n * Valida que todos los items tengan alícuota IVA definida\r\n */\r\n private validateItemsWithVAT(items: InvoiceItem[]): void {\r\n const missingVAT = items.filter(item =>\r\n item.vatRate === undefined || item.vatRate === null\r\n );\r\n\r\n if (missingVAT.length > 0) {\r\n throw new ArcaValidationError(\r\n 'Esta operación requiere `vatRate` en todos los items',\r\n {\r\n itemsMissingVAT: missingVAT.map(i => i.description),\r\n hint: 'Agregá vatRate a cada item (21, 10.5, 27, o 0)'\r\n }\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Calcula el IVA agrupado por alícuota (requerido por ARCA para Factura A/B)\r\n */\r\n private calculateVATByRate(items: InvoiceItem[], includesVAT = false): {\r\n rate: number;\r\n taxBase: number;\r\n amount: number;\r\n }[] {\r\n const byRate = new Map<number, { base: number; amount: number }>();\r\n\r\n items.forEach(item => {\r\n const rate = item.vatRate || 0;\r\n let netPrice = item.unitPrice;\r\n\r\n if (includesVAT && rate) {\r\n netPrice = item.unitPrice / (1 + (rate / 100));\r\n }\r\n\r\n const base = item.quantity * netPrice;\r\n const amount = base * rate / 100;\r\n\r\n const current = byRate.get(rate) || { base: 0, amount: 0 };\r\n byRate.set(rate, {\r\n base: current.base + base,\r\n amount: current.amount + amount,\r\n });\r\n });\r\n\r\n return Array.from(byRate.entries()).map(([rate, values]) => ({\r\n rate,\r\n taxBase: round(values.base),\r\n amount: round(values.amount),\r\n }));\r\n }\r\n\r\n /**\r\n * Mapea alícuota % al código interno de ARCA\r\n */\r\n private getVATCode(percentage: number): number {\r\n const map: Record<number, number> = {\r\n 0: 3,\r\n 10.5: 4,\r\n 21: 5,\r\n 27: 6,\r\n };\r\n\r\n const code = map[percentage];\r\n if (code === undefined) {\r\n throw new ArcaValidationError(\r\n `Alícuota IVA inválida: ${percentage}%`,\r\n {\r\n validRates: [0, 10.5, 21, 27],\r\n hint: 'Usá una de las alícuotas oficiales de Argentina'\r\n }\r\n );\r\n }\r\n\r\n return code;\r\n }\r\n\r\n private buildCAERequest(params: {\r\n type: InvoiceType;\r\n pointOfSale: number;\r\n invoiceNumber: number;\r\n concept: BillingConcept;\r\n date: Date;\r\n buyer?: IssueInvoiceRequest['buyer'];\r\n net: number;\r\n vat: number;\r\n total: number;\r\n vatData?: IssueInvoiceRequest['vatData'];\r\n }): string {\r\n const dateStr = params.date.toISOString().split('T')[0].replace(/-/g, '');\r\n\r\n let vatXml = '';\r\n if (params.vatData && params.vatData.length > 0) {\r\n vatXml = '<ar:Iva>';\r\n params.vatData.forEach(entry => {\r\n vatXml += `\r\n <ar:AlicIva>\r\n <ar:Id>${this.getVATCode(entry.rate)}</ar:Id>\r\n <ar:BaseImp>${entry.taxBase.toFixed(2)}</ar:BaseImp>\r\n <ar:Importe>${entry.amount.toFixed(2)}</ar:Importe>\r\n </ar:AlicIva>`;\r\n });\r\n vatXml += '\\n </ar:Iva>';\r\n }\r\n\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECAESolicitar>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:FeCAEReq>\r\n <ar:FeCabReq>\r\n <ar:CantReg>1</ar:CantReg>\r\n <ar:PtoVta>${params.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${params.type}</ar:CbteTipo>\r\n </ar:FeCabReq>\r\n <ar:FeDetReq>\r\n <ar:FECAEDetRequest>\r\n <ar:Concepto>${params.concept}</ar:Concepto>\r\n <ar:DocTipo>${params.buyer?.docType || 99}</ar:DocTipo>\r\n <ar:DocNro>${params.buyer?.docNumber || 0}</ar:DocNro>\r\n <ar:CbteDesde>${params.invoiceNumber}</ar:CbteDesde>\r\n <ar:CbteHasta>${params.invoiceNumber}</ar:CbteHasta>\r\n <ar:CbteFch>${dateStr}</ar:CbteFch>\r\n <ar:ImpTotal>${params.total.toFixed(2)}</ar:ImpTotal>\r\n <ar:ImpTotConc>0.00</ar:ImpTotConc>\r\n <ar:ImpNeto>${params.net.toFixed(2)}</ar:ImpNeto>\r\n <ar:ImpOpEx>0.00</ar:ImpOpEx>\r\n <ar:ImpIVA>${params.vat.toFixed(2)}</ar:ImpIVA>\r\n <ar:ImpTrib>0.00</ar:ImpTrib>\r\n <ar:MonId>PES</ar:MonId>\r\n <ar:MonCotiz>1</ar:MonCotiz>\r\n ${vatXml}\r\n </ar:FECAEDetRequest>\r\n </ar:FeDetReq>\r\n </ar:FeCAEReq>\r\n </ar:FECAESolicitar>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private buildLastInvoiceRequest(type: InvoiceType): string {\r\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:ar=\"http://ar.gov.afip.dif.FEV1/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <ar:FECompUltimoAutorizado>\r\n <ar:Auth>\r\n <ar:Token>${this.config.ticket.token}</ar:Token>\r\n <ar:Sign>${this.config.ticket.sign}</ar:Sign>\r\n <ar:Cuit>${this.config.cuit}</ar:Cuit>\r\n </ar:Auth>\r\n <ar:PtoVta>${this.config.pointOfSale}</ar:PtoVta>\r\n <ar:CbteTipo>${type}</ar:CbteTipo>\r\n </ar:FECompUltimoAutorizado>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n }\r\n\r\n private async parseCAEResponse(xml: string): Promise<CAEResponse> {\r\n const result = parseXml(xml);\r\n const data = result?.Envelope?.Body?.FECAESolicitarResponse?.FECAESolicitarResult;\r\n\r\n if (!data) {\r\n throw new ArcaError('Respuesta WSFE inválida: estructura no reconocida', 'PARSE_ERROR', { xml });\r\n }\r\n\r\n if (data.Errors) {\r\n const error = Array.isArray(data.Errors.Err) ? data.Errors.Err[0] : data.Errors.Err;\r\n const code = error?.Code || 'UNKNOWN';\r\n throw new ArcaError(\r\n `Error ARCA: ${error?.Msg || 'Error desconocido'}`,\r\n 'ARCA_ERROR',\r\n data.Errors,\r\n getArcaHint(code)\r\n );\r\n }\r\n\r\n const cab = data.FeCabResp;\r\n const det = Array.isArray(data.FeDetResp.FECAEDetResponse)\r\n ? data.FeDetResp.FECAEDetResponse[0]\r\n : data.FeDetResp.FECAEDetResponse;\r\n\r\n if (!det) {\r\n throw new ArcaError('Respuesta WSFE incompleta: falta detalle del comprobante', 'PARSE_ERROR');\r\n }\r\n\r\n const observations: string[] = [];\r\n if (det.Observaciones) {\r\n const obsArray = Array.isArray(det.Observaciones.Obs)\r\n ? det.Observaciones.Obs\r\n : [det.Observaciones.Obs];\r\n obsArray.forEach((o: { Msg: string }) => observations.push(o.Msg));\r\n }\r\n\r\n return {\r\n invoiceType: Number(cab.CbteTipo),\r\n pointOfSale: Number(cab.PtoVta),\r\n invoiceNumber: Number(det.CbteDesde),\r\n date: String(det.CbteFch),\r\n cae: String(det.CAE),\r\n caeExpiry: String(det.CAEFchVto),\r\n result: det.Resultado,\r\n observations: observations.length > 0 ? observations : undefined,\r\n };\r\n }\r\n}\r\n","import { WsaaService } from '../auth/wsaa';\r\nimport { getPadronEndpoint } from '../constants/endpoints';\r\nimport { ArcaNetworkError, ArcaError } from '../types/common';\r\nimport type {\r\n TaxpayerServiceConfig,\r\n Taxpayer,\r\n TaxpayerResponse,\r\n Address,\r\n Activity,\r\n TaxRecord,\r\n} from '../types/padron';\r\nimport { callArcaApi } from '../utils/network';\r\nimport { XMLParser } from 'fast-xml-parser';\r\n\r\n/**\r\n * Servicio para consultar el Padrón de AFIP (ws_sr_padron_a13)\r\n *\r\n * @example\r\n * ```typescript\r\n * const padron = new PadronService({\r\n * environment: 'homologacion',\r\n * cuit: '20123456789',\r\n * cert: fs.readFileSync('cert.pem', 'utf-8'),\r\n * key: fs.readFileSync('key.pem', 'utf-8'),\r\n * });\r\n *\r\n * const { taxpayer, error } = await padron.getTaxpayer('30111111118');\r\n * if (taxpayer) {\r\n * console.log(taxpayer.companyName || `${taxpayer.firstName} ${taxpayer.lastName}`);\r\n * console.log('¿Inscripto IVA?:', taxpayer.isVATRegistered);\r\n * }\r\n * ```\r\n */\r\nexport class PadronService {\r\n private wsaa: WsaaService;\r\n private config: TaxpayerServiceConfig;\r\n\r\n constructor(config: TaxpayerServiceConfig) {\r\n this.config = config;\r\n this.wsaa = new WsaaService({\r\n environment: config.environment,\r\n cuit: config.cuit,\r\n cert: config.cert,\r\n key: config.key,\r\n service: 'ws_sr_padron_a13',\r\n storage: config.storage,\r\n });\r\n }\r\n\r\n /**\r\n * Consulta los datos de un contribuyente por CUIT\r\n *\r\n * @param taxId CUIT a consultar (11 dígitos sin guiones)\r\n * @returns Datos del contribuyente o mensaje de error\r\n */\r\n async getTaxpayer(taxId: string): Promise<TaxpayerResponse> {\r\n const ticket = await this.wsaa.login();\r\n\r\n const soapRequest = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" \r\n xmlns:a13=\"http://a13.soap.ws.server.puc.sr/\">\r\n <soapenv:Header/>\r\n <soapenv:Body>\r\n <a13:getPersona>\r\n <token>${ticket.token}</token>\r\n <sign>${ticket.sign}</sign>\r\n <cuitRepresentada>${this.config.cuit}</cuitRepresentada>\r\n <idPersona>${taxId}</idPersona>\r\n </a13:getPersona>\r\n </soapenv:Body>\r\n</soapenv:Envelope>`;\r\n\r\n const endpoint = getPadronEndpoint(this.config.environment);\r\n\r\n const response = await callArcaApi(endpoint, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'text/xml; charset=utf-8',\r\n 'SOAPAction': '',\r\n },\r\n body: soapRequest,\r\n timeout: this.config.timeout || 15000,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ArcaNetworkError(\r\n `Error HTTP al comunicarse con Padrón A13: ${response.status}`,\r\n { status: response.status }\r\n );\r\n }\r\n\r\n const xml = await response.text();\r\n return this.parseResponse(xml);\r\n }\r\n\r\n /**\r\n * Parsea la respuesta XML de getPersona\r\n */\r\n private parseResponse(xml: string): TaxpayerResponse {\r\n const parser = new XMLParser({\r\n ignoreAttributes: false,\r\n removeNSPrefix: true,\r\n });\r\n const result = parser.parse(xml);\r\n\r\n const body = result.Envelope?.Body;\r\n if (!body) {\r\n throw new ArcaError('Respuesta del Padrón inválida: Body no encontrado', 'PADRON_ERROR');\r\n }\r\n\r\n const response = body.getPersonaResponse?.personaReturn;\r\n if (!response) {\r\n const fault = body.Fault;\r\n if (fault) {\r\n return { error: fault.faultstring || 'Error desconocido en ARCA' };\r\n }\r\n return { error: 'No se encontraron datos para el CUIT informado' };\r\n }\r\n\r\n if (response.errorConstancia) {\r\n return { error: response.errorConstancia };\r\n }\r\n\r\n const p = response.persona;\r\n if (!p) {\r\n return { error: 'CUIT no encontrado' };\r\n }\r\n\r\n const taxpayer: Taxpayer = {\r\n taxId: Number(p.idPersona),\r\n personType: p.tipoPersona as 'FISICA' | 'JURIDICA',\r\n firstName: p.nombre,\r\n lastName: p.apellido,\r\n companyName: p.razonSocial,\r\n status: p.estadoClave,\r\n addresses: this.mapAddresses(p.domicilio),\r\n activities: this.mapActivities(p.actividad),\r\n taxes: this.mapTaxRecords(p.impuesto),\r\n mainActivity: p.descripcionActividadPrincipal,\r\n isVATRegistered: this.hasTaxId(p, 30), // 30 = IVA\r\n isMonotax: this.hasTaxId(p, 20), // 20 = Monotributo\r\n isVATExempt: this.hasTaxId(p, 32), // 32 = IVA Exento\r\n };\r\n\r\n return { taxpayer };\r\n }\r\n\r\n private mapAddresses(raw: unknown): Address[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n street: item.direccion as string,\r\n city: item.localidad as string | undefined,\r\n postalCode: item.codPostal as string | undefined,\r\n provinceId: Number(item.idProvincia),\r\n province: item.descripcionProvincia as string,\r\n type: item.tipoDomicilio as string,\r\n }));\r\n }\r\n\r\n private mapActivities(raw: unknown): Activity[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idActividad),\r\n description: item.descripcion as string,\r\n order: Number(item.orden),\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private mapTaxRecords(raw: unknown): TaxRecord[] {\r\n if (!raw) return [];\r\n return this.toArray(raw).map((item: Record<string, unknown>) => ({\r\n id: Number(item.idImpuesto),\r\n description: item.descripcion as string,\r\n period: Number(item.periodo),\r\n }));\r\n }\r\n\r\n private hasTaxId(p: Record<string, unknown>, id: number): boolean {\r\n const taxes = p.impuesto;\r\n if (!taxes) return false;\r\n return this.toArray(taxes).some((i: Record<string, unknown>) => Number(i.idImpuesto) === id);\r\n }\r\n\r\n /**\r\n * Normaliza un valor que puede ser un objeto único o un array (comportamiento de fast-xml-parser)\r\n */\r\n private toArray(data: unknown): Record<string, unknown>[] {\r\n if (data === undefined || data === null) return [];\r\n if (Array.isArray(data)) return data as Record<string, unknown>[];\r\n return [data as Record<string, unknown>];\r\n }\r\n}\r\n"],"mappings":"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","names":["InvoiceType","BillingConcept","TaxIdType","XMLParser"]}
|