@ramiidv/arca-agro 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +229 -202
  3. package/dist/cpe-client.d.ts +14 -2
  4. package/dist/cpe-client.d.ts.map +1 -1
  5. package/dist/cpe-client.js +60 -48
  6. package/dist/cpe-client.js.map +1 -1
  7. package/dist/cpe-schemas.d.ts +12 -0
  8. package/dist/cpe-schemas.d.ts.map +1 -1
  9. package/dist/cpe-schemas.js +16 -0
  10. package/dist/cpe-schemas.js.map +1 -1
  11. package/dist/cpe-types.d.ts +25 -6
  12. package/dist/cpe-types.d.ts.map +1 -1
  13. package/dist/errors.d.ts +30 -6
  14. package/dist/errors.d.ts.map +1 -1
  15. package/dist/errors.js +39 -11
  16. package/dist/errors.js.map +1 -1
  17. package/dist/index.d.ts +7 -6
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +3 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/internal.d.ts +49 -0
  22. package/dist/internal.d.ts.map +1 -0
  23. package/dist/internal.js +184 -0
  24. package/dist/internal.js.map +1 -0
  25. package/dist/lpg-client.d.ts +42 -6
  26. package/dist/lpg-client.d.ts.map +1 -1
  27. package/dist/lpg-client.js +130 -59
  28. package/dist/lpg-client.js.map +1 -1
  29. package/dist/lpg-schemas.d.ts +18 -0
  30. package/dist/lpg-schemas.d.ts.map +1 -1
  31. package/dist/lpg-schemas.js +227 -50
  32. package/dist/lpg-schemas.js.map +1 -1
  33. package/dist/lpg-types.d.ts +178 -11
  34. package/dist/lpg-types.d.ts.map +1 -1
  35. package/dist/schema.d.ts +7 -3
  36. package/dist/schema.d.ts.map +1 -1
  37. package/dist/schema.js +10 -5
  38. package/dist/schema.js.map +1 -1
  39. package/dist/types.d.ts +10 -1
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/validation.d.ts +17 -2
  42. package/dist/validation.d.ts.map +1 -1
  43. package/dist/validation.js +29 -2
  44. package/dist/validation.js.map +1 -1
  45. package/llms.txt +88 -62
  46. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e33abdd: Auditoría contra el Manual WSCPE v2.0.3 y el Manual WSLPG.
8
+
9
+ **Cambio de comportamiento: errores admitidos (WSCPE 550, WSLPG 1021).** "Error al generar el archivo pdf" no cancela la operación (estado Aceptada, manual WSCPE §2.4 y §2.6). Antes se lanzaba `ArcaAgroServiceError` y una CPE o liquidación ya autorizada parecía rechazada (reintentarla podía duplicarla). Ahora el método devuelve el resultado, sin `pdf`, con el error en el nuevo campo `advertencias: ServiceErrorDetail[]` (presente solo si hubo). Si viene junto con otro error, se sigue lanzando con todos.
10
+
11
+ Errores e incertidumbre:
12
+
13
+ - `ArcaAgroServiceError` tiene `uncertain`: es `true` en una emisión cuya respuesta trae errores **y también** el resultado (`cabecera.nroCTG`/`cabecera.estado` en WSCPE; `autorizacion.coe`, `ajusteUnificado.coe` o `resultado: 'A'` en WSLPG). Consultá antes de reintentar.
14
+ - Un `<error>` sin código (o con código vacío) ahora cuenta como error; solo se ignora el código explícito `0`.
15
+ - `liquidacionAnular` lanza `ArcaAgroServiceError` si ARCA responde `resultado: 'R'` (rechazada).
16
+ - `resultado` de `liquidacionAnular` y `estadoCertificado` de `cgSolicitarAnulacion`/`cgConfirmarAnulacion` son opcionales (`minOccurs=0` en el XSD): si no vienen, la anulación ya no termina en un `ArcaAgroResponseError` incierto. Los tipos pasan a `resultado?: 'A' | 'R' | string` y `estadoCertificado?: string`.
17
+ - En las emisiones, un campo secundario de la respuesta con forma inválida se omite en lugar de volver incierta una operación aceptada; solo la falta del identificador (`nroCTG`, `coe`) es incierta.
18
+ - Nuevo `cpeFaultException(error)`: lee el `Exception` (`businessErrorId`, `uuid`, ...) del SOAP Fault de WSCPE desde `ArcaSoapError.faultDetail`.
19
+
20
+ Nuevas operaciones:
21
+
22
+ - WSLPG, para recuperar emisiones inciertas: `cgConsultarXNroOrden`, `cgConsultarXCoe`, `ajusteXNroOrdenConsultar`, `ajusteXCoeConsultar`. También `ajustePorContratoConsultar`, `liquidacionPorContratoConsultar`, `cgBuscarCtg` y `cgBuscarCertConSaldoDisponible`.
23
+ - WSCPE: `consultarRenspa`, `consultarDomiciliosPorCUIT`, `consultarTiposEmbalaje` y `consultarUnidadesMedida`.
24
+ - Validadores: `validateCgAutorizar`, `validateEditarCPEAutomotor`, `validateEditarCPEFerroviaria`, `validateEditarCPEConfirmada`, `validateConfirmacionDefinitivaCPEAutomotor` y `validateConfirmacionDefinitivaCPEFerroviaria`.
25
+ - Se reexportan `FileTicketStorage`, `MemoryTicketStorage` y `WsaaClient`.
26
+
27
+ Otros:
28
+
29
+ - `cgAutorizar`: `cabecera.cuitCorredor` acepta `0` (sin corredor, `LpgCuit0Type`); una CUIT distinta de 0 se sigue validando.
30
+ - README y llms.txt reescritos: recetas de recuperación corregidas (certificación con `cgConsultarXNroOrden`; ajuste con `liquidacionUltimoNroOrdenConsultar` + `ajusteXNroOrdenConsultar`, que comparten el contador; en WSCPE, comparar los datos de la CPE consultada antes de darla por propia), lista de operaciones no implementadas y nota sobre el formato `dateTime`. Los ejemplos hacen el arribo y la confirmación con la instancia del destino.
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies [b152f08]
35
+ - @ramiidv/arca-common@0.7.0
36
+
3
37
  ## 0.5.0
4
38
 
5
39
  ### Minor Changes
package/README.md CHANGED
@@ -1,55 +1,50 @@
1
1
  # @ramiidv/arca-agro
2
2
 
3
- SDK para los servicios web agropecuarios de ARCA (ex AFIP), Argentina:
3
+ [![npm](https://img.shields.io/npm/v/@ramiidv/arca-agro)](https://www.npmjs.com/package/@ramiidv/arca-agro)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node >= 20.19](https://img.shields.io/badge/node-%3E%3D20.19-brightgreen)](https://nodejs.org)
4
6
 
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
+ SDK en TypeScript para los web services agropecuarios de **ARCA** (ex AFIP):
7
8
 
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`).
9
+ - **WSCPE**: Carta de Porte Electrónica de granos (automotor y ferroviaria). Reemplazó al CTG (RG 5017/2021).
10
+ - **WSLPG**: Liquidación Primaria de Granos, ajustes y certificación primaria.
11
+
12
+ Los requests siguen el XSD de los WSDL oficiales (mismos nombres y anidamiento): el SDK arma el XML en el orden del XSD, valida los datos antes de enviarlos y devuelve objetos tipados. La autenticación con WSAA es automática.
13
+
14
+ Fuentes: [Manual WSCPE v2.0.3](https://www.afip.gob.ar/ws/documentos/manual_wscpe_version-2-0-3.pdf), [Manual WSLPG](https://www.afip.gob.ar/ws/WSLiquiGranos/manual-wslpg.pdf) y los WSDL de homologación.
15
+
16
+ > **WSCTG ya no existe.** El Código de Trazabilidad de Granos se derogó el 1/11/2021 y sus endpoints responden 404. El número de CTG ahora lo asigna WSCPE al autorizar la carta de porte (`cabecera.nroCTG`).
9
17
 
10
18
  ## Instalación
11
19
 
12
20
  ```bash
13
- npm install @ramiidv/arca-agro @ramiidv/arca-common
21
+ npm install @ramiidv/arca-agro
14
22
  ```
15
23
 
16
24
  ## Requisitos
17
25
 
18
- - Node.js >= 18
19
- - Certificado digital y clave privada emitidos por ARCA, autorizados en WSAA para `wscpe` y/o `wslpg`.
26
+ - Node >= 20.19. Solo ESM; desde CommonJS se carga con `require()` (require(esm)).
27
+ - Certificado digital X.509 y clave privada de ARCA, con los servicios **`wscpe`** y/o **`wslpg`** asociados
28
+ - **Homologación**: [WSASS](https://wsass-homo.afip.gob.ar/wsass/portal/main.aspx)
29
+ - **Producción**: [Administración de Certificados Digitales](https://www.afip.gob.ar/ws/documentacion/certificados.asp)
20
30
 
21
31
  ## Inicio rápido
22
32
 
23
33
  ```ts
24
34
  import fs from 'node:fs';
25
- import { FileTicketStorage } from '@ramiidv/arca-common';
26
- import { ArcaAgro, TIPO_CPE } from '@ramiidv/arca-agro';
35
+ import { ArcaAgro, FileTicketStorage, TIPO_CPE } from '@ramiidv/arca-agro';
27
36
 
28
37
  const agro = new ArcaAgro({
29
38
  cuit: '20-12345678-6', // CUIT representada (se valida el dígito verificador)
30
39
  cert: fs.readFileSync('cert.pem', 'utf-8'),
31
40
  key: fs.readFileSync('key.pem', 'utf-8'),
32
- production: false, // true para producción
41
+ production: false,
33
42
  ticketStorage: new FileTicketStorage('.arca-tickets'), // recomendado: persiste el TA entre reinicios
34
43
  });
35
- ```
36
-
37
- La autenticación WSAA es automática: el ticket se cachea y se renueva cuando vence.
38
-
39
- Todos los métodos aceptan un último argumento opcional `{ signal }` (`AbortSignal`) para cancelar la llamada.
40
44
 
41
- ## WSCPE: Carta de Porte Electrónica
42
-
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
48
-
49
- ```ts
45
+ // Carta de Porte automotor
50
46
  const sucursal = 1;
51
47
  const nroOrden = await agro.cpe.siguienteNroOrden(sucursal, TIPO_CPE.AUTOMOTOR);
52
-
53
48
  const cpe = await agro.cpe.autorizarCPEAutomotor({
54
49
  cabecera: { tipoCP: TIPO_CPE.AUTOMOTOR, cuitSolicitante: '20123456786', sucursal, nroOrden },
55
50
  origen: { productor: { codProvincia: 1, codLocalidad: 10270 } }, // o { operador: { codProvincia, codLocalidad, planta } }
@@ -69,99 +64,15 @@ const cpe = await agro.cpe.autorizarCPEAutomotor({
69
64
  mercaderiaFumigada: false,
70
65
  },
71
66
  });
67
+ console.log(cpe.cabecera.nroCTG, cpe.cabecera.estado); // '010100012345' 'AC'
68
+ if (cpe.pdf) fs.writeFileSync(`cpe-${cpe.cabecera.nroCTG}.pdf`, Buffer.from(cpe.pdf, 'base64'));
72
69
 
73
- cpe.cabecera.nroCTG; // '010100012345' (string)
74
- cpe.cabecera.estado; // 'AC'
75
- cpe.pdf; // constancia en base64
76
- ```
77
-
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.
79
-
80
- ### Circuito automotor
81
-
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({
87
- cuitSolicitante,
88
- cartaPorte,
89
- pesoBrutoDescarga: 41900,
90
- pesoTaraDescarga: 12000,
91
- });
92
- await agro.cpe.descargadoDestinoCPE({ cuitSolicitante, cartaPorte });
93
- await agro.cpe.rechazoCPE({ cuitSolicitante, cartaPorte, rechazoMotivo: 2, rechazoObservaciones: 'Humedad' });
94
- await agro.cpe.anularCPE({ cartaPorte, anulacionMotivo: 3, anulacionObservaciones: 'Error de carga' });
95
- await agro.cpe.editarCPEAutomotor({
96
- nroCTG,
97
- cuitDestinatario,
98
- cuitChofer,
99
- cuitTransportista,
100
- destino,
101
- pesoBruto,
102
- codGrano,
103
- });
104
- await agro.cpe.editarCPEConfirmadaAutomotor({ nroCTG, intervinientes: { cuitCorredorVentaPrimaria } });
105
- await agro.cpe.nuevoDestinoDestinatarioCPEAutomotor({
106
- cartaPorte,
107
- destino,
108
- transporte: { fechaHoraPartida, kmRecorrer },
109
- });
110
- await agro.cpe.regresoOrigenCPEAutomotor({ cartaPorte, transporte: { fechaHoraPartida, kmRecorrer } });
111
- await agro.cpe.desvioCPEAutomotor({ cuitSolicitante, cartaPorte, destino, transporte });
112
- await agro.cpe.informarContingencia({
113
- cartaPorte,
114
- contingencia: { concepto: 'C', descripcion: 'Desperfecto mecánico' },
115
- });
116
- await agro.cpe.cerrarContingenciaCPE({ cartaPorte, concepto: 'A' });
117
-
118
- const detalle = await agro.cpe.consultarCPEAutomotor({ nroCTG: '010100012345' }); // o { cartaPorte }
119
- ```
120
-
121
- Las operaciones que modifican una CPE devuelven `CPEResultado` (`{ cabecera?, pdf?, metadata? }`).
122
-
123
- ### Circuito ferroviario
124
-
125
- `autorizarCPEFerroviaria`, `consultarCPEFerroviaria`, `editarCPEFerroviaria`, `editarCPEConfirmadaFerroviaria`, `confirmacionDefinitivaCPEFerroviaria`, `nuevoDestinoDestinatarioCPEFerroviaria`, `regresoOrigenCPEFerroviaria`, `desvioCPEFerroviaria` y `consultaCPEFerroviariaPorNroOperativo`.
126
-
127
- ### Consultas y paramétricas
128
-
129
- ```ts
130
- await agro.cpe.consultarUltNroOrden(1, TIPO_CPE.AUTOMOTOR); // número; si ARCA no lo devuelve, lanza
131
- await agro.cpe.consultarCPEPorDestino({
132
- planta: 1938,
133
- fechaPartidaDesde: '2026-11-01',
134
- fechaPartidaHasta: '2026-11-07',
135
- });
136
- await agro.cpe.consultarCPEPPendientesDeResolucion({ perfil: 'D', planta: 1938 });
137
- await agro.cpe.consultarProvincias();
138
- await agro.cpe.consultarLocalidadesPorProvincia(12);
139
- await agro.cpe.consultarTiposGrano();
140
- await agro.cpe.consultarPlantas('30500011129');
141
- await agro.cpe.consultarLocalidadesProductor('20123456786');
142
- await agro.cpe.consultarCategoriasSemillas();
143
- await agro.cpe.consultarVariedadesSemillas(23);
144
- await agro.cpe.dummy();
145
- ```
146
-
147
- Las listas sin resultados devuelven `[]`; si ARCA devuelve errores, se lanza `ArcaAgroServiceError` (nunca una lista vacía).
148
-
149
- ### No soportado en WSCPE
150
-
151
- 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.
152
-
153
- ## WSLPG: Liquidación Primaria de Granos
154
-
155
- `liquidacion` sigue `LpgLiquidacionBaseType` del XSD; `deducciones`, `retenciones` y `percepciones` van como hermanos (arrays).
156
-
157
- ```ts
70
+ // Liquidación primaria de granos
158
71
  const ptoEmision = 1;
159
- const nroOrden = (await agro.lpg.liquidacionUltimoNroOrdenConsultar(ptoEmision)) + 1;
160
-
161
- const { autorizacion, eventos } = await agro.lpg.liquidacionAutorizar({
72
+ const { autorizacion } = await agro.lpg.liquidacionAutorizar({
162
73
  liquidacion: {
163
74
  ptoEmision,
164
- nroOrden,
75
+ nroOrden: (await agro.lpg.liquidacionUltimoNroOrdenConsultar(ptoEmision)) + 1,
165
76
  cuitComprador: '20123456786',
166
77
  nroActComprador: 40,
167
78
  nroIngBrutoComprador: 901234567,
@@ -182,144 +93,260 @@ const { autorizacion, eventos } = await agro.lpg.liquidacionAutorizar({
182
93
  deducciones: [{ codigoConcepto: 'CO', comisionGastosAdm: 1.5, alicuotaIva: 21 }],
183
94
  retenciones: [{ codigoConcepto: 'RG', baseCalculo: 7500000, alicuota: 2 }],
184
95
  });
96
+ console.log(autorizacion.coe, autorizacion.totalNetoAPagar); // '330100012345' 8130274.01
97
+ ```
98
+
99
+ > **`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. Lo mismo vale para el número de orden de WSLPG.
185
100
 
186
- autorizacion.coe; // '330100012345' (string)
187
- autorizacion.totalNetoAPagar; // number
101
+ ## Configuración
102
+
103
+ `ArcaAgroConfig` extiende `ArcaSdkConfig` de `@ramiidv/arca-common`:
104
+
105
+ | Opción | Tipo | Default | Descripción |
106
+ | ------------------------------------------------------------------------------------ | ------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------- |
107
+ | `cert`, `key` | `string` | — | Certificado y clave privada (PEM) |
108
+ | `keyPassphrase` | `string` | — | Contraseña de la clave, si está encriptada |
109
+ | `cuit` | `number \| string` | — | CUIT representada (con o sin guiones); se valida el dígito verificador |
110
+ | `production` | `boolean` | `false` | Homologación o producción |
111
+ | `timeout` | `number` | `30000` | Timeout HTTP (ms) |
112
+ | `retries` / `retryDelayMs` | `number` | `1` / `1000` | Reintentos de **consultas** (las emisiones nunca se reintentan) |
113
+ | `tokenTTLMinutes` | `number` | `720` | Vigencia del TRA pedida a WSAA |
114
+ | `ticketStorage` | `TicketStorage` | memoria | Persistencia del TA (recomendado en producción: `FileTicketStorage` o propio) |
115
+ | `clockOffsetMs`, `autoClockSkew`, `loginErrorCooldownMs`, `permanentErrorCooldownMs` | | | Opciones de WSAA (ver `@ramiidv/arca-common`) |
116
+ | `fetch` | `typeof fetch` | `globalThis.fetch` | `fetch` propio (proxy, tests) |
117
+ | `legacyTls` | `'auto' \| 'never' \| 'always'` | `'auto'` | Transporte TLS legacy |
118
+ | `onEvent` | `(e: ArcaEvent) => void` | — | Eventos `auth:*` y `request:*` |
119
+ | `wsaa` | `WsaaClient` | — | `WsaaClient` compartido con otros SDKs (mismo certificado); tiene que ser del mismo entorno (`production`) |
120
+ | `signal` | `AbortSignal` | — | Cancela todas las llamadas de la instancia (ej: al apagar la app); se combina con el `signal` de cada llamada |
121
+ | `endpoints` | `{ cpe?, lpg?, wsaa? }` | oficiales | Endpoints propios (ej: un proxy) |
122
+
123
+ Todos los métodos aceptan un último parámetro opcional `opts?: CallOptions` (`{ signal }`) para cancelar la llamada. `clearAuthCache()` (async) invalida los tickets de WSCPE y WSLPG; `status()` consulta el `dummy` de los dos servicios en paralelo (con `statusOf` de common: la caída de uno no oculta el estado del otro).
124
+
125
+ ## API
126
+
127
+ ### WSCPE (`agro.cpe`)
128
+
129
+ Tipos de carta de porte (`TIPO_CPE`): `74` automotor, `75` ferroviaria, `274` automotor flete corto. Estados: `ESTADOS_CPE`.
130
+
131
+ **Emisiones** (nunca se reintentan). `autorizar*` devuelve el detalle de la CPE (`cabecera.nroCTG` siempre presente); el resto devuelve `CPEResultado` (`{ cabecera?, pdf?, metadata?, advertencias? }`).
132
+
133
+ | Circuito | Métodos |
134
+ | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
135
+ | Automotor | `autorizarCPEAutomotor`, `editarCPEAutomotor`, `editarCPEConfirmadaAutomotor`, `confirmarArriboCPE`, `confirmacionDefinitivaCPEAutomotor`, `descargadoDestinoCPE`, `rechazoCPE`, `anularCPE`, `nuevoDestinoDestinatarioCPEAutomotor`, `regresoOrigenCPEAutomotor`, `desvioCPEAutomotor`, `informarContingencia`, `cerrarContingenciaCPE` |
136
+ | Ferroviario | `autorizarCPEFerroviaria`, `editarCPEFerroviaria`, `editarCPEConfirmadaFerroviaria`, `confirmacionDefinitivaCPEFerroviaria`, `nuevoDestinoDestinatarioCPEFerroviaria`, `regresoOrigenCPEFerroviaria`, `desvioCPEFerroviaria` |
137
+
138
+ ```ts
139
+ const cartaPorte = { tipoCPE: TIPO_CPE.AUTOMOTOR, sucursal: 1, nroOrden: 15 };
140
+
141
+ // Las informa el destino (con su propia instancia de ArcaAgro: su CUIT y su certificado).
142
+ await agroDestino.cpe.confirmarArriboCPE({ cuitSolicitante: cuitDestino, cartaPorte });
143
+ await agroDestino.cpe.confirmacionDefinitivaCPEAutomotor({
144
+ cuitSolicitante: cuitDestino,
145
+ cartaPorte,
146
+ pesoBrutoDescarga: 41900,
147
+ pesoTaraDescarga: 12000,
148
+ });
149
+ await agro.cpe.anularCPE({ cartaPorte, anulacionMotivo: 3, anulacionObservaciones: 'Error de carga' });
150
+ await agro.cpe.informarContingencia({ cartaPorte, contingencia: { concepto: 'C', descripcion: 'Desperfecto mecánico' } });
188
151
  ```
189
152
 
190
- Los códigos de actividad, operación, puerto, grano, deducción y retención salen de las paramétricas.
153
+ **Consultas** (se reintentan ante errores transitorios). Las listas sin resultados devuelven `[]`; si ARCA devuelve errores se lanza `ArcaAgroServiceError`, nunca una lista vacía.
154
+
155
+ | Método | Devuelve |
156
+ | ------------------------------------------------------------------------------------- | ------------------------------------------------ |
157
+ | `consultarCPEAutomotor({ cartaPorte } \| { nroCTG })` | `CPEAutomotorDetalle` |
158
+ | `consultarCPEFerroviaria({ cartaPorte } \| { nroCTG })` | `CPEFerroviariaDetalle` |
159
+ | `consultaCPEFerroviariaPorNroOperativo(nroOperativo)` | `OperativoFerroviarioCPE` |
160
+ | `consultarCPEPorDestino({ planta, fechaPartidaDesde, fechaPartidaHasta })` | `CPEResumen[]` |
161
+ | `consultarCPEPPendientesDeResolucion({ perfil, planta? })` | `CPEResumen[]` |
162
+ | `consultarUltNroOrden(sucursal, tipoCPE)` / `siguienteNroOrden(...)` | `number` (si ARCA no devuelve `nroOrden`, lanza) |
163
+ | `consultarProvincias()`, `consultarLocalidadesPorProvincia(codProvincia)` | `CodigoDescripcion[]` |
164
+ | `consultarTiposGrano()`, `consultarCategoriasSemillas()`, `consultarUnidadesMedida()` | `CodigoDescripcion[]` |
165
+ | `consultarVariedadesSemillas(codGrano?)` | `VariedadSemillaCPE[]` |
166
+ | `consultarTiposEmbalaje()` | `TipoEmbalajeCPE[]` (con sus unidades de medida) |
167
+ | `consultarPlantas(cuit)` | `PlantaCPE[]` |
168
+ | `consultarLocalidadesProductor(cuit)` | `LocalidadProductorCPE[]` |
169
+ | `consultarRenspa(cuit, codProvincia)` | `RenspaCPE[]` |
170
+ | `consultarDomiciliosPorCUIT(cuit)` | `DomicilioCPE[]` |
171
+ | `dummy()` | `ServerStatus` (sin autenticación) |
172
+
173
+ **No implementado en WSCPE:** el circuito de **derivados granarios** (CPE DG): `autorizarCPEAutomotorDG`, `autorizarCPEFerroviariaDG`, `autorizarCPEDuctosDG`, `autorizarCPEEmisionDestinoDG`, `aceptarEmisionDG`, `aceptarEmisionDestinoDG`, `rechazarEmisionDG`, `rechazarEmisionDestinoDG`, las variantes `*DG` / `*Ductos` / `*EmisionDestinoDG` de editar, confirmar, desviar, regresar, nuevo destino, anular, contingencia y descarga, y las consultas `consultarCPEAutomotorDG`, `consultarCPEFerroviariaDG`, `consultarCPEDuctos`, `consultarCPEEmisionDestinoDG`, `consultarCPEDGPendienteActivacion`, `consultarCPEEmitidasDestinoDGPendientesActivacion`, `consultarDerivadosGranarios` y `consultarPlantasDG`.
174
+
175
+ ### WSLPG (`agro.lpg`)
176
+
177
+ `liquidacion` sigue `LpgLiquidacionBaseType` del XSD; `deducciones`, `retenciones` y `percepciones` van como hermanos (arrays). Los códigos de actividad, operación, puerto, grano, deducción y retención salen de las paramétricas.
178
+
179
+ | Grupo | Emisiones (nunca se reintentan) | Consultas |
180
+ | --------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
181
+ | Liquidación primaria | `liquidacionAutorizar`, `liquidacionAnular` | `liquidacionXCoeConsultar(coe, { pdf? })`, `liquidacionXNroOrdenConsultar(ptoEmision, nroOrden)`, `liquidacionUltimoNroOrdenConsultar(ptoEmision)`, `liquidacionPorContratoConsultar(params)` (COEs) |
182
+ | Ajustes | `liquidacionAjustarUnificado` | `ajusteXCoeConsultar(coe, { pdf? })`, `ajusteXNroOrdenConsultar(ptoEmision, nroOrden)`, `ajustePorContratoConsultar(nroContrato)` |
183
+ | Certificación (`cg*`) | `cgAutorizar`, `cgSolicitarAnulacion`, `cgConfirmarAnulacion` | `cgConsultarXCoe(coe, { pdf? })`, `cgConsultarXNroOrden(ptoEmision, nroOrden)`, `cgConsultarUltimoNroOrden(ptoEmision)`, `cgBuscarCtg(params)`, `cgBuscarCertConSaldoDisponible(params)` |
184
+ | Paramétricas | | `provinciasConsultar`, `localidadXProvinciaConsultar`, `tipoGranoConsultar`, `puertoConsultar`, `tipoActividadConsultar`, `tipoActividadRepresentadoConsultar`, `tipoOperacionXActividadConsultar`, `tipoDeduccionConsultar`, `tipoRetencionConsultar`, `tipoCertificadoDepositoConsultar`, `codigoGradoReferenciaConsultar`, `codigoGradoEntregadoXTipoGranoConsultar`, `campaniasConsultar`, `dummy` |
191
185
 
192
186
  ```ts
193
- await agro.lpg.liquidacionXCoeConsultar(coe, { pdf: true }); // { liquidacion, autorizacion, pdf, eventos }
194
- await agro.lpg.liquidacionXNroOrdenConsultar(ptoEmision, nroOrden);
195
- await agro.lpg.liquidacionAnular(coe); // { coe, resultado, pdf?, eventos }
187
+ await agro.lpg.liquidacionXCoeConsultar(coe, { pdf: true }); // { liquidacion?, autorizacion, pdf?, eventos, advertencias? }
188
+ await agro.lpg.liquidacionAnular(coe); // { coe?, resultado?: 'A', pdf?, eventos }; resultado 'R' → ArcaAgroServiceError
196
189
  await agro.lpg.liquidacionAjustarUnificado({
197
190
  ajusteBase: { ptoEmision, nroOrden, coeAjustado: coe, codLocalidad: 3, codProv: 1 },
198
191
  ajusteDebito: { diferenciaPesoNeto: 0, diferenciaPrecioOperacion: 1000, diferenciaPrecioFleteTn: 0 },
199
192
  });
200
-
201
- // Certificación primaria
202
- await agro.lpg.cgConsultarUltimoNroOrden(ptoEmision);
203
- await agro.lpg.cgAutorizar({ cabecera: { ... }, primaria: { ... } }); // o retiroTransferencia / preexistente
204
- await agro.lpg.cgSolicitarAnulacion(coe);
205
- await agro.lpg.cgConfirmarAnulacion(coe, { pdf: true });
206
-
207
- // Paramétricas
208
- await agro.lpg.tipoGranoConsultar();
209
- await agro.lpg.puertoConsultar();
210
- await agro.lpg.provinciasConsultar();
211
- await agro.lpg.localidadXProvinciaConsultar(1);
212
- await agro.lpg.tipoActividadConsultar();
213
- await agro.lpg.tipoActividadRepresentadoConsultar();
214
- await agro.lpg.tipoOperacionXActividadConsultar(40);
215
- await agro.lpg.tipoDeduccionConsultar();
216
- await agro.lpg.tipoRetencionConsultar();
217
- await agro.lpg.tipoCertificadoDepositoConsultar();
218
- await agro.lpg.codigoGradoReferenciaConsultar();
219
- await agro.lpg.codigoGradoEntregadoXTipoGranoConsultar(2);
220
- await agro.lpg.campaniasConsultar();
221
- await agro.lpg.dummy();
193
+ await agro.lpg.cgAutorizar({ cabecera: { /* ... */ cuitCorredor: 0 }, primaria: { /* ... */ } }); // cuitCorredor 0: sin corredor
222
194
  ```
223
195
 
224
- ### No soportado en WSLPG
196
+ **No implementado en WSLPG:** liquidación secundaria (`lsgAutorizar`, `lsgAnular`, `lsgAnularContraDocumento`, `lsgAjustarXCoe`, `lsgAjustarXContrato`, `lsgAsociarAContrato`, `lsgConsultarXCoe`, `lsgConsultarXNroOrden`, `lsgConsultarXContrato`, `lsgConsultarUltimoNroOrden`), anticipos (`lpgAutorizarAnticipo`, `lpgCancelarAnticipo`), `lpgAnularContraDocumento`, `liquidacionAjustarContrato`, `asociarLiquidacionAContrato` y `cgInformarCalidad`.
225
197
 
226
- 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`).
198
+ ### Validación local
227
199
 
228
- ## Errores
200
+ Los métodos validan antes de enviar. Para validar de antemano (ej: en un formulario): `validateAutorizarCPEAutomotor`, `validateAutorizarCPEFerroviaria`, `validateEditarCPEAutomotor`, `validateEditarCPEFerroviaria`, `validateEditarCPEConfirmada`, `validateConfirmacionDefinitivaCPEAutomotor`, `validateConfirmacionDefinitivaCPEFerroviaria`, `validateLiquidacion`, `validateAjusteUnificado` y `validateCgAutorizar`. Lanzan `ArcaValidationError` con `details[]`.
201
+
202
+ ### Formatos
203
+
204
+ - Los montos se redondean a los decimales del XSD (`fractionDigits`).
205
+ - `xsd:date` acepta `Date` o `AAAAMMDD` / `AAAA-MM-DD`.
206
+ - `xsd:dateTime` acepta `Date` (se envía en hora de Argentina, con `-03:00`) o un string ISO-8601, que se envía tal cual.
207
+ - En las respuestas, los IDs largos (`nroCTG`, `coe`) y los `xs:string` (ej: `codigo` de las paramétricas) son `string`; los CUIT y montos son `number`.
208
+
209
+ **`dateTime`:** un `Date` se envía en hora de Argentina con `-03:00` (válido según el XSD). El manual WSCPE (§4.5) muestra el formato sin zona horaria: para enviarlo así, pasá el string (ej: `'2026-11-02T08:00:00'`), que se envía tal cual.
210
+
211
+ ## Manejo de errores
229
212
 
230
213
  | Error | Cuándo |
231
214
  | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
232
215
  | `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]`). |
233
- | `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). |
234
- | `ArcaSoapError` | Red, timeout, HTTP o SOAP Fault. `uncertain` indica si ARCA pudo haber procesado el request. |
235
- | `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. |
216
+ | `ArcaAgroServiceError` (extiende `ArcaServiceError`) | ARCA rechazó la operación: `errores.error[]` (y en WSLPG también `erroresFormato.error[]`), o `liquidacionAnular` respondió `resultado: 'R'`. Trae `errors[]`, `service`, `method`, `response` (el nodo completo) y `uncertain`. |
217
+ | `ArcaSoapError` | Red, timeout, HTTP o SOAP Fault. `uncertain` indica si ARCA pudo haber procesado el request; `faultDetail` trae el `<detail>` del Fault. |
218
+ | `ArcaAgroResponseError` | La respuesta no trae un dato imprescindible (`nroCTG` al autorizar, `coe` al liquidar, `nroOrden` al consultar el último) o, en una consulta, no tiene la forma del XSD. `uncertain` es `true` en emisiones. |
236
219
  | `ArcaAuthError` / `ArcaTicketVigenteError` | Errores de WSAA. |
237
220
 
238
- 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.
221
+ Un `<error>` sin código (o con código no numérico) cuenta como error; solo se ignora el código explícito `0`.
239
222
 
240
- 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`.
223
+ ### Errores admitidos: `advertencias`
241
224
 
242
- ## Emisiones y reintentos
225
+ ARCA informa algunos errores en `errores` **sin rechazar la operación**: WSCPE **550** y WSLPG **1021**, "Error al generar el archivo pdf" (estado de la operación: Aceptada). En ese caso el SDK no lanza: devuelve el resultado (sin `pdf`) con el error en `advertencias`. Las operaciones que devuelven listas o números no tienen `pdf` y no reciben estos errores.
243
226
 
244
- Las operaciones que crean o modifican algo en ARCA **nunca se reintentan**:
227
+ ```ts
228
+ import { ArcaAgro, TIPO_CPE } from '@ramiidv/arca-agro';
229
+ import type { AutorizarCPEAutomotorParams } from '@ramiidv/arca-agro';
230
+
231
+ declare const agro: ArcaAgro;
232
+ declare const params: AutorizarCPEAutomotorParams;
233
+
234
+ const cpe = await agro.cpe.autorizarCPEAutomotor(params);
235
+ for (const a of cpe.advertencias ?? []) console.warn(`[${a.code}] ${a.msg}`); // [550] Error al generar el archivo pdf.
236
+ if (!cpe.pdf) {
237
+ // La CPE está autorizada: la constancia se puede pedir más tarde.
238
+ const { sucursal, nroOrden } = params.cabecera;
239
+ const detalle = await agro.cpe.consultarCPEAutomotor({ cartaPorte: { tipoCPE: TIPO_CPE.AUTOMOTOR, sucursal, nroOrden } });
240
+ console.log(detalle.pdf ? 'PDF recuperado' : 'Todavía sin PDF');
241
+ }
242
+ ```
243
+
244
+ Si junto con un 550 viene otro error, se lanza `ArcaAgroServiceError` con todos.
245
+
246
+ ### Emisiones y resultado incierto
247
+
248
+ Las emisiones (autorizar, editar, confirmar, anular, ajustar, `cg*` de autorización y anulación) **nunca se reintentan**. Las consultas sí, ante errores transitorios.
249
+
250
+ Una emisión puede terminar con `uncertain: true`, es decir, ARCA **pudo haberla procesado**:
245
251
 
246
- - WSCPE: `autorizarCPEAutomotor`, `autorizarCPEFerroviaria`, `confirmarArriboCPE`, `confirmacionDefinitivaCPE*`, `descargadoDestinoCPE`, `rechazoCPE`, `anularCPE`, `editarCPE*`, `nuevoDestinoDestinatarioCPE*`, `regresoOrigenCPE*`, `desvioCPE*`, `informarContingencia`, `cerrarContingenciaCPE`.
247
- - WSLPG: `liquidacionAutorizar`, `liquidacionAnular`, `liquidacionAjustarUnificado`, `cgAutorizar`, `cgSolicitarAnulacion`, `cgConfirmarAnulacion`.
252
+ - `ArcaSoapError`: timeout, conexión cortada, HTTP 5xx o SOAP Fault `Server`. Los Faults `Client` no son inciertos (ARCA rechazó el request sin procesarlo).
253
+ - `ArcaAgroResponseError`: la respuesta no trae el identificador (`nroCTG`, `coe`).
254
+ - `ArcaAgroServiceError`: la respuesta trae errores **y también** el resultado (`cabecera.nroCTG` o `cabecera.estado` en WSCPE; `autorizacion.coe`, `ajusteUnificado.coe` o `resultado: 'A'` en WSLPG).
248
255
 
249
- Las consultas se reintentan ante errores transitorios (`retries`, default 1).
256
+ En una emisión aceptada, un campo secundario de la respuesta que no tiene la forma del XSD se omite: no vuelve incierta una operación que ARCA aceptó.
250
257
 
251
258
  ### Recuperar una emisión incierta
252
259
 
253
- 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.
260
+ **No reintentes a ciegas**: consultá primero.
254
261
 
255
- - **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`.
256
- - **Liquidación**: `liquidacionUltimoNroOrdenConsultar(ptoEmision)` y `liquidacionXNroOrdenConsultar(ptoEmision, nroOrden)`. Para anulaciones y ajustes, `liquidacionXCoeConsultar(coe)` y mirá `autorizacion.estado`.
257
- - **Certificación**: `cgConsultarUltimoNroOrden(ptoEmision)`.
262
+ - **CPE** (manual WSCPE §1.3): `consultarUltNroOrden(sucursal, tipoCPE)`. Si es menor que el `nroOrden` que enviaste, no se emitió: reintentá con el mismo número. Si es mayor o igual, consultá la CPE con `consultarCPEAutomotor({ cartaPorte: { tipoCPE, sucursal, nroOrden } })` (o `consultarCPEFerroviaria`) y **comprobá que sea la tuya** (destino, dominio, fecha de partida): otro proceso pudo haber usado ese número. Para las demás operaciones, consultá la CPE y mirá `cabecera.estado`.
263
+ - **Liquidación**: `liquidacionUltimoNroOrdenConsultar(ptoEmision)` + `liquidacionXNroOrdenConsultar(ptoEmision, nroOrden)`. Para una anulación, `liquidacionXCoeConsultar(coe)` y mirá `autorizacion.estado` (`AN`).
264
+ - **Ajuste**: el número de orden es el **mismo contador** que el de las liquidaciones (manual WSLPG §1.9.1): `liquidacionUltimoNroOrdenConsultar(ptoEmision)` + `ajusteXNroOrdenConsultar(ptoEmision, nroOrden)`.
265
+ - **Certificación**: `cgConsultarUltimoNroOrden(ptoEmision)` + `cgConsultarXNroOrden(ptoEmision, nroOrden)`. Para una anulación, `cgConsultarXCoe(coe)` y mirá `autorizacion.estado`.
258
266
 
259
267
  ```ts
260
- try {
261
- return await agro.cpe.autorizarCPEAutomotor(params);
262
- } catch (e) {
263
- if (!((e instanceof ArcaSoapError || e instanceof ArcaAgroResponseError) && e.uncertain)) throw e;
264
- const { tipoCP, sucursal, nroOrden } = params.cabecera;
265
- if ((await agro.cpe.consultarUltNroOrden(sucursal, tipoCP)) >= nroOrden) {
266
- return agro.cpe.consultarCPEAutomotor({ cartaPorte: { tipoCPE: tipoCP, sucursal, nroOrden } });
268
+ import { ArcaAgro, ArcaAgroResponseError, ArcaAgroServiceError, ArcaSoapError } from '@ramiidv/arca-agro';
269
+ import type { AutorizarCPEAutomotorParams, CPEAutomotorDetalle } from '@ramiidv/arca-agro';
270
+
271
+ declare const agro: ArcaAgro;
272
+
273
+ const digitos = (v: unknown) => String(v ?? '').replace(/\D/g, '');
274
+ const segundos = (v?: Date | string) => (v === undefined ? Number.NaN : Math.floor(new Date(v).getTime() / 1000));
275
+
276
+ /** ¿La CPE consultada es la que intentamos autorizar? */
277
+ function esLaMisma(cpe: CPEAutomotorDetalle, p: AutorizarCPEAutomotorParams): boolean {
278
+ return (
279
+ digitos(cpe.destino?.cuit) === digitos(p.destino.cuit) &&
280
+ cpe.destino?.planta === p.destino.planta &&
281
+ (cpe.transporte?.dominio ?? []).join() === p.transporte.dominio.join() &&
282
+ segundos(cpe.transporte?.fechaHoraPartida) === segundos(p.transporte.fechaHoraPartida)
283
+ );
284
+ }
285
+
286
+ async function autorizar(params: AutorizarCPEAutomotorParams): Promise<CPEAutomotorDetalle> {
287
+ try {
288
+ return await agro.cpe.autorizarCPEAutomotor(params);
289
+ } catch (e) {
290
+ const incierto =
291
+ (e instanceof ArcaSoapError || e instanceof ArcaAgroServiceError || e instanceof ArcaAgroResponseError) &&
292
+ e.uncertain;
293
+ if (!incierto) throw e;
294
+ const { tipoCP, sucursal, nroOrden } = params.cabecera;
295
+ if ((await agro.cpe.consultarUltNroOrden(sucursal, tipoCP)) < nroOrden) {
296
+ return agro.cpe.autorizarCPEAutomotor(params); // no se emitió
297
+ }
298
+ const cpe = await agro.cpe.consultarCPEAutomotor({ cartaPorte: { tipoCPE: tipoCP, sucursal, nroOrden } });
299
+ if (esLaMisma(cpe, params)) return cpe;
300
+ throw new Error(`El número de orden ${nroOrden} lo usó otra CPE (CTG ${cpe.cabecera.nroCTG})`);
267
301
  }
268
- return agro.cpe.autorizarCPEAutomotor(params); // no se emitió
269
302
  }
270
303
  ```
271
304
 
272
- ## Estado de los servicios
305
+ ### SOAP Fault de WSCPE (`Exception`)
306
+
307
+ Ante algunos errores WSCPE responde un SOAP Fault con un `<detail><Exception>` (`uuid`, `timestamp`, `businessErrorId`, `exceptionDetails`, `serverName`). Viene en `ArcaSoapError.faultDetail`; `cpeFaultException(error)` lo devuelve como objeto (o `undefined`):
273
308
 
274
309
  ```ts
275
- const estado = await agro.status();
276
- // { cpe: { ok: true, status: { appserver, dbserver, authserver } }, lpg: { ok: false, error } }
277
- ```
310
+ import { ArcaAgro, cpeFaultException } from '@ramiidv/arca-agro';
278
311
 
279
- Usa `Promise.allSettled`: la caída de un servicio no oculta el estado del otro.
312
+ declare const agro: ArcaAgro;
313
+
314
+ try {
315
+ await agro.cpe.consultarProvincias();
316
+ } catch (e) {
317
+ const ex = cpeFaultException(e);
318
+ if (ex) console.error(`businessErrorId=${ex.businessErrorId} uuid=${ex.uuid}: ${ex.exceptionDetails}`);
319
+ throw e;
320
+ }
321
+ ```
280
322
 
281
323
  ## Eventos
282
324
 
325
+ `onEvent` (o `agro.on(tipo, handler)` / `agro.off`) recibe `auth:login`, `auth:cache-hit`, `auth:clock-skew`, `auth:storage-error`, `request:start`, `request:end`, `request:retry` y `request:error` (ver `ArcaEvent` en `@ramiidv/arca-common`). Los errores de los handlers se ignoran.
326
+
283
327
  ```ts
284
- agro.on('auth:login', (e) => console.log(`Login ${e.service}`));
285
- agro.on('request:end', (e) => console.log(`${e.method} en ${e.durationMs}ms`));
286
- agro.on('request:retry', (e) => console.warn(`Reintento #${e.attempt}`));
287
- agro.on('request:error', (e) => console.error(`Error en ${e.method}`));
288
- ```
328
+ import { ArcaAgro } from '@ramiidv/arca-agro';
289
329
 
290
- También se puede pasar `onEvent` en la configuración. Los errores de los handlers se ignoran.
330
+ declare const agro: ArcaAgro;
291
331
 
292
- ## Configuración
332
+ agro.on('request:end', (e) => {
333
+ if (e.type === 'request:end') console.log(`${e.method} en ${e.durationMs} ms`);
334
+ });
335
+ agro.on('request:retry', (e) => console.warn('Reintento', e));
336
+ ```
293
337
 
294
- `ArcaAgroConfig` extiende `ArcaBaseConfig` de `@ramiidv/arca-common`.
295
-
296
- | Opción | Tipo | Default | Descripción |
297
- | --------------------------------- | ------------------------------- | ------------- | ----------------------------------------------------------- |
298
- | `cuit` | `number \| string` | **requerido** | CUIT representada (con o sin guiones) |
299
- | `cert` / `key` | `string` | **requerido** | Certificado y clave privada PEM |
300
- | `production` | `boolean` | `false` | Entorno de producción |
301
- | `timeout` | `number` | `30000` | Timeout HTTP (ms) |
302
- | `retries` | `number` | `1` | Reintentos de consultas (las emisiones nunca se reintentan) |
303
- | `retryDelayMs` | `number` | `1000` | Delay base entre reintentos (ms) |
304
- | `tokenTTLMinutes` | `number` | `720` | Vida del ticket WSAA |
305
- | `ticketStorage` | `TicketStorage` | memoria | Persistencia del ticket WSAA (recomendado en producción) |
306
- | `clockOffsetMs` / `autoClockSkew` | | `0` / `true` | Desfase de reloj con ARCA |
307
- | `loginErrorCooldownMs` | `number` | `60000` | Espera tras un login WSAA fallido |
308
- | `fetch` | `typeof fetch` | global | `fetch` propio (proxy, tests) |
309
- | `legacyTls` | `'auto' \| 'never' \| 'always'` | `'auto'` | Transporte TLS legacy |
310
- | `endpoints` | `{ cpe?, lpg?, wsaa? }` | oficiales | Endpoints propios |
311
- | `onEvent` | `function` | | Callback de eventos |
312
-
313
- `clearAuthCache()` (async) invalida los tickets de WSCPE y WSLPG.
314
-
315
- ## Endpoints
338
+ ## Entornos
316
339
 
317
340
  | Servicio | Homologación | Producción |
318
341
  | -------- | ------------------------------------------------------- | ---------------------------------------------------- |
319
342
  | WSCPE | `https://cpea-ws-qaext.afip.gob.ar/wscpe/services/soap` | `https://cpea-ws.afip.gob.ar/wscpe/services/soap` |
320
343
  | WSLPG | `https://fwshomo.afip.gov.ar/wslpg/LpgService` | `https://serviciosjava.afip.gob.ar/wslpg/LpgService` |
321
344
 
322
- Namespaces: WSCPE `https://serviciosjava.afip.gob.ar/wscpe/`, WSLPG `http://serviciosjava.afip.gob.ar/wslpg/`.
345
+ Los endpoints están en `CPE_ENDPOINTS` y `LPG_ENDPOINTS`; los namespaces en `CPE_NAMESPACE` (`https://serviciosjava.afip.gob.ar/wscpe/`) y `LPG_NAMESPACE` (`http://serviciosjava.afip.gob.ar/wslpg/`). Los de WSAA están en `WSAA_ENDPOINTS` de `@ramiidv/arca-common`.
346
+
347
+ ## Ejemplos
348
+
349
+ En [examples](https://github.com/ramiidv/arca-sdks/tree/main/packages/agro/examples): circuito completo de una Carta de Porte automotor (`carta-de-porte.ts`), liquidación primaria de granos (`liquidacion-granos.ts`) y manejo de errores con recuperación de emisiones inciertas (`manejo-errores.ts`).
323
350
 
324
351
  ## Licencia
325
352