@inowu/cashdro 0.3.0 → 0.3.1
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/LICENSE +13 -0
- package/README.md +215 -199
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright (c) 2026 Inowu
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
proprietary property of Inowu. No part of the Software may be used,
|
|
7
|
+
copied, modified, merged, published, distributed, sublicensed, or sold
|
|
8
|
+
without the prior written permission of Inowu.
|
|
9
|
+
|
|
10
|
+
Distribution of compiled or packaged forms of the Software (e.g. via a
|
|
11
|
+
package registry) does not grant any license or rights to use, modify, or
|
|
12
|
+
redistribute the Software beyond what is expressly agreed in writing with
|
|
13
|
+
Inowu.
|
package/README.md
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
1
|
# CashDro TypeScript SDK
|
|
2
2
|
|
|
3
|
-
`@inowu/cashdro`
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
17
|
-
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
|
|
27
|
-
|
|
3
|
+
`@inowu/cashdro` proporciona acceso conveniente y tipado a los recicladores
|
|
4
|
+
de efectivo automatizados **CashDro** desde TypeScript y JavaScript — ejecutando
|
|
5
|
+
ventas, pagos, depósitos, retiros y operaciones de gestión de efectivo, además
|
|
6
|
+
de consultas de niveles de efectivo y reportes.
|
|
7
|
+
|
|
8
|
+
## Tabla de contenidos
|
|
9
|
+
|
|
10
|
+
- [Instalación](#instalación)
|
|
11
|
+
- [Inicio rápido](#inicio-rápido)
|
|
12
|
+
- [Autenticación](#autenticación)
|
|
13
|
+
- [Configuración](#configuración)
|
|
14
|
+
- [Cómo funcionan las transacciones](#cómo-funcionan-las-transacciones)
|
|
15
|
+
- [Uso no bloqueante](#uso-no-bloqueante)
|
|
16
|
+
- [Modo debug](#modo-debug)
|
|
17
|
+
- [Referencia del cliente](#referencia-del-cliente)
|
|
18
|
+
- [Conectividad y salud](#conectividad-y-salud)
|
|
19
|
+
- [Transacciones — ciclo de vida](#transacciones--ciclo-de-vida)
|
|
20
|
+
- [Transacciones — métodos de conveniencia](#transacciones--métodos-de-conveniencia)
|
|
21
|
+
- [Helpers de orquestación](#helpers-de-orquestación)
|
|
22
|
+
- [Consultas y reportes](#consultas-y-reportes)
|
|
23
|
+
- [Tipos de transacción](#tipos-de-transacción)
|
|
24
|
+
- [Respuestas](#respuestas)
|
|
25
|
+
- [Manejo de errores](#manejo-de-errores)
|
|
26
|
+
- [Avanzado](#avanzado)
|
|
27
|
+
|
|
28
|
+
## Instalación
|
|
28
29
|
|
|
29
30
|
```sh
|
|
30
31
|
npm i @inowu/cashdro
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
**
|
|
34
|
+
**Requisitos:** Node.js 18+ (o cualquier runtime con `fetch` global).
|
|
34
35
|
|
|
35
|
-
##
|
|
36
|
+
## Inicio rápido
|
|
36
37
|
|
|
37
38
|
```ts
|
|
38
39
|
import { CashDroClient } from "@inowu/cashdro";
|
|
@@ -43,48 +44,49 @@ const cashdro = new CashDroClient({
|
|
|
43
44
|
password: "••••",
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
// 1.
|
|
47
|
+
// 1. Verificar conectividad + credenciales
|
|
47
48
|
const ping = await cashdro.doTest();
|
|
48
49
|
if (ping.code !== 1) throw new Error("CashDro unreachable or bad credentials");
|
|
49
50
|
|
|
50
|
-
// 2.
|
|
51
|
+
// 2. Realizar una venta de 12.50 (los montos están en unidades menores — valor × 100)
|
|
51
52
|
const { operationId } = await cashdro.sale(1250, { posuser: "Ana" });
|
|
52
53
|
|
|
53
|
-
// 3.
|
|
54
|
+
// 3. Esperar a que el cliente termine de pagar
|
|
54
55
|
const final = await cashdro.pollUntilFinished(operationId);
|
|
55
56
|
const op = final.response?.operation?.operation;
|
|
56
|
-
console.log(`paid=${op?.totalin} change=${op?.totalout}`); //
|
|
57
|
+
console.log(`paid=${op?.totalin} change=${op?.totalout}`); // el cambio es negativo
|
|
57
58
|
|
|
58
|
-
// 4.
|
|
59
|
+
// 4. Confirmar que registraste la transacción
|
|
59
60
|
await cashdro.setOperationImported(operationId);
|
|
60
61
|
```
|
|
61
62
|
|
|
62
|
-
##
|
|
63
|
+
## Autenticación
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
Cada llamada se autentica como un **usuario de CashDro** mediante HTTP Basic.
|
|
66
|
+
El usuario debe existir en la máquina y tener permiso para la operación.
|
|
66
67
|
|
|
67
68
|
```ts
|
|
68
69
|
const cashdro = new CashDroClient({ baseUrl, username: "manager", password: "••••" });
|
|
69
70
|
```
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
**
|
|
73
|
-
*
|
|
72
|
+
Los campos opcionales `posuser`, `posid` y `aliasid` aceptados por las
|
|
73
|
+
transacciones **no** son credenciales — solo etiquetan *quién* (cajero),
|
|
74
|
+
*qué terminal* y un *id de referencia del lado del host* inició una operación
|
|
75
|
+
(≤ 50 caracteres cada uno).
|
|
74
76
|
|
|
75
|
-
##
|
|
77
|
+
## Configuración
|
|
76
78
|
|
|
77
|
-
`CashDroClient`
|
|
79
|
+
`CashDroClient` acepta las siguientes opciones:
|
|
78
80
|
|
|
79
|
-
|
|
|
81
|
+
| Opción | Descripción |
|
|
80
82
|
|--------|-------------|
|
|
81
|
-
| `baseUrl` | URL
|
|
82
|
-
| `username`, `password` |
|
|
83
|
-
| `timeoutInSeconds` |
|
|
84
|
-
| `maxRetries` |
|
|
85
|
-
| `headers` |
|
|
86
|
-
| `fetch` |
|
|
87
|
-
| `debug` |
|
|
83
|
+
| `baseUrl` | URL de la unidad CashDro. Apunta esto a tu dispositivo / unidad de producción. |
|
|
84
|
+
| `username`, `password` | Credenciales de usuario de CashDro (HTTP Basic). |
|
|
85
|
+
| `timeoutInSeconds` | Timeout por solicitud (por defecto 60). |
|
|
86
|
+
| `maxRetries` | Reintentos automáticos con backoff exponencial (por defecto 2). |
|
|
87
|
+
| `headers` | Encabezados adicionales para enviar en cada solicitud. |
|
|
88
|
+
| `fetch` | Implementación personalizada de `fetch` (ver [Avanzado](#custom-fetch--self-signed-tls)). |
|
|
89
|
+
| `debug` | Traza los helpers de multi-operación — `true` para loguear, o una función handler (ver [Modo debug](#modo-debug)). |
|
|
88
90
|
|
|
89
91
|
```ts
|
|
90
92
|
const cashdro = new CashDroClient({
|
|
@@ -96,80 +98,87 @@ const cashdro = new CashDroClient({
|
|
|
96
98
|
});
|
|
97
99
|
```
|
|
98
100
|
|
|
99
|
-
##
|
|
101
|
+
## Cómo funcionan las transacciones
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
**
|
|
103
|
+
Una transacción de movimiento de efectivo (venta, pago, depósito, retiro, …)
|
|
104
|
+
corre **de forma asíncrona en el hardware**, por lo que se conduce mediante
|
|
105
|
+
un ciclo de vida corto:
|
|
103
106
|
|
|
104
107
|
```
|
|
105
108
|
start ─▶ acknowledge ─▶ (poll status) ─▶ finish? ─▶ import
|
|
106
|
-
id launch I → Q → E → F finalize
|
|
109
|
+
id launch I → Q → E → F finalize registrarla
|
|
107
110
|
```
|
|
108
111
|
|
|
109
|
-
- **`start`**
|
|
110
|
-
|
|
111
|
-
- **`acknowledge`**
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- **`
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
112
|
+
- **`start`** abre la transacción y devuelve un **`operationId`** (el handle
|
|
113
|
+
para todo lo demás). La unidad aún no hace nada.
|
|
114
|
+
- **`acknowledge`** lanza la ejecución (los aceptadores se abren / comienza
|
|
115
|
+
la dispensación).
|
|
116
|
+
- **poll status** hasta que `state === "F"`. Estados: `I` pendiente, `Q` en cola,
|
|
117
|
+
`E` ejecutando, `F` finalizado.
|
|
118
|
+
- **`finish`** finaliza o cancela (solo algunas transacciones necesitan un
|
|
119
|
+
finish explícito).
|
|
120
|
+
- **`import`** le indica a la unidad que el host ya registró el resultado.
|
|
121
|
+
|
|
122
|
+
Los métodos de conveniencia (`sale`, `payment`, …) y los helpers
|
|
123
|
+
(`runOperation`, `pollUntilFinished`) colapsan este boilerplate por ti
|
|
124
|
+
mientras siguen devolviendo el `operationId` y cada respuesta cruda.
|
|
125
|
+
|
|
126
|
+
**Dinero:** todos los montos son enteros en **unidades menores** (valor × 100 —
|
|
127
|
+
`1250` = 12.50). Los montos dispensados (`totalout`) son **negativos**. La
|
|
128
|
+
moneda es la que tenga configurada la unidad.
|
|
129
|
+
|
|
130
|
+
**Una a la vez:** un CashDro ejecuta una sola operación a la vez; iniciar otra
|
|
131
|
+
mientras una está activa falla con `code -2`. Usa `askOperationExecuting()`
|
|
132
|
+
para detectar y recuperar una operación atascada.
|
|
133
|
+
|
|
134
|
+
## Uso no bloqueante
|
|
135
|
+
|
|
136
|
+
Una venta puede tardar — la unidad espera a que el cliente inserte efectivo.
|
|
137
|
+
No hagas `await` de toda la cadena `start → wait → import` dentro de un
|
|
138
|
+
request handler; en su lugar déjala correr en segundo plano y reacciona
|
|
139
|
+
mediante callbacks. El callback `onStart` te entrega el `operationId` en el
|
|
140
|
+
instante en que se conoce (antes de cualquier espera), para que la UI pueda
|
|
141
|
+
mostrar una pantalla de pago y ofrecer un botón de Cancelar de inmediato.
|
|
136
142
|
|
|
137
143
|
```ts
|
|
138
144
|
import { CashDroClient, CashDroTimeoutError } from "@inowu/cashdro";
|
|
139
145
|
|
|
140
|
-
// Fire-and-forget:
|
|
146
|
+
// Fire-and-forget: ejecuta start → acknowledge → poll → import en segundo plano.
|
|
141
147
|
void cashdro
|
|
142
148
|
.sale(1250, {
|
|
143
|
-
waitForFinish: true, //
|
|
144
|
-
autoImport: true, //
|
|
145
|
-
onStart: (operationId) => showPayScreen(operationId), //
|
|
149
|
+
waitForFinish: true, // sondear hasta que el cliente termine de pagar
|
|
150
|
+
autoImport: true, // registrarlo en la unidad cuando termine
|
|
151
|
+
onStart: (operationId) => showPayScreen(operationId), // se devuelve de inmediato
|
|
146
152
|
poll: { onPoll: (status) => updateUi(status), timeoutMs: 120_000 },
|
|
147
153
|
})
|
|
148
154
|
.then((r) => onPaid(r.final?.response?.operation?.operation)) // totalin / totalout
|
|
149
155
|
.catch((err) => {
|
|
150
|
-
if (err instanceof CashDroTimeoutError) return; //
|
|
156
|
+
if (err instanceof CashDroTimeoutError) return; // nadie pagó a tiempo
|
|
151
157
|
onError(err);
|
|
152
158
|
});
|
|
153
159
|
```
|
|
154
160
|
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
Para permitir que un botón de **Cancelar** detenga una venta en curso,
|
|
162
|
+
cancélala en la unidad — el poll en segundo plano se resuelve entonces en
|
|
163
|
+
el estado `F` en su siguiente tick:
|
|
157
164
|
|
|
158
165
|
```ts
|
|
159
166
|
cancelButton.onclick = () => cashdro.finishOperation(operationId, 2);
|
|
160
167
|
```
|
|
161
168
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
De forma equivalente puedes conducir los pasos tú mismo: `await cashdro.sale(...)`
|
|
170
|
+
retorna después de start+acknowledge (rápido), luego llama a
|
|
171
|
+
`cashdro.pollUntilFinished(id)` desde una tarea en segundo plano. Pasa un
|
|
172
|
+
`AbortSignal` en las opciones de `poll`/`pollUntilFinished` si necesitas
|
|
173
|
+
detener el sondeo sin cancelar la transacción, o `cancelOnTimeout: true`
|
|
174
|
+
para auto-cancelar la venta si nadie paga a tiempo.
|
|
167
175
|
|
|
168
|
-
##
|
|
176
|
+
## Modo debug
|
|
169
177
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
Los helpers de multi-operación (`sale`, `runOperation`, `pollUntilFinished`, …)
|
|
179
|
+
pueden trazar exactamente lo que hacen — cada llamada subyacente, su
|
|
180
|
+
resultado, y cada sondeo de estado. Pasa `debug: true` para loguear a la
|
|
181
|
+
consola:
|
|
173
182
|
|
|
174
183
|
```ts
|
|
175
184
|
const cashdro = new CashDroClient({ baseUrl, username, password, debug: true });
|
|
@@ -188,8 +197,8 @@ await cashdro.sale(100, { waitForFinish: true, autoImport: true });
|
|
|
188
197
|
[cashdro] sale: done (operationId=128)
|
|
189
198
|
```
|
|
190
199
|
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
Para logging estructurado, pasa un handler en su lugar y enruta los
|
|
201
|
+
`CashDroDebugEvent` a tu propio logger:
|
|
193
202
|
|
|
194
203
|
```ts
|
|
195
204
|
const cashdro = new CashDroClient({
|
|
@@ -200,87 +209,91 @@ const cashdro = new CashDroClient({
|
|
|
200
209
|
});
|
|
201
210
|
```
|
|
202
211
|
|
|
203
|
-
|
|
204
|
-
`"call"`, `"result"`, `"poll"`,
|
|
205
|
-
|
|
212
|
+
Cada evento es `{ seq, at, helper, op, phase, detail, message }` — `phase`
|
|
213
|
+
es `"call"`, `"result"`, `"poll"`, o `"info"`. Esto traza la orquestación
|
|
214
|
+
del helper y es independiente de la capa de transporte.
|
|
206
215
|
|
|
207
|
-
##
|
|
216
|
+
## Referencia del cliente
|
|
208
217
|
|
|
209
|
-
|
|
210
|
-
|
|
218
|
+
Los métodos que mapean 1:1 a una operación del dispositivo devuelven la
|
|
219
|
+
respuesta cruda; los helpers de conveniencia y orquestación combinan varias
|
|
220
|
+
llamadas pero nunca ocultan los datos subyacentes.
|
|
211
221
|
|
|
212
|
-
###
|
|
222
|
+
### Conectividad y salud
|
|
213
223
|
|
|
214
|
-
|
|
|
224
|
+
| Método | Qué hace / cuándo usarlo |
|
|
215
225
|
|--------|----------------------------|
|
|
216
|
-
| `doTest()` |
|
|
217
|
-
| `getDiagnosis()` |
|
|
218
|
-
| `getAlerts()` |
|
|
219
|
-
| `askOperationExecuting()` |
|
|
226
|
+
| `doTest()` | Ping autenticado. Verifica accesibilidad + credenciales antes de transaccionar. |
|
|
227
|
+
| `getDiagnosis()` | Estado de error del dispositivo (`WithError`) + lista de dispositivos. Usa esto como gate antes de transaccionar para evitar hardware atascado. |
|
|
228
|
+
| `getAlerts()` | Denominaciones en niveles críticos / de inhibición / por debajo del mínimo / por encima del máximo. Para avisos de reabastecimiento/vaciado. |
|
|
229
|
+
| `askOperationExecuting()` | La operación que se está ejecutando actualmente (o `OperationId: -1` cuando está inactiva). Recupera una operación huérfana al iniciar. |
|
|
220
230
|
|
|
221
|
-
###
|
|
231
|
+
### Transacciones — ciclo de vida
|
|
222
232
|
|
|
223
|
-
|
|
233
|
+
Bloques de construcción de bajo nivel (normalmente usarás los métodos de
|
|
234
|
+
conveniencia de abajo):
|
|
224
235
|
|
|
225
|
-
|
|
|
236
|
+
| Método | Qué hace / cuándo usarlo |
|
|
226
237
|
|--------|----------------------------|
|
|
227
|
-
| `startOperation({ type, amount?, parameters?, … })` |
|
|
228
|
-
| `acknowledgeOperationId(id)` |
|
|
229
|
-
| `askOperation(id)` |
|
|
230
|
-
| `finishOperation(id, type)` | `type 1`
|
|
231
|
-
| `setOperationImported(id)` |
|
|
238
|
+
| `startOperation({ type, amount?, parameters?, … })` | Abre una transacción de un [tipo](#tipos-de-transacción) dado; devuelve `operationId`. |
|
|
239
|
+
| `acknowledgeOperationId(id)` | Lanza una operación iniciada. |
|
|
240
|
+
| `askOperation(id)` | Sondea el estado completo (estado, `total`, `totalin`, `totalout`, niveles por denominación, mensajes). |
|
|
241
|
+
| `finishOperation(id, type)` | `type 1` finaliza/acepta, `2` cancela, `4` finaliza con una lista explícita de piezas. |
|
|
242
|
+
| `setOperationImported(id)` | Marca la operación como registrada por el host (la elimina de la lista pendiente). |
|
|
232
243
|
|
|
233
|
-
###
|
|
244
|
+
### Transacciones — métodos de conveniencia
|
|
234
245
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
246
|
+
Cada uno abre + confirma una transacción y devuelve `{ operationId, started, … }`.
|
|
247
|
+
Las opciones aceptan `posid` / `posuser` / `aliasid` y las [opciones de
|
|
248
|
+
orquestación](#helpers-de-orquestación).
|
|
238
249
|
|
|
239
|
-
|
|
|
250
|
+
| Método | Transacción |
|
|
240
251
|
|--------|-------------|
|
|
241
|
-
| `sale(amount, opts?)` |
|
|
242
|
-
| `payment(amount, opts?)` |
|
|
243
|
-
| `paymentByDenomination(pieces, opts?)` |
|
|
244
|
-
| `depositByAmount(amount, opts?)` |
|
|
245
|
-
| `deposit(opts?)` |
|
|
246
|
-
| `change(opts?)` |
|
|
247
|
-
| `load(opts?)` |
|
|
248
|
-
| `withdraw(opts?)` |
|
|
249
|
-
| `transferToCassette(opts?)` |
|
|
250
|
-
| `emptyNoteCassette(opts?)` / `emptyCoinCassette(opts?)` |
|
|
251
|
-
| `finishWithPieces(id, { recycler?, cassette? })` |
|
|
252
|
+
| `sale(amount, opts?)` | Venta — el cliente paga, se devuelve el cambio. |
|
|
253
|
+
| `payment(amount, opts?)` | Pago / desembolso de un monto. |
|
|
254
|
+
| `paymentByDenomination(pieces, opts?)` | Pagar piezas específicas (ver abajo). |
|
|
255
|
+
| `depositByAmount(amount, opts?)` | Depositar hasta un monto objetivo. |
|
|
256
|
+
| `deposit(opts?)` | Depósito abierto; finaliza con `finishOperation(id, 1)`. |
|
|
257
|
+
| `change(opts?)` | Cambio / romper un billete. |
|
|
258
|
+
| `load(opts?)` | Cargar efectivo en los recicladores. |
|
|
259
|
+
| `withdraw(opts?)` | Retirar efectivo (el operador selecciona en la unidad). |
|
|
260
|
+
| `transferToCassette(opts?)` | Mover efectivo de los recicladores al cassette. |
|
|
261
|
+
| `emptyNoteCassette(opts?)` / `emptyCoinCassette(opts?)` | Registrar un cassette como vaciado. |
|
|
262
|
+
| `finishWithPieces(id, { recycler?, cassette? })` | Finalizar un retiro/transferencia con una lista explícita de piezas. |
|
|
252
263
|
|
|
253
264
|
```ts
|
|
254
|
-
//
|
|
265
|
+
// Pagar exactamente 3×1.00 monedas y 1×20.00 billete
|
|
255
266
|
await cashdro.paymentByDenomination([
|
|
256
267
|
{ value: 100, level: 3, isBill: false },
|
|
257
268
|
{ value: 2000, level: 1, isBill: true },
|
|
258
269
|
]);
|
|
259
270
|
|
|
260
|
-
//
|
|
271
|
+
// Retirar 1×500 billete directamente de los recicladores (sin selección en el dispositivo)
|
|
261
272
|
const { operationId } = await cashdro.withdraw();
|
|
262
273
|
await cashdro.finishWithPieces(operationId, { recycler: [{ value: 500, level: 1, isBill: true }] });
|
|
263
274
|
await cashdro.setOperationImported(operationId);
|
|
264
275
|
```
|
|
265
276
|
|
|
266
|
-
###
|
|
277
|
+
### Helpers de orquestación
|
|
267
278
|
|
|
268
|
-
|
|
|
279
|
+
| Método | Qué hace |
|
|
269
280
|
|--------|--------------|
|
|
270
|
-
| `runOperation(params, opts?)` |
|
|
271
|
-
| `pollUntilFinished(id, opts?)` |
|
|
272
|
-
|
|
273
|
-
`runOperation
|
|
274
|
-
`false` —
|
|
275
|
-
|
|
276
|
-
`pollUntilFinished`
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
281
|
+
| `runOperation(params, opts?)` | El motor detrás de los métodos de conveniencia: `start → (acknowledge) → poll opcional → import opcional`. Devuelve `{ operationId, started, final?, imported? }`. |
|
|
282
|
+
| `pollUntilFinished(id, opts?)` | Sondea `askOperation` hasta que `state === "F"`; devuelve la respuesta final completa. Lanza `CashDroTimeoutError` en caso de timeout. |
|
|
283
|
+
|
|
284
|
+
Opciones de `runOperation`: `acknowledge` (por defecto `true`), `waitForFinish`
|
|
285
|
+
(por defecto `false` — una venta bloquea en espera del efectivo del cliente),
|
|
286
|
+
`autoImport`, un callback `onStart(id, started)`, y `poll` (reenviado a
|
|
287
|
+
`pollUntilFinished`).
|
|
288
|
+
Opciones de `pollUntilFinished`: `intervalMs`, `timeoutMs`, `signal`
|
|
289
|
+
(`AbortSignal`), `onPoll(status)`, y **`cancelOnTimeout`** — cuando es `true`,
|
|
290
|
+
un timeout cancela e importa la operación antes de lanzar el error, para que
|
|
291
|
+
no quede abierta bloqueando la siguiente transacción con `code -2` (un
|
|
292
|
+
error común de testing al probar ventas sin efectivo).
|
|
280
293
|
|
|
281
294
|
```ts
|
|
282
295
|
const { operationId } = await cashdro.sale(500, {
|
|
283
|
-
onStart: (id) => showOnScreen(id), // operationId
|
|
296
|
+
onStart: (id) => showOnScreen(id), // operationId en el instante en que se conoce
|
|
284
297
|
});
|
|
285
298
|
const final = await cashdro.pollUntilFinished(operationId, {
|
|
286
299
|
timeoutMs: 120_000,
|
|
@@ -288,13 +301,13 @@ const final = await cashdro.pollUntilFinished(operationId, {
|
|
|
288
301
|
});
|
|
289
302
|
```
|
|
290
303
|
|
|
291
|
-
###
|
|
304
|
+
### Consultas y reportes
|
|
292
305
|
|
|
293
|
-
|
|
|
306
|
+
| Método | Qué hace / cuándo usarlo |
|
|
294
307
|
|--------|----------------------------|
|
|
295
|
-
| `getPiecesCurrency({ currencyId, includeLevels?, includeImages? })` |
|
|
296
|
-
| `askPendingOperations({ terminal?, importManualOperations? })` |
|
|
297
|
-
| `askMovements({ fromDate, toDate, group?, operationType? })` |
|
|
308
|
+
| `getPiecesCurrency({ currencyId, includeLevels?, includeImages? })` | Niveles de efectivo por denominación. Para UI de inventario y para pre-verificar un retiro. |
|
|
309
|
+
| `askPendingOperations({ terminal?, importManualOperations? })` | Operaciones aún no importadas por el host. Reconciliar antes de un cierre de caja. |
|
|
310
|
+
| `askMovements({ fromDate, toDate, group?, operationType? })` | Operaciones entre dos fechas, detalladas o agregadas. Para reportes. |
|
|
298
311
|
|
|
299
312
|
```ts
|
|
300
313
|
const levels = await cashdro.getPiecesCurrency({ currencyId: "EUR", includeLevels: 1 });
|
|
@@ -302,49 +315,49 @@ const report = await cashdro.askMovements({
|
|
|
302
315
|
fromDate: "2026-06-01_00:00:00",
|
|
303
316
|
toDate: "2026-06-30_23:59:59",
|
|
304
317
|
group: true,
|
|
305
|
-
operationType: JSON.stringify([{ Id: 4 }]), //
|
|
318
|
+
operationType: JSON.stringify([{ Id: 4 }]), // solo ventas
|
|
306
319
|
});
|
|
307
320
|
```
|
|
308
321
|
|
|
309
|
-
##
|
|
322
|
+
## Tipos de transacción
|
|
310
323
|
|
|
311
|
-
`startOperation` (
|
|
324
|
+
`startOperation` (y los métodos de conveniencia) aceptan un `type` numérico:
|
|
312
325
|
|
|
313
|
-
| `type` |
|
|
326
|
+
| `type` | Transacción | Monto/piezas |
|
|
314
327
|
|-------:|-------------|---------------|
|
|
315
|
-
| 1 |
|
|
316
|
-
| 2 |
|
|
317
|
-
| 3 |
|
|
318
|
-
| 4 |
|
|
319
|
-
| 8 |
|
|
320
|
-
| 10 |
|
|
321
|
-
| 11 |
|
|
322
|
-
| 16 |
|
|
323
|
-
| 17 |
|
|
324
|
-
| 18 |
|
|
328
|
+
| 1 | carga | — |
|
|
329
|
+
| 2 | retiro | en el dispositivo, o `finishWithPieces` |
|
|
330
|
+
| 3 | pago | `amount`, o `paymentByDenomination` |
|
|
331
|
+
| 4 | venta | `amount` |
|
|
332
|
+
| 8 | transferencia al cassette | en el dispositivo, o `finishWithPieces` |
|
|
333
|
+
| 10 | vaciar cassette de billetes | — |
|
|
334
|
+
| 11 | vaciar cassette de monedas | — |
|
|
335
|
+
| 16 | depósito | finaliza con `finishOperation(id, 1)` |
|
|
336
|
+
| 17 | depósito por monto | `amount` |
|
|
337
|
+
| 18 | cambio | — |
|
|
325
338
|
|
|
326
|
-
|
|
327
|
-
`{ value: number, level: number, isBill: boolean }` — `value`
|
|
328
|
-
`level`
|
|
339
|
+
Una "pieza" (para `paymentByDenomination` / `finishWithPieces`) es
|
|
340
|
+
`{ value: number, level: number, isBill: boolean }` — `value` en unidades
|
|
341
|
+
menores, `level` la cantidad, `isBill` `true` para billetes.
|
|
329
342
|
|
|
330
|
-
##
|
|
343
|
+
## Respuestas
|
|
331
344
|
|
|
332
|
-
|
|
345
|
+
Cada llamada resuelve a un envelope tipado:
|
|
333
346
|
|
|
334
347
|
```ts
|
|
335
|
-
{ code: number; response: { errorMessage: string; /*
|
|
348
|
+
{ code: number; response: { errorMessage: string; /* datos de la operación */ } }
|
|
336
349
|
```
|
|
337
350
|
|
|
338
|
-
`code >= 1`
|
|
339
|
-
|
|
340
|
-
|
|
351
|
+
`code >= 1` significa éxito; un `code` negativo es un error (los métodos de
|
|
352
|
+
conveniencia/helper lanzan una excepción en su lugar — ver abajo). Los tipos
|
|
353
|
+
de solicitud y respuesta están disponibles bajo el namespace `CashDroApi`:
|
|
341
354
|
|
|
342
355
|
```ts
|
|
343
356
|
import { CashDroApi } from "@inowu/cashdro";
|
|
344
357
|
const res: CashDroApi.AskOperationResponse = await cashdro.askOperation(id);
|
|
345
358
|
```
|
|
346
359
|
|
|
347
|
-
##
|
|
360
|
+
## Manejo de errores
|
|
348
361
|
|
|
349
362
|
```ts
|
|
350
363
|
import { CashDroError, CashDroTimeoutError } from "@inowu/cashdro";
|
|
@@ -355,48 +368,51 @@ try {
|
|
|
355
368
|
await cashdro.setOperationImported(operationId);
|
|
356
369
|
} catch (err) {
|
|
357
370
|
if (err instanceof CashDroTimeoutError) {
|
|
358
|
-
// no
|
|
371
|
+
// no se insertó efectivo a tiempo — la operación sigue abierta; cancélala
|
|
359
372
|
await cashdro.finishOperation(err.operationId, 2);
|
|
360
373
|
} else if (err instanceof CashDroError) {
|
|
361
374
|
console.error("CashDro rejected the request:", err.response);
|
|
362
375
|
} else {
|
|
363
|
-
throw err; //
|
|
376
|
+
throw err; // error de transporte/HTTP
|
|
364
377
|
}
|
|
365
378
|
}
|
|
366
379
|
```
|
|
367
380
|
|
|
368
|
-
- **`CashDroError`** —
|
|
369
|
-
- **`CashDroTimeoutError`** — `pollUntilFinished`
|
|
381
|
+
- **`CashDroError`** — una llamada devolvió un `code` de no-éxito (contiene la `response` cruda).
|
|
382
|
+
- **`CashDroTimeoutError`** — `pollUntilFinished` alcanzó el timeout (contiene `operationId` y el último poll).
|
|
370
383
|
|
|
371
|
-
|
|
372
|
-
|
|
384
|
+
Códigos de dispositivo comunes: `-1` credenciales incorrectas, `-2` ocupado /
|
|
385
|
+
no encontrado, `-3` monto incorrecto, `-4` sin permiso, `-998`/`-999`
|
|
386
|
+
dispositivo no disponible (revisar diagnóstico).
|
|
373
387
|
|
|
374
|
-
##
|
|
388
|
+
## Avanzado
|
|
375
389
|
|
|
376
|
-
###
|
|
390
|
+
### Acceso a la respuesta cruda
|
|
377
391
|
|
|
378
|
-
|
|
379
|
-
|
|
392
|
+
Los métodos que mapean 1:1 a una operación del dispositivo devuelven un
|
|
393
|
+
awaitable que también expone la respuesta HTTP cruda:
|
|
380
394
|
|
|
381
395
|
```ts
|
|
382
396
|
const { data, rawResponse } = await cashdro.askOperation(id).withRawResponse();
|
|
383
397
|
console.log(rawResponse.headers);
|
|
384
398
|
```
|
|
385
399
|
|
|
386
|
-
###
|
|
400
|
+
### Fetch personalizado / TLS autofirmado
|
|
387
401
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
402
|
+
Proporciona tu propio `fetch` para plataformas sin uno incorporado, o para
|
|
403
|
+
alcanzar una unidad que sirve un **certificado autofirmado**. Prefiere
|
|
404
|
+
instalar la CA de la unidad en tu almacén de confianza; solo relaja la
|
|
405
|
+
verificación en entornos confiables y que no sean de producción.
|
|
391
406
|
|
|
392
407
|
```ts
|
|
393
408
|
import { Agent, setGlobalDispatcher } from "undici";
|
|
394
|
-
setGlobalDispatcher(new Agent({ connect: { rejectUnauthorized: false } })); //
|
|
409
|
+
setGlobalDispatcher(new Agent({ connect: { rejectUnauthorized: false } })); // solo no-prod
|
|
395
410
|
```
|
|
396
411
|
|
|
397
|
-
###
|
|
412
|
+
### Opciones por solicitud
|
|
398
413
|
|
|
399
|
-
|
|
414
|
+
Cada método 1:1 acepta un segundo argumento opcional para overrides por
|
|
415
|
+
llamada:
|
|
400
416
|
|
|
401
417
|
```ts
|
|
402
418
|
const controller = new AbortController();
|
|
@@ -408,11 +424,11 @@ await cashdro.askOperation(id, {
|
|
|
408
424
|
});
|
|
409
425
|
```
|
|
410
426
|
|
|
411
|
-
###
|
|
427
|
+
### Cliente de bajo nivel
|
|
412
428
|
|
|
413
|
-
|
|
414
|
-
|
|
429
|
+
Para endpoints aún no envueltos, `cashdro.api` expone el cliente subyacente
|
|
430
|
+
usado para hacer las solicitudes.
|
|
415
431
|
|
|
416
|
-
###
|
|
432
|
+
### Compatibilidad de runtime
|
|
417
433
|
|
|
418
|
-
|
|
434
|
+
Funciona en Node.js 18+, Deno, Bun, Cloudflare Workers, Vercel y React Native.
|