From cc063512bdf820db7e14ca242a1a98fd6edd4964 Mon Sep 17 00:00:00 2001 From: Antoine Prieels Date: Thu, 23 May 2019 09:33:17 +0200 Subject: [PATCH 1/5] [IMP] hw_posbox_homepage: Six payment terminal Add configuration for a Six payment terminal on the IoTBox's homepage. The Terminal ID specified on the homepage is saved to: `/home/pi/odoo-six-payment-terminal.conf` TaskId: 1932416 --- addons/hw_posbox_homepage/controllers/main.py | 35 +++++++++++ addons/hw_posbox_homepage/views/homepage.html | 7 +++ .../views/six_payment_terminal.html | 61 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 addons/hw_posbox_homepage/views/six_payment_terminal.html diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py index 36a22356327..6494d11bc4f 100644 --- a/addons/hw_posbox_homepage/controllers/main.py +++ b/addons/hw_posbox_homepage/controllers/main.py @@ -53,6 +53,7 @@ wifi_config_template = jinja_env.get_template('wifi_config.html') driver_list_template = jinja_env.get_template('driver_list.html') remote_connect_template = jinja_env.get_template('remote_connect.html') configure_wizard_template = jinja_env.get_template('configure_wizard.html') +six_payment_terminal_template = jinja_env.get_template('six_payment_terminal.html') class IoTboxHomepage(web.Home): @@ -72,6 +73,12 @@ class IoTboxHomepage(web.Home): statuses[driver] = hw_proxy.drivers[driver].get_status() return statuses + def get_six_terminal(self): + path = Path.home() / 'odoo-six-payment-terminal.conf' + if path.exists(): + return path.read_text() + return 'Not Configured' + def get_homepage_data(self): hostname = str(socket.gethostname()) mac = get_mac() @@ -113,6 +120,7 @@ class IoTboxHomepage(web.Home): 'mac': ":".join(i + next(h) for i in h), 'iot_device_status': iot_device, 'server_status': get_odoo_server_url() or 'Not Configured', + 'six_terminal': self.get_six_terminal(), 'network_status': network, } @@ -296,3 +304,30 @@ class IoTboxHomepage(web.Home): return 'starting with ' + auth_token else: return 'already running' + + @http.route('/six_payment_terminal', type='http', auth='none', cors='*', csrf=False) + def six_payment_terminal(self): + return six_payment_terminal_template.render({ + 'title': 'Six Payment Terminal', + 'breadcrumb': 'Six Payment Terminal', + 'terminalId': self.get_six_terminal(), + }) + + @http.route('/six_payment_terminal_add', type='http', auth='none', cors='*', csrf=False) + def add_six_payment_terminal(self, terminal_id): + subprocess.check_call(["sudo", "mount", "-o", "remount,rw", "/"]) + path = Path.home() / 'odoo-six-payment-terminal.conf' + path.write_text(terminal_id) + subprocess.check_call(["sudo", "service", "odoo", "restart"]) + subprocess.check_call(["sudo", "mount", "-o", "remount,ro", "/"]) + return 'http://' + get_ip() + ':8069' + + @http.route('/six_payment_terminal_clear', type='http', auth='none', cors='*', csrf=False) + def clear_six_payment_terminal(self): + subprocess.check_call(["sudo", "mount", "-o", "remount,rw", "/"]) + path = Path.home() / 'odoo-six-payment-terminal.conf' + if path.exists(): + path.unlink() + subprocess.check_call(["sudo", "service", "odoo", "restart"]) + subprocess.check_call(["sudo", "mount", "-o", "remount,ro", "/"]) + return "" diff --git a/addons/hw_posbox_homepage/views/homepage.html b/addons/hw_posbox_homepage/views/homepage.html index 74a502f7ca7..d70238fc54f 100644 --- a/addons/hw_posbox_homepage/views/homepage.html +++ b/addons/hw_posbox_homepage/views/homepage.html @@ -22,6 +22,7 @@ font-weight: bold; vertical-align: top; width: 30%; + text-align: left; } .device-status { margin: 6px 0; @@ -109,6 +110,12 @@ Server {{ server_status }}configure + {% if server_status != "Not Configured" %} + + Six payment terminal + {{ six_terminal }} configure + + {% endif %} IOT Device diff --git a/addons/hw_posbox_homepage/views/six_payment_terminal.html b/addons/hw_posbox_homepage/views/six_payment_terminal.html new file mode 100644 index 00000000000..622c6a84a6e --- /dev/null +++ b/addons/hw_posbox_homepage/views/six_payment_terminal.html @@ -0,0 +1,61 @@ +{% extends "layout.html" %} +{% from "loading.html" import loading_block_ui %} +{% block head %} + +{% endblock %} +{% block content %} +

Six Payment Terminal

+

+ Set the Terminal ID (TID) of the terminal you want to use. +

+
+ + + + + + + + +
Terminal ID
+
+ {{ loading_block_ui(loading_message) }} +
+ {% if terminalId %} +

+ Current Terminal Id: {{ terminalId }} +

+
+ You can clear the terminal configuration +
+ +
+
+ {% endif %} +{% endblock %} From dc449a4ae52307289f64dffd0fc794cb9517cb91 Mon Sep 17 00:00:00 2001 From: Antoine Prieels Date: Thu, 23 May 2019 09:37:56 +0200 Subject: [PATCH 2/5] [IMP] hw_drivers: support Six payment terminals Add MPDManager to driver.py to keep a list of connected terminals up to date. Add the files needed to communicate with the payment terminals: eftdvs --> MPD server that needs to run on the IoTBox eftapi.so --> Library to connect Odoo to the MPD server TaskId: 1932416 --- addons/hw_drivers/controllers/driver.py | 37 +++++++++++++++++++ .../etc/init_posbox_image.sh | 3 ++ 2 files changed, 40 insertions(+) diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 0bd0286c3d5..b7c6c42dca6 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -19,6 +19,7 @@ from glob import glob from base64 import b64decode from pathlib import Path import socket +import ctypes from odoo import http, _ from odoo.modules.module import get_resource_path @@ -379,6 +380,7 @@ class Manager(Thread): while 1: updated_devices = self.usb_loop() updated_devices.update(self.video_loop()) + updated_devices.update(mpdm.devices) updated_devices.update(bt_devices) updated_devices.update(socket_devices) updated_devices.update(self.serial_loop()) @@ -441,11 +443,46 @@ class SocketManager(Thread): iot_device = IoTDevice(type('', (), {'dev': dev}), 'socket') socket_devices[addr[0]] = iot_device +class MPDManager(Thread): + def __init__(self): + super(MPDManager, self).__init__() + self.devices = {} + self.mpd_session = ctypes.c_void_p() + + def run(self): + eftapi.EFT_CreateSession(ctypes.byref(self.mpd_session)) + eftapi.EFT_PutDeviceId(self.mpd_session, terminal_id.encode()) + while True: + if self.terminal_connected(terminal_id): + self.devices[terminal_id] = IoTDevice(terminal_id, 'mpd') + elif terminal_id in self.devices: + self.devices = {} + time.sleep(20) + + def terminal_connected(self, terminal_id): + eftapi.EFT_QueryStatus(self.mpd_session) + eftapi.EFT_Complete(self.mpd_session, 1) # Needed to read messages from driver + device_status = ctypes.c_long() + eftapi.EFT_GetDeviceStatusCode(self.mpd_session, ctypes.byref(device_status)) + return device_status.value in [0, 1] + + conn = cups_connection() PPDs = conn.getPPDs() printers = conn.getPrinters() cups_lock = Lock() # We can only make one call to Cups at a time +mpdm = MPDManager() +terminal_id = read_file_first_line('odoo-six-payment-terminal.conf') +if terminal_id: + try: + subprocess.check_output(["pidof", "eftdvs"]) # Check if MPD server is running + except subprocess.CalledProcessError: + subprocess.Popen(["eftdvs"]) # Start MPD server + eftapi = ctypes.CDLL("eftapi.so") # Library given by Six + mpdm.daemon = True + mpdm.start() + m = Manager() m.daemon = True m.start() diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh index bd0198a8db6..2153380d9dc 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh @@ -121,6 +121,9 @@ PIP_TO_INSTALL=" pip3 install ${PIP_TO_INSTALL} +# Dowload MPD server and library for Six terminals +wget 'https://nightly.odoo.com/master/iotbox/eftdvs' -P /usr/local/bin/ +wget 'https://nightly.odoo.com/master/iotbox/eftapi.so' -P /usr/lib/ groupadd usbusers usermod -a -G usbusers pi From 187eb053d6ca7e4d28459940e0f68bb11e88cdc4 Mon Sep 17 00:00:00 2001 From: Antoine Prieels Date: Thu, 23 May 2019 09:41:16 +0200 Subject: [PATCH 3/5] [IMP] point_of_sale: Six terminal interface Small changes to prepare the modifications needed by the interface of Six terminals in Enterprise: - With the possibility of reversing payments, we could possibly have payment lines that have an amount of 0. The computation of the 'extradue' will be wrong in this case and we need to put it in a separate function so that we can override it in pos_iot. - Add ids to "Validate Closing & Post Entries" buttons to override them to send balance on close. TaskId: 1932416 --- addons/point_of_sale/static/src/js/screens.js | 15 +++++++++------ addons/point_of_sale/views/pos_session_view.xml | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index fc9649129ab..48dbfd28b90 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -1945,12 +1945,7 @@ var PaymentScreenWidget = ScreenWidget.extend({ } var lines = order.get_paymentlines(); - var due = order.get_due(); - var extradue = 0; - if (due && lines.length && due !== order.get_due(lines[lines.length-1])) { - extradue = due; - } - + var extradue = this.compute_extradue(order); this.$('.paymentlines-container').empty(); var lines = $(QWeb.render('PaymentScreen-Paymentlines', { @@ -1970,6 +1965,14 @@ var PaymentScreenWidget = ScreenWidget.extend({ lines.appendTo(this.$('.paymentlines-container')); }, + compute_extradue: function (order) { + var lines = order.get_paymentlines(); + var due = order.get_due(); + if (due && lines.length && due !== order.get_due(lines[lines.length-1])) { + return due; + } + return 0; + }, click_paymentmethods: function(id) { var payment_method = this.pos.payment_methods_by_id[id] this.pos.get_order().add_paymentline(payment_method); diff --git a/addons/point_of_sale/views/pos_session_view.xml b/addons/point_of_sale/views/pos_session_view.xml index 2ef12e16b2e..afc0cab74d6 100644 --- a/addons/point_of_sale/views/pos_session_view.xml +++ b/addons/point_of_sale/views/pos_session_view.xml @@ -13,13 +13,13 @@ attrs="{'invisible' : ['|', ('cash_control', '=', False), ('state', '!=', 'opening_control')]}" class="oe_highlight"/>