diff --git a/app/printer.py b/app/printer.py index 107dd66..c299402 100644 --- a/app/printer.py +++ b/app/printer.py @@ -14,7 +14,7 @@ from PIL import Image, ImageDraw, ImageFont from os import remove, getcwd, path, name, system -from app.utils import absolute_path, get_with_alias +from app.utils import absolute_path, get_with_alias, log_error from app.middleware import gtranslator from app.constants import VERSION, PRINTED_TICKET_DIMENSIONS, PRINTED_TICKET_MAXIMUM_HEIGH_OR_WIDTH @@ -120,12 +120,9 @@ def print_ticket_windows(pname, a, b, c, d, cit, ip, l='en', scale=1): def assign(v, p, in_ep, out_ep): - try: - printer = getp.Usb(v, p, 0, in_ep, out_ep) - printer.text("\n") - return printer - except Exception: - return None + printer = getp.Usb(v, p, 0, in_ep, out_ep) + printer.text("\n") + return printer def listp(): @@ -136,8 +133,8 @@ def listp(): in_ep = int(cfg[(0, 0)][0].bEndpointAddress) out_ep = int(cfg[(0, 0)][1].bEndpointAddress) vl.append([ll.idVendor, ll.idProduct, in_ep, out_ep]) - except Exception: - pass + except Exception as exception: + log_error(exception) return vl diff --git a/app/views/core.py b/app/views/core.py index af7ff1d..ad483f4 100644 --- a/app/views/core.py +++ b/app/views/core.py @@ -104,10 +104,7 @@ def printer_failure_redirect(exception): office = office or task.least_tickets_office() if printed: - try: - current_ticket = data.Serial.all_office_tickets(office.id).first().number - except Exception: - current_ticket = None + current_ticket = getattr(data.Serial.all_office_tickets(office.id).first(), 'number', None) common_arguments = (f'{office.prefix}.{next_number}', f'{office.prefix}{office.name}', data.Serial.all_office_tickets(office.id).count(), @@ -129,7 +126,7 @@ def printer_failure_redirect(exception): return printer_failure_redirect(exception) else: try: - printer = assign(int(ticket_settings.vendor), int(ticket_settings.product), + printer = assign(int(ticket_settings.vendor, 16), int(ticket_settings.product, 16), int(ticket_settings.in_ep), int(ticket_settings.out_ep)) (printit_ar if ticket_settings.langu == 'ar' else printit)(printer, diff --git a/app/views/customize.py b/app/views/customize.py index e6bb6d8..a71894f 100644 --- a/app/views/customize.py +++ b/app/views/customize.py @@ -57,13 +57,14 @@ def ticket(): return redirect(url_for('cust_app.ticket')) if windows: + printer.product = printer_id + else: id_chunks = printer_id.split('_') printer.vendor = id_chunks[0] printer.product = id_chunks[1] printer.in_ep = int(id_chunks[2]) printer.out_ep = int(id_chunks[3]) - printer.product = printer_id printer.active = True printer.langu = form.langu.data printer.value = form.value.data diff --git a/requirements/deploy.txt b/requirements/deploy.txt index 301a82c..ce768b0 100644 --- a/requirements/deploy.txt +++ b/requirements/deploy.txt @@ -49,7 +49,7 @@ jsmin==2.2.2 lesscpy==0.13.0 Mako==1.0.7 Markdown==2.6.9 -MarkupSafe==1.0 +MarkupSafe==1.1.1 mccabe==0.6.1 netifaces==0.10.6 olefile==0.44 diff --git a/tests/common.py b/tests/common.py index 6d69ef2..1ca5981 100644 --- a/tests/common.py +++ b/tests/common.py @@ -8,7 +8,7 @@ from app.main import bundle_app from app.middleware import db from app.database import (User, Operators, Office, Task, Serial, Media, Touch_store, - Display_store, Vid, Slides_c, Slides, Aliases) + Display_store, Vid, Slides_c, Slides, Aliases, Printer) from app.utils import absolute_path from app.tasks import stop_tasks @@ -31,7 +31,7 @@ PREFIXES = [p for p in list(map(lambda i: chr(i).upper(), range(97, 123))) if p != TEST_PREFIX] MODULES = [Serial, User, Operators, Task, Office, Media, Slides] -DEFAULT_MODULES = [Touch_store, Display_store, Vid, Slides_c, Aliases] +DEFAULT_MODULES = [Touch_store, Display_store, Vid, Slides_c, Aliases, Printer] DB_PATH = absolute_path('testing.sqlite') TEST_REPEATS = 3 ENTRY_NUMBER = 10 diff --git a/tests/core.py b/tests/core.py index 5ee52aa..86128b3 100644 --- a/tests/core.py +++ b/tests/core.py @@ -1,10 +1,13 @@ import pytest +import escpos.printer from random import choice +from unittest.mock import MagicMock from .common import NAMES, TEST_REPEATS from app.middleware import db from app.utils import absolute_path -from app.database import (Task, Office, Serial, Settings, Touch_store, Display_store) +from app.database import (Task, Office, Serial, Settings, Touch_store, Display_store, + Printer) @pytest.mark.usefixtures('c') @@ -40,6 +43,43 @@ def test_new_registered_ticket(c): assert new_ticket.name == name +@pytest.mark.usefixtures('c') +def test_new_printed_ticket(c, monkeypatch): + last_ticket = None + mock_printer = MagicMock() + monkeypatch.setattr(escpos.printer, 'Usb', mock_printer) + + with c.application.app_context(): + # NOTE: set ticket setting to printed + printer_settings = Printer.get() + touch_screen_settings = Touch_store.get() + touch_screen_settings.n = False + printer_settings.vendor = '0xAA' + printer_settings.product = '0xAA' + printer_settings.in_ep = 170 + printer_settings.out_ep = 170 + db.session.commit() + + task = choice(Task.query.all()) + last_ticket = Serial.query.filter_by(task_id=task.id)\ + .order_by(Serial.number.desc()).first() + + name = 'TESTING PRINTED TICKET' + response = c.post(f'/serial/{task.id}', data={ + 'name': name + }, follow_redirects=True) + new_ticket = Serial.query.filter_by(task_id=task.id)\ + .order_by(Serial.number.desc()).first() + + assert response.status == '200 OK' + assert last_ticket.number != new_ticket.number + assert new_ticket.name == name + assert mock_printer().text.call_count == 12 + assert mock_printer().set.call_count == 7 + mock_printer().set.assert_called_with(align='left', height=1, width=1) + mock_printer().cut.assert_called_once() + + @pytest.mark.usefixtures('c') def test_new_printed_ticket_fail(c): with c.application.app_context(): @@ -61,7 +101,7 @@ def test_new_printed_ticket_fail(c): assert response.status == '200 OK' assert new_ticket.id == last_ticket.id - assert "ValueError: invalid literal for int() with base 10: ' '" in errors_log_content + assert "ValueError: invalid literal for int() with base 16: ' '" in errors_log_content @pytest.mark.usefixtures('c') diff --git a/tests/customize.py b/tests/customize.py index 6064260..8d3bf3c 100644 --- a/tests/customize.py +++ b/tests/customize.py @@ -1,5 +1,8 @@ import pytest import io +import usb.core +from unittest.mock import MagicMock +from collections import namedtuple from app.middleware import db from app.helpers import get_tts_safely @@ -34,6 +37,52 @@ def test_ticket_registered(c): assert Touch_store.get().n is True +@pytest.mark.usefixtures('c') +def test_ticket_printed(c, monkeypatch): + vendor = '0xAA' + product = '0xAA' + in_ep = 170 + out_ep = 170 + in_config = namedtuple('in_config', ['bEndpointAddress']) + usb_device = namedtuple('usb', ['get_active_configuration', 'idVendor', 'idProduct']) + mock_usb_find = MagicMock(return_value=[usb_device( + lambda: {(0, 0): [in_config(in_ep), in_config(out_ep)]}, + vendor, + product)]) + monkeypatch.setattr(usb.core, 'find', mock_usb_find) + + with c.application.app_context(): + # NOTE: set ticket setting to printed + touch_screen_settings = Touch_store.get() + touch_screen_settings.n = False + db.session.commit() + + printer_value = 1 + kind = 2 # NOTE: Printed + lang = 'en' + printers = f'{vendor}_{product}_{in_ep}_{out_ep}' + scale = 1 + response = c.post('/ticket', data={ + 'value': printer_value, + 'kind': kind, + 'langu': lang, + 'printers': printers, + 'scale': scale + }, follow_redirects=True) + + assert response.status == '200 OK' + assert Touch_store.get().n is False + assert Printer.get().active is True + assert Printer.get().value == printer_value + assert Printer.get().langu == lang + assert Printer.get().scale == scale + assert Printer.get().in_ep == in_ep + assert Printer.get().out_ep == out_ep + assert Printer.get().vendor == vendor + assert Printer.get().product == product + assert mock_usb_find.call_count == 2 + + @pytest.mark.usefixtures('c') def test_video(c): name = 'testing.mp4'