Skip to content

Commit 62cfe23

Browse files
committed
fix(openDrawer): corregir fallback ESC/POS y agregar win32print a PyInstaller
- control() NO es para cajón (es LF/CR/TAB): reemplazado por _raw() - cashdraw() en python-escpos v3.x espera entero 2/5, no bytes CD_KICK_2 - Fallback 1: _raw(CD_KICK_2) - bytes crudos directamente - Fallback 2: _raw ESC p con timing extendido 250ms para impresoras lentas - Agrega win32print/win32api/win32con/pywintypes a hiddenimports en specs (sin estos el driver Win32Raw falla silenciosamente en builds PyInstaller)
1 parent 7f59cdd commit 62cfe23

3 files changed

Lines changed: 62 additions & 25 deletions

File tree

fiscalberry-cli.spec

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@ a = Analysis(
66
pathex=[],
77
binaries=[],
88
datas=[('./capabilities.json', 'escpos')],
9-
hiddenimports=[],
9+
hiddenimports=[
10+
# Windows: driver Win32Raw requiere win32print para enviar bytes crudos
11+
# Si falta, cashdraw() falla silenciosamente en el binario PyInstaller
12+
'win32print',
13+
'win32api',
14+
'win32con',
15+
'pywintypes',
16+
],
1017
hookspath=[],
1118
hooksconfig={},
1219
runtime_hooks=[],

fiscalberry-gui.spec

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ a = Analysis(
1111
('src/fiscalberry/ui/assets/fiscalberry.ico', 'fiscalberry/ui/assets/'),
1212
('src/fiscalberry/ui/assets', 'fiscalberry/ui/assets')
1313
],
14-
hiddenimports=[],
14+
hiddenimports=[
15+
# Windows: driver Win32Raw requiere win32print para enviar bytes crudos
16+
# Si falta, cashdraw() falla silenciosamente en el binario PyInstaller
17+
'win32print',
18+
'win32api',
19+
'win32con',
20+
'pywintypes',
21+
],
1522
hookspath=[],
1623
hooksconfig={},
1724
runtime_hooks=[],

src/fiscalberry/common/EscPComandos.py

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -231,37 +231,60 @@ def printBytes(self, escpos: EscposIO, bytes=None, **kwargs):
231231

232232
def openDrawer(self, escpos: EscposIO, *args, **kwargs):
233233
"""
234-
Abre el cajón de dinero.
235-
NOTA: *args es necesario porque run() despacha con fnAction(escpos, params)
236-
cuando params no es list ni dict (ej: {"openDrawer": true} → params=True).
237-
Sin *args, True se convierte en argumento posicional extra → TypeError.
234+
Abre el cajón de dinero electrónico mediante pulso ESC/POS.
235+
236+
NOTAS DE COMPATIBILIDAD:
237+
- *args es obligatorio: run() llama fnAction(escpos, params) cuando params
238+
no es list ni dict (ej: {"openDrawer": true} → params=True). Sin *args
239+
ese argumento posicional extra genera TypeError.
240+
- Primero intenta cashdraw(2) que es la API correcta en python-escpos v3.x.
241+
(CD_KICK_2 es bytes, el método espera el entero 2 ó 5).
242+
- Fallback 1: _raw(CD_KICK_2) — envía bytes crudos directamente.
243+
- Fallback 2: _raw con timing extendido, útil en impresoras lentas.
244+
- control() NO es válido aquí: es para LF/CR/TAB, no para cajón.
238245
"""
239246
try:
240-
escpos.printer.cashdraw(CD_KICK_2)
247+
# API correcta v3.x: pasar entero 2 (pin 2)
248+
escpos.printer.cashdraw(2)
241249
return {"status": "success", "message": "Cajón abierto correctamente"}
242250
except Exception as e:
243-
# Fallback: comando ESC/POS directo para impresoras que requieren secuencia diferente
251+
# Fallback 1: enviar bytes ESC/POS crudos del pin 2
244252
try:
245-
escpos.printer.control("\x1b\x70\x00\x19\x19")
246-
return {"status": "success", "message": "Cajón abierto con comando alternativo"}
253+
escpos.printer._raw(CD_KICK_2)
254+
return {"status": "success", "message": "Cajón abierto con _raw(CD_KICK_2)"}
247255
except Exception as e2:
248-
error_msg = f"Error al abrir cajón: {e}, comando alternativo falló: {e2}"
249-
logger.error(error_msg)
250-
256+
# Fallback 2: bytes con timing extendido (250ms) para impresoras lentas
251257
try:
252-
publish_error(
253-
error_type="CASH_DRAWER_ERROR",
254-
error_message=error_msg,
255-
context={
256-
"primary_error": str(e),
257-
"secondary_error": str(e2),
258-
"exception_types": [type(e).__name__, type(e2).__name__]
259-
}
258+
escpos.printer._raw(b"\x1b\x70\x00\x19\xfa")
259+
return {"status": "success", "message": "Cajón abierto con pulso extendido"}
260+
except Exception as e3:
261+
error_msg = (
262+
f"Error abriendo cajón — "
263+
f"cashdraw(2): {e} | "
264+
f"_raw(CD_KICK_2): {e2} | "
265+
f"_raw(extendido): {e3}"
260266
)
261-
except Exception as publish_err:
262-
logger.error(f"Error publicando error de cajón a RabbitMQ: {publish_err}")
263-
264-
return {"status": "error", "message": error_msg}
267+
logger.error(error_msg)
268+
269+
try:
270+
publish_error(
271+
error_type="CASH_DRAWER_ERROR",
272+
error_message=error_msg,
273+
context={
274+
"cashdraw_error": str(e),
275+
"raw_kick2_error": str(e2),
276+
"raw_extended_error": str(e3),
277+
"exception_types": [
278+
type(e).__name__,
279+
type(e2).__name__,
280+
type(e3).__name__,
281+
]
282+
}
283+
)
284+
except Exception as publish_err:
285+
logger.error(f"Error publicando error de cajón a RabbitMQ: {publish_err}")
286+
287+
return {"status": "error", "message": error_msg}
265288

266289

267290
def printPedido(self, escpos: EscposIO, **kwargs):

0 commit comments

Comments
 (0)