diff options
| author | Odoo's Mergebot <xmo+roboto@odoo.com> | 2019-09-04 17:07:43 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-09-04 17:07:43 +0200 |
| commit | 24c93d3f7f2e17674a59e81764684fe4493403f0 (patch) | |
| tree | 6d511bb1e99449f996a0495bef81eb039218d1ca | |
| parent | f75fc4ed6394cbeb00286b58d48e2cd2784f8b90 (diff) | |
| parent | 5d0afddaf221756378fa5d3cb459fd25aa147f93 (diff) | |
[IMP] Customer Display as IoT Device
Linked to odoo/enterprise#5266
Move all the logic that was inside hw_screen into an IoT Driver
in order to have consistency between devices.
Move the configuration of screen_url from the IoT Box form to
the IoT Device.
If an URL different than the default one is used, refresh the
page every minute.
--
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
closes odoo/odoo#36074
Signed-off-by: Quentin Lejeune (qle) <qle@odoo.com>
| -rwxr-xr-x | addons/hw_drivers/controllers/driver.py | 27 | ||||
| -rw-r--r-- | addons/hw_drivers/drivers/DisplayDriver.py | 202 | ||||
| -rw-r--r-- | addons/hw_drivers/static/src/js/worker.js (renamed from addons/hw_screen/static/src/js/worker.js) | 16 | ||||
| -rw-r--r-- | addons/hw_drivers/views/pos_display.html (renamed from addons/hw_screen/views/pos_display.html) | 0 | ||||
| -rw-r--r-- | addons/hw_posbox_homepage/controllers/main.py | 10 | ||||
| -rw-r--r-- | addons/hw_screen/__init__.py | 4 | ||||
| -rw-r--r-- | addons/hw_screen/__manifest__.py | 21 | ||||
| -rw-r--r-- | addons/hw_screen/controllers/__init__.py | 4 | ||||
| -rw-r--r-- | addons/hw_screen/controllers/main.py | 154 | ||||
| -rw-r--r-- | addons/point_of_sale/static/src/js/models.js | 6 | ||||
| -rw-r--r-- | addons/point_of_sale/static/src/js/screens.js | 1 | ||||
| -rwxr-xr-x | addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart | 30 | ||||
| -rw-r--r-- | addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js | 5 | ||||
| -rwxr-xr-x | addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo | 2 |
14 files changed, 241 insertions, 241 deletions
diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 7cda51f9f9d..5b01df584f4 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -142,7 +142,7 @@ class Driver(Thread, metaclass=DriverMetaClass): """ On specific driver override this method to give connection type of device return string - possible value : direct - network - bluetooth - serial + possible value : direct - network - bluetooth - serial - hdmi """ return self._device_connection @@ -151,7 +151,7 @@ class Driver(Thread, metaclass=DriverMetaClass): """ On specific driver override this method to give type of device return string - possible value : printer - camera - keyboard - scanner - device + possible value : printer - camera - keyboard - scanner - display - device """ return self._device_type @@ -294,6 +294,26 @@ class Manager(Thread): else: _logger.warning('Odoo server not set') + def get_connected_displays(self): + display_devices = {} + hdmi = subprocess.check_output(['tvservice', '-n']).decode('utf-8') + if hdmi.find('=') != -1: + hdmi_serial = sub('[^a-zA-Z0-9 ]+', '', hdmi.split('=')[1]).replace(' ', '_') + iot_device = IoTDevice({ + 'identifier': hdmi_serial, + 'name': hdmi.split('=')[1], + }, 'display') + display_devices[hdmi_serial] = iot_device + + if not len(display_devices): + # No display connected, create "fake" device to be accessed from another computer + display_devices['distant_display'] = IoTDevice({ + 'identifier': "distant_display", + 'name': "Distant Display", + }, 'display') + + return display_devices + def serial_loop(self): serial_devices = {} for identifier in glob('/dev/serial/by-path/*'): @@ -364,11 +384,14 @@ class Manager(Thread): updated_devices = {} self.send_alldevices() self.load_drivers() + # The list of devices doesn't change after the Raspberry has booted + display_devices = self.get_connected_displays() cpt = 0 while 1: updated_devices = self.usb_loop() updated_devices.update(self.video_loop()) updated_devices.update(mpdm.devices) + updated_devices.update(display_devices) updated_devices.update(bt_devices) updated_devices.update(socket_devices) updated_devices.update(self.serial_loop()) diff --git a/addons/hw_drivers/drivers/DisplayDriver.py b/addons/hw_drivers/drivers/DisplayDriver.py new file mode 100644 index 00000000000..35547fbcbe1 --- /dev/null +++ b/addons/hw_drivers/drivers/DisplayDriver.py @@ -0,0 +1,202 @@ +import jinja2 +import json +import logging +import netifaces as ni +import os +from pathlib import Path +import subprocess +import threading +import time +import urllib3 + +from odoo import http +from odoo.addons.hw_drivers.tools import helpers +from odoo.addons.hw_drivers.controllers.driver import Driver, event_manager, iot_devices + +path = os.path.realpath(os.path.join(os.path.dirname(__file__), '../views')) +loader = jinja2.FileSystemLoader(path) + +jinja_env = jinja2.Environment(loader=loader, autoescape=True) +jinja_env.filters["json"] = json.dumps + +pos_display_template = jinja_env.get_template('pos_display.html') + +_logger = logging.getLogger(__name__) + + +class DisplayDriver(Driver): + connection_type = 'display' + + def __init__(self, device): + super(DisplayDriver, self).__init__(device) + self._device_type = 'display' + self._device_connection = 'hdmi' + self._device_name = device['name'] + self.event_data = threading.Event() + self.owner = False + self.rendered_html = '' + self.load_url() + + @property + def device_identifier(self): + return self.dev['identifier'] + + @classmethod + def supported(cls, device): + return True # All devices with connection_type == 'display' are supported + + @classmethod + def get_default_display(cls): + displays = list(filter(lambda d: iot_devices[d].device_type == 'display', iot_devices)) + return len(displays) and iot_devices[displays[0]] + + def action(self, data): + if data.get('action') == "update_url": + self.update_url(data.get('url')) + elif data.get('action') == "display_refresh": + self.call_xdotools('F5') + elif data.get('action') == "take_control": + self.take_control(self.data['owner'], data.get('html')) + elif data.get('action') == "customer_facing_display": + self.update_customer_facing_display(self.data['owner'], data.get('html')) + elif data.get('action') == "get_owner": + self.data = { + 'value': '', + 'owner': self.owner, + } + event_manager.device_changed(self) + + def run(self): + while True: + if self.url != 'http://localhost:8069/point_of_sale/display/': + # Refresh the page every minute + time.sleep(60) + self.call_xdotools('F5') + + def update_url(self, url=None): + firefox_env = os.environ.copy() + firefox_env['HOME'] = '/tmp' + firefox_env['DISPLAY'] = ':0.0' + firefox_env['XAUTHORITY'] = '/run/lightdm/pi/xauthority' + self.url = url or 'http://localhost:8069/point_of_sale/display/' + if self.device_identifier != 'distant_display': + subprocess.Popen(['firefox', self.url], env=firefox_env) + + def load_url(self): + if helpers.get_odoo_server_url(): + # disable certifiacte verification + urllib3.disable_warnings() + http = urllib3.PoolManager(cert_reqs='CERT_NONE') + try: + response = http.request('GET', "%s/iot/box/%s/screen_url" % (helpers.get_odoo_server_url(), helpers.get_mac_address())) + urls = json.loads(response.data.decode('utf8')) + return self.update_url(urls[self.device_identifier]) + except json.decoder.JSONDecodeError: + return self.update_url(response.data.decode('utf8')) + except Exception: + pass + return self.update_url() + + def call_xdotools(self, keystroke): + os.environ['DISPLAY'] = ":0.0" + os.environ['XAUTHORITY'] = "/run/lightdm/pi/xauthority" + try: + subprocess.call(['xdotool', 'key', keystroke]) + return "xdotool succeeded in stroking " + keystroke + except: + return "xdotool threw an error, maybe it is not installed on the IoTBox" + + def update_customer_facing_display(self, origin, html=None): + if origin == self.owner: + self.rendered_html = html + self.event_data.set() + + def get_serialized_order(self): + # IMPLEMENTATION OF LONGPOLLING + # Times out 2 seconds before the JS request does + if self.event_data.wait(28): + self.event_data.clear() + return {'rendered_html': self.rendered_html} + return {'rendered_html': False} + + def take_control(self, new_owner, html=None): + # ALLOW A CASHIER TO TAKE CONTROL OVER THE POSBOX, IN CASE OF MULTIPLE CASHIER PER DISPLAY + self.owner = new_owner + self.rendered_html = html + self.data = { + 'value': '', + 'owner': self.owner, + } + event_manager.device_changed(self) + self.event_data.set() + +class DisplayController(http.Controller): + + @http.route('/hw_proxy/display_refresh', type='json', auth='none', cors='*') + def display_refresh(self): + display = DisplayDriver.get_default_display() + if display: + return display.call_xdotools('F5') + + @http.route('/hw_proxy/customer_facing_display', type='json', auth='none', cors='*') + def customer_facing_display(self, html=None): + display = DisplayDriver.get_default_display() + if display: + display.update_customer_facing_display(http.request.httprequest.remote_addr, html) + return {'status': 'updated'} + return {'status': 'failed'} + + @http.route('/hw_proxy/take_control', type='json', auth='none', cors='*') + def take_control(self, html=None): + display = DisplayDriver.get_default_display() + if display: + display.take_control(http.request.httprequest.remote_addr, html) + return { + 'status': 'success', + 'message': 'You now have access to the display', + } + + @http.route('/hw_proxy/test_ownership', type='json', auth='none', cors='*') + def test_ownership(self): + display = DisplayDriver.get_default_display() + if display and display.owner == http.request.httprequest.remote_addr: + return {'status': 'OWNER'} + return {'status': 'NOWNER'} + + @http.route(['/point_of_sale/get_serialized_order'], type='json', auth='none') + def get_serialized_order(self): + display = DisplayDriver.get_default_display() + if display: + return display.get_serialized_order() + return { + 'rendered_html': False, + 'error': "No display found", + } + + @http.route(['/point_of_sale/display'], type='http', auth='none') + def display(self): + cust_js = None + interfaces = ni.interfaces() + + with open(os.path.join(os.path.dirname(__file__), "../static/src/js/worker.js")) as js: + cust_js = js.read() + + display_ifaces = [] + for iface_id in interfaces: + if 'wlan' in iface_id or 'eth' in iface_id: + iface_obj = ni.ifaddresses(iface_id) + ifconfigs = iface_obj.get(ni.AF_INET, []) + for conf in ifconfigs: + if conf.get('addr'): + display_ifaces.append({ + 'iface_id': iface_id, + 'addr': conf.get('addr'), + 'icon': 'sitemap' if 'eth' in iface_id else 'wifi', + }) + + return pos_display_template.render({ + 'title': "Odoo -- Point of Sale", + 'breadcrumb': 'POS Client display', + 'cust_js': cust_js, + 'display_ifaces': display_ifaces, + }) diff --git a/addons/hw_screen/static/src/js/worker.js b/addons/hw_drivers/static/src/js/worker.js index 5949ab39cef..a485a946588 100644 --- a/addons/hw_screen/static/src/js/worker.js +++ b/addons/hw_drivers/static/src/js/worker.js @@ -4,7 +4,6 @@ // It allows to transform the <head> only once var mergedHead = false; var current_client_url = ""; - var stop_longpolling = false; function longpolling() { $.ajax({ @@ -15,14 +14,13 @@ data: JSON.stringify({jsonrpc: '2.0'}), success: function(data) { - if (typeof data.result.stop_longpolling !== 'undefined') { - stop_longpolling = data.result.stop_longpolling; - } if (data.result.error) { $('.error-message').text(data.result.error); $('.error-message').removeClass('d-none'); + setTimeout(longpolling, 5000); + return; } - if (data.result.ip_from && data.result.rendered_html) { + if (data.result.rendered_html) { var trimmed = $.trim(data.result.rendered_html); var $parsedHTML = $('<div>').html($.parseHTML(trimmed,true)); // WARNING: the true here will executes any script present in the string to parse var new_client_url = $parsedHTML.find(".resources > base").attr('href'); @@ -47,15 +45,11 @@ foreign_js(); } } - if (!stop_longpolling) { - longpolling(); - } + longpolling(); }, error: function (jqXHR, status, err) { - if (!stop_longpolling) { - setTimeout(longpolling, 5000); - } + setTimeout(longpolling, 5000); }, timeout: 30000, diff --git a/addons/hw_screen/views/pos_display.html b/addons/hw_drivers/views/pos_display.html index b7cb5fd52bb..b7cb5fd52bb 100644 --- a/addons/hw_screen/views/pos_display.html +++ b/addons/hw_drivers/views/pos_display.html diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py index 54712e32083..b1353e98cf1 100644 --- a/addons/hw_posbox_homepage/controllers/main.py +++ b/addons/hw_posbox_homepage/controllers/main.py @@ -49,16 +49,6 @@ list_credential_template = jinja_env.get_template('list_credential.html') class IoTboxHomepage(web.Home): - def get_hw_screen_message(self): - return """ - <p> - The activate the customer display feature, you will need to reinstall the IoT Box software. - You can find the latest images on the <a href="http://nightly.odoo.com/master/posbox/">Odoo Nightly builds</a> website. - Make sure to download at least the version 16.<br/> - Odoo version 11, or above, is required to use the customer display feature. - </p> - """ - def get_pos_device_status(self): statuses = {} for driver in hw_proxy.drivers: diff --git a/addons/hw_screen/__init__.py b/addons/hw_screen/__init__.py deleted file mode 100644 index dd15b5c32e5..00000000000 --- a/addons/hw_screen/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import controllers diff --git a/addons/hw_screen/__manifest__.py b/addons/hw_screen/__manifest__.py deleted file mode 100644 index 756d385a550..00000000000 --- a/addons/hw_screen/__manifest__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. -{ - 'name': 'Screen Driver', - 'version': '1.0', - 'category': 'Hardware Drivers', - 'sequence': 6, - 'summary': 'Add a customer facing displays for POS', - 'website': 'https://www.odoo.com/page/point-of-sale-hardware', - 'description': """ -Screen Driver -============= - -This module allows the POS client to send rendered HTML to a remotely -installed screen. This module then displays this HTML using a web -browser. -""", - 'depends': ['hw_proxy'], - 'installable': False, - 'auto_install': False, -} diff --git a/addons/hw_screen/controllers/__init__.py b/addons/hw_screen/controllers/__init__.py deleted file mode 100644 index 5d4b25db9c0..00000000000 --- a/addons/hw_screen/controllers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from . import main diff --git a/addons/hw_screen/controllers/main.py b/addons/hw_screen/controllers/main.py deleted file mode 100644 index 1ee346ae3f7..00000000000 --- a/addons/hw_screen/controllers/main.py +++ /dev/null @@ -1,154 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import http -from odoo.tools import config -from odoo.addons.web.controllers import main as web -from openerp.addons.hw_posbox_homepage.controllers import main as homepage - -import jinja2 -import json -import logging -import netifaces as ni -import os -from subprocess import call -import sys -import time -import threading - -self_port = str(config['http_port'] or 8069) - -_logger = logging.getLogger(__name__) - -if hasattr(sys, 'frozen'): - # When running on compiled windows binary, we don't have access to package loader. - path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'views')) - loader = jinja2.FileSystemLoader(path) -else: - loader = jinja2.PackageLoader('odoo.addons.hw_screen', "views") - -jinja_env = jinja2.Environment(loader=loader, autoescape=True) -jinja_env.filters["json"] = json.dumps - -pos_display_template = jinja_env.get_template('pos_display.html') - - -class Homepage(homepage.IoTboxHomepage): - - def get_hw_screen_message(self): - return """ -<p> -If you need to display the current customer basket on another device, you can do it <a href='/point_of_sale/display'>here</a>. -</p> -""" - -class HardwareScreen(web.Home): - - event_data = threading.Event() - pos_client_data = {'rendered_html': False, - 'ip_from': False} - display_in_use = '' - failure_count = {} - - def _call_xdotools(self, keystroke): - os.environ['DISPLAY'] = ":0.0" - os.environ['XAUTHORITY'] = "/run/lightdm/pi/xauthority" - try: - call(['xdotool', 'key', keystroke]) - return "xdotool succeeded in stroking " + keystroke - except: - return "xdotool threw an error, maybe it is not installed on the IoTBox" - - @http.route('/hw_proxy/display_refresh', type='json', auth='none', cors='*') - def display_refresh(self): - return self._call_xdotools('F5') - - # POS CASHIER'S ROUTES - @http.route('/hw_proxy/customer_facing_display', type='json', auth='none', cors='*') - def update_user_facing_display(self, html=None): - request_ip = http.request.httprequest.remote_addr - if request_ip == HardwareScreen.pos_client_data.get('ip_from', ''): - HardwareScreen.pos_client_data['rendered_html'] = html - HardwareScreen.event_data.set() - - return {'status': 'updated'} - else: - return {'status': 'failed'} - - @http.route('/hw_proxy/take_control', type='json', auth='none', cors='*') - def take_control(self, html=None): - # ALLOW A CASHIER TO TAKE CONTROL OVER THE POSBOX, IN CASE OF MULTIPLE CASHIER PER POSBOX - HardwareScreen.pos_client_data['rendered_html'] = html - HardwareScreen.pos_client_data['ip_from'] = http.request.httprequest.remote_addr - HardwareScreen.event_data.set() - - return {'status': 'success', - 'message': 'You now have access to the display'} - - @http.route('/hw_proxy/test_ownership', type='json', auth='none', cors='*') - def test_ownership(self): - if HardwareScreen.pos_client_data.get('ip_from') == http.request.httprequest.remote_addr: - return {'status': 'OWNER'} - else: - return {'status': 'NOWNER'} - - # POSBOX ROUTES (SELF) - @http.route('/point_of_sale/display', type='http', auth='none') - def render_main_display(self): - return self._get_html() - - @http.route('/point_of_sale/get_serialized_order', type='json', auth='none') - def get_serialized_order(self): - request_addr = http.request.httprequest.remote_addr - result = HardwareScreen.pos_client_data - if HardwareScreen.display_in_use and request_addr != HardwareScreen.display_in_use: - if not HardwareScreen.failure_count.get(request_addr): - HardwareScreen.failure_count[request_addr] = 0 - if HardwareScreen.failure_count[request_addr] > 0: - time.sleep(10) - HardwareScreen.failure_count[request_addr] += 1 - return { - 'rendered_html': False, - 'error': "Not Authorized. Another browser is in use to display for the client. Please refresh.", - 'stop_longpolling': True, - 'ip_from': request_addr, - } - - # IMPLEMENTATION OF LONGPOLLING - # Times out 2 seconds before the JS request does - if HardwareScreen.event_data.wait(28): - HardwareScreen.event_data.clear() - HardwareScreen.failure_count[request_addr] = 0 - return result - return { - 'rendered_html': False, - 'ip_from': HardwareScreen.pos_client_data['ip_from'], - } - - def _get_html(self): - cust_js = None - interfaces = ni.interfaces() - HardwareScreen.display_in_use = http.request.httprequest.remote_addr - - with open(os.path.join(os.path.dirname(__file__), "../static/src/js/worker.js")) as js: - cust_js = js.read() - - display_ifaces = [] - for iface_id in interfaces: - if 'wlan' in iface_id or 'eth' in iface_id: - iface_obj = ni.ifaddresses(iface_id) - ifconfigs = iface_obj.get(ni.AF_INET, []) - for conf in ifconfigs: - if conf.get('addr'): - display_ifaces.append({ - 'iface_id': iface_id, - 'addr': conf.get('addr'), - 'icon': 'sitemap' if 'eth' in iface_id else 'wifi', - }) - - return pos_display_template.render({ - 'title': "Odoo -- Point of Sale", - 'breadcrumb': 'POS Client display', - 'cust_js': cust_js, - 'display_ifaces': display_ifaces, - }) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 1bfe646ebee..de64e9cb139 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -652,6 +652,7 @@ exports.PosModel = Backbone.Model.extend({ var order = new exports.Order({},{pos:this}); this.get('orders').add(order); this.set('selectedOrder', order); + this.send_current_order_to_customer_facing_display(); return order; }, /** @@ -2252,9 +2253,6 @@ exports.Order = Backbone.Model.extend({ this.paymentlines.on('remove', function(){ this.save_to_db("paymentline:rem"); }, this); if (this.pos.config.iface_customer_facing_display) { - this.orderlines.on('change', this.pos.send_current_order_to_customer_facing_display, this.pos); - // removing last orderline does not trigger change event - this.orderlines.on('remove', this.pos.send_current_order_to_customer_facing_display, this.pos); this.paymentlines.on('change', this.pos.send_current_order_to_customer_facing_display, this.pos); // removing last paymentline does not trigger change event this.paymentlines.on('remove', this.pos.send_current_order_to_customer_facing_display, this.pos); @@ -2655,6 +2653,8 @@ exports.Order = Backbone.Model.extend({ if(line.has_product_lot){ this.display_lot_popup(); } + + this.pos.send_current_order_to_customer_facing_display(); }, get_selected_orderline: function(){ return this.selected_orderline; diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index c988db5cfdb..80ddbde9191 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -551,6 +551,7 @@ var OrderWidget = PosBaseWidget.extend({ selected_orderline.price_manually_set = true; selected_orderline.set_unit_price(val); } + this.pos.send_current_order_to_customer_facing_display(); } }, change_selected_order: function() { diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart deleted file mode 100755 index d7b5349a74f..00000000000 --- a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -xset s off -xset -dpms - -export HOME=/tmp - -DISPLAY_URL='http://localhost:8069/point_of_sale/display' -URL=${DISPLAY_URL} - -maciotbox=$(/sbin/ifconfig eth0 |grep -Eo ..\(\:..\){5}) - -if [ -e /home/pi/odoo-remote-server.conf ] - then - URL_SERVER=$(grep "" /home/pi/odoo-remote-server.conf)/iot/box/${maciotbox}/screen_url - var=0 - while [ ${var} -lt 30 ]; do - var=$((var+1)) - sleep 1 - status_code=$(wget ${URL_SERVER} --server-response 2>&1|grep 'HTTP/'|awk '{print $2}') - if [ ${status_code} -eq 200 ] - then - URL=$(wget ${URL_SERVER} -q -O -) - break - fi - done -fi -# wait until odoo is ready, otherwise you will have to plug a -# keyboard into the posbox just to refresh firefox -until wget -q "${DISPLAY_URL}" -O /dev/null ; do sleep 1 ; done -/usr/bin/firefox "${URL}" &
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js index 3a1fcac9cbd..a519ae55745 100644 --- a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js @@ -4,4 +4,7 @@ pref("app.update.checkInstallTime", false); pref("devtools.webide.widget.autoinstall", false); pref("xpinstall.customConfirmationUI", false); pref("xpinstall.signatures.required", false); -pref("browser.shell.checkDefaultBrowser",false) +pref("browser.shell.checkDefaultBrowser", false); +// Open all links in the same tab +// Needed to change URL without having multiple tabs running +pref("browser.link.open_newwindow", 1); diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo index f633be2b7c7..73f9b777c88 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo @@ -26,7 +26,7 @@ test -x $DAEMON || exit 0 set -e function _start() { - start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_escpos,hw_blackbox_be,hw_screen,hw_drivers + start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_escpos,hw_blackbox_be,hw_drivers } function _stop() { |
