@ramiidv/arca-agro 0.2.0 → 0.4.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 (62) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +239 -183
  3. package/dist/arca-agro.d.ts +27 -143
  4. package/dist/arca-agro.d.ts.map +1 -1
  5. package/dist/arca-agro.js +28 -277
  6. package/dist/arca-agro.js.map +1 -1
  7. package/dist/constants.d.ts +34 -8
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/constants.js +34 -11
  10. package/dist/constants.js.map +1 -1
  11. package/dist/context.d.ts +16 -0
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/context.js +2 -0
  14. package/dist/context.js.map +1 -0
  15. package/dist/cpe-client.d.ts +97 -52
  16. package/dist/cpe-client.d.ts.map +1 -1
  17. package/dist/cpe-client.js +238 -229
  18. package/dist/cpe-client.js.map +1 -1
  19. package/dist/cpe-schemas.d.ts +74 -0
  20. package/dist/cpe-schemas.d.ts.map +1 -0
  21. package/dist/cpe-schemas.js +510 -0
  22. package/dist/cpe-schemas.js.map +1 -0
  23. package/dist/cpe-types.d.ts +599 -0
  24. package/dist/cpe-types.d.ts.map +1 -0
  25. package/dist/cpe-types.js +2 -0
  26. package/dist/cpe-types.js.map +1 -0
  27. package/dist/errors.d.ts +33 -0
  28. package/dist/errors.d.ts.map +1 -0
  29. package/dist/errors.js +47 -0
  30. package/dist/errors.js.map +1 -0
  31. package/dist/index.d.ts +10 -10
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +8 -13
  34. package/dist/index.js.map +1 -1
  35. package/dist/lpg-client.d.ts +66 -44
  36. package/dist/lpg-client.d.ts.map +1 -1
  37. package/dist/lpg-client.js +216 -176
  38. package/dist/lpg-client.js.map +1 -1
  39. package/dist/lpg-schemas.d.ts +48 -0
  40. package/dist/lpg-schemas.d.ts.map +1 -0
  41. package/dist/lpg-schemas.js +477 -0
  42. package/dist/lpg-schemas.js.map +1 -0
  43. package/dist/lpg-types.d.ts +470 -0
  44. package/dist/lpg-types.d.ts.map +1 -0
  45. package/dist/lpg-types.js +2 -0
  46. package/dist/lpg-types.js.map +1 -0
  47. package/dist/schema.d.ts +6 -0
  48. package/dist/schema.d.ts.map +1 -0
  49. package/dist/schema.js +15 -0
  50. package/dist/schema.js.map +1 -0
  51. package/dist/types.d.ts +28 -455
  52. package/dist/types.d.ts.map +1 -1
  53. package/dist/validation.d.ts +22 -43
  54. package/dist/validation.d.ts.map +1 -1
  55. package/dist/validation.js +31 -134
  56. package/dist/validation.js.map +1 -1
  57. package/llms.txt +78 -159
  58. package/package.json +18 -22
  59. package/dist/ctg-client.d.ts +0 -56
  60. package/dist/ctg-client.d.ts.map +0 -1
  61. package/dist/ctg-client.js +0 -214
  62. package/dist/ctg-client.js.map +0 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,119 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8c02c30: API uniforme entre los SDKs (los nombres anteriores siguen funcionando,
8
+ marcados `@deprecated`, hasta la próxima major):
9
+
10
+ - arca-facturacion: la clase principal es `ArcaFacturacion` (`Arca` queda como
11
+ alias). Nuevo `status()` → `{ wsfe, wsfex }` con `ServiceStatus` y el
12
+ `ServerStatus` de arca-common (`appserver`/`dbserver`/`authserver`);
13
+ `serverStatus()`/`serverStatusExpo()` y su `ServerStatus` en mayúsculas
14
+ quedan deprecados.
15
+ - arca-agro: `status()` (antes `serverStatus()`).
16
+ - arca-fecred: el cliente de bajo nivel es `client` (antes `fecred`).
17
+ - arca-common: `ServiceStatus` y `statusOf()` para el estado de varios servicios.
18
+ - bed68e8: Paquetes solo ESM y Node >= 20.19. `arca-common`, `arca-facturacion` y
19
+ `arca-padron` dejan de publicar un build CommonJS: desde CommonJS se cargan con
20
+ `require()` (require(esm), Node >= 20.19 / 22.12). Todos los paquetes pasan a
21
+ requerir Node >= 20.19.0 (Node 18 y 20 sin soporte). El código vive ahora en el
22
+ monorepo `arca-sdks`.
23
+ - f8bd053: Las clases principales extienden `ArcaSdkBase` de arca-common, así que todos
24
+ los SDKs tienen la misma base: `wsaa`, `cuit`, `production`, `on()`/`off()`,
25
+ `clearAuthCache()`, `config.wsaa` (WsaaClient compartido) y `config.signal`
26
+ (signal global). arca-mtxca acepta `endpoints: { mtxca, wsaa }` (`endpoint` y
27
+ `wsaaEndpoint` quedan deprecados). Los `dummy`/`status` validan la respuesta con
28
+ `parseServerStatus`: si falta un campo lanzan `ArcaSoapError`.
29
+
30
+ ### Patch Changes
31
+
32
+ - 20ecf7d: DSL de schemas, segunda versión:
33
+
34
+ - Corrección: `dec()` redondea sobre el valor decimal escrito (`8.575` →
35
+ `8.58`; antes daba `8.57` por la representación binaria). Afecta los importes
36
+ que los SDKs envían redondeados.
37
+ - `must()` rechaza también el valor vacío; los elementos `xsi:nil` cuentan
38
+ como ausentes (en una lista, como lista vacía); `must()` en listas exige el
39
+ elemento; un objeto opcional vacío se omite y uno obligatorio valida sus hijos.
40
+ - Al decodificar se validan enteros (`int()`) y valores permitidos
41
+ (`str({ values })`).
42
+ - Nuevos: `siNo()` (S/N ↔ boolean), `double()`, `xml(nombre, campo)` (nombre
43
+ distinto en el XML), `custom(encode, decode)`, `roundHalfUp()` y
44
+ `decodeResponse(..., { emptyLists: 'omit' })`.
45
+ - b86db00: Nuevo subpath `@ramiidv/arca-common/schema`: el DSL para describir los tipos
46
+ del XSD de un servicio y, con la misma descripción, validar y serializar
47
+ requests en el orden del XSD (`encodeRequest`) y decodificar respuestas con
48
+ tipos (`decodeResponse`). Nuevo error `ArcaResponseError` (respuesta con forma
49
+ inválida, con `uncertain`).
50
+
51
+ arca-agro usa el DSL de common (`ArcaAgroResponseError` extiende
52
+ `ArcaResponseError`) y parsea las respuestas sin conversión numérica: los
53
+ `xs:string` con contenido numérico (ej: `"0012"`, `"10.50"`) ya no pierden ceros
54
+ ni decimales.
55
+ - Updated dependencies [8c02c30]
56
+ - Updated dependencies [f8bd053]
57
+ - Updated dependencies [242fb5f]
58
+ - Updated dependencies [fd438bc]
59
+ - Updated dependencies [bed68e8]
60
+ - Updated dependencies [20ecf7d]
61
+ - Updated dependencies [b86db00]
62
+ - @ramiidv/arca-common@0.5.0
63
+
64
+ ## 0.3.0 (2026-11-01)
65
+
66
+ Reescritura de los clientes contra los WSDL/XSD oficiales. La versión anterior no funcionaba contra ARCA en ningún servicio (endpoints, namespaces, elementos y campos incorrectos).
67
+
68
+ ### Breaking
69
+
70
+ - **Se elimina WSCTG** (cliente `CtgClient`, `agro.ctg`, tipos, constantes `CTG_*`, `validateCTG`, servicio en `serverStatus`): el CTG fue derogado el 1/11/2021 (RG 5017/2021, reemplazado por la Carta de Porte Electrónica) y sus endpoints responden 404.
71
+ - WSCPE: los requests ahora siguen el XSD (`cabecera`, `origen`, `datosCarga`, `destino`, `destinatario`, `transporte`, ...). Se renombran/reemplazan métodos: `confirmadoArriboCPE` → `confirmarArriboCPE`, `editarCPE` → `editarCPEAutomotor`, `consultarCPE` → `consultarCPEAutomotor`, `consultarConstanciaCPEPDF` eliminado (el PDF viene en `pdf` de las respuestas). `consultarUltNroOrden`/`siguienteNroOrden` reciben `(sucursal, tipoCPE)`.
72
+ - WSLPG: `liquidacionAutorizar` recibe `{ liquidacion, deducciones?, retenciones?, percepciones? }` según `LpgLiquidacionBaseType`; `liquidacionConsultar` se reemplaza por `liquidacionXCoeConsultar` y `liquidacionXNroOrdenConsultar`; `liquidacionAnular(coe)`; `liquidacionAjustarUnificado({ ajusteBase, ajusteCredito?, ajusteDebito? })`; `certificacionAutorizar`/`certificacionAnular` → `cgAutorizar`, `cgSolicitarAnulacion`, `cgConfirmarAnulacion`; `consultarParametros(nombre)` → un método por paramétrica (`tipoGranoConsultar`, `puertoConsultar`, ...).
73
+ - Respuestas tipadas según el XSD: `nroCTG` y `coe` son `string`; los `xs:string` (ej: `codigo` de paramétricas) son `string`. Se eliminan `AgroAuth`, `AgroError`, `raw` y las index signatures `[key: string]: unknown`.
74
+ - Los errores de negocio se lanzan como `ArcaAgroServiceError` (extiende `ArcaServiceError`) en lugar de devolverse en `errores`.
75
+ - `ArcaAgroConfig` extiende `ArcaBaseConfig`: `requestTimeoutMs` → `timeout`; `cuit` acepta `number | string` y se valida el dígito verificador.
76
+ - `CpeClient`/`LpgClient` solo se obtienen desde `ArcaAgro` (se exportan como tipos); sus métodos reciben `opts?: { signal }` en lugar de `auth`.
77
+ - `serverStatus()` devuelve `{ cpe, lpg }` con `{ ok: true, status } | { ok: false, error }`; `clearAuthCache()` es async.
78
+ - `validateCPE`/`validateCTG` → `validateAutorizarCPEAutomotor`, `validateAutorizarCPEFerroviaria`, `validateLiquidacion`, `validateAjusteUnificado`.
79
+ - Requiere `@ramiidv/arca-common` ^0.4.0.
80
+
81
+ ### Features
82
+
83
+ - WSCPE, circuito automotor completo: `autorizarCPEAutomotor` (tipos 74 y 274), `consultarCPEAutomotor`, `editarCPEAutomotor`, `editarCPEConfirmadaAutomotor`, `confirmarArriboCPE`, `confirmacionDefinitivaCPEAutomotor`, `descargadoDestinoCPE`, `rechazoCPE`, `anularCPE`, `nuevoDestinoDestinatarioCPEAutomotor`, `regresoOrigenCPEAutomotor`, `desvioCPEAutomotor`, `informarContingencia`, `cerrarContingenciaCPE`.
84
+ - WSCPE, circuito ferroviario: `autorizarCPEFerroviaria`, `consultarCPEFerroviaria`, `editarCPEFerroviaria`, `editarCPEConfirmadaFerroviaria`, `confirmacionDefinitivaCPEFerroviaria`, `nuevoDestinoDestinatarioCPEFerroviaria`, `regresoOrigenCPEFerroviaria`, `desvioCPEFerroviaria`, `consultaCPEFerroviariaPorNroOperativo`.
85
+ - WSCPE, consultas y paramétricas: `consultarCPEPorDestino`, `consultarCPEPPendientesDeResolucion`, `consultarProvincias`, `consultarLocalidadesPorProvincia`, `consultarTiposGrano`, `consultarPlantas`, `consultarLocalidadesProductor`, `consultarCategoriasSemillas`, `consultarVariedadesSemillas`.
86
+ - WSLPG: `liquidacionUltimoNroOrdenConsultar`, `cgConsultarUltimoNroOrden` y paramétricas (`provinciasConsultar`, `localidadXProvinciaConsultar`, `tipoOperacionXActividadConsultar`, `puertoConsultar`, `tipoActividadConsultar`, `tipoActividadRepresentadoConsultar`, `tipoCertificadoDepositoConsultar`, `tipoRetencionConsultar`, `tipoDeduccionConsultar`, `tipoGranoConsultar`, `codigoGradoReferenciaConsultar`, `codigoGradoEntregadoXTipoGranoConsultar`, `campaniasConsultar`).
87
+ - Validación local completa contra el XSD (obligatorios, campos desconocidos, rangos, largos, CUIT con dígito verificador, números finitos, redondeo según `fractionDigits`, fechas) reportando todos los errores juntos.
88
+ - Constantes `TIPO_CPE` y `ESTADOS_CPE`. Endpoints configurables (`endpoints: { cpe, lpg, wsaa }`).
89
+ - Configuración de WSAA: `ticketStorage`, `clockOffsetMs`, `autoClockSkew`, `loginErrorCooldownMs`, `fetch`, `legacyTls`.
90
+ - Todos los métodos aceptan `{ signal }`.
91
+
92
+ ### Fixes
93
+
94
+ - WSCPE: endpoints de homologación (`cpea-ws-qaext.afip.gob.ar`) y producción (`cpea-ws.afip.gob.ar`), elementos `<Op>Req`/`<Op>Resp`, SOAPAction y auth `{ token, sign, cuitRepresentada }`.
95
+ - WSLPG: namespace `http://serviciosjava.afip.gob.ar/wslpg/` (era `https`), elementos del WSDL (`liquidacionReq`, `liqConsXCoeReq`, ...) y auth `{ token, sign, cuit }`.
96
+ - Los errores de negocio (`errores.error[]`, `erroresFormato.error[]`) ya no se pierden: siempre se lanzan.
97
+ - Las consultas sin resultados devuelven `[]` (antes devolvían `[respuestaCompleta]`).
98
+ - `consultarUltNroOrden` lanza si ARCA no devuelve `nroOrden` (antes devolvía 0 y `siguienteNroOrden` daba 1, un número ya usado).
99
+ - Las emisiones (autorizar, anular, rechazar, confirmar, editar, contingencias, desvíos, liquidar, ajustar, certificar) nunca se reintentan y conservan `uncertain`.
100
+ - `serverStatus()` usa `Promise.allSettled`; `clearAuthCache()` espera el borrado de los tickets.
101
+ - Validación: `NaN` ya no pasa como número positivo; el CUIT se valida con dígito verificador.
102
+ - Los ejemplos usaban `codTipoCartaPorte: 1` (inválido); ahora usan el tipo 74.
103
+
104
+ ## 0.2.0 (2026-06-03)
105
+
106
+ ### Chore
107
+ - Build standalone para CI y workflow de release en GitHub Actions.
108
+ - `homepage` apunta a arca-sdk.dev.
109
+
110
+ ## 0.1.0 (2026-03-31)
111
+
112
+ ### Features
113
+ - Initial release
114
+ - WSCPE (Carta de Porte Electronica) - Electronic bill of lading for grain transport
115
+ - WSCTG (Codigo de Trazabilidad de Granos) - Grain traceability codes
116
+ - WSLPG (Liquidacion Primaria de Granos) - Primary grain settlement/liquidation
117
+ - Auto-handles WSAA authentication for all 3 services
118
+ - Retry with exponential backoff on transient errors
119
+ - Event system for logging/debugging
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,255 +16,310 @@ 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.
38
+
39
+ Todos los métodos aceptan un último argumento opcional `{ signal }` (`AbortSignal`) para cancelar la llamada.
40
+
41
+ ## WSCPE: Carta de Porte Electrónica
36
42
 
37
- ## WSCPE - Carta de Porte Electrónica
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
38
48
 
39
49
  ```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',
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
+ },
59
71
  });
60
72
 
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
- });
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
69
81
 
70
- // Consultar CPEs
71
- const cpes = await agro.cpe.consultarCPE({
72
- fechaDesde: '2026-03-01',
73
- fechaHasta: '2026-03-31',
74
- codGrano: 23,
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,
75
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' });
76
117
 
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 });
118
+ const detalle = await agro.cpe.consultarCPEAutomotor({ nroCTG: '010100012345' }); // o { cartaPorte }
119
+ ```
80
120
 
81
- // Obtener constancia PDF (base64)
82
- const pdfBase64 = await agro.cpe.consultarConstanciaCPEPDF(12345);
121
+ Las operaciones que modifican una CPE devuelven `CPEResultado` (`{ cabecera?, pdf?, metadata? }`).
83
122
 
84
- // Obtener siguiente número de orden
85
- const nroOrden = await agro.cpe.siguienteNroOrden(1);
123
+ ### Circuito ferroviario
86
124
 
87
- // Estado del servicio
88
- const status = await agro.cpe.dummy();
89
- ```
125
+ `autorizarCPEFerroviaria`, `consultarCPEFerroviaria`, `editarCPEFerroviaria`, `editarCPEConfirmadaFerroviaria`, `confirmacionDefinitivaCPEFerroviaria`, `nuevoDestinoDestinatarioCPEFerroviaria`, `regresoOrigenCPEFerroviaria`, `desvioCPEFerroviaria` y `consultaCPEFerroviariaPorNroOperativo`.
90
126
 
91
- ## WSCTG - Código de Trazabilidad de Granos
127
+ ### Consultas y paramétricas
92
128
 
93
129
  ```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,
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',
104
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
+ ```
105
146
 
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
- });
147
+ Las listas sin resultados devuelven `[]`; si ARCA devuelve errores, se lanza `ArcaAgroServiceError` (nunca una lista vacía).
114
148
 
115
- // Consultar CTGs
116
- const ctgs = await agro.ctg.consultarCTG({
117
- fechaDesde: '2026-03-01',
118
- fechaHasta: '2026-03-31',
119
- });
149
+ ### No soportado en WSCPE
120
150
 
121
- // Exportar a Excel (base64)
122
- const excelBase64 = await agro.ctg.consultarCTGExcel({
123
- fechaDesde: '2026-03-01',
124
- fechaHasta: '2026-03-31',
125
- });
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.
126
152
 
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 });
153
+ ## WSLPG: Liquidación Primaria de Granos
130
154
 
131
- // CTGs activos
132
- const activos = await agro.ctg.obtenerCTGActivos();
155
+ `liquidacion` sigue `LpgLiquidacionBaseType` del XSD; `deducciones`, `retenciones` y `percepciones` van como hermanos (arrays).
133
156
 
134
- // Constancia PDF (base64)
135
- const pdf = await agro.ctg.consultarConstanciaCTGPDF(12345);
157
+ ```ts
158
+ const ptoEmision = 1;
159
+ const nroOrden = (await agro.lpg.liquidacionUltimoNroOrdenConsultar(ptoEmision)) + 1;
160
+
161
+ const { autorizacion, eventos } = await agro.lpg.liquidacionAutorizar({
162
+ liquidacion: {
163
+ ptoEmision,
164
+ nroOrden,
165
+ cuitComprador: '20123456786',
166
+ nroActComprador: 40,
167
+ nroIngBrutoComprador: 901234567,
168
+ codTipoOperacion: '1',
169
+ codPuerto: 14,
170
+ codGrano: 31,
171
+ cuitVendedor: '30712345671',
172
+ nroIngBrutoVendedor: 900123,
173
+ liquidaCorredor: 'N',
174
+ fechaPrecioOperacion: '2026-10-30',
175
+ precioRefTn: 250000,
176
+ precioFleteTn: 0,
177
+ campaniaPPal: 2526,
178
+ codLocalidadProcedencia: 3,
179
+ codProvProcedencia: 1,
180
+ pesoNetoSinCertificado: 30000,
181
+ },
182
+ deducciones: [{ codigoConcepto: 'CO', comisionGastosAdm: 1.5, alicuotaIva: 21 }],
183
+ retenciones: [{ codigoConcepto: 'RG', baseCalculo: 7500000, alicuota: 2 }],
184
+ });
136
185
 
137
- // Estado del servicio
138
- const status = await agro.ctg.dummy();
186
+ autorizacion.coe; // '330100012345' (string)
187
+ autorizacion.totalNetoAPagar; // number
139
188
  ```
140
189
 
141
- ## WSLPG - Liquidación Primaria de Granos
190
+ Los códigos de actividad, operación, puerto, grano, deducción y retención salen de las paramétricas.
142
191
 
143
192
  ```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,
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 }
196
+ await agro.lpg.liquidacionAjustarUnificado({
197
+ ajusteBase: { ptoEmision, nroOrden, coeAjustado: coe, codLocalidad: 3, codProv: 1 },
198
+ ajusteDebito: { diferenciaPesoNeto: 0, diferenciaPrecioOperacion: 1000, diferenciaPrecioFleteTn: 0 },
151
199
  });
152
200
 
153
- // Consultar liquidaciones
154
- const liquidaciones = await agro.lpg.liquidacionConsultar({
155
- fechaDesde: '2026-03-01',
156
- fechaHasta: '2026-03-31',
157
- });
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();
222
+ ```
158
223
 
159
- // Anular liquidación
160
- await agro.lpg.liquidacionAnular(1, 100);
224
+ ### No soportado en WSLPG
161
225
 
162
- // Ajuste unificado
163
- await agro.lpg.liquidacionAjustarUnificado({
164
- nroOrdenOriginal: 100,
165
- ptoEmisionOriginal: 1,
166
- tipoAjuste: 'credito',
167
- liquidacion: { pesoNeto: 29500 },
168
- });
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`).
169
227
 
170
- // Autorizar certificación
171
- const cert = await agro.lpg.certificacionAutorizar({
172
- tipoCertificacion: 1,
173
- cuitDepositante: 20123456789,
174
- codGrano: 23,
175
- pesoNeto: 30000,
176
- });
228
+ ## Errores
177
229
 
178
- // Anular certificación
179
- await agro.lpg.certificacionAnular(1, cert.nroCertificacion!);
230
+ | Error | Cuándo |
231
+ | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
232
+ | `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. |
236
+ | `ArcaAuthError` / `ArcaTicketVigenteError` | Errores de WSAA. |
180
237
 
181
- // Consultar parámetros (tipos de grano, grados, puertos, etc.)
182
- const granos = await agro.lpg.consultarParametros('tipoGranoConsultar');
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.
183
239
 
184
- // Estado del servicio
185
- const status = await agro.lpg.dummy();
186
- ```
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`.
187
241
 
188
- ## Verificar todos los servicios
242
+ ## Emisiones y reintentos
189
243
 
190
- ```ts
191
- const status = await agro.serverStatus();
192
- // { cpe: { appserver, dbserver, authserver }, ctg: { ... }, lpg: { ... } }
193
- ```
244
+ Las operaciones que crean o modifican algo en ARCA **nunca se reintentan**:
194
245
 
195
- ## Clientes de bajo nivel
246
+ - WSCPE: `autorizarCPEAutomotor`, `autorizarCPEFerroviaria`, `confirmarArriboCPE`, `confirmacionDefinitivaCPE*`, `descargadoDestinoCPE`, `rechazoCPE`, `anularCPE`, `editarCPE*`, `nuevoDestinoDestinatarioCPE*`, `regresoOrigenCPE*`, `desvioCPE*`, `informarContingencia`, `cerrarContingenciaCPE`.
247
+ - WSLPG: `liquidacionAutorizar`, `liquidacionAnular`, `liquidacionAjustarUnificado`, `cgAutorizar`, `cgSolicitarAnulacion`, `cgConfirmarAnulacion`.
196
248
 
197
- Para control total sobre la autenticación, se pueden usar los clientes individuales directamente:
249
+ Las consultas se reintentan ante errores transitorios (`retries`, default 1).
198
250
 
199
- ```ts
200
- import { CpeClient, CtgClient, LpgClient } from '@ramiidv/arca-agro';
201
- import { WsaaClient } from '@ramiidv/arca-common';
251
+ ### Recuperar una emisión incierta
202
252
 
203
- const wsaa = new WsaaClient({ cert, key, production: false });
204
- const cpeClient = new CpeClient(false, { timeoutMs: 60000 });
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.
205
254
 
206
- const ticket = await wsaa.getAccessTicket('wscpe');
207
- const auth = { Token: ticket.token, Sign: ticket.sign, Cuit: 20123456789 };
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)`.
208
258
 
209
- const resultado = await cpeClient.autorizarCPEAutomotor(auth, { ... });
259
+ ```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 } });
267
+ }
268
+ return agro.cpe.autorizarCPEAutomotor(params); // no se emitió
269
+ }
210
270
  ```
211
271
 
212
- ## Eventos
272
+ ## Estado de los servicios
213
273
 
214
274
  ```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}`));
275
+ const estado = await agro.status();
276
+ // { cpe: { ok: true, status: { appserver, dbserver, authserver } }, lpg: { ok: false, error } }
219
277
  ```
220
278
 
221
- ## Manejo de errores
279
+ Usa `Promise.allSettled`: la caída de un servicio no oculta el estado del otro.
222
280
 
223
- ```ts
224
- import {
225
- ArcaAuthError,
226
- ArcaSoapError,
227
- ArcaServiceError,
228
- } from '@ramiidv/arca-agro';
281
+ ## Eventos
229
282
 
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
- }
283
+ ```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}`));
244
288
  ```
245
289
 
290
+ También se puede pasar `onEvent` en la configuración. Los errores de los handlers se ignoran.
291
+
246
292
  ## Configuración
247
293
 
248
- | Opción | Tipo | Default | Descripción |
249
- |--------|------|---------|-------------|
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 |
257
- | `retryDelayMs` | `number` | `1000` | Delay base entre reintentos (ms) |
258
- | `onEvent` | `function` | `undefined` | Callback para eventos del SDK |
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.
259
314
 
260
315
  ## Endpoints
261
316
 
262
- | Servicio | Homologación | Producción |
263
- |----------|-------------|------------|
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` |
266
- | WSLPG | `https://fwshomo.afip.gov.ar/wslpg/LpgService` | `https://serviciosjava.afip.gob.ar/wslpg/LpgService` |
317
+ | Servicio | Homologación | Producción |
318
+ | -------- | ------------------------------------------------------- | ---------------------------------------------------- |
319
+ | WSCPE | `https://cpea-ws-qaext.afip.gob.ar/wscpe/services/soap` | `https://cpea-ws.afip.gob.ar/wscpe/services/soap` |
320
+ | WSLPG | `https://fwshomo.afip.gov.ar/wslpg/LpgService` | `https://serviciosjava.afip.gob.ar/wslpg/LpgService` |
321
+
322
+ Namespaces: WSCPE `https://serviciosjava.afip.gob.ar/wscpe/`, WSLPG `http://serviciosjava.afip.gob.ar/wslpg/`.
267
323
 
268
324
  ## Licencia
269
325