@ramiidv/arca-agro 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +211 -179
  2. package/dist/arca-agro.d.ts +25 -140
  3. package/dist/arca-agro.d.ts.map +1 -1
  4. package/dist/arca-agro.js +69 -264
  5. package/dist/arca-agro.js.map +1 -1
  6. package/dist/constants.d.ts +34 -8
  7. package/dist/constants.d.ts.map +1 -1
  8. package/dist/constants.js +34 -11
  9. package/dist/constants.js.map +1 -1
  10. package/dist/context.d.ts +13 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +2 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/cpe-client.d.ts +95 -51
  15. package/dist/cpe-client.d.ts.map +1 -1
  16. package/dist/cpe-client.js +236 -228
  17. package/dist/cpe-client.js.map +1 -1
  18. package/dist/cpe-schemas.d.ts +76 -0
  19. package/dist/cpe-schemas.d.ts.map +1 -0
  20. package/dist/cpe-schemas.js +512 -0
  21. package/dist/cpe-schemas.js.map +1 -0
  22. package/dist/cpe-types.d.ts +599 -0
  23. package/dist/cpe-types.d.ts.map +1 -0
  24. package/dist/cpe-types.js +2 -0
  25. package/dist/cpe-types.js.map +1 -0
  26. package/dist/errors.d.ts +38 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +53 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/index.d.ts +10 -10
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +8 -13
  33. package/dist/index.js.map +1 -1
  34. package/dist/lpg-client.d.ts +64 -43
  35. package/dist/lpg-client.d.ts.map +1 -1
  36. package/dist/lpg-client.js +215 -175
  37. package/dist/lpg-client.js.map +1 -1
  38. package/dist/lpg-schemas.d.ts +50 -0
  39. package/dist/lpg-schemas.d.ts.map +1 -0
  40. package/dist/lpg-schemas.js +478 -0
  41. package/dist/lpg-schemas.js.map +1 -0
  42. package/dist/lpg-types.d.ts +470 -0
  43. package/dist/lpg-types.d.ts.map +1 -0
  44. package/dist/lpg-types.js +2 -0
  45. package/dist/lpg-types.js.map +1 -0
  46. package/dist/schema.d.ts +90 -0
  47. package/dist/schema.d.ts.map +1 -0
  48. package/dist/schema.js +301 -0
  49. package/dist/schema.js.map +1 -0
  50. package/dist/types.d.ts +33 -455
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/validation.d.ts +22 -43
  53. package/dist/validation.d.ts.map +1 -1
  54. package/dist/validation.js +31 -134
  55. package/dist/validation.js.map +1 -1
  56. package/llms.txt +78 -159
  57. package/package.json +6 -7
  58. package/dist/ctg-client.d.ts +0 -56
  59. package/dist/ctg-client.d.ts.map +0 -1
  60. package/dist/ctg-client.js +0 -214
  61. package/dist/ctg-client.js.map +0 -1
package/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # @ramiidv/arca-agro
2
2
 
3
- SDK para los servicios web agropecuarios de ARCA (ex AFIP), Argentina. Integra tres servicios en un solo paquete:
3
+ SDK para los servicios web agropecuarios de ARCA (ex AFIP), Argentina:
4
4
 
5
- - **WSCPE** - Carta de Porte Electrónica (transporte de granos por vía automotor)
6
- - **WSCTG** - Código de Trazabilidad de Granos (seguimiento del transporte)
7
- - **WSLPG** - Liquidación Primaria de Granos (liquidaciones y certificaciones)
5
+ - **WSCPE**: Carta de Porte Electrónica (granos, automotor y ferroviaria). Reemplazó al CTG (RG 5017/2021).
6
+ - **WSLPG**: Liquidación Primaria de Granos y certificación primaria.
7
+
8
+ > **WSCTG ya no existe.** El Código de Trazabilidad de Granos fue derogado el 1/11/2021 y reemplazado por la Carta de Porte Electrónica; sus endpoints responden 404. Desde la versión 0.3.0 este paquete no lo incluye. El número de CTG ahora lo asigna WSCPE al autorizar la CPE (`cabecera.nroCTG`).
8
9
 
9
10
  ## Instalación
10
11
 
@@ -15,256 +16,287 @@ npm install @ramiidv/arca-agro @ramiidv/arca-common
15
16
  ## Requisitos
16
17
 
17
18
  - Node.js >= 18
18
- - Certificado digital y clave privada emitidos por ARCA
19
- - Autorización en los servicios `wscpe`, `wsctg` y/o `wslpg` en WSAA
19
+ - Certificado digital y clave privada emitidos por ARCA, autorizados en WSAA para `wscpe` y/o `wslpg`.
20
20
 
21
21
  ## Inicio rápido
22
22
 
23
23
  ```ts
24
- import { ArcaAgro } from '@ramiidv/arca-agro';
25
24
  import fs from 'node:fs';
25
+ import { FileTicketStorage } from '@ramiidv/arca-common';
26
+ import { ArcaAgro, TIPO_CPE } from '@ramiidv/arca-agro';
26
27
 
27
28
  const agro = new ArcaAgro({
28
- cuit: 20123456789,
29
+ cuit: '20-12345678-6', // CUIT representada (se valida el dígito verificador)
29
30
  cert: fs.readFileSync('cert.pem', 'utf-8'),
30
31
  key: fs.readFileSync('key.pem', 'utf-8'),
31
32
  production: false, // true para producción
33
+ ticketStorage: new FileTicketStorage('.arca-tickets'), // recomendado: persiste el TA entre reinicios
32
34
  });
33
35
  ```
34
36
 
35
- La autenticación WSAA se maneja automáticamente. Los tokens se cachean y renuevan según sea necesario.
37
+ La autenticación WSAA es automática: el ticket se cachea y se renueva cuando vence.
36
38
 
37
- ## WSCPE - Carta de Porte Electrónica
39
+ Todos los métodos aceptan un último argumento opcional `{ signal }` (`AbortSignal`) para cancelar la llamada.
38
40
 
39
- ```ts
40
- // Autorizar una carta de porte
41
- const resultado = await agro.cpe.autorizarCPEAutomotor({
42
- cuitTitularCartaPorte: 20123456789,
43
- sucursal: 1,
44
- nroOrden: 1,
45
- codTipoCartaPorte: 1,
46
- codGrano: 23, // soja
47
- codLocalidadProcedencia: 10001,
48
- codProvProcedencia: 1,
49
- codLocalidadDestino: 20001,
50
- codProvDestino: 12,
51
- cuitDestino: 30111222333,
52
- plantaDestino: 1,
53
- pesoNeto: 30000,
54
- pesoBruto: 32000,
55
- pesoTara: 2000,
56
- patente: 'ABC123',
57
- cuitTransportista: 20999888777,
58
- fechaEmision: '2026-03-31',
59
- });
41
+ ## WSCPE: Carta de Porte Electrónica
60
42
 
61
- // Confirmar arribo
62
- await agro.cpe.confirmadoArriboCPE({
63
- nroCTG: resultado.nroCTG!,
64
- nroCartaPorte: resultado.nroCartaPorte!,
65
- cuitDestino: 30111222333,
66
- pesoNeto: 29800,
67
- fechaArribo: '2026-04-01',
68
- });
43
+ Los requests siguen el XSD oficial de WSCPE (mismos nombres y anidamiento). El SDK arma el XML en el orden del XSD, valida los datos antes de enviarlos y devuelve objetos tipados.
44
+
45
+ Tipos de carta de porte (`TIPO_CPE`): `74` automotor, `75` ferroviaria, `274` automotor flete corto.
46
+
47
+ ### Autorizar una CPE automotor
69
48
 
70
- // Consultar CPEs
71
- const cpes = await agro.cpe.consultarCPE({
72
- fechaDesde: '2026-03-01',
73
- fechaHasta: '2026-03-31',
74
- codGrano: 23,
49
+ ```ts
50
+ const sucursal = 1;
51
+ const nroOrden = await agro.cpe.siguienteNroOrden(sucursal, TIPO_CPE.AUTOMOTOR);
52
+
53
+ const cpe = await agro.cpe.autorizarCPEAutomotor({
54
+ cabecera: { tipoCP: TIPO_CPE.AUTOMOTOR, cuitSolicitante: '20123456786', sucursal, nroOrden },
55
+ origen: { productor: { codProvincia: 1, codLocalidad: 10270 } }, // o { operador: { codProvincia, codLocalidad, planta } }
56
+ correspondeRetiroProductor: false,
57
+ esSolicitanteCampo: true,
58
+ datosCarga: { codGrano: 23, cosecha: 2526, pesoBruto: 42000, pesoTara: 12000 },
59
+ destino: { cuit: '30500011129', esDestinoCampo: false, codProvincia: 12, codLocalidad: 5244, planta: 1938 },
60
+ destinatario: { cuit: '30500011129' },
61
+ transporte: {
62
+ cuitTransportista: '20999888772',
63
+ dominio: ['AB123CD'],
64
+ fechaHoraPartida: new Date('2026-11-02T08:00:00-03:00'),
65
+ kmRecorrer: 250,
66
+ cuitChofer: '27300000008',
67
+ tarifa: 1500.5,
68
+ cuitPagadorFlete: '30712345671',
69
+ mercaderiaFumigada: false,
70
+ },
75
71
  });
76
72
 
77
- // Rechazar / Anular
78
- await agro.cpe.rechazoCPE({ nroCTG: 12345, nroCartaPorte: 67890, codMotivo: 1 });
79
- await agro.cpe.anularCPE({ nroCTG: 12345, nroCartaPorte: 67890, codMotivo: 2 });
73
+ cpe.cabecera.nroCTG; // '010100012345' (string)
74
+ cpe.cabecera.estado; // 'AC'
75
+ cpe.pdf; // constancia en base64
76
+ ```
80
77
 
81
- // Obtener constancia PDF (base64)
82
- const pdfBase64 = await agro.cpe.consultarConstanciaCPEPDF(12345);
78
+ > **`siguienteNroOrden` no es atómico.** Hace `consultarUltNroOrden + 1`: dos procesos que lo llamen a la vez obtienen el mismo número y ARCA rechaza la segunda autorización. Si emitís en paralelo para la misma sucursal y tipo, serializá las emisiones o llevá tu propio contador.
83
79
 
84
- // Obtener siguiente número de orden
85
- const nroOrden = await agro.cpe.siguienteNroOrden(1);
80
+ ### Circuito automotor
86
81
 
87
- // Estado del servicio
88
- const status = await agro.cpe.dummy();
82
+ ```ts
83
+ const cartaPorte = { tipoCPE: TIPO_CPE.AUTOMOTOR, sucursal: 1, nroOrden: 15 };
84
+
85
+ await agro.cpe.confirmarArriboCPE({ cuitSolicitante, cartaPorte });
86
+ await agro.cpe.confirmacionDefinitivaCPEAutomotor({ cuitSolicitante, cartaPorte, pesoBrutoDescarga: 41900, pesoTaraDescarga: 12000 });
87
+ await agro.cpe.descargadoDestinoCPE({ cuitSolicitante, cartaPorte });
88
+ await agro.cpe.rechazoCPE({ cuitSolicitante, cartaPorte, rechazoMotivo: 2, rechazoObservaciones: 'Humedad' });
89
+ await agro.cpe.anularCPE({ cartaPorte, anulacionMotivo: 3, anulacionObservaciones: 'Error de carga' });
90
+ await agro.cpe.editarCPEAutomotor({ nroCTG, cuitDestinatario, cuitChofer, cuitTransportista, destino, pesoBruto, codGrano });
91
+ await agro.cpe.editarCPEConfirmadaAutomotor({ nroCTG, intervinientes: { cuitCorredorVentaPrimaria } });
92
+ await agro.cpe.nuevoDestinoDestinatarioCPEAutomotor({ cartaPorte, destino, transporte: { fechaHoraPartida, kmRecorrer } });
93
+ await agro.cpe.regresoOrigenCPEAutomotor({ cartaPorte, transporte: { fechaHoraPartida, kmRecorrer } });
94
+ await agro.cpe.desvioCPEAutomotor({ cuitSolicitante, cartaPorte, destino, transporte });
95
+ await agro.cpe.informarContingencia({ cartaPorte, contingencia: { concepto: 'C', descripcion: 'Desperfecto mecánico' } });
96
+ await agro.cpe.cerrarContingenciaCPE({ cartaPorte, concepto: 'A' });
97
+
98
+ const detalle = await agro.cpe.consultarCPEAutomotor({ nroCTG: '010100012345' }); // o { cartaPorte }
89
99
  ```
90
100
 
91
- ## WSCTG - Código de Trazabilidad de Granos
101
+ Las operaciones que modifican una CPE devuelven `CPEResultado` (`{ cabecera?, pdf?, metadata? }`).
92
102
 
93
- ```ts
94
- // Solicitar un CTG
95
- const ctg = await agro.ctg.solicitarCTGInicial({
96
- nroCartaPorte: 67890,
97
- codEspecie: 23,
98
- cuitDestino: 30111222333,
99
- cuitDestinatario: 30111222333,
100
- codLocalidadOrigen: 10001,
101
- codLocalidadDestino: 20001,
102
- codCosecha: 2526,
103
- pesoNeto: 30000,
104
- });
103
+ ### Circuito ferroviario
105
104
 
106
- // Confirmar arribo
107
- await agro.ctg.confirmarArribo({
108
- nroCTG: ctg.nroCTG!,
109
- nroCartaPorte: 67890,
110
- cuitDestino: 30111222333,
111
- pesoNeto: 29800,
112
- fechaArribo: '2026-04-01',
113
- });
105
+ `autorizarCPEFerroviaria`, `consultarCPEFerroviaria`, `editarCPEFerroviaria`, `editarCPEConfirmadaFerroviaria`, `confirmacionDefinitivaCPEFerroviaria`, `nuevoDestinoDestinatarioCPEFerroviaria`, `regresoOrigenCPEFerroviaria`, `desvioCPEFerroviaria` y `consultaCPEFerroviariaPorNroOperativo`.
114
106
 
115
- // Consultar CTGs
116
- const ctgs = await agro.ctg.consultarCTG({
117
- fechaDesde: '2026-03-01',
118
- fechaHasta: '2026-03-31',
119
- });
107
+ ### Consultas y paramétricas
120
108
 
121
- // Exportar a Excel (base64)
122
- const excelBase64 = await agro.ctg.consultarCTGExcel({
123
- fechaDesde: '2026-03-01',
124
- fechaHasta: '2026-03-31',
125
- });
109
+ ```ts
110
+ await agro.cpe.consultarUltNroOrden(1, TIPO_CPE.AUTOMOTOR); // número; si ARCA no lo devuelve, lanza
111
+ await agro.cpe.consultarCPEPorDestino({ planta: 1938, fechaPartidaDesde: '2026-11-01', fechaPartidaHasta: '2026-11-07' });
112
+ await agro.cpe.consultarCPEPPendientesDeResolucion({ perfil: 'D', planta: 1938 });
113
+ await agro.cpe.consultarProvincias();
114
+ await agro.cpe.consultarLocalidadesPorProvincia(12);
115
+ await agro.cpe.consultarTiposGrano();
116
+ await agro.cpe.consultarPlantas('30500011129');
117
+ await agro.cpe.consultarLocalidadesProductor('20123456786');
118
+ await agro.cpe.consultarCategoriasSemillas();
119
+ await agro.cpe.consultarVariedadesSemillas(23);
120
+ await agro.cpe.dummy();
121
+ ```
126
122
 
127
- // Rechazar / Anular
128
- await agro.ctg.rechazarCTG({ nroCTG: 123, nroCartaPorte: 456, codMotivo: 1 });
129
- await agro.ctg.anularCTG({ nroCTG: 123, nroCartaPorte: 456, codMotivo: 2 });
123
+ Las listas sin resultados devuelven `[]`; si ARCA devuelve errores, se lanza `ArcaAgroServiceError` (nunca una lista vacía).
130
124
 
131
- // CTGs activos
132
- const activos = await agro.ctg.obtenerCTGActivos();
125
+ ### No soportado en WSCPE
133
126
 
134
- // Constancia PDF (base64)
135
- const pdf = await agro.ctg.consultarConstanciaCTGPDF(12345);
127
+ El circuito de **derivados granarios** (CPE DG, tipos 284-287: `autorizarCPEAutomotorDG`, `autorizarCPEFerroviariaDG`, `autorizarCPEDuctosDG`, `autorizarCPEEmisionDestinoDG`, etc.), `consultarCPEDuctos`, `consultarRenspa`, `consultarDomiciliosPorCUIT` y las paramétricas de DG (`consultarTiposEmbalaje`, `consultarUnidadesMedida`, `consultarDerivadosGranarios`, `consultarPlantasDG`) todavía no están implementados.
136
128
 
137
- // Estado del servicio
138
- const status = await agro.ctg.dummy();
139
- ```
129
+ ## WSLPG: Liquidación Primaria de Granos
140
130
 
141
- ## WSLPG - Liquidación Primaria de Granos
131
+ `liquidacion` sigue `LpgLiquidacionBaseType` del XSD; `deducciones`, `retenciones` y `percepciones` van como hermanos (arrays).
142
132
 
143
133
  ```ts
144
- // Autorizar una liquidación
145
- const liq = await agro.lpg.liquidacionAutorizar({
146
- cuitComprador: 30111222333,
147
- cuitVendedor: 20123456789,
148
- codGrano: 23,
149
- pesoNeto: 30000,
150
- precioRefTn: 350000,
134
+ const ptoEmision = 1;
135
+ const nroOrden = (await agro.lpg.liquidacionUltimoNroOrdenConsultar(ptoEmision)) + 1;
136
+
137
+ const { autorizacion, eventos } = await agro.lpg.liquidacionAutorizar({
138
+ liquidacion: {
139
+ ptoEmision,
140
+ nroOrden,
141
+ cuitComprador: '20123456786',
142
+ nroActComprador: 40,
143
+ nroIngBrutoComprador: 901234567,
144
+ codTipoOperacion: '1',
145
+ codPuerto: 14,
146
+ codGrano: 31,
147
+ cuitVendedor: '30712345671',
148
+ nroIngBrutoVendedor: 900123,
149
+ liquidaCorredor: 'N',
150
+ fechaPrecioOperacion: '2026-10-30',
151
+ precioRefTn: 250000,
152
+ precioFleteTn: 0,
153
+ campaniaPPal: 2526,
154
+ codLocalidadProcedencia: 3,
155
+ codProvProcedencia: 1,
156
+ pesoNetoSinCertificado: 30000,
157
+ },
158
+ deducciones: [{ codigoConcepto: 'CO', comisionGastosAdm: 1.5, alicuotaIva: 21 }],
159
+ retenciones: [{ codigoConcepto: 'RG', baseCalculo: 7500000, alicuota: 2 }],
151
160
  });
152
161
 
153
- // Consultar liquidaciones
154
- const liquidaciones = await agro.lpg.liquidacionConsultar({
155
- fechaDesde: '2026-03-01',
156
- fechaHasta: '2026-03-31',
157
- });
162
+ autorizacion.coe; // '330100012345' (string)
163
+ autorizacion.totalNetoAPagar; // number
164
+ ```
158
165
 
159
- // Anular liquidación
160
- await agro.lpg.liquidacionAnular(1, 100);
166
+ Los códigos de actividad, operación, puerto, grano, deducción y retención salen de las paramétricas.
161
167
 
162
- // Ajuste unificado
168
+ ```ts
169
+ await agro.lpg.liquidacionXCoeConsultar(coe, { pdf: true }); // { liquidacion, autorizacion, pdf, eventos }
170
+ await agro.lpg.liquidacionXNroOrdenConsultar(ptoEmision, nroOrden);
171
+ await agro.lpg.liquidacionAnular(coe); // { coe, resultado, pdf?, eventos }
163
172
  await agro.lpg.liquidacionAjustarUnificado({
164
- nroOrdenOriginal: 100,
165
- ptoEmisionOriginal: 1,
166
- tipoAjuste: 'credito',
167
- liquidacion: { pesoNeto: 29500 },
173
+ ajusteBase: { ptoEmision, nroOrden, coeAjustado: coe, codLocalidad: 3, codProv: 1 },
174
+ ajusteDebito: { diferenciaPesoNeto: 0, diferenciaPrecioOperacion: 1000, diferenciaPrecioFleteTn: 0 },
168
175
  });
169
176
 
170
- // Autorizar certificación
171
- const cert = await agro.lpg.certificacionAutorizar({
172
- tipoCertificacion: 1,
173
- cuitDepositante: 20123456789,
174
- codGrano: 23,
175
- pesoNeto: 30000,
176
- });
177
+ // Certificación primaria
178
+ await agro.lpg.cgConsultarUltimoNroOrden(ptoEmision);
179
+ await agro.lpg.cgAutorizar({ cabecera: { ... }, primaria: { ... } }); // o retiroTransferencia / preexistente
180
+ await agro.lpg.cgSolicitarAnulacion(coe);
181
+ await agro.lpg.cgConfirmarAnulacion(coe, { pdf: true });
182
+
183
+ // Paramétricas
184
+ await agro.lpg.tipoGranoConsultar();
185
+ await agro.lpg.puertoConsultar();
186
+ await agro.lpg.provinciasConsultar();
187
+ await agro.lpg.localidadXProvinciaConsultar(1);
188
+ await agro.lpg.tipoActividadConsultar();
189
+ await agro.lpg.tipoActividadRepresentadoConsultar();
190
+ await agro.lpg.tipoOperacionXActividadConsultar(40);
191
+ await agro.lpg.tipoDeduccionConsultar();
192
+ await agro.lpg.tipoRetencionConsultar();
193
+ await agro.lpg.tipoCertificadoDepositoConsultar();
194
+ await agro.lpg.codigoGradoReferenciaConsultar();
195
+ await agro.lpg.codigoGradoEntregadoXTipoGranoConsultar(2);
196
+ await agro.lpg.campaniasConsultar();
197
+ await agro.lpg.dummy();
198
+ ```
177
199
 
178
- // Anular certificación
179
- await agro.lpg.certificacionAnular(1, cert.nroCertificacion!);
200
+ ### No soportado en WSLPG
180
201
 
181
- // Consultar parámetros (tipos de grano, grados, puertos, etc.)
182
- const granos = await agro.lpg.consultarParametros('tipoGranoConsultar');
202
+ Liquidación secundaria (`lsg*`), anticipos (`lpgAutorizarAnticipo`, `lpgCancelarAnticipo`), anulación contra documento, ajuste por contrato (`liquidacionAjustarContrato`, `asociarLiquidacionAContrato`, `*PorContratoConsultar`, `ajusteXCoeConsultar`, `ajusteXNroOrdenConsultar`) y el resto de las operaciones de certificación (`cgBuscarCtg`, `cgBuscarCertConSaldoDisponible`, `cgConsultarXCoe`, `cgConsultarXNroOrden`, `cgInformarCalidad`).
183
203
 
184
- // Estado del servicio
185
- const status = await agro.lpg.dummy();
186
- ```
204
+ ## Errores
187
205
 
188
- ## Verificar todos los servicios
206
+ | Error | Cuándo |
207
+ |-------|--------|
208
+ | `ArcaValidationError` | Datos inválidos, antes de llamar a ARCA: campo obligatorio faltante, campo desconocido, CUIT con dígito verificador incorrecto, `NaN`/`Infinity`, rangos y largos del XSD, fechas. `details[]` trae cada campo con su ruta (ej: `transporte.dominio[0]`). |
209
+ | `ArcaAgroServiceError` (extiende `ArcaServiceError`) | ARCA rechazó la operación: `errores.error[]` (y en WSLPG también `erroresFormato.error[]`). `errors[]`, `service`, `method` y `response` (el nodo completo devuelto). |
210
+ | `ArcaSoapError` | Red, timeout, HTTP o SOAP Fault. `uncertain` indica si ARCA pudo haber procesado el request. |
211
+ | `ArcaAgroResponseError` | La respuesta no trae un dato imprescindible (ej: `nroCTG` al autorizar, `coe` al liquidar, `nroOrden` al consultar el último). `uncertain` es `true` en emisiones. |
212
+ | `ArcaAuthError` / `ArcaTicketVigenteError` | Errores de WSAA. |
189
213
 
190
- ```ts
191
- const status = await agro.serverStatus();
192
- // { cpe: { appserver, dbserver, authserver }, ctg: { ... }, lpg: { ... } }
193
- ```
214
+ Los montos se redondean a los decimales del XSD (`fractionDigits`). Las fechas `xsd:date` aceptan `Date` o `AAAAMMDD`/`AAAA-MM-DD`; las `xsd:dateTime` aceptan `Date` (se envía en hora de Argentina, `-03:00`) o un string ISO-8601.
194
215
 
195
- ## Clientes de bajo nivel
216
+ En las respuestas, los campos `xs:string` (ej: `codigo` de las paramétricas) son `string`, los IDs largos (`nroCTG`, `coe`) son `string`, los CUIT y montos son `number`.
196
217
 
197
- Para control total sobre la autenticación, se pueden usar los clientes individuales directamente:
218
+ ## Emisiones y reintentos
198
219
 
199
- ```ts
200
- import { CpeClient, CtgClient, LpgClient } from '@ramiidv/arca-agro';
201
- import { WsaaClient } from '@ramiidv/arca-common';
220
+ Las operaciones que crean o modifican algo en ARCA **nunca se reintentan**:
202
221
 
203
- const wsaa = new WsaaClient({ cert, key, production: false });
204
- const cpeClient = new CpeClient(false, { timeoutMs: 60000 });
222
+ - WSCPE: `autorizarCPEAutomotor`, `autorizarCPEFerroviaria`, `confirmarArriboCPE`, `confirmacionDefinitivaCPE*`, `descargadoDestinoCPE`, `rechazoCPE`, `anularCPE`, `editarCPE*`, `nuevoDestinoDestinatarioCPE*`, `regresoOrigenCPE*`, `desvioCPE*`, `informarContingencia`, `cerrarContingenciaCPE`.
223
+ - WSLPG: `liquidacionAutorizar`, `liquidacionAnular`, `liquidacionAjustarUnificado`, `cgAutorizar`, `cgSolicitarAnulacion`, `cgConfirmarAnulacion`.
205
224
 
206
- const ticket = await wsaa.getAccessTicket('wscpe');
207
- const auth = { Token: ticket.token, Sign: ticket.sign, Cuit: 20123456789 };
225
+ Las consultas se reintentan ante errores transitorios (`retries`, default 1).
208
226
 
209
- const resultado = await cpeClient.autorizarCPEAutomotor(auth, { ... });
210
- ```
227
+ ### Recuperar una emisión incierta
211
228
 
212
- ## Eventos
229
+ Si una emisión falla con `error.uncertain === true` (timeout, conexión cortada, HTTP 5xx, SOAP Fault, respuesta incompleta), ARCA pudo haberla procesado. **No reintentes a ciegas**: consultá primero.
230
+
231
+ - **CPE** (manual WSCPE §1.3): `consultarUltNroOrden(sucursal, tipoCPE)`. Si es `>=` al `nroOrden` que enviaste, la CPE se autorizó: obtenela con `consultarCPEAutomotor({ cartaPorte: { tipoCPE, sucursal, nroOrden } })` (o `consultarCPEFerroviaria`). Si no, reintentá con el mismo `nroOrden`. Para las demás operaciones, consultá la CPE y mirá `cabecera.estado`.
232
+ - **Liquidación**: `liquidacionUltimoNroOrdenConsultar(ptoEmision)` y `liquidacionXNroOrdenConsultar(ptoEmision, nroOrden)`. Para anulaciones y ajustes, `liquidacionXCoeConsultar(coe)` y mirá `autorizacion.estado`.
233
+ - **Certificación**: `cgConsultarUltimoNroOrden(ptoEmision)`.
213
234
 
214
235
  ```ts
215
- agro.on('auth:login', (e) => console.log(`Login ${e.service} en ${e.durationMs}ms`));
216
- agro.on('request:end', (e) => console.log(`${e.method} completado en ${e.durationMs}ms`));
217
- agro.on('request:retry', (e) => console.warn(`Reintento #${e.attempt}: ${e.error}`));
218
- agro.on('request:error', (e) => console.error(`Error en ${e.method}: ${e.error}`));
236
+ try {
237
+ return await agro.cpe.autorizarCPEAutomotor(params);
238
+ } catch (e) {
239
+ if (!((e instanceof ArcaSoapError || e instanceof ArcaAgroResponseError) && e.uncertain)) throw e;
240
+ const { tipoCP, sucursal, nroOrden } = params.cabecera;
241
+ if ((await agro.cpe.consultarUltNroOrden(sucursal, tipoCP)) >= nroOrden) {
242
+ return agro.cpe.consultarCPEAutomotor({ cartaPorte: { tipoCPE: tipoCP, sucursal, nroOrden } });
243
+ }
244
+ return agro.cpe.autorizarCPEAutomotor(params); // no se emitió
245
+ }
219
246
  ```
220
247
 
221
- ## Manejo de errores
248
+ ## Estado de los servicios
222
249
 
223
250
  ```ts
224
- import {
225
- ArcaAuthError,
226
- ArcaSoapError,
227
- ArcaServiceError,
228
- } from '@ramiidv/arca-agro';
251
+ const estado = await agro.serverStatus();
252
+ // { cpe: { ok: true, status: { appserver, dbserver, authserver } }, lpg: { ok: false, error } }
253
+ ```
229
254
 
230
- try {
231
- await agro.cpe.autorizarCPEAutomotor({ ... });
232
- } catch (error) {
233
- if (error instanceof ArcaServiceError) {
234
- // Errores de negocio (datos inválidos, CPE rechazada, etc.)
235
- console.error('Errores:', error.errors);
236
- } else if (error instanceof ArcaSoapError) {
237
- // Error de comunicación SOAP / HTTP
238
- console.error('Error SOAP:', error.message, error.statusCode);
239
- } else if (error instanceof ArcaAuthError) {
240
- // Error de autenticación WSAA
241
- console.error('Error auth:', error.message);
242
- }
243
- }
255
+ Usa `Promise.allSettled`: la caída de un servicio no oculta el estado del otro.
256
+
257
+ ## Eventos
258
+
259
+ ```ts
260
+ agro.on('auth:login', (e) => console.log(`Login ${e.service}`));
261
+ agro.on('request:end', (e) => console.log(`${e.method} en ${e.durationMs}ms`));
262
+ agro.on('request:retry', (e) => console.warn(`Reintento #${e.attempt}`));
263
+ agro.on('request:error', (e) => console.error(`Error en ${e.method}`));
244
264
  ```
245
265
 
266
+ También se puede pasar `onEvent` en la configuración. Los errores de los handlers se ignoran.
267
+
246
268
  ## Configuración
247
269
 
270
+ `ArcaAgroConfig` extiende `ArcaBaseConfig` de `@ramiidv/arca-common`.
271
+
248
272
  | Opción | Tipo | Default | Descripción |
249
273
  |--------|------|---------|-------------|
250
- | `cuit` | `number` | **requerido** | CUIT del contribuyente |
251
- | `cert` | `string` | **requerido** | Certificado X.509 en formato PEM |
252
- | `key` | `string` | **requerido** | Clave privada en formato PEM |
253
- | `production` | `boolean` | `false` | Usar entorno de producción |
254
- | `tokenTTLMinutes` | `number` | `720` | Tiempo de vida del token WSAA (minutos) |
255
- | `requestTimeoutMs` | `number` | `30000` | Timeout para requests HTTP (ms) |
256
- | `retries` | `number` | `1` | Reintentos en errores transitorios |
274
+ | `cuit` | `number \| string` | **requerido** | CUIT representada (con o sin guiones) |
275
+ | `cert` / `key` | `string` | **requerido** | Certificado y clave privada PEM |
276
+ | `production` | `boolean` | `false` | Entorno de producción |
277
+ | `timeout` | `number` | `30000` | Timeout HTTP (ms) |
278
+ | `retries` | `number` | `1` | Reintentos de consultas (las emisiones nunca se reintentan) |
257
279
  | `retryDelayMs` | `number` | `1000` | Delay base entre reintentos (ms) |
258
- | `onEvent` | `function` | `undefined` | Callback para eventos del SDK |
280
+ | `tokenTTLMinutes` | `number` | `720` | Vida del ticket WSAA |
281
+ | `ticketStorage` | `TicketStorage` | memoria | Persistencia del ticket WSAA (recomendado en producción) |
282
+ | `clockOffsetMs` / `autoClockSkew` | | `0` / `true` | Desfase de reloj con ARCA |
283
+ | `loginErrorCooldownMs` | `number` | `60000` | Espera tras un login WSAA fallido |
284
+ | `fetch` | `typeof fetch` | global | `fetch` propio (proxy, tests) |
285
+ | `legacyTls` | `'auto' \| 'never' \| 'always'` | `'auto'` | Transporte TLS legacy |
286
+ | `endpoints` | `{ cpe?, lpg?, wsaa? }` | oficiales | Endpoints propios |
287
+ | `onEvent` | `function` | | Callback de eventos |
288
+
289
+ `clearAuthCache()` (async) invalida los tickets de WSCPE y WSLPG.
259
290
 
260
291
  ## Endpoints
261
292
 
262
293
  | Servicio | Homologación | Producción |
263
294
  |----------|-------------|------------|
264
- | WSCPE | `https://fwshomo.afip.gov.ar/wscpe/services/soap` | `https://serviciosjava.afip.gob.ar/wscpe/services/soap` |
265
- | WSCTG | `https://fwshomo.afip.gov.ar/wsctg/services/CTGService_v4.0` | `https://serviciosjava.afip.gob.ar/wsctg/services/CTGService_v4.0` |
295
+ | WSCPE | `https://cpea-ws-qaext.afip.gob.ar/wscpe/services/soap` | `https://cpea-ws.afip.gob.ar/wscpe/services/soap` |
266
296
  | WSLPG | `https://fwshomo.afip.gov.ar/wslpg/LpgService` | `https://serviciosjava.afip.gob.ar/wslpg/LpgService` |
267
297
 
298
+ Namespaces: WSCPE `https://serviciosjava.afip.gob.ar/wscpe/`, WSLPG `http://serviciosjava.afip.gob.ar/wslpg/`.
299
+
268
300
  ## Licencia
269
301
 
270
302
  MIT