@ramiidv/arca-mtxca 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.
- package/CHANGELOG.md +129 -0
- package/README.md +175 -318
- package/dist/arca-mtxca.d.ts +81 -78
- package/dist/arca-mtxca.d.ts.map +1 -1
- package/dist/arca-mtxca.js +174 -153
- package/dist/arca-mtxca.js.map +1 -1
- package/dist/constants.d.ts +37 -21
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +49 -22
- package/dist/constants.js.map +1 -1
- package/dist/format.d.ts +10 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +22 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -1
- package/dist/mtxca-client.d.ts +94 -33
- package/dist/mtxca-client.d.ts.map +1 -1
- package/dist/mtxca-client.js +307 -332
- package/dist/mtxca-client.js.map +1 -1
- package/dist/schemas.d.ts +104 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +285 -0
- package/dist/schemas.js.map +1 -0
- package/dist/serialize.d.ts +26 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +116 -0
- package/dist/serialize.js.map +1 -0
- package/dist/types.d.ts +328 -174
- package/dist/types.d.ts.map +1 -1
- package/dist/validation.d.ts +21 -7
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +301 -83
- package/dist/validation.js.map +1 -1
- package/llms.txt +82 -159
- package/package.json +19 -20
package/dist/mtxca-client.js
CHANGED
|
@@ -1,374 +1,349 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return
|
|
9
|
-
code: Number(o['codigo'] ?? 0),
|
|
10
|
-
msg: String(o['descripcion'] ?? ''),
|
|
11
|
-
}));
|
|
1
|
+
import { ArcaSoapError, checkServiceErrors, parseServerStatus, SoapServiceClient } from '@ramiidv/arca-common';
|
|
2
|
+
import { decodeResponse, encodeRequest } from '@ramiidv/arca-common/schema';
|
|
3
|
+
import { MTXCA_NAMESPACE } from './constants.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';
|
|
6
|
+
const SERVICE = 'WSMTXCA';
|
|
7
|
+
function isResultado(value) {
|
|
8
|
+
return value === 'A' || value === 'O' || value === 'R';
|
|
12
9
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
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);
|
|
22
29
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
if (!items)
|
|
26
|
-
return [];
|
|
27
|
-
const arr = ensureArray(items['item']);
|
|
28
|
-
return arr.map((i) => ({
|
|
29
|
-
codigo: i['codigo'] != null ? String(i['codigo']) : undefined,
|
|
30
|
-
descripcion: String(i['descripcion'] ?? ''),
|
|
31
|
-
cantidad: Number(i['cantidad'] ?? 0),
|
|
32
|
-
unidadMedida: Number(i['unidadMedida'] ?? 0),
|
|
33
|
-
precioUnitario: Number(i['precioUnitario'] ?? 0),
|
|
34
|
-
importeItem: Number(i['importeItem'] ?? 0),
|
|
35
|
-
codigoCondicionIVA: Number(i['codigoCondicionIVA'] ?? 0),
|
|
36
|
-
importeIVA: Number(i['importeIVA'] ?? 0),
|
|
37
|
-
importeBonificacion: i['importeBonificacion'] != null
|
|
38
|
-
? Number(i['importeBonificacion'])
|
|
39
|
-
: undefined,
|
|
40
|
-
}));
|
|
30
|
+
function toCAEA({ CAEA, arrayObservaciones, ...rest }) {
|
|
31
|
+
return { ...rest, caea: CAEA, observaciones: arrayObservaciones };
|
|
41
32
|
}
|
|
42
33
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
34
|
+
* Cliente de bajo nivel de WSMTXCA: una función por operación del WSDL. No
|
|
35
|
+
* maneja la autenticación (recibe `MtxcaAuth`) ni la numeración.
|
|
36
|
+
*
|
|
37
|
+
* - Valida los requests contra el XSD y redondea importes (`ArcaValidationError`).
|
|
38
|
+
* - Las consultas lanzan `ArcaServiceError` si ARCA devuelve `arrayErrores`.
|
|
39
|
+
* - Las emisiones (`autorizar*`, `informar*`, `solicitarCAEA`) usan
|
|
40
|
+
* `kind: 'emision'`: no se reintentan y, si no hay respuesta, el
|
|
41
|
+
* `ArcaSoapError` tiene `uncertain: true`.
|
|
45
42
|
*/
|
|
46
|
-
export class MtxcaClient {
|
|
47
|
-
endpoint;
|
|
48
|
-
soapOptions;
|
|
49
|
-
onEvent;
|
|
43
|
+
export class MtxcaClient extends SoapServiceClient {
|
|
50
44
|
constructor(config) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
if (!config?.endpoint)
|
|
46
|
+
throw new TypeError('MtxcaClient: endpoint es obligatorio');
|
|
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
|
+
});
|
|
53
|
+
}
|
|
54
|
+
call(method, params, kind, opts, requestElement = `${method}Request`) {
|
|
55
|
+
return this.soapCall(method, params, {
|
|
56
|
+
kind,
|
|
57
|
+
signal: opts?.signal,
|
|
58
|
+
requestElement,
|
|
59
|
+
responseElement: `${method}Response`,
|
|
60
|
+
soapActionFromMethod: true,
|
|
61
|
+
// Todo como texto: los schemas convierten cada campo según el XSD.
|
|
62
|
+
parseNumbers: false,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
static authRequest(auth) {
|
|
66
|
+
return { token: auth.token, sign: auth.sign, cuitRepresentada: auth.cuitRepresentada };
|
|
56
67
|
}
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
/** Llamada autenticada: `authRequest` primero, como en todos los request del XSD. */
|
|
69
|
+
callAuth(method, auth, params, kind, opts) {
|
|
70
|
+
return this.call(method, { authRequest: MtxcaClient.authRequest(auth), ...params }, kind, opts);
|
|
59
71
|
}
|
|
72
|
+
/** Consulta: lanza `ArcaServiceError` si la respuesta trae `arrayErrores`. */
|
|
73
|
+
async consulta(method, auth, params, opts) {
|
|
74
|
+
const result = await this.callAuth(method, auth, params, 'consulta', opts);
|
|
75
|
+
checkServiceErrors(result, `${SERVICE} ${method}`);
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
// =========================================================================
|
|
79
|
+
// Estado
|
|
60
80
|
// =========================================================================
|
|
61
|
-
|
|
81
|
+
/** `dummy`: estado de los servidores. No requiere autenticación. */
|
|
82
|
+
async dummy(opts) {
|
|
83
|
+
return parseServerStatus(await this.call('dummy', {}, 'consulta', opts, null));
|
|
84
|
+
}
|
|
85
|
+
// =========================================================================
|
|
86
|
+
// CAE
|
|
62
87
|
// =========================================================================
|
|
63
88
|
/**
|
|
64
|
-
*
|
|
89
|
+
* `autorizarComprobante`. Valida contra el XSD y redondea; no valida la
|
|
90
|
+
* coherencia de importes (eso lo hace `ArcaMtxca.autorizar`). Un rechazo
|
|
91
|
+
* devuelve `resultado: 'R'` con `errores` (no lanza).
|
|
65
92
|
*/
|
|
66
|
-
async autorizarComprobante(auth,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
// Optional fields
|
|
96
|
-
if (request.invoice.codigoMoneda != null) {
|
|
97
|
-
comprobante['codigoMoneda'] = request.invoice.codigoMoneda;
|
|
98
|
-
}
|
|
99
|
-
if (request.invoice.cotizacionMoneda != null) {
|
|
100
|
-
comprobante['cotizacionMoneda'] = request.invoice.cotizacionMoneda;
|
|
101
|
-
}
|
|
102
|
-
if (request.invoice.importeGravado != null) {
|
|
103
|
-
comprobante['importeGravado'] = request.invoice.importeGravado;
|
|
104
|
-
}
|
|
105
|
-
if (request.invoice.importeNoGravado != null) {
|
|
106
|
-
comprobante['importeNoGravado'] = request.invoice.importeNoGravado;
|
|
107
|
-
}
|
|
108
|
-
if (request.invoice.importeExento != null) {
|
|
109
|
-
comprobante['importeExento'] = request.invoice.importeExento;
|
|
110
|
-
}
|
|
111
|
-
if (request.invoice.importeOtrosTributos != null) {
|
|
112
|
-
comprobante['importeOtrosTributos'] = request.invoice.importeOtrosTributos;
|
|
113
|
-
}
|
|
114
|
-
// Subtotales de IVA
|
|
115
|
-
if (request.invoice.subtotalesIVA && request.invoice.subtotalesIVA.length > 0) {
|
|
116
|
-
comprobante['arraySubtotalesIVA'] = {
|
|
117
|
-
subtotalIVA: request.invoice.subtotalesIVA.map((s) => ({
|
|
118
|
-
codigo: s.codigo,
|
|
119
|
-
baseImponible: s.baseImponible,
|
|
120
|
-
importe: s.importe,
|
|
121
|
-
})),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
// Otros tributos
|
|
125
|
-
if (request.invoice.otrosTributos && request.invoice.otrosTributos.length > 0) {
|
|
126
|
-
comprobante['arrayOtrosTributos'] = {
|
|
127
|
-
otroTributo: request.invoice.otrosTributos.map((t) => {
|
|
128
|
-
const mapped = {
|
|
129
|
-
codigo: t.codigoTributo,
|
|
130
|
-
baseImponible: t.baseImponible,
|
|
131
|
-
importe: t.importe,
|
|
132
|
-
};
|
|
133
|
-
if (t.descripcion != null)
|
|
134
|
-
mapped['descripcion'] = t.descripcion;
|
|
135
|
-
if (t.alicuota != null)
|
|
136
|
-
mapped['alicuota'] = t.alicuota;
|
|
137
|
-
return mapped;
|
|
138
|
-
}),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
// Comprobantes asociados
|
|
142
|
-
if (request.invoice.comprobanteAsociado && request.invoice.comprobanteAsociado.length > 0) {
|
|
143
|
-
comprobante['arrayComprobantesAsociados'] = {
|
|
144
|
-
comprobanteAsociado: request.invoice.comprobanteAsociado.map((c) => {
|
|
145
|
-
const mapped = {
|
|
146
|
-
codigoTipoComprobante: c.codigoTipoComprobante,
|
|
147
|
-
numeroPuntoVenta: c.numeroPuntoVenta,
|
|
148
|
-
numeroComprobante: c.numeroComprobante,
|
|
149
|
-
};
|
|
150
|
-
if (c.cuit != null)
|
|
151
|
-
mapped['cuit'] = c.cuit;
|
|
152
|
-
return mapped;
|
|
153
|
-
}),
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
// Fechas de servicio
|
|
157
|
-
if (request.invoice.fechaDesde != null) {
|
|
158
|
-
comprobante['fechaDesde'] = request.invoice.fechaDesde;
|
|
159
|
-
}
|
|
160
|
-
if (request.invoice.fechaHasta != null) {
|
|
161
|
-
comprobante['fechaHasta'] = request.invoice.fechaHasta;
|
|
162
|
-
}
|
|
163
|
-
if (request.invoice.fechaVtoPago != null) {
|
|
164
|
-
comprobante['fechaVtoPago'] = request.invoice.fechaVtoPago;
|
|
93
|
+
async autorizarComprobante(auth, comprobante, opts) {
|
|
94
|
+
return this.autorizarCAE('autorizarComprobante', auth, comprobante, opts);
|
|
95
|
+
}
|
|
96
|
+
/** `autorizarAjusteIVA`: comprobante de ajuste de IVA con CAE (ND/NC 2, 3, 7, 8, 52, 53). */
|
|
97
|
+
async autorizarAjusteIVA(auth, comprobante, opts) {
|
|
98
|
+
return this.autorizarCAE('autorizarAjusteIVA', auth, comprobante, opts);
|
|
99
|
+
}
|
|
100
|
+
async autorizarCAE(method, auth, comprobante, opts) {
|
|
101
|
+
const comprobanteCAERequest = buildComprobante(comprobante, 'cae');
|
|
102
|
+
const result = await this.callAuth(method, auth, { comprobanteCAERequest }, 'emision', opts);
|
|
103
|
+
const { resultado, base } = this.resultado(result, method);
|
|
104
|
+
if (resultado === 'R')
|
|
105
|
+
return { resultado, ...base };
|
|
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 };
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Decodifica `resultado`, `arrayObservaciones`, `arrayErrores` y `evento`.
|
|
112
|
+
* `resultado` es obligatorio: si falta y hay `arrayErrores`, es un rechazo
|
|
113
|
+
* (`ArcaServiceError`); si falta sin errores, la respuesta es ilegible
|
|
114
|
+
* (`ArcaSoapError` con `uncertain`).
|
|
115
|
+
*/
|
|
116
|
+
resultado(result, method, schema = RESULTADO) {
|
|
117
|
+
const r = decode(result, schema, method, 'emision');
|
|
118
|
+
if (!r.resultado) {
|
|
119
|
+
checkServiceErrors(result, `${SERVICE} ${method}`);
|
|
120
|
+
throw invalid(`Respuesta inválida: falta ${method}.resultado`, 'emision');
|
|
165
121
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
comprobante['observaciones'] = request.invoice.observaciones;
|
|
122
|
+
if (!isResultado(r.resultado)) {
|
|
123
|
+
throw invalid(`Respuesta inválida: valor "${r.resultado}" inesperado en ${method}.resultado`, 'emision');
|
|
169
124
|
}
|
|
170
|
-
const result = await this.call('autorizarComprobante', {
|
|
171
|
-
authRequest: {
|
|
172
|
-
token: auth.Token,
|
|
173
|
-
sign: auth.Sign,
|
|
174
|
-
cuitRepresentada: auth.Cuit,
|
|
175
|
-
},
|
|
176
|
-
comprobanteCAERequest: comprobante,
|
|
177
|
-
});
|
|
178
|
-
const comprobanteResponse = (result['comprobanteResponse'] ?? result);
|
|
179
125
|
return {
|
|
180
|
-
resultado:
|
|
181
|
-
|
|
182
|
-
? String(comprobanteResponse['CAE'])
|
|
183
|
-
: undefined,
|
|
184
|
-
caeFchVto: comprobanteResponse['fechaVencimientoCAE'] != null
|
|
185
|
-
? String(comprobanteResponse['fechaVencimientoCAE'])
|
|
186
|
-
: undefined,
|
|
187
|
-
cbteNro: Number(comprobanteResponse['numeroComprobante'] ?? 0),
|
|
188
|
-
observaciones: extractObservaciones(result),
|
|
189
|
-
errores: extractErrores(result),
|
|
126
|
+
resultado: r.resultado,
|
|
127
|
+
base: { observaciones: r.arrayObservaciones, errores: r.arrayErrores, evento: r.evento },
|
|
190
128
|
};
|
|
191
129
|
}
|
|
130
|
+
// =========================================================================
|
|
131
|
+
// CAEA
|
|
132
|
+
// =========================================================================
|
|
192
133
|
/**
|
|
193
|
-
*
|
|
134
|
+
* `solicitarCAEA`. `periodo` AAAAMM, `orden` 1 (primera quincena) o 2.
|
|
135
|
+
* Lanza `ArcaServiceError` si ARCA lo rechaza. Es una emisión: si el
|
|
136
|
+
* resultado es incierto, recuperalo con `consultarCAEAEntreFechas`.
|
|
194
137
|
*/
|
|
195
|
-
async
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
},
|
|
202
|
-
consultaComprobanteRequest: {
|
|
203
|
-
codigoTipoComprobante: cbteTipo,
|
|
204
|
-
numeroPuntoVenta: ptoVta,
|
|
205
|
-
numeroComprobante: cbteNro,
|
|
206
|
-
},
|
|
138
|
+
async solicitarCAEA(auth, periodo, orden, opts) {
|
|
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
|
+
}
|
|
207
144
|
});
|
|
208
|
-
const
|
|
145
|
+
const result = await this.callAuth('solicitarCAEA', auth, { solicitudCAEA }, 'emision', opts);
|
|
146
|
+
checkServiceErrors(result, `${SERVICE} solicitarCAEA`);
|
|
147
|
+
return this.parseCAEA(result, 'solicitarCAEA', 'emision');
|
|
148
|
+
}
|
|
149
|
+
/** `consultarCAEA`: datos de un CAEA otorgado. */
|
|
150
|
+
async consultarCAEA(auth, caea, opts) {
|
|
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));
|
|
159
|
+
}
|
|
160
|
+
/** `consultarCAEAEntreFechas`: CAEAs otorgados con vigencia entre dos fechas. */
|
|
161
|
+
async consultarCAEAEntreFechas(auth, fechaDesde, fechaHasta, opts) {
|
|
162
|
+
const params = encodeRequest({ fechaDesde, fechaHasta }, ENTRE_FECHAS, 'consultarCAEAEntreFechas');
|
|
163
|
+
const result = await this.consulta('consultarCAEAEntreFechas', auth, params, opts);
|
|
164
|
+
const { arrayCAEAResponse } = decode(result, CAEA_ENTRE_FECHAS_RESPONSE, 'consultarCAEAEntreFechas', 'consulta');
|
|
165
|
+
return arrayCAEAResponse.map(toCAEA);
|
|
166
|
+
}
|
|
167
|
+
/** `informarComprobanteCAEA`. Un rechazo devuelve `resultado: 'R'` con `errores`. */
|
|
168
|
+
async informarComprobanteCAEA(auth, comprobante, opts) {
|
|
169
|
+
return this.informarCAEA('informarComprobanteCAEA', auth, comprobante, opts);
|
|
170
|
+
}
|
|
171
|
+
/** `informarAjusteIVACAEA`. Un rechazo devuelve `resultado: 'R'` con `errores`. */
|
|
172
|
+
async informarAjusteIVACAEA(auth, comprobante, opts) {
|
|
173
|
+
return this.informarCAEA('informarAjusteIVACAEA', auth, comprobante, opts);
|
|
174
|
+
}
|
|
175
|
+
async informarCAEA(method, auth, comprobante, opts) {
|
|
176
|
+
const comprobanteCAEARequest = buildComprobante(comprobante, 'caea');
|
|
177
|
+
const result = await this.callAuth(method, auth, { comprobanteCAEARequest }, 'emision', opts);
|
|
178
|
+
const { resultado, base } = this.resultado(result, method);
|
|
179
|
+
const { fechaProceso } = decode(result, FECHA_PROCESO, method, 'emision');
|
|
180
|
+
if (resultado === 'R')
|
|
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 };
|
|
187
|
+
}
|
|
188
|
+
/** `informarCAEANoUtilizado`: informa que un CAEA no se usó en ningún punto de venta. */
|
|
189
|
+
async informarCAEANoUtilizado(auth, caea, opts) {
|
|
190
|
+
const method = 'informarCAEANoUtilizado';
|
|
191
|
+
return this.caeaNoUtilizado(method, auth, encodeConCaea({ caea }, CON_CAEA, method), CAEA_NO_UTILIZADO, opts);
|
|
192
|
+
}
|
|
193
|
+
/** `informarCAEANoUtilizadoPtoVta`: informa que un CAEA no se usó en un punto de venta. */
|
|
194
|
+
async informarCAEANoUtilizadoPtoVta(auth, caea, numeroPuntoVenta, 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);
|
|
198
|
+
}
|
|
199
|
+
async caeaNoUtilizado(method, auth, params, schema, opts) {
|
|
200
|
+
const result = await this.callAuth(method, auth, params, 'emision', opts);
|
|
201
|
+
const { resultado, base } = this.resultado(result, method, schema);
|
|
202
|
+
const r = decode(result, schema, method, 'emision');
|
|
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');
|
|
209
212
|
return {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
importeTotal: Number(comp['importeTotal'] ?? 0),
|
|
217
|
-
importeNoGravado: Number(comp['importeNoGravado'] ?? 0),
|
|
218
|
-
importeGravado: Number(comp['importeGravado'] ?? 0),
|
|
219
|
-
importeExento: Number(comp['importeExento'] ?? 0),
|
|
220
|
-
importeOtrosTributos: Number(comp['importeOtrosTributos'] ?? 0),
|
|
221
|
-
importeSubtotal: Number(comp['importeSubtotal'] ?? 0),
|
|
222
|
-
codigoMoneda: String(comp['codigoMoneda'] ?? 'PES'),
|
|
223
|
-
cotizacionMoneda: Number(comp['cotizacionMoneda'] ?? 1),
|
|
224
|
-
resultado: String(comp['resultado'] ?? ''),
|
|
225
|
-
codigoAutorizacion: comp['codigoAutorizacion'] != null
|
|
226
|
-
? String(comp['codigoAutorizacion'])
|
|
227
|
-
: undefined,
|
|
228
|
-
fechaVencimiento: comp['fechaVencimiento'] != null
|
|
229
|
-
? String(comp['fechaVencimiento'])
|
|
230
|
-
: undefined,
|
|
231
|
-
observaciones: extractObservaciones(comp),
|
|
232
|
-
items: extractItems(comp),
|
|
213
|
+
resultado,
|
|
214
|
+
fechaProceso: r.fechaProceso,
|
|
215
|
+
caea: r.CAEA,
|
|
216
|
+
...(conPtoVta ? { numeroPuntoVenta: r.numeroPuntoVenta } : {}),
|
|
217
|
+
errores: base.errores,
|
|
218
|
+
evento: base.evento,
|
|
233
219
|
};
|
|
234
220
|
}
|
|
221
|
+
/** `consultarPtosVtaCAEANoInformados`: puntos de venta que todavía no informaron movimientos para el CAEA. */
|
|
222
|
+
async consultarPtosVtaCAEANoInformados(auth, caea, opts) {
|
|
223
|
+
const method = 'consultarPtosVtaCAEANoInformados';
|
|
224
|
+
const result = await this.consulta(method, auth, encodeConCaea({ caea }, CON_CAEA, method), opts);
|
|
225
|
+
return this.parsePuntosVenta(result, method);
|
|
226
|
+
}
|
|
227
|
+
// =========================================================================
|
|
228
|
+
// Consultas de comprobantes
|
|
229
|
+
// =========================================================================
|
|
235
230
|
/**
|
|
236
|
-
*
|
|
231
|
+
* `consultarUltimoComprobanteAutorizado`. Lanza `ArcaServiceError` ante
|
|
232
|
+
* cualquier error, incluido 1502 (no hay comprobantes para ese punto de venta
|
|
233
|
+
* y tipo); `ArcaMtxca.ultimoComprobante` lo traduce a 0.
|
|
237
234
|
*/
|
|
238
|
-
async consultarUltimoComprobanteAutorizado(auth, ptoVta, cbteTipo) {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
235
|
+
async consultarUltimoComprobanteAutorizado(auth, ptoVta, cbteTipo, opts) {
|
|
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;
|
|
240
|
+
}
|
|
241
|
+
/** `consultarComprobante`: datos de un comprobante autorizado (CAE) o informado (CAEA). */
|
|
242
|
+
async consultarComprobante(auth, cbteTipo, ptoVta, cbteNro, opts) {
|
|
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;
|
|
250
|
+
return {
|
|
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),
|
|
248
260
|
},
|
|
249
|
-
|
|
250
|
-
|
|
261
|
+
observaciones: r.arrayObservaciones,
|
|
262
|
+
evento: r.evento,
|
|
263
|
+
};
|
|
251
264
|
}
|
|
252
265
|
// =========================================================================
|
|
253
|
-
//
|
|
266
|
+
// Parámetros
|
|
254
267
|
// =========================================================================
|
|
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];
|
|
275
|
+
}
|
|
276
|
+
consultarTiposComprobante(auth, opts) {
|
|
277
|
+
return this.codigos('consultarTiposComprobante', auth, opts);
|
|
278
|
+
}
|
|
279
|
+
consultarTiposDocumento(auth, opts) {
|
|
280
|
+
return this.codigos('consultarTiposDocumento', auth, opts);
|
|
281
|
+
}
|
|
282
|
+
consultarAlicuotasIVA(auth, opts) {
|
|
283
|
+
return this.codigos('consultarAlicuotasIVA', auth, opts);
|
|
284
|
+
}
|
|
285
|
+
consultarCondicionesIVA(auth, opts) {
|
|
286
|
+
return this.codigos('consultarCondicionesIVA', auth, opts);
|
|
287
|
+
}
|
|
288
|
+
/** Condiciones de IVA del receptor admitidas para un tipo de comprobante (RG 5616). */
|
|
289
|
+
async consultarCondicionesIVAReceptor(auth, cbteTipo, opts) {
|
|
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;
|
|
294
|
+
}
|
|
295
|
+
consultarUnidadesMedida(auth, opts) {
|
|
296
|
+
return this.codigos('consultarUnidadesMedida', auth, opts);
|
|
297
|
+
}
|
|
298
|
+
consultarTiposTributo(auth, opts) {
|
|
299
|
+
return this.codigos('consultarTiposTributo', auth, opts);
|
|
300
|
+
}
|
|
301
|
+
consultarTiposDatosAdicionales(auth, opts) {
|
|
302
|
+
return this.codigos('consultarTiposDatosAdicionales', auth, opts);
|
|
303
|
+
}
|
|
304
|
+
consultarMonedas(auth, opts) {
|
|
305
|
+
return this.codigos('consultarMonedas', auth, opts);
|
|
306
|
+
}
|
|
255
307
|
/**
|
|
256
|
-
*
|
|
308
|
+
* `consultarCotizacionMoneda`. `cotizacion` es `null` si ARCA no tiene
|
|
309
|
+
* cotización para la moneda en esa fecha (responde sin valor y sin error).
|
|
257
310
|
*/
|
|
258
|
-
async
|
|
259
|
-
const
|
|
311
|
+
async consultarCotizacionMoneda(auth, codigoMoneda, fechaCotizacion, opts) {
|
|
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');
|
|
260
316
|
return {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
317
|
+
codigoMoneda: params['codigoMoneda'],
|
|
318
|
+
fechaCotizacion: params['fechaCotizacion'],
|
|
319
|
+
cotizacion: cotizacionMoneda ?? null,
|
|
264
320
|
};
|
|
265
321
|
}
|
|
266
|
-
|
|
267
|
-
|
|
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;
|
|
268
328
|
}
|
|
269
|
-
async
|
|
270
|
-
return this.
|
|
329
|
+
async puntosVenta(method, auth, opts) {
|
|
330
|
+
return this.parsePuntosVenta(await this.consulta(method, auth, {}, opts), method, true);
|
|
271
331
|
}
|
|
272
|
-
|
|
273
|
-
return this.
|
|
332
|
+
consultarPuntosVenta(auth, opts) {
|
|
333
|
+
return this.puntosVenta('consultarPuntosVenta', auth, opts);
|
|
274
334
|
}
|
|
275
|
-
|
|
276
|
-
return this.
|
|
335
|
+
consultarPuntosVentaCAE(auth, opts) {
|
|
336
|
+
return this.puntosVenta('consultarPuntosVentaCAE', auth, opts);
|
|
277
337
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
authRequest: {
|
|
281
|
-
token: auth.Token,
|
|
282
|
-
sign: auth.Sign,
|
|
283
|
-
cuitRepresentada: auth.Cuit,
|
|
284
|
-
},
|
|
285
|
-
});
|
|
286
|
-
const container = (result['arrayMonedas'] ?? result);
|
|
287
|
-
const arr = ensureArray(container['codigoDescripcion']);
|
|
288
|
-
return arr.map((m) => ({
|
|
289
|
-
Id: String(m['codigo'] ?? ''),
|
|
290
|
-
Desc: String(m['descripcion'] ?? ''),
|
|
291
|
-
FchDesde: m['fechaDesde'] != null ? String(m['fechaDesde']) : undefined,
|
|
292
|
-
FchHasta: m['fechaHasta'] != null ? String(m['fechaHasta']) : undefined,
|
|
293
|
-
}));
|
|
294
|
-
}
|
|
295
|
-
async consultarUnidadesMedida(auth) {
|
|
296
|
-
const result = await this.call('consultarUnidadesMedida', {
|
|
297
|
-
authRequest: {
|
|
298
|
-
token: auth.Token,
|
|
299
|
-
sign: auth.Sign,
|
|
300
|
-
cuitRepresentada: auth.Cuit,
|
|
301
|
-
},
|
|
302
|
-
});
|
|
303
|
-
const container = (result['arrayUnidadesMedida'] ?? result);
|
|
304
|
-
const arr = ensureArray(container['codigoDescripcion']);
|
|
305
|
-
return arr.map((u) => ({
|
|
306
|
-
Id: Number(u['codigo'] ?? 0),
|
|
307
|
-
Desc: String(u['descripcion'] ?? ''),
|
|
308
|
-
FchDesde: u['fechaDesde'] != null ? String(u['fechaDesde']) : undefined,
|
|
309
|
-
FchHasta: u['fechaHasta'] != null ? String(u['fechaHasta']) : undefined,
|
|
310
|
-
}));
|
|
311
|
-
}
|
|
312
|
-
async consultarPuntosVenta(auth) {
|
|
313
|
-
return this.getPtosVenta(auth, 'consultarPuntosVenta', 'arrayPuntosVenta');
|
|
314
|
-
}
|
|
315
|
-
async consultarPuntosVentaCAE(auth) {
|
|
316
|
-
return this.getPtosVenta(auth, 'consultarPuntosVentaCAE', 'arrayPuntosVenta');
|
|
317
|
-
}
|
|
318
|
-
async consultarPuntosVentaCAEA(auth) {
|
|
319
|
-
return this.getPtosVenta(auth, 'consultarPuntosVentaCAEA', 'arrayPuntosVenta');
|
|
320
|
-
}
|
|
321
|
-
async consultarCotizacionMoneda(auth, monedaId) {
|
|
322
|
-
const result = await this.call('consultarCotizacionMoneda', {
|
|
323
|
-
authRequest: {
|
|
324
|
-
token: auth.Token,
|
|
325
|
-
sign: auth.Sign,
|
|
326
|
-
cuitRepresentada: auth.Cuit,
|
|
327
|
-
},
|
|
328
|
-
codigoMoneda: monedaId,
|
|
329
|
-
});
|
|
330
|
-
return {
|
|
331
|
-
monedaId: String(result['codigoMoneda'] ?? monedaId),
|
|
332
|
-
cotizacion: Number(result['cotizacionMoneda'] ?? 0),
|
|
333
|
-
fechaCotizacion: String(result['fechaCotizacion'] ?? ''),
|
|
334
|
-
};
|
|
338
|
+
consultarPuntosVentaCAEA(auth, opts) {
|
|
339
|
+
return this.puntosVenta('consultarPuntosVentaCAEA', auth, opts);
|
|
335
340
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
token: auth.Token,
|
|
343
|
-
sign: auth.Sign,
|
|
344
|
-
cuitRepresentada: auth.Cuit,
|
|
345
|
-
},
|
|
346
|
-
});
|
|
347
|
-
const container = (result[containerKey] ?? result);
|
|
348
|
-
const arr = ensureArray(container[itemKey]);
|
|
349
|
-
return arr.map((item) => ({
|
|
350
|
-
Id: Number(item['codigo'] ?? 0),
|
|
351
|
-
Desc: String(item['descripcion'] ?? ''),
|
|
352
|
-
FchDesde: item['fechaDesde'] != null ? String(item['fechaDesde']) : undefined,
|
|
353
|
-
FchHasta: item['fechaHasta'] != null ? String(item['fechaHasta']) : undefined,
|
|
354
|
-
}));
|
|
355
|
-
}
|
|
356
|
-
async getPtosVenta(auth, method, containerKey) {
|
|
357
|
-
const result = await this.call(method, {
|
|
358
|
-
authRequest: {
|
|
359
|
-
token: auth.Token,
|
|
360
|
-
sign: auth.Sign,
|
|
361
|
-
cuitRepresentada: auth.Cuit,
|
|
362
|
-
},
|
|
363
|
-
});
|
|
364
|
-
const container = (result[containerKey] ?? result);
|
|
365
|
-
const arr = ensureArray(container['puntoVenta']);
|
|
366
|
-
return arr.map((pv) => ({
|
|
367
|
-
Nro: Number(pv['numeroPuntoVenta'] ?? 0),
|
|
368
|
-
EmisionTipo: String(pv['tipoEmision'] ?? ''),
|
|
369
|
-
Bloqueado: String(pv['bloqueado'] ?? ''),
|
|
370
|
-
FchBaja: String(pv['fechaBaja'] ?? ''),
|
|
371
|
-
}));
|
|
341
|
+
/** `consultarActividadesVigentes`: actividades vigentes del emisor. */
|
|
342
|
+
async consultarActividadesVigentes(auth, opts) {
|
|
343
|
+
const method = 'consultarActividadesVigentes';
|
|
344
|
+
const result = await this.consulta(method, auth, {}, opts);
|
|
345
|
+
return decode(result, ACTIVIDADES_VIGENTES_RESPONSE, method, 'consulta')
|
|
346
|
+
.arrayActividades;
|
|
372
347
|
}
|
|
373
348
|
}
|
|
374
349
|
//# sourceMappingURL=mtxca-client.js.map
|