@ramiidv/arca-mtxca 0.3.0 → 0.5.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.
@@ -1,19 +1,34 @@
1
- import { afipSoapCall, checkServiceErrors } from '@ramiidv/arca-common';
1
+ import { ArcaSoapError, checkServiceErrors, parseServerStatus, SoapServiceClient } from '@ramiidv/arca-common';
2
+ import { decodeResponse, encodeRequest } from '@ramiidv/arca-common/schema';
2
3
  import { MTXCA_NAMESPACE } from './constants.js';
3
- import { buildComprobante, XsdFields } from './serialize.js';
4
- import { ResponseReader } from './parse.js';
4
+ import { ACTIVIDADES_VIGENTES_RESPONSE, CAEA_ENTRE_FECHAS_RESPONSE, CAEA_NO_UTILIZADO, CAEA_NO_UTILIZADO_PTO_VTA, CAEA_RESPONSE, COMPROBANTE_CAE_RESPONSE, COMPROBANTE_CAEA_RESPONSE, CON_CAEA, CON_CAEA_PTO_VTA, CONDICIONES_IVA_RECEPTOR_RESPONSE, CONSULTA_COMPROBANTE, CONSULTA_COMPROBANTE_RESPONSE, CONSULTA_CONDICIONES_IVA, CONSULTA_ULTIMO, COTIZACION, COTIZACION_RESPONSE, ENTRE_FECHAS, FECHA_PROCESO, PARAMETROS, PUNTOS_VENTA_RESPONSE, RESULTADO, SOLICITUD_CAEA, ULTIMO_RESPONSE, } from './schemas.js';
5
+ import { buildComprobante, encodeConCaea } from './serialize.js';
5
6
  const SERVICE = 'WSMTXCA';
6
7
  function isResultado(value) {
7
8
  return value === 'A' || value === 'O' || value === 'R';
8
9
  }
9
- function validated(build) {
10
- const f = new XsdFields();
11
- const value = build(f);
12
- f.throwIfErrors('Parámetros inválidos');
13
- return value;
10
+ /**
11
+ * Respuesta ilegible: `ArcaSoapError` (`uncertain` en emisiones: el
12
+ * comprobante pudo haberse procesado aunque la respuesta no se pueda leer).
13
+ */
14
+ function invalid(message, kind) {
15
+ return new ArcaSoapError(message, { uncertain: kind === 'emision' });
16
+ }
17
+ function decode(node, schema, path, kind) {
18
+ return decodeResponse(node, schema, path, { error: (m) => invalid(m, kind) });
19
+ }
20
+ /**
21
+ * Elemento obligatorio del XSD que el DSL no verifica: un contenedor de lista
22
+ * (`[]` si viene vacío) o un elemento complejo (`complex`: tiene que tener hijos).
23
+ */
24
+ function requerido(node, key, path, kind, complex = false) {
25
+ const v = node[key];
26
+ const ok = complex ? v !== null && typeof v === 'object' && !Array.isArray(v) : v !== undefined && v !== null;
27
+ if (!ok)
28
+ throw invalid(`Respuesta inválida: falta ${path}.${key}`, kind);
14
29
  }
15
- function validCaea(caea) {
16
- return validated((f) => f.codigoAutorizacion('caea', caea, true));
30
+ function toCAEA({ CAEA, arrayObservaciones, ...rest }) {
31
+ return { ...rest, caea: CAEA, observaciones: arrayObservaciones };
17
32
  }
18
33
  /**
19
34
  * Cliente de bajo nivel de WSMTXCA: una función por operación del WSDL. No
@@ -25,30 +40,26 @@ function validCaea(caea) {
25
40
  * `kind: 'emision'`: no se reintentan y, si no hay respuesta, el
26
41
  * `ArcaSoapError` tiene `uncertain: true`.
27
42
  */
28
- export class MtxcaClient {
29
- config;
43
+ export class MtxcaClient extends SoapServiceClient {
30
44
  constructor(config) {
31
45
  if (!config?.endpoint)
32
46
  throw new TypeError('MtxcaClient: endpoint es obligatorio');
33
- this.config = config;
34
- }
35
- get endpoint() {
36
- return this.config.endpoint;
47
+ const { endpoint, timeout, retries, retryDelayMs, onEvent, fetch, legacyTls } = config;
48
+ super({
49
+ endpoint,
50
+ namespace: MTXCA_NAMESPACE,
51
+ transport: { timeout, retries, retryDelayMs, onEvent, fetch, legacyTls },
52
+ });
37
53
  }
38
54
  call(method, params, kind, opts, requestElement = `${method}Request`) {
39
- const { endpoint, timeout, retries, retryDelayMs, onEvent, fetch, legacyTls } = this.config;
40
- return afipSoapCall(endpoint, MTXCA_NAMESPACE, method, params, {
41
- timeout,
42
- retries,
43
- retryDelayMs,
44
- onEvent,
45
- fetch,
46
- legacyTls,
55
+ return this.soapCall(method, params, {
47
56
  kind,
48
57
  signal: opts?.signal,
49
58
  requestElement,
50
59
  responseElement: `${method}Response`,
51
60
  soapActionFromMethod: true,
61
+ // Todo como texto: los schemas convierten cada campo según el XSD.
62
+ parseNumbers: false,
52
63
  });
53
64
  }
54
65
  static authRequest(auth) {
@@ -69,13 +80,7 @@ export class MtxcaClient {
69
80
  // =========================================================================
70
81
  /** `dummy`: estado de los servidores. No requiere autenticación. */
71
82
  async dummy(opts) {
72
- const result = await this.call('dummy', {}, 'consulta', opts, null);
73
- const r = new ResponseReader('dummy', 'consulta');
74
- return {
75
- appserver: r.str(result, 'appserver'),
76
- authserver: r.str(result, 'authserver'),
77
- dbserver: r.str(result, 'dbserver'),
78
- };
83
+ return parseServerStatus(await this.call('dummy', {}, 'consulta', opts, null));
79
84
  }
80
85
  // =========================================================================
81
86
  // CAE
@@ -95,44 +100,32 @@ export class MtxcaClient {
95
100
  async autorizarCAE(method, auth, comprobante, opts) {
96
101
  const comprobanteCAERequest = buildComprobante(comprobante, 'cae');
97
102
  const result = await this.callAuth(method, auth, { comprobanteCAERequest }, 'emision', opts);
98
- const r = new ResponseReader(method, 'emision');
99
- const resultado = this.resultado(r, result, method);
100
- const base = {
101
- observaciones: r.codigosDescripciones(result['arrayObservaciones'], 'arrayObservaciones'),
102
- errores: r.codigosDescripciones(result['arrayErrores'], 'arrayErrores'),
103
- evento: r.evento(result),
104
- };
103
+ const { resultado, base } = this.resultado(result, method);
105
104
  if (resultado === 'R')
106
105
  return { resultado, ...base };
107
- const cr = r.obj(result, 'comprobanteResponse');
108
- return {
109
- resultado,
110
- comprobante: {
111
- cuit: r.str(cr, 'cuit', 'comprobanteResponse.cuit'),
112
- codigoTipoComprobante: r.num(cr, 'codigoTipoComprobante', 'comprobanteResponse.codigoTipoComprobante'),
113
- numeroPuntoVenta: r.num(cr, 'numeroPuntoVenta', 'comprobanteResponse.numeroPuntoVenta'),
114
- numeroComprobante: r.num(cr, 'numeroComprobante', 'comprobanteResponse.numeroComprobante'),
115
- fechaEmision: r.str(cr, 'fechaEmision', 'comprobanteResponse.fechaEmision'),
116
- cae: r.str(cr, 'CAE', 'comprobanteResponse.CAE'),
117
- fechaVencimientoCAE: r.str(cr, 'fechaVencimientoCAE', 'comprobanteResponse.fechaVencimientoCAE'),
118
- },
119
- ...base,
120
- };
106
+ requerido(result, 'comprobanteResponse', method, 'emision', true);
107
+ const { CAE, ...cr } = decode(result['comprobanteResponse'], COMPROBANTE_CAE_RESPONSE, `${method}.comprobanteResponse`, 'emision');
108
+ return { resultado, comprobante: { ...cr, cae: CAE }, ...base };
121
109
  }
122
110
  /**
123
- * `resultado` es obligatorio. Si falta y hay `arrayErrores`, es un rechazo
111
+ * Decodifica `resultado`, `arrayObservaciones`, `arrayErrores` y `evento`.
112
+ * `resultado` es obligatorio: si falta y hay `arrayErrores`, es un rechazo
124
113
  * (`ArcaServiceError`); si falta sin errores, la respuesta es ilegible
125
114
  * (`ArcaSoapError` con `uncertain`).
126
115
  */
127
- resultado(r, result, method) {
128
- if (!r.has(result, 'resultado')) {
116
+ resultado(result, method, schema = RESULTADO) {
117
+ const r = decode(result, schema, method, 'emision');
118
+ if (!r.resultado) {
129
119
  checkServiceErrors(result, `${SERVICE} ${method}`);
130
- throw r.invalid('resultado');
120
+ throw invalid(`Respuesta inválida: falta ${method}.resultado`, 'emision');
131
121
  }
132
- const resultado = r.str(result, 'resultado');
133
- if (!isResultado(resultado))
134
- throw r.invalid('resultado', `valor "${resultado}" inesperado en`);
135
- return resultado;
122
+ if (!isResultado(r.resultado)) {
123
+ throw invalid(`Respuesta inválida: valor "${r.resultado}" inesperado en ${method}.resultado`, 'emision');
124
+ }
125
+ return {
126
+ resultado: r.resultado,
127
+ base: { observaciones: r.arrayObservaciones, errores: r.arrayErrores, evento: r.evento },
128
+ };
136
129
  }
137
130
  // =========================================================================
138
131
  // CAEA
@@ -143,44 +136,33 @@ export class MtxcaClient {
143
136
  * resultado es incierto, recuperalo con `consultarCAEAEntreFechas`.
144
137
  */
145
138
  async solicitarCAEA(auth, periodo, orden, opts) {
146
- const solicitudCAEA = validated((f) => {
147
- const p = f.int('periodo', periodo, true, 190001, 999912);
148
- if (p !== undefined && (p % 100 < 1 || p % 100 > 12))
149
- f.fail('periodo', 'formato AAAAMM', periodo);
150
- return { periodo: p, orden: f.int('orden', orden, true, 1, 2) };
139
+ const solicitudCAEA = encodeRequest({ periodo, orden }, SOLICITUD_CAEA, 'solicitarCAEA', (i, errors) => {
140
+ const p = i['periodo'];
141
+ if (Number.isInteger(p) && (p % 100 < 1 || p % 100 > 12)) {
142
+ errors.push({ field: 'periodo', message: 'periodo: debe tener formato AAAAMM (mes 01 a 12)', value: p });
143
+ }
151
144
  });
152
145
  const result = await this.callAuth('solicitarCAEA', auth, { solicitudCAEA }, 'emision', opts);
153
146
  checkServiceErrors(result, `${SERVICE} solicitarCAEA`);
154
- const r = new ResponseReader('solicitarCAEA', 'emision');
155
- return this.parseCAEA(r, r.obj(result, 'CAEAResponse'), 'CAEAResponse');
147
+ return this.parseCAEA(result, 'solicitarCAEA', 'emision');
156
148
  }
157
149
  /** `consultarCAEA`: datos de un CAEA otorgado. */
158
150
  async consultarCAEA(auth, caea, opts) {
159
- const result = await this.consulta('consultarCAEA', auth, { CAEA: validCaea(caea) }, opts);
160
- const r = new ResponseReader('consultarCAEA', 'consulta');
161
- return this.parseCAEA(r, r.obj(result, 'CAEAResponse'), 'CAEAResponse');
151
+ const params = encodeConCaea({ caea }, CON_CAEA, 'consultarCAEA');
152
+ const result = await this.consulta('consultarCAEA', auth, params, opts);
153
+ return this.parseCAEA(result, 'consultarCAEA', 'consulta');
154
+ }
155
+ /** `CAEAResponse` obligatorio de `solicitarCAEA` / `consultarCAEA`. */
156
+ parseCAEA(result, method, kind) {
157
+ requerido(result, 'CAEAResponse', method, kind, true);
158
+ return toCAEA(decode(result['CAEAResponse'], CAEA_RESPONSE, `${method}.CAEAResponse`, kind));
162
159
  }
163
160
  /** `consultarCAEAEntreFechas`: CAEAs otorgados con vigencia entre dos fechas. */
164
161
  async consultarCAEAEntreFechas(auth, fechaDesde, fechaHasta, opts) {
165
- const params = validated((f) => ({
166
- fechaDesde: f.date('fechaDesde', fechaDesde, true),
167
- fechaHasta: f.date('fechaHasta', fechaHasta, true),
168
- }));
162
+ const params = encodeRequest({ fechaDesde, fechaHasta }, ENTRE_FECHAS, 'consultarCAEAEntreFechas');
169
163
  const result = await this.consulta('consultarCAEAEntreFechas', auth, params, opts);
170
- const r = new ResponseReader('consultarCAEAEntreFechas', 'consulta');
171
- return r.list(result['arrayCAEAResponse'], 'CAEAResponse').map((c, i) => this.parseCAEA(r, c, `arrayCAEAResponse.CAEAResponse[${i}]`));
172
- }
173
- parseCAEA(r, c, path) {
174
- return {
175
- fechaProceso: r.str(c, 'fechaProceso', `${path}.fechaProceso`),
176
- caea: r.str(c, 'CAEA', `${path}.CAEA`),
177
- periodo: r.num(c, 'periodo', `${path}.periodo`),
178
- orden: r.num(c, 'orden', `${path}.orden`),
179
- fechaDesde: r.str(c, 'fechaDesde', `${path}.fechaDesde`),
180
- fechaHasta: r.str(c, 'fechaHasta', `${path}.fechaHasta`),
181
- fechaTopeInforme: r.str(c, 'fechaTopeInforme', `${path}.fechaTopeInforme`),
182
- observaciones: r.codigosDescripciones(c['arrayObservaciones'], `${path}.arrayObservaciones`),
183
- };
164
+ const { arrayCAEAResponse } = decode(result, CAEA_ENTRE_FECHAS_RESPONSE, 'consultarCAEAEntreFechas', 'consulta');
165
+ return arrayCAEAResponse.map(toCAEA);
184
166
  }
185
167
  /** `informarComprobanteCAEA`. Un rechazo devuelve `resultado: 'R'` con `errores`. */
186
168
  async informarComprobanteCAEA(auth, comprobante, opts) {
@@ -193,57 +175,54 @@ export class MtxcaClient {
193
175
  async informarCAEA(method, auth, comprobante, opts) {
194
176
  const comprobanteCAEARequest = buildComprobante(comprobante, 'caea');
195
177
  const result = await this.callAuth(method, auth, { comprobanteCAEARequest }, 'emision', opts);
196
- const r = new ResponseReader(method, 'emision');
197
- const resultado = this.resultado(r, result, method);
198
- const base = {
199
- observaciones: r.codigosDescripciones(result['arrayObservaciones'], 'arrayObservaciones'),
200
- errores: r.codigosDescripciones(result['arrayErrores'], 'arrayErrores'),
201
- evento: r.evento(result),
202
- };
178
+ const { resultado, base } = this.resultado(result, method);
179
+ const { fechaProceso } = decode(result, FECHA_PROCESO, method, 'emision');
203
180
  if (resultado === 'R')
204
- return { resultado, fechaProceso: r.optStr(result, 'fechaProceso'), ...base };
205
- const cr = r.obj(result, 'comprobanteCAEAResponse');
206
- return {
207
- resultado,
208
- fechaProceso: r.str(result, 'fechaProceso'),
209
- comprobante: {
210
- caea: r.str(cr, 'CAEA', 'comprobanteCAEAResponse.CAEA'),
211
- codigoTipoComprobante: r.num(cr, 'codigoTipoComprobante', 'comprobanteCAEAResponse.codigoTipoComprobante'),
212
- numeroPuntoVenta: r.num(cr, 'numeroPuntoVenta', 'comprobanteCAEAResponse.numeroPuntoVenta'),
213
- numeroComprobante: r.num(cr, 'numeroComprobante', 'comprobanteCAEAResponse.numeroComprobante'),
214
- },
215
- ...base,
216
- };
181
+ return { resultado, fechaProceso, ...base };
182
+ if (fechaProceso === undefined)
183
+ throw invalid(`Respuesta inválida: falta ${method}.fechaProceso`, 'emision');
184
+ requerido(result, 'comprobanteCAEAResponse', method, 'emision', true);
185
+ const { CAEA, ...cr } = decode(result['comprobanteCAEAResponse'], COMPROBANTE_CAEA_RESPONSE, `${method}.comprobanteCAEAResponse`, 'emision');
186
+ return { resultado, fechaProceso, comprobante: { caea: CAEA, ...cr }, ...base };
217
187
  }
218
188
  /** `informarCAEANoUtilizado`: informa que un CAEA no se usó en ningún punto de venta. */
219
189
  async informarCAEANoUtilizado(auth, caea, opts) {
220
- return this.caeaNoUtilizado('informarCAEANoUtilizado', auth, { CAEA: validCaea(caea) }, opts);
190
+ const method = 'informarCAEANoUtilizado';
191
+ return this.caeaNoUtilizado(method, auth, encodeConCaea({ caea }, CON_CAEA, method), CAEA_NO_UTILIZADO, opts);
221
192
  }
222
193
  /** `informarCAEANoUtilizadoPtoVta`: informa que un CAEA no se usó en un punto de venta. */
223
194
  async informarCAEANoUtilizadoPtoVta(auth, caea, numeroPuntoVenta, opts) {
224
- const ptoVta = validated((f) => f.int('numeroPuntoVenta', numeroPuntoVenta, true, 1, 99998));
225
- return this.caeaNoUtilizado('informarCAEANoUtilizadoPtoVta', auth, { CAEA: validCaea(caea), numeroPuntoVenta: ptoVta }, opts);
195
+ const method = 'informarCAEANoUtilizadoPtoVta';
196
+ const params = encodeConCaea({ caea, numeroPuntoVenta }, CON_CAEA_PTO_VTA, method);
197
+ return this.caeaNoUtilizado(method, auth, params, CAEA_NO_UTILIZADO_PTO_VTA, opts);
226
198
  }
227
- async caeaNoUtilizado(method, auth, params, opts) {
199
+ async caeaNoUtilizado(method, auth, params, schema, opts) {
228
200
  const result = await this.callAuth(method, auth, params, 'emision', opts);
229
- const r = new ResponseReader(method, 'emision');
230
- const resultado = this.resultado(r, result, method);
231
- const aprobado = resultado !== 'R';
201
+ const { resultado, base } = this.resultado(result, method, schema);
202
+ const r = decode(result, schema, method, 'emision');
232
203
  const conPtoVta = 'numeroPuntoVenta' in params;
204
+ // Obligatorios en el XSD; en un rechazo se toleran ausentes.
205
+ const faltante = [
206
+ r.fechaProceso === undefined && 'fechaProceso',
207
+ r.CAEA === undefined && 'CAEA',
208
+ conPtoVta && r.numeroPuntoVenta === undefined && 'numeroPuntoVenta',
209
+ ].find(Boolean);
210
+ if (resultado !== 'R' && faltante)
211
+ throw invalid(`Respuesta inválida: falta ${method}.${faltante}`, 'emision');
233
212
  return {
234
213
  resultado,
235
- fechaProceso: aprobado ? r.str(result, 'fechaProceso') : r.optStr(result, 'fechaProceso'),
236
- caea: aprobado ? r.str(result, 'CAEA') : r.optStr(result, 'CAEA'),
237
- ...(conPtoVta ? { numeroPuntoVenta: aprobado ? r.num(result, 'numeroPuntoVenta') : r.optNum(result, 'numeroPuntoVenta') } : {}),
238
- errores: r.codigosDescripciones(result['arrayErrores'], 'arrayErrores'),
239
- evento: r.evento(result),
214
+ fechaProceso: r.fechaProceso,
215
+ caea: r.CAEA,
216
+ ...(conPtoVta ? { numeroPuntoVenta: r.numeroPuntoVenta } : {}),
217
+ errores: base.errores,
218
+ evento: base.evento,
240
219
  };
241
220
  }
242
221
  /** `consultarPtosVtaCAEANoInformados`: puntos de venta que todavía no informaron movimientos para el CAEA. */
243
222
  async consultarPtosVtaCAEANoInformados(auth, caea, opts) {
244
- const result = await this.consulta('consultarPtosVtaCAEANoInformados', auth, { CAEA: validCaea(caea) }, opts);
245
- const r = new ResponseReader('consultarPtosVtaCAEANoInformados', 'consulta');
246
- return this.parsePuntosVenta(r, r.list(result['arrayPuntosVenta'], 'puntoVenta'));
223
+ const method = 'consultarPtosVtaCAEANoInformados';
224
+ const result = await this.consulta(method, auth, encodeConCaea({ caea }, CON_CAEA, method), opts);
225
+ return this.parsePuntosVenta(result, method);
247
226
  }
248
227
  // =========================================================================
249
228
  // Consultas de comprobantes
@@ -254,100 +233,101 @@ export class MtxcaClient {
254
233
  * y tipo); `ArcaMtxca.ultimoComprobante` lo traduce a 0.
255
234
  */
256
235
  async consultarUltimoComprobanteAutorizado(auth, ptoVta, cbteTipo, opts) {
257
- const consultaUltimoComprobanteAutorizadoRequest = validated((f) => ({
258
- codigoTipoComprobante: f.int('cbteTipo', cbteTipo, true),
259
- numeroPuntoVenta: f.int('ptoVta', ptoVta, true, 1, 99998),
260
- }));
261
- const result = await this.consulta('consultarUltimoComprobanteAutorizado', auth, { consultaUltimoComprobanteAutorizadoRequest }, opts);
262
- return new ResponseReader('consultarUltimoComprobanteAutorizado', 'consulta').num(result, 'numeroComprobante');
236
+ const method = 'consultarUltimoComprobanteAutorizado';
237
+ const consultaUltimoComprobanteAutorizadoRequest = encodeRequest({ codigoTipoComprobante: cbteTipo, numeroPuntoVenta: ptoVta }, CONSULTA_ULTIMO, method);
238
+ const result = await this.consulta(method, auth, { consultaUltimoComprobanteAutorizadoRequest }, opts);
239
+ return decode(result, ULTIMO_RESPONSE, method, 'consulta').numeroComprobante;
263
240
  }
264
241
  /** `consultarComprobante`: datos de un comprobante autorizado (CAE) o informado (CAEA). */
265
242
  async consultarComprobante(auth, cbteTipo, ptoVta, cbteNro, opts) {
266
- const consultaComprobanteRequest = validated((f) => ({
267
- codigoTipoComprobante: f.int('cbteTipo', cbteTipo, true),
268
- numeroPuntoVenta: f.int('ptoVta', ptoVta, true, 1, 99998),
269
- numeroComprobante: f.int('cbteNro', cbteNro, true, 1, 99999999),
270
- }));
271
- const result = await this.consulta('consultarComprobante', auth, { consultaComprobanteRequest }, opts);
272
- const r = new ResponseReader('consultarComprobante', 'consulta');
243
+ const method = 'consultarComprobante';
244
+ const consultaComprobanteRequest = encodeRequest({ codigoTipoComprobante: cbteTipo, numeroPuntoVenta: ptoVta, numeroComprobante: cbteNro }, CONSULTA_COMPROBANTE, method);
245
+ const result = await this.consulta(method, auth, { consultaComprobanteRequest }, opts);
246
+ requerido(result, 'comprobante', method, 'consulta', true);
247
+ requerido(result['comprobante'], 'arrayItems', `${method}.comprobante`, 'consulta');
248
+ const r = decode(result, CONSULTA_COMPROBANTE_RESPONSE, method, 'consulta');
249
+ const { arrayComprobantesAsociados, arrayOtrosTributos, arrayItems, arraySubtotalesIVA, arrayDatosAdicionales, arrayCompradores, arrayActividades, ...c } = r.comprobante;
273
250
  return {
274
- comprobante: parseComprobante(r, r.obj(result, 'comprobante')),
275
- observaciones: r.codigosDescripciones(result['arrayObservaciones'], 'arrayObservaciones'),
276
- evento: r.evento(result),
251
+ comprobante: {
252
+ ...c,
253
+ comprobantesAsociados: arrayComprobantesAsociados,
254
+ otrosTributos: arrayOtrosTributos,
255
+ items: arrayItems,
256
+ subtotalesIVA: arraySubtotalesIVA,
257
+ datosAdicionales: arrayDatosAdicionales,
258
+ compradores: arrayCompradores,
259
+ actividades: arrayActividades.map((a) => a.codigo),
260
+ },
261
+ observaciones: r.arrayObservaciones,
262
+ evento: r.evento,
277
263
  };
278
264
  }
279
265
  // =========================================================================
280
266
  // Parámetros
281
267
  // =========================================================================
282
- async codigos(method, container, auth, opts, params = {}) {
283
- const result = await this.consulta(method, auth, params, opts);
284
- const r = new ResponseReader(method, 'consulta');
285
- return r.requiredList(result, container, 'codigoDescripcion').map((cd, i) => r.codigoDescripcion(cd, `${container}[${i}]`));
268
+ /** Consulta cuya respuesta es un `ArrayCodigosDescripciones[String]Type` obligatorio (ver `PARAMETROS`). */
269
+ async codigos(method, auth, opts) {
270
+ const schema = PARAMETROS[method];
271
+ const [container] = Object.keys(schema);
272
+ const result = await this.consulta(method, auth, {}, opts);
273
+ requerido(result, container, method, 'consulta');
274
+ return decode(result, schema, method, 'consulta')[container];
286
275
  }
287
276
  consultarTiposComprobante(auth, opts) {
288
- return this.codigos('consultarTiposComprobante', 'arrayTiposComprobante', auth, opts);
277
+ return this.codigos('consultarTiposComprobante', auth, opts);
289
278
  }
290
279
  consultarTiposDocumento(auth, opts) {
291
- return this.codigos('consultarTiposDocumento', 'arrayTiposDocumento', auth, opts);
280
+ return this.codigos('consultarTiposDocumento', auth, opts);
292
281
  }
293
282
  consultarAlicuotasIVA(auth, opts) {
294
- return this.codigos('consultarAlicuotasIVA', 'arrayAlicuotasIVA', auth, opts);
283
+ return this.codigos('consultarAlicuotasIVA', auth, opts);
295
284
  }
296
285
  consultarCondicionesIVA(auth, opts) {
297
- return this.codigos('consultarCondicionesIVA', 'arrayCondicionesIVA', auth, opts);
286
+ return this.codigos('consultarCondicionesIVA', auth, opts);
298
287
  }
299
288
  /** Condiciones de IVA del receptor admitidas para un tipo de comprobante (RG 5616). */
300
289
  async consultarCondicionesIVAReceptor(auth, cbteTipo, opts) {
301
- const consultaCondicionesIVAReceptorRequest = validated((f) => ({ codigoTipoComprobante: f.int('cbteTipo', cbteTipo, true) }));
302
- const result = await this.consulta('consultarCondicionesIVAReceptor', auth, { consultaCondicionesIVAReceptorRequest }, opts);
303
- const r = new ResponseReader('consultarCondicionesIVAReceptor', 'consulta');
304
- return r.codigosDescripciones(result['arrayCondicionesIVAReceptor'], 'arrayCondicionesIVAReceptor');
290
+ const method = 'consultarCondicionesIVAReceptor';
291
+ const consultaCondicionesIVAReceptorRequest = encodeRequest({ codigoTipoComprobante: cbteTipo }, CONSULTA_CONDICIONES_IVA, method);
292
+ const result = await this.consulta(method, auth, { consultaCondicionesIVAReceptorRequest }, opts);
293
+ return decode(result, CONDICIONES_IVA_RECEPTOR_RESPONSE, method, 'consulta').arrayCondicionesIVAReceptor;
305
294
  }
306
295
  consultarUnidadesMedida(auth, opts) {
307
- return this.codigos('consultarUnidadesMedida', 'arrayUnidadesMedida', auth, opts);
296
+ return this.codigos('consultarUnidadesMedida', auth, opts);
308
297
  }
309
298
  consultarTiposTributo(auth, opts) {
310
- return this.codigos('consultarTiposTributo', 'arrayTiposTributo', auth, opts);
299
+ return this.codigos('consultarTiposTributo', auth, opts);
311
300
  }
312
301
  consultarTiposDatosAdicionales(auth, opts) {
313
- return this.codigos('consultarTiposDatosAdicionales', 'arrayTiposDatosAdicionales', auth, opts);
302
+ return this.codigos('consultarTiposDatosAdicionales', auth, opts);
314
303
  }
315
- async consultarMonedas(auth, opts) {
316
- const result = await this.consulta('consultarMonedas', auth, {}, opts);
317
- const r = new ResponseReader('consultarMonedas', 'consulta');
318
- return r.requiredList(result, 'arrayMonedas', 'codigoDescripcion').map((m, i) => ({
319
- codigo: r.str(m, 'codigo', `arrayMonedas[${i}].codigo`),
320
- descripcion: r.str(m, 'descripcion', `arrayMonedas[${i}].descripcion`),
321
- }));
304
+ consultarMonedas(auth, opts) {
305
+ return this.codigos('consultarMonedas', auth, opts);
322
306
  }
323
307
  /**
324
308
  * `consultarCotizacionMoneda`. `cotizacion` es `null` si ARCA no tiene
325
309
  * cotización para la moneda en esa fecha (responde sin valor y sin error).
326
310
  */
327
311
  async consultarCotizacionMoneda(auth, codigoMoneda, fechaCotizacion, opts) {
328
- const params = validated((f) => ({
329
- codigoMoneda: f.text('codigoMoneda', codigoMoneda, true, 3),
330
- fechaCotizacion: f.date('fechaCotizacion', fechaCotizacion, true),
331
- }));
332
- const result = await this.consulta('consultarCotizacionMoneda', auth, params, opts);
333
- const r = new ResponseReader('consultarCotizacionMoneda', 'consulta');
312
+ const method = 'consultarCotizacionMoneda';
313
+ const params = encodeRequest({ codigoMoneda, fechaCotizacion }, COTIZACION, method);
314
+ const result = await this.consulta(method, auth, params, opts);
315
+ const { cotizacionMoneda } = decode(result, COTIZACION_RESPONSE, method, 'consulta');
334
316
  return {
335
- codigoMoneda: params.codigoMoneda,
336
- fechaCotizacion: params.fechaCotizacion,
337
- cotizacion: r.optNum(result, 'cotizacionMoneda') ?? null,
317
+ codigoMoneda: params['codigoMoneda'],
318
+ fechaCotizacion: params['fechaCotizacion'],
319
+ cotizacion: cotizacionMoneda ?? null,
338
320
  };
339
321
  }
340
- async puntosVenta(method, auth, opts) {
341
- const result = await this.consulta(method, auth, {}, opts);
342
- const r = new ResponseReader(method, 'consulta');
343
- return this.parsePuntosVenta(r, r.requiredList(result, 'arrayPuntosVenta', 'puntoVenta'));
322
+ /** `ArrayPuntosVentaType` (obligatorio salvo en `consultarPtosVtaCAEANoInformados`). */
323
+ parsePuntosVenta(result, method, obligatorio = false) {
324
+ if (obligatorio)
325
+ requerido(result, 'arrayPuntosVenta', method, 'consulta');
326
+ return decode(result, PUNTOS_VENTA_RESPONSE, method, 'consulta')
327
+ .arrayPuntosVenta;
344
328
  }
345
- parsePuntosVenta(r, list) {
346
- return list.map((pv, i) => ({
347
- numeroPuntoVenta: r.num(pv, 'numeroPuntoVenta', `puntoVenta[${i}].numeroPuntoVenta`),
348
- bloqueado: r.str(pv, 'bloqueado', `puntoVenta[${i}].bloqueado`),
349
- fechaBaja: r.optStr(pv, 'fechaBaja'),
350
- }));
329
+ async puntosVenta(method, auth, opts) {
330
+ return this.parsePuntosVenta(await this.consulta(method, auth, {}, opts), method, true);
351
331
  }
352
332
  consultarPuntosVenta(auth, opts) {
353
333
  return this.puntosVenta('consultarPuntosVenta', auth, opts);
@@ -360,107 +340,10 @@ export class MtxcaClient {
360
340
  }
361
341
  /** `consultarActividadesVigentes`: actividades vigentes del emisor. */
362
342
  async consultarActividadesVigentes(auth, opts) {
363
- const result = await this.consulta('consultarActividadesVigentes', auth, {}, opts);
364
- const r = new ResponseReader('consultarActividadesVigentes', 'consulta');
365
- return r.list(result['arrayActividades'], 'actividad').map((a, i) => ({
366
- codigo: r.num(a, 'codigo', `arrayActividades[${i}].codigo`),
367
- orden: r.num(a, 'orden', `arrayActividades[${i}].orden`),
368
- descripcion: r.str(a, 'descripcion', `arrayActividades[${i}].descripcion`),
369
- }));
343
+ const method = 'consultarActividadesVigentes';
344
+ const result = await this.consulta(method, auth, {}, opts);
345
+ return decode(result, ACTIVIDADES_VIGENTES_RESPONSE, method, 'consulta')
346
+ .arrayActividades;
370
347
  }
371
348
  }
372
- /** Parsea un `ComprobanteType` de `consultarComprobante`. */
373
- function parseComprobante(r, c) {
374
- const periodo = r.optObj(c, 'periodoComprobantesAsociados');
375
- return {
376
- codigoTipoComprobante: r.num(c, 'codigoTipoComprobante', 'comprobante.codigoTipoComprobante'),
377
- numeroPuntoVenta: r.num(c, 'numeroPuntoVenta', 'comprobante.numeroPuntoVenta'),
378
- numeroComprobante: r.num(c, 'numeroComprobante', 'comprobante.numeroComprobante'),
379
- fechaEmision: r.optStr(c, 'fechaEmision'),
380
- codigoTipoAutorizacion: r.optStr(c, 'codigoTipoAutorizacion'),
381
- codigoAutorizacion: r.optStr(c, 'codigoAutorizacion'),
382
- fechaVencimiento: r.optStr(c, 'fechaVencimiento'),
383
- codigoTipoDocumento: r.optNum(c, 'codigoTipoDocumento'),
384
- numeroDocumento: r.optStr(c, 'numeroDocumento'),
385
- condicionIVAReceptor: r.optNum(c, 'condicionIVAReceptor'),
386
- importeGravado: r.optNum(c, 'importeGravado'),
387
- importeNoGravado: r.optNum(c, 'importeNoGravado'),
388
- importeExento: r.optNum(c, 'importeExento'),
389
- importeSubtotal: r.num(c, 'importeSubtotal', 'comprobante.importeSubtotal'),
390
- importeOtrosTributos: r.optNum(c, 'importeOtrosTributos'),
391
- importeTotal: r.num(c, 'importeTotal', 'comprobante.importeTotal'),
392
- codigoMoneda: r.str(c, 'codigoMoneda', 'comprobante.codigoMoneda'),
393
- cotizacionMoneda: r.optNum(c, 'cotizacionMoneda'),
394
- cancelaEnMismaMonedaExtranjera: r.optStr(c, 'cancelaEnMismaMonedaExtranjera'),
395
- observaciones: r.optStr(c, 'observaciones'),
396
- codigoConcepto: r.num(c, 'codigoConcepto', 'comprobante.codigoConcepto'),
397
- fechaServicioDesde: r.optStr(c, 'fechaServicioDesde'),
398
- fechaServicioHasta: r.optStr(c, 'fechaServicioHasta'),
399
- fechaVencimientoPago: r.optStr(c, 'fechaVencimientoPago'),
400
- fechaHoraGen: r.optStr(c, 'fechaHoraGen'),
401
- comprobantesAsociados: r.list(c['arrayComprobantesAsociados'], 'comprobanteAsociado').map((a, i) => {
402
- const p = `comprobante.arrayComprobantesAsociados[${i}]`;
403
- return {
404
- codigoTipoComprobante: r.num(a, 'codigoTipoComprobante', `${p}.codigoTipoComprobante`),
405
- numeroPuntoVenta: r.num(a, 'numeroPuntoVenta', `${p}.numeroPuntoVenta`),
406
- numeroComprobante: r.num(a, 'numeroComprobante', `${p}.numeroComprobante`),
407
- cuit: r.optStr(a, 'cuit'),
408
- fechaEmision: r.optStr(a, 'fechaEmision'),
409
- };
410
- }),
411
- periodoComprobantesAsociados: periodo
412
- ? {
413
- fechaDesde: r.str(periodo, 'fechaDesde', 'comprobante.periodoComprobantesAsociados.fechaDesde'),
414
- fechaHasta: r.str(periodo, 'fechaHasta', 'comprobante.periodoComprobantesAsociados.fechaHasta'),
415
- }
416
- : undefined,
417
- otrosTributos: r.list(c['arrayOtrosTributos'], 'otroTributo').map((t, i) => {
418
- const p = `comprobante.arrayOtrosTributos[${i}]`;
419
- return {
420
- codigo: r.num(t, 'codigo', `${p}.codigo`),
421
- descripcion: r.optStr(t, 'descripcion'),
422
- baseImponible: r.num(t, 'baseImponible', `${p}.baseImponible`),
423
- importe: r.num(t, 'importe', `${p}.importe`),
424
- };
425
- }),
426
- items: r.requiredList(c, 'arrayItems', 'item').map((it, i) => {
427
- const p = `comprobante.arrayItems[${i}]`;
428
- return {
429
- unidadesMtx: r.optNum(it, 'unidadesMtx'),
430
- codigoMtx: r.optStr(it, 'codigoMtx'),
431
- codigo: r.optStr(it, 'codigo'),
432
- descripcion: r.str(it, 'descripcion', `${p}.descripcion`),
433
- cantidad: r.optNum(it, 'cantidad'),
434
- codigoUnidadMedida: r.num(it, 'codigoUnidadMedida', `${p}.codigoUnidadMedida`),
435
- precioUnitario: r.optNum(it, 'precioUnitario'),
436
- importeBonificacion: r.optNum(it, 'importeBonificacion'),
437
- codigoCondicionIVA: r.num(it, 'codigoCondicionIVA', `${p}.codigoCondicionIVA`),
438
- importeIVA: r.optNum(it, 'importeIVA'),
439
- importeItem: r.num(it, 'importeItem', `${p}.importeItem`),
440
- };
441
- }),
442
- subtotalesIVA: r.list(c['arraySubtotalesIVA'], 'subtotalIVA').map((s, i) => ({
443
- codigo: r.num(s, 'codigo', `comprobante.arraySubtotalesIVA[${i}].codigo`),
444
- importe: r.num(s, 'importe', `comprobante.arraySubtotalesIVA[${i}].importe`),
445
- })),
446
- datosAdicionales: r.list(c['arrayDatosAdicionales'], 'datoAdicional').map((d, i) => ({
447
- t: r.num(d, 't', `comprobante.arrayDatosAdicionales[${i}].t`),
448
- c1: r.optStr(d, 'c1'),
449
- c2: r.optStr(d, 'c2'),
450
- c3: r.optStr(d, 'c3'),
451
- c4: r.optStr(d, 'c4'),
452
- c5: r.optStr(d, 'c5'),
453
- c6: r.optStr(d, 'c6'),
454
- })),
455
- compradores: r.list(c['arrayCompradores'], 'comprador').map((x, i) => {
456
- const p = `comprobante.arrayCompradores[${i}]`;
457
- return {
458
- codigoTipoDocumento: r.num(x, 'codigoTipoDocumento', `${p}.codigoTipoDocumento`),
459
- numeroDocumento: r.str(x, 'numeroDocumento', `${p}.numeroDocumento`),
460
- porcentaje: r.num(x, 'porcentaje', `${p}.porcentaje`),
461
- };
462
- }),
463
- actividades: r.list(c['arrayActividades'], 'actividad').map((a, i) => r.num(a, 'codigo', `comprobante.arrayActividades[${i}].codigo`)),
464
- };
465
- }
466
349
  //# sourceMappingURL=mtxca-client.js.map