@openfactura/cli 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +395 -2
- package/dist/index.js +2137 -0
- package/package.json +51 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xaviigna
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,396 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @openfactura/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Cliente de línea de comandos de [Open Factura](../../README.md), la plataforma abierta de facturación
|
|
4
|
+
electrónica de El Salvador (DTE, Ministerio de Hacienda). Emite, consulta e invalida documentos desde la
|
|
5
|
+
terminal o desde un script, e incluye un servidor MCP por stdio para Claude y otros asistentes.
|
|
6
|
+
|
|
7
|
+
La CLI habla con un servidor de Open Factura únicamente por su API REST: no firma ni transmite por su
|
|
8
|
+
cuenta, y no necesita el certificado de Hacienda en su equipo.
|
|
9
|
+
|
|
10
|
+
## Instalación
|
|
11
|
+
|
|
12
|
+
Requiere Node.js 20 o superior (también funciona con Bun).
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm i -g @openfactura/cli
|
|
16
|
+
openfactura --version
|
|
17
|
+
|
|
18
|
+
# o sin instalar
|
|
19
|
+
npx @openfactura/cli --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Inicio de sesión
|
|
23
|
+
|
|
24
|
+
Cree una clave de API en el panel web (Desarrolladores → Nueva clave). Las claves `of_test_…` trabajan contra
|
|
25
|
+
el ambiente de pruebas del MH y las `of_live_…` contra producción.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
openfactura login --url https://factura.su-empresa.sv
|
|
29
|
+
# Clave de API (of_test_… u of_live_…): ← se teclea sin mostrarse
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`login` verifica la clave contra el servidor y la guarda en `~/.config/openfactura/config.json`
|
|
33
|
+
(o en `$XDG_CONFIG_HOME/openfactura/config.json`) con permisos `0600`. La clave completa nunca se
|
|
34
|
+
imprime: la CLI muestra sólo sus primeros 14 caracteres.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
openfactura login --url https://factura.su-empresa.sv --key of_test_… # sin preguntar
|
|
38
|
+
echo "$CLAVE" | openfactura login # desde una tubería
|
|
39
|
+
openfactura login --profile produccion # otro perfil
|
|
40
|
+
openfactura logout # borra la clave guardada
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Evite `--key` en equipos compartidos: el valor queda en el historial de la terminal.
|
|
44
|
+
|
|
45
|
+
En un servidor de integración continua no hace falta `login`; basta con las variables de entorno:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
export OPENFACTURA_URL=https://factura.su-empresa.sv
|
|
49
|
+
export OPENFACTURA_API_KEY=of_test_…
|
|
50
|
+
openfactura whoami
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### De dónde sale cada valor
|
|
54
|
+
|
|
55
|
+
| Valor | Orden de prioridad |
|
|
56
|
+
| ---------------- | ----------------------------------------------------------------------- |
|
|
57
|
+
| URL del servidor | `--url` → `OPENFACTURA_URL` → perfil guardado → `http://localhost:8788` |
|
|
58
|
+
| Clave de API | `OPENFACTURA_API_KEY` → perfil guardado |
|
|
59
|
+
| Perfil | `--profile` → `OPENFACTURA_PROFILE` → `default` |
|
|
60
|
+
|
|
61
|
+
## Comandos
|
|
62
|
+
|
|
63
|
+
Todos aceptan `--json` (imprime el JSON de la API en stdout, para scripts), `--url`, `--profile` y
|
|
64
|
+
`--help`.
|
|
65
|
+
|
|
66
|
+
### Sesión y emisor
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
openfactura whoami # actor, permisos, ambiente, servidor y prefijo de la clave
|
|
70
|
+
openfactura emisor # datos fiscales, establecimientos, puntos de venta y credenciales cargadas
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
$ openfactura whoami
|
|
75
|
+
Actor: clave
|
|
76
|
+
Organización: aaFgOwpa4md9Tl6Ct9e42AJ2jNnAltjh
|
|
77
|
+
Ambiente: 00 Pruebas (simulador del MH)
|
|
78
|
+
Servidor: http://localhost:8788 (defecto)
|
|
79
|
+
Clave: of_test_0d2aEw… (entorno)
|
|
80
|
+
Perfil: default
|
|
81
|
+
Permisos: dte:read, dte:emit, dte:invalidate, clientes:read, …
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Clientes
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
openfactura clientes list
|
|
88
|
+
openfactura clientes list --q "contribuyente"
|
|
89
|
+
|
|
90
|
+
openfactura clientes add --file cliente.json
|
|
91
|
+
openfactura clientes add \
|
|
92
|
+
--tipo-documento 36 --num-documento 0614-290786-103-1 --nrc 234567-8 \
|
|
93
|
+
--nombre "CLIENTE CONTRIBUYENTE, S.A. DE C.V." \
|
|
94
|
+
--cod-actividad 46900 --desc-actividad "Venta al por mayor de otros productos" \
|
|
95
|
+
--departamento 06 --municipio 23 --distrito 14 --complemento "Av. Olímpica #100" \
|
|
96
|
+
--telefono 22445566 --correo compras@cliente.com.sv
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`--tipo-documento`: `36` NIT, `13` DUI, `03` pasaporte, `02` carné de residente, `37` otro. También
|
|
100
|
+
existe `--nombre-comercial`. El archivo de `--file` lleva los mismos campos que la API
|
|
101
|
+
(`tipoDocumento`, `numDocumento`, `nombre`, …); `--file -` lee la entrada estándar.
|
|
102
|
+
|
|
103
|
+
### Productos
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
openfactura productos list --q licencia
|
|
107
|
+
|
|
108
|
+
openfactura productos add --file producto.json
|
|
109
|
+
openfactura productos add --codigo LIC-001 --descripcion "Licencia anual" --precio 100 --tipo-item 2
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`--precio` va **sin IVA**. `--tipo-item`: `1` bien (por defecto), `2` servicio, `3` ambos, `4` otros
|
|
113
|
+
tributos. `--uni-medida`: código de CAT-014 (por defecto `59`, unidad). `--tipo-venta`: `gravada`
|
|
114
|
+
(por defecto), `exenta` o `noSujeta`.
|
|
115
|
+
|
|
116
|
+
### Catálogos del MH
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
openfactura catalogos # lista de catálogos
|
|
120
|
+
openfactura catalogos CAT-012 # departamentos
|
|
121
|
+
openfactura catalogos CAT-013 --departamento 06 # municipios de San Salvador
|
|
122
|
+
openfactura catalogos CAT-019 --q "programación" # actividades económicas
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### DTE
|
|
126
|
+
|
|
127
|
+
El archivo de emisión es el mismo cuerpo de `POST /api/v1/dte`:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"tipoDte": "01",
|
|
132
|
+
"datos": {
|
|
133
|
+
"items": [
|
|
134
|
+
{ "descripcion": "Servicio de consultoría", "cantidad": 2, "precioUni": 11.3, "tipoItem": 2 }
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- `tipoDte`: `01` Factura, `03` Crédito Fiscal, `04` Nota de Remisión, `05` Nota de Crédito, `06` Nota de
|
|
141
|
+
Débito, `07` Comprobante de Retención, `11` Factura de Exportación, `14` Sujeto Excluido.
|
|
142
|
+
- `datos`: `items`, `receptor`, `condicionOperacion`, `pagos`, `documentosRelacionados`… En Factura,
|
|
143
|
+
`precioUni` **incluye** IVA; en Crédito Fiscal, notas y remisión va **sin** IVA.
|
|
144
|
+
- `clienteId` (opcional): usa un cliente guardado como receptor. `puntoVentaId` (opcional): punto de
|
|
145
|
+
venta que emite; por defecto el primero.
|
|
146
|
+
|
|
147
|
+
Un Crédito Fiscal para un cliente guardado:
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"tipoDte": "03",
|
|
152
|
+
"clienteId": "c6de4c6c-d772-4f19-811a-5419655dcd06",
|
|
153
|
+
"datos": { "items": [{ "descripcion": "Licencia anual", "cantidad": 1, "precioUni": 100 }] }
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### Validar
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
openfactura dte validar factura.json
|
|
161
|
+
cat factura.json | openfactura dte validar -
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Construye el documento y lo valida contra el esquema del MH sin consumir número de control, sin firmar y
|
|
165
|
+
sin transmitir. Imprime los totales y los problemas; termina con salida `1` si hay problemas.
|
|
166
|
+
|
|
167
|
+
#### Emitir
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
openfactura dte emitir factura.json
|
|
171
|
+
generar-factura | openfactura dte emitir - --json > emitido.json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
$ openfactura dte emitir factura.json
|
|
176
|
+
Idempotency-Key: 853c48f2-f488-45d5-af00-0369495f0c05
|
|
177
|
+
Estado: procesado
|
|
178
|
+
Tipo: 01 Factura
|
|
179
|
+
Número de control: DTE-01-M001P001-000000000000002
|
|
180
|
+
Código de generación: 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4
|
|
181
|
+
Total: $22.60
|
|
182
|
+
Sello recibido: 20265EE94C1B2C4CBB56F56121E37F5AC8CA7D27
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Cada emisión lleva una `Idempotency-Key`. Si no la indica, la CLI genera un UUID y lo muestra (por
|
|
186
|
+
stderr) **antes** de enviar. Si la red falla y no sabe si el documento se emitió, repita el comando con
|
|
187
|
+
esa misma clave: el servidor devuelve el resultado original y no emite dos veces.
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
openfactura dte emitir factura.json --idempotency-key 853c48f2-f488-45d5-af00-0369495f0c05
|
|
191
|
+
openfactura dte emitir factura.json --idempotency-key pedido-1042 # su propio identificador
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Si el MH no responde, el documento queda firmado en estado `contingencia` y se transmite después con
|
|
195
|
+
`openfactura contingencia transmitir`.
|
|
196
|
+
|
|
197
|
+
#### Consultar
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
openfactura dte list
|
|
201
|
+
openfactura dte list --tipo 01 --estado procesado --desde 2026-11-01 --hasta 2026-11-30
|
|
202
|
+
openfactura dte list --q "cliente contribuyente" --pagina 2
|
|
203
|
+
|
|
204
|
+
openfactura dte get 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 # estado, sello, respuesta del MH, eventos
|
|
205
|
+
|
|
206
|
+
openfactura dte json 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 # JSON oficial a stdout
|
|
207
|
+
openfactura dte json 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 -o dte.json
|
|
208
|
+
|
|
209
|
+
openfactura dte pdf 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 # guarda <codigo>.pdf aquí
|
|
210
|
+
openfactura dte pdf 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 -o factura.pdf
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`--estado`: `pendiente`, `procesado`, `rechazado`, `contingencia` o `invalidado`.
|
|
214
|
+
|
|
215
|
+
#### Invalidar
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
openfactura dte invalidar 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 --tipo 2 --motivo "Operación rescindida"
|
|
219
|
+
openfactura dte invalidar <codigo> --tipo 1 --reemplazo <codigo-del-dte-que-lo-corrige>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`--tipo`: `1` error en la información (requiere `--reemplazo`), `2` rescindir la operación, `3` otro
|
|
223
|
+
(requiere `--motivo` y `--reemplazo`). La invalidación es irreversible. El mismo comando invalida un
|
|
224
|
+
evento de retorno u operaciones especiales si recibe su código. Un DTE con un retorno vigente no se
|
|
225
|
+
invalida hasta invalidar antes el retorno.
|
|
226
|
+
|
|
227
|
+
#### Retorno (evento 18)
|
|
228
|
+
|
|
229
|
+
Devolución de bienes, reembolso o envases sobre una Factura (01), Factura de Exportación (11) o Sujeto
|
|
230
|
+
Excluido (14) procesados, sin invalidar el documento. Plazo: 3 meses desde la fecha del documento.
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
echo '{ "items": [{ "descripcion": "Silla", "cantidad": 1, "precioUni": 22.6 }] }' \
|
|
234
|
+
| openfactura dte retorno 0862382B-0BB8-42A0-BB6B-B42DCCDF1EA4 -
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`precioUni` va como en el documento original: en Factura con IVA, en 11 y 14 sin IVA. Como `dte emitir`,
|
|
238
|
+
lleva `Idempotency-Key` y pide confirmación con una clave `of_live_…`.
|
|
239
|
+
|
|
240
|
+
### Eventos
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
openfactura eventos operaciones-especiales simplificadas.json # evento 17
|
|
244
|
+
openfactura eventos list --tipo retorno
|
|
245
|
+
openfactura eventos get <codigo>
|
|
246
|
+
openfactura eventos json <codigo> -o retorno.json
|
|
247
|
+
openfactura eventos pdf <codigo> -o retorno.pdf
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
El archivo de operaciones especiales informa facturas simplificadas (`"tipoDocumento": "02"`, por rangos)
|
|
251
|
+
o comprobantes de control interno (`"97"`):
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"tipoDocumento": "02",
|
|
256
|
+
"fecha": "2026-10-31",
|
|
257
|
+
"items": [
|
|
258
|
+
{ "descripcion": "Facturas simplificadas", "docDel": "1", "docAl": "25", "precioUni": 10 }
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Contingencia
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
openfactura contingencia transmitir
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Webhooks
|
|
270
|
+
|
|
271
|
+
Su sistema recibe un `POST` firmado cuando un documento cambia de estado. La clave necesita el permiso
|
|
272
|
+
`webhooks:manage`.
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
openfactura webhooks add https://erp.su-empresa.sv/hooks/openfactura \
|
|
276
|
+
--eventos dte.procesado,dte.rechazado --descripcion "ERP" # sin --eventos: todos
|
|
277
|
+
openfactura webhooks list
|
|
278
|
+
openfactura webhooks test <id> # envía webhook.prueba; salida 1 si no se entrega
|
|
279
|
+
openfactura webhooks deliveries <id> # últimas 50 entregas, con intentos y errores
|
|
280
|
+
openfactura webhooks rotate <id> # secreto nuevo; el anterior deja de firmar
|
|
281
|
+
openfactura webhooks remove <id>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
`add` y `rotate` muestran el secreto de firma (`whsec_…`) una sola vez. Eventos: `dte.procesado`,
|
|
285
|
+
`dte.rechazado`, `dte.contingencia`, `dte.invalidado`, `retorno.procesado`,
|
|
286
|
+
`operaciones_especiales.procesado`. Cómo verificar la cabecera `OpenFactura-Signature`: sección
|
|
287
|
+
«Webhooks» de `docs/api.md` en el repositorio del servidor.
|
|
288
|
+
|
|
289
|
+
### Confirmación en producción
|
|
290
|
+
|
|
291
|
+
Con una clave `of_live_…`, `dte emitir`, `dte retorno`, `eventos operaciones-especiales`,
|
|
292
|
+
`dte invalidar` y `contingencia transmitir` piden confirmación
|
|
293
|
+
porque tienen efecto fiscal. Use `--yes` para omitirla. Si no hay una terminal interactiva (un script,
|
|
294
|
+
una tubería, `dte emitir -`), la CLI no pregunta: exige `--yes` y termina con salida `2` si falta.
|
|
295
|
+
|
|
296
|
+
## Uso en scripts
|
|
297
|
+
|
|
298
|
+
`--json` imprime en stdout exactamente el JSON de la API; los avisos y errores van a stderr.
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
codigo=$(openfactura dte emitir factura.json --json | jq -r .codigoGeneracion)
|
|
302
|
+
openfactura dte pdf "$codigo" -o "facturas/$codigo.pdf"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Los errores se imprimen en stderr como `Error [codigo]: mensaje`, seguidos del detalle: cada problema de
|
|
306
|
+
`dte_invalido` como `ruta: mensaje`, o las observaciones del MH en `dte_rechazado`. Con `--json`, stderr
|
|
307
|
+
recibe el JSON de error de la API (`{ "error": { "code", "message", "details" } }`); en un `429` se le
|
|
308
|
+
agrega el campo `retryAfter` con los segundos de espera.
|
|
309
|
+
|
|
310
|
+
### Códigos de salida
|
|
311
|
+
|
|
312
|
+
| Código | Significado |
|
|
313
|
+
| ------ | -------------------------------------------------------------------------------------- |
|
|
314
|
+
| `0` | Todo bien |
|
|
315
|
+
| `1` | Error de la API o de validación (incluye `dte validar` con problemas y errores de red) |
|
|
316
|
+
| `2` | Uso incorrecto: opción o argumento inválido, archivo ilegible, falta `--yes` |
|
|
317
|
+
| `3` | Sin autenticar: falta la clave, o es inválida, fue revocada o expiró |
|
|
318
|
+
| `4` | Límite de peticiones excedido; se imprime `Retry-After` |
|
|
319
|
+
|
|
320
|
+
### Variables de entorno
|
|
321
|
+
|
|
322
|
+
| Variable | Uso |
|
|
323
|
+
| --------------------- | ---------------------------------------------------------- |
|
|
324
|
+
| `OPENFACTURA_API_KEY` | Clave de API. Tiene prioridad sobre la clave guardada |
|
|
325
|
+
| `OPENFACTURA_URL` | URL del servidor |
|
|
326
|
+
| `OPENFACTURA_PROFILE` | Perfil de configuración (por defecto `default`) |
|
|
327
|
+
| `XDG_CONFIG_HOME` | Carpeta base de la configuración (por defecto `~/.config`) |
|
|
328
|
+
|
|
329
|
+
## Servidor MCP (stdio)
|
|
330
|
+
|
|
331
|
+
`openfactura mcp` es un servidor [MCP](https://modelcontextprotocol.io) por stdio. Sirve para los
|
|
332
|
+
clientes que no pueden enviar un encabezado HTTP fijo al servidor MCP remoto (`/mcp`). Expone las mismas
|
|
333
|
+
herramientas que el remoto y las ejecuta llamando a la API REST con su clave:
|
|
334
|
+
|
|
335
|
+
`emisor_obtener`, `catalogo_buscar`, `clientes_buscar`, `cliente_crear`, `productos_buscar`,
|
|
336
|
+
`producto_crear`, `dte_validar`, `dte_emitir`, `dte_listar`, `dte_obtener`, `dte_invalidar`,
|
|
337
|
+
`dte_retorno`, `operaciones_especiales_informar`, `eventos_listar`, `evento_obtener`,
|
|
338
|
+
`webhooks_listar`, `webhook_crear`, `webhook_eliminar`, `webhook_probar`.
|
|
339
|
+
|
|
340
|
+
Cada herramienta exige el mismo permiso que su ruta REST, así que la clave decide qué puede hacer el
|
|
341
|
+
asistente. Empiece con una clave `of_test_…`; `dte_emitir`, `dte_retorno`, `operaciones_especiales_informar` y
|
|
342
|
+
`dte_invalidar` tienen efecto fiscal con una
|
|
343
|
+
clave `of_live_…`, y aquí no hay confirmación de la CLI: la da usted en su cliente MCP al aprobar la
|
|
344
|
+
llamada.
|
|
345
|
+
|
|
346
|
+
### Claude Code
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
claude mcp add openfactura \
|
|
350
|
+
--env OPENFACTURA_API_KEY=of_test_… \
|
|
351
|
+
--env OPENFACTURA_URL=https://factura.su-empresa.sv \
|
|
352
|
+
-- npx -y @openfactura/cli mcp
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Claude Desktop
|
|
356
|
+
|
|
357
|
+
En `claude_desktop_config.json` (o en un `.mcp.json` de proyecto para Claude Code):
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"mcpServers": {
|
|
362
|
+
"openfactura": {
|
|
363
|
+
"command": "npx",
|
|
364
|
+
"args": ["-y", "@openfactura/cli", "mcp"],
|
|
365
|
+
"env": {
|
|
366
|
+
"OPENFACTURA_API_KEY": "of_test_…",
|
|
367
|
+
"OPENFACTURA_URL": "https://factura.su-empresa.sv"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Si ya ejecutó `openfactura login` en ese equipo puede omitir `env`: el servidor usa el perfil guardado.
|
|
375
|
+
|
|
376
|
+
Si su cliente sí admite encabezados HTTP, puede conectarse al servidor remoto sin instalar nada:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
claude mcp add --transport http openfactura https://factura.su-empresa.sv/mcp \
|
|
380
|
+
--header "Authorization: Bearer of_test_…"
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Desarrollo
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
bun install
|
|
387
|
+
bun run dev -- whoami # ejecuta desde el código fuente
|
|
388
|
+
bun run build # dist/index.js
|
|
389
|
+
bun run test
|
|
390
|
+
bun run type-check
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Licencia
|
|
394
|
+
|
|
395
|
+
MIT. La CLI es un cliente independiente del servidor de Open Factura (AGPL-3.0): se comunica con él
|
|
396
|
+
únicamente por HTTP y no incluye su código.
|