From 71ba505c8b387658111516dcb8fc5369b5013c82 Mon Sep 17 00:00:00 2001 From: crudo Date: Sat, 25 Mar 2017 02:38:02 +0100 Subject: [PATCH] Implement transaction printing. --- docs/config_core/core_debug_sqlite.ini | 4 ++ docs/config_core/core_production_mysql.ini | 4 ++ requirements.txt | 1 + static/img/macao-logo-printer.png | Bin 0 -> 5426 bytes web.py | 52 ++++++++++++++++++++- 5 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 static/img/macao-logo-printer.png diff --git a/docs/config_core/core_debug_sqlite.ini b/docs/config_core/core_debug_sqlite.ini index 43f365e..2f847e3 100644 --- a/docs/config_core/core_debug_sqlite.ini +++ b/docs/config_core/core_debug_sqlite.ini @@ -7,3 +7,7 @@ Path = pos.db [FLASK] SECRET_KEY = CHANGE_ME_NOW! + +[PRINTER] +Host = 192.168.1.100 +Post = 9100 diff --git a/docs/config_core/core_production_mysql.ini b/docs/config_core/core_production_mysql.ini index af4207c..6ef2a25 100644 --- a/docs/config_core/core_production_mysql.ini +++ b/docs/config_core/core_production_mysql.ini @@ -11,3 +11,7 @@ Password = secret [FLASK] SECRET_KEY = CHANGE_ME_NOW! + +[PRINTER] +Host = 192.168.1.100 +Post = 9100 diff --git a/requirements.txt b/requirements.txt index 66f9508..920c23a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,3 +8,4 @@ tabulate PyYAML flask>=0.12.0 flask_login>=0.4.0 +python-escpos diff --git a/static/img/macao-logo-printer.png b/static/img/macao-logo-printer.png new file mode 100644 index 0000000000000000000000000000000000000000..05d3042b681b6adf97d7588f595f8f2a0e689422 GIT binary patch literal 5426 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 E2ft7=2mk;8 literal 0 HcmV?d00001 diff --git a/web.py b/web.py index b9c1584..6457edb 100644 --- a/web.py +++ b/web.py @@ -1,4 +1,6 @@ from datetime import datetime +from time import sleep +import escpos.printer from flask import Flask, redirect, request, render_template, flash from flask_login import LoginManager, login_user, logout_user, login_required @@ -11,11 +13,20 @@ from pos.database import Database, User, Product, Event, Transaction, Order config = Config() debug = config.core['GENERAL'].getboolean('Debug', False) conf_db = config.core['DATABASE'] +conf_printer = config.core['PRINTER'] conf_flask = config.core['FLASK'] init_logging(config.logging) log = get_logger('web') +printer = escpos.printer.Network( + conf_printer['Host'], + port=conf_printer.getint('Port'), + timeout=15) + + +db = Database(**conf_db) + app = Flask(__name__) app.config.update( debug=debug, @@ -27,8 +38,6 @@ login_manager.init_app(app) login_manager.login_view = 'login' login_manager.login_message_category = 'error' -db = Database(**conf_db) - @login_manager.user_loader def load_user(uid): @@ -110,6 +119,43 @@ def sell_page(): title='Sell', event=event, products=products) +def print_orders(event, orders): + printer.open() + + printer.set(align='CENTER') + printer.image('static/img/macao-logo-printer.png', impl='bitImageColumn') + + printer.set(align='CENTER', text_type='B') + printer.text(event.name.upper()) + printer.text("\n\n") + + for o in orders: + printer.set(align='LEFT', width=2, height=2) + printer.text("{} x {}".format(o.quantity, o.product.name.upper())) + printer.text("\n") + + printer.text("\n") + + printer.cut() + printer.close() + sleep(0.7) + + +def print_transaction(transaction): + categorized_orders = {} + + for o in transaction.orders: + uid = o.product.category_uid + + if not categorized_orders.get(uid, False): + categorized_orders[uid] = [] + + categorized_orders[uid].append(o) + + for cat, orders in categorized_orders.items(): + print_orders(transaction.event, orders) + + @app.route('/sell', methods=['POST']) @login_required def sell(): @@ -135,6 +181,8 @@ def sell(): transaction = Transaction(event_uid=event.uid, orders=orders) session.add(transaction) + session.flush() + print_transaction(transaction) flash("Success!", 'success') return sell_page()