diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-03-24 15:23:16 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-03-24 15:23:16 +0100 |
| commit | 8caac6bc440159ecac051b999875cf673a61d818 (patch) | |
| tree | ab06367556a8be9f8b277c8758e6bc350a30b896 | |
| parent | 31474efec2f09bd65cbda901bda80264213247ce (diff) | |
| parent | 5847de4aaf94eb5d69a4cf9aba9ceb74a7b9ab43 (diff) | |
[MERGE] forward port branch 8.0 up to 5847de4aaf9
32 files changed, 824 insertions, 63 deletions
diff --git a/addons/hw_escpos/controllers/main.py b/addons/hw_escpos/controllers/main.py index 23672e12385..cefa8919580 100644 --- a/addons/hw_escpos/controllers/main.py +++ b/addons/hw_escpos/controllers/main.py @@ -86,10 +86,15 @@ class EscposDriver(Thread): printers = usb.core.find(find_all=True, idVendor=0x0519) for printer in printers: + try: + description = usb.util.get_string(printer, 256, printer.iManufacturer) + " " + usb.util.get_string(printer, 256, printer.iProduct) + except Exception as e: + _logger.error("Can not get printer description: %s" % (e.message or repr(e))) + description = 'Unknown printer' connected.append({ 'vendor': printer.idVendor, 'product': printer.idProduct, - 'name': usb.util.get_string(printer, 256, printer.iManufacturer) + " " + usb.util.get_string(printer, 256, printer.iProduct) + 'name': description }) return connected diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py index 65b276075d2..8a448e386f5 100644 --- a/addons/hw_posbox_homepage/controllers/main.py +++ b/addons/hw_posbox_homepage/controllers/main.py @@ -58,7 +58,10 @@ index_template = """ If you need to grant remote debugging access to a developer, you can do it <a href='/remote_connect'>here</a>. </p> <p> - The PosBox software installed on this posbox is <b>version 15</b>, + 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> + <p> + The PosBox software installed on this posbox is <b>version 16</b>, the posbox version number is independent from Odoo. You can upgrade the software on the <a href='/hw_proxy/upgrade/'>upgrade page</a>. </p> diff --git a/addons/hw_screen/__init__.py b/addons/hw_screen/__init__.py new file mode 100644 index 00000000000..502f47ce57c --- /dev/null +++ b/addons/hw_screen/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2015 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +import controllers diff --git a/addons/hw_screen/__openerp__.py b/addons/hw_screen/__openerp__.py new file mode 100644 index 00000000000..1e6438bf25c --- /dev/null +++ b/addons/hw_screen/__openerp__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2015 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + + +{ + 'name': 'Screen Driver', + 'version': '1.0', + 'category': 'Hardware Drivers', + 'sequence': 6, + 'summary': 'Provides support for customer facing displays', + 'website': 'https://www.odoo.com/page/point-of-sale', + '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. +""", + 'author': 'OpenERP SA', + 'depends': ['hw_proxy'], + 'installable': False, + 'auto_install': False, +} diff --git a/addons/hw_screen/controllers/__init__.py b/addons/hw_screen/controllers/__init__.py new file mode 100644 index 00000000000..517985a53ef --- /dev/null +++ b/addons/hw_screen/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2015 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +import main diff --git a/addons/hw_screen/controllers/main.py b/addons/hw_screen/controllers/main.py new file mode 100644 index 00000000000..aa4b8a1a729 --- /dev/null +++ b/addons/hw_screen/controllers/main.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2015 Tiny SPRL (<http://tiny.be>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + + +from openerp import http +from openerp.tools import config +from openerp.addons.web.controllers import main as web + +import logging +import netifaces as ni +import os +from subprocess import call +import time +import threading + +self_port = str(config['xmlrpc_port'] or 8069) + +_logger = logging.getLogger(__name__) + + +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 posbox" + + @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': """<div class="pos-customer_facing_display"><p>Not Authorized. Another browser is in use to display for the client. Please refresh.</p></div> """, + '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() + my_ip = '127.0.0.1' + 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() + + with open(os.path.join(os.path.dirname(__file__), "../static/src/css/cust_css.css")) as css: + cust_css = css.read() + + display_ifaces = "" + for iface_id in interfaces: + iface_obj = ni.ifaddresses(iface_id) + ifconfigs = iface_obj.get(ni.AF_INET, []) + for conf in ifconfigs: + if conf.get('addr'): + display_ifaces += "<tr><td>" + iface_id + "</td>" + display_ifaces += "<td>" + conf.get('addr') + "</td>" + display_ifaces += "<td>" + conf.get('netmask') + "</td></tr>" + # What is my external IP ? + if iface_id != 'lo': + my_ip = conf.get('addr') + + my_ip_port = my_ip + ":" + self_port + + html = """ + <!DOCTYPE html> + <html> + <head> + <title class="origin">Odoo -- Point of Sale</title> + <script type="text/javascript" class="origin" src="http://""" + my_ip_port + """/web/static/lib/jquery/jquery.js" > + </script> + <script type="text/javascript" class="origin"> + """ + cust_js + """ + </script> + <link rel="stylesheet" class="origin" href="http://""" + my_ip_port + """/web/static/lib/bootstrap/css/bootstrap.css" > + </link> + <script class="origin" src="http://""" + my_ip_port + """/web/static/lib/bootstrap/js/bootstrap.min.js"></script> + <style class="origin"> + """ + cust_css + """ + </style> + </head> + <body class="original_body"> + <div hidden class="shadow"></div> + <div class="container"> + <div class="row"> + <div class="col-md-4 col-md-offset-4"> + <h1>Odoo Point of Sale</h1> + <h2>POSBox Client display</h2> + <h3>My IPs</h3> + <table id="table_ip" class="table table-condensed"> + <tr> + <th>Interface</th> + <th>IP</th> + <th>Netmask</th> + </tr> + """ + display_ifaces + """ + </table> + <p>The customer cart will be displayed here once a Point of Sale session is started.</p> + <p>Odoo version 11 or above is required.</p> + </div> + </div> + </div> + </body> + </html> + """ + return html diff --git a/addons/hw_screen/static/src/css/cust_css.css b/addons/hw_screen/static/src/css/cust_css.css new file mode 100644 index 00000000000..69fddb25457 --- /dev/null +++ b/addons/hw_screen/static/src/css/cust_css.css @@ -0,0 +1,21 @@ +html { + width: 100%; + height: 100%; + font-size: 11px; +} + +body { + width: 100%; + height: 100%; + font-size: 14px; + margin: 0; +} + +.original_body { + background-color: #797083; + color: white; +} + +.ajax_got_body { + color: black; +}
\ No newline at end of file diff --git a/addons/hw_screen/static/src/js/worker.js b/addons/hw_screen/static/src/js/worker.js new file mode 100644 index 00000000000..55e389e78ab --- /dev/null +++ b/addons/hw_screen/static/src/js/worker.js @@ -0,0 +1,60 @@ + $(function() { + "use strict"; + // mergedHead will be turned to true the first time we receive something from a new host + // It allows to transform the <head> only once + var mergedHead = false; + var current_client_url = ""; + var stop_longpolling = false; + + function longpolling() { + $.ajax({ + type: 'POST', + url: 'http://'+window.location.host+'/point_of_sale/get_serialized_order', + dataType: 'json', + beforeSend: function(xhr){xhr.setRequestHeader('Content-Type', 'application/json');}, + 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.ip_from && 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'); + + if (!mergedHead || (current_client_url !== new_client_url)) { + + mergedHead = true; + current_client_url = new_client_url; + $("body").removeClass('original_body').addClass('ajax_got_body'); + $("head").children().not('.origin').remove(); + $("head").append($parsedHTML.find(".resources").html()); + } + + $(".container").html($parsedHTML.find('.pos-customer_facing_display').html()); + $(".container").attr('class', 'container').addClass($parsedHTML.find('.pos-customer_facing_display').attr('class')); + + var d = $('.pos_orderlines_list'); + d.scrollTop(d.prop("scrollHeight")); + + // Here we execute the code coming from the pos, apparently $.parseHTML() executes scripts right away, + // Since we modify the dom afterwards, the script might not have any effect + if (typeof foreign_js !== 'undefined' && $.isFunction(foreign_js)) { + foreign_js(); + } + } + }, + + complete: function(jqXHR,err) { + if (!stop_longpolling) { + longpolling(); + } + }, + + timeout: 30000, + }); + }; + + longpolling(); + });
\ No newline at end of file diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index 5d36262f5b9..c3985a3d258 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -9,51 +9,49 @@ var _t = instance.web._t; instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags.extend({ start: function() { - this.values = []; - this.values_checking = []; + this.mutex = new openerp.Mutex(); - this.on("change:value", this, this.on_change_value_check); - this.trigger("change:value"); + // This widget will indirectly trigger a change:value to it's parent widget + // when setting the value of valid partners. For this reason we have to keep an + // internal state of the last value in order to compute the effective value changes. + this.last_processed_value = []; + this.on("change:value", this, this.on_change_value_check); this._super.apply(this, arguments); }, on_change_value_check : function () { - this.values = _.uniq(this.values); - - // filter for removed values - var values_removed = _.difference(this.values, this.get('value')); - if (values_removed.length) { - this.values = _.difference(this.values, values_removed); - this.set({'value': this.values}); - return false; - } + var self = this; + var values = this.get('value').slice(0); // Clone the array - // find not checked values that are not currently on checking - var not_checked = _.difference(this.get('value'), this.values, this.values_checking); - if (not_checked.length) { - // remember values on checking for cheked only one time - this.values_checking = this.values_checking.concat(not_checked); - // check values - this._check_email_popup(not_checked); + // We only validate partners emails in case the value is not empty + // and is different from the last processed value + var effective_change = _.difference(values, self.last_processed_value).length; + if (values.length && effective_change) { + this.mutex.exec(function() { + return self._check_email_popup(values); + }); } }, _check_email_popup: function (ids) { var self = this; + var valid_partners; + new instance.web.Model('res.partner').call("search", [[ - ["id", "in", ids], - ["email", "=", false], - ["notify_email", "=", 'always'] ]], + ["id", "in", ids], + ["email", "=", false], + ["notify_email", "=", 'always'] ]], {context: this.build_context()}) .then(function (record_ids) { - // valid partner - var valid_partner = _.difference(ids, record_ids); - self.values = self.values.concat(valid_partner); - self.values_checking = _.difference(self.values_checking, valid_partner); + var popups_deferreds = []; + self.valid_partners = _.difference(ids, record_ids); - // unvalid partner + // Propose the user to correct invalid partners _.each(record_ids, function (id) { + var popup_def = $.Deferred(); + popups_deferreds.push(popup_def); + var pop = new instance.web.form.FormOpenPopup(self); pop.show_element( 'res.partner', @@ -64,15 +62,19 @@ instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags } ); pop.on('write_completed', self, function () { - this.values.push(id); - this.values_checking = _.without(this.values_checking, id); - this.set({'value': this.values}); + self.valid_partners.push(id); }); pop.on('closed', self, function () { - this.values_checking = _.without(this.values_checking, id); - this.set({'value': this.values}); + popup_def.resolve(); }); }); + return $.when.apply($, popups_deferreds).then(function() { + // All popups have been processed for the given ids + // It is now time to set the final value with valid partners ids. + var filtered_value = _.uniq(self.valid_partners); + self.last_processed_value = filtered_value; + self.set({'value': filtered_value}); + }); }); }, }); diff --git a/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh b/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh index ce2f2e633e6..618c4b1fd48 100755 --- a/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh +++ b/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh @@ -11,7 +11,7 @@ create_ramdisk () { echo "Creating ramdisk for ${1} of size ${SIZE}..." mount -t tmpfs -o size="${SIZE}" tmpfs "${RAMDISK}" - rsync -a --exclude="swap" --exclude="apt" --exclude="dpkg" "${ORIGINAL}/" "${RAMDISK}/" + rsync -a --exclude="swap" --exclude="apt" --exclude="dpkg" --exclude=".mozilla" "${ORIGINAL}/" "${RAMDISK}/" mount --bind "${RAMDISK}" "${ORIGINAL}" } diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/lightdm/lightdm.conf b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/lightdm/lightdm.conf new file mode 100644 index 00000000000..977903c1c90 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/lightdm/lightdm.conf @@ -0,0 +1,8 @@ + +[LightDM] +user-authority-in-system-dir=true + +[SeatDefaults] +xserver-command=/usr/bin/X -s 0 dpms -nolisten tcp +greeter-hide-users=false +autologin-user=pi
\ No newline at end of file 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 new file mode 100755 index 00000000000..e2b61e2f591 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart @@ -0,0 +1,6 @@ +#!/bin/bash +xset s off +xset -dpms + +export HOME=/tmp +/usr/bin/firefox http://localhost:8069/point_of_sale/display & diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/manifest.mf b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/manifest.mf new file mode 100644 index 00000000000..63a9098e00d --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/manifest.mf @@ -0,0 +1,32 @@ +Manifest-Version: 1.0 + +Name: install.rdf +Digest-Algorithms: MD5 SHA1 +MD5-Digest: xnFKNbJgc33dy/FJ+4cmHA== +SHA1-Digest: 4YLgHgdgCw4lGCfsX7+r4zVmKJ4= + +Name: chrome.manifest +Digest-Algorithms: MD5 SHA1 +MD5-Digest: O5ce4bajAqUxG6iVul0K2w== +SHA1-Digest: wb6VleWnV5GgLypmg1ij9TfmPLE= + +Name: content/rkioskbrowser.js +Digest-Algorithms: MD5 SHA1 +MD5-Digest: /cF15tfVnbkfbxRVTL5N+g== +SHA1-Digest: lvbY92PbsjwY+0TguEYoXWw0lxQ= + +Name: content/rkioskbrowser.xul +Digest-Algorithms: MD5 SHA1 +MD5-Digest: NFOIpAmZtn20Y+XfTo4cpw== +SHA1-Digest: VVIo7GdG+4mvAOtgR0DJUsSc/yg= + +Name: content/rkioskunknownContentType.xul +Digest-Algorithms: MD5 SHA1 +MD5-Digest: 6cNGoHJS9Xvm+wmvo4IesQ== +SHA1-Digest: T8i1MkMKjmn5HICqWv+iXSPRKIU= + +Name: content/rkioskxpinstallConfirm.xul +Digest-Algorithms: MD5 SHA1 +MD5-Digest: SxN1YnRJiuood2WhU85v9g== +SHA1-Digest: Msj21u4bTAKUi496xld5YCGdjiA= + diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.rsa b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.rsa Binary files differnew file mode 100644 index 00000000000..521b08d182a --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.rsa diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.sf b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.sf new file mode 100644 index 00000000000..37eae3e21fb --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.sf @@ -0,0 +1,4 @@ +Signature-Version: 1.0 +MD5-Digest-Manifest: 7hFyhNW67+H+rf9OhWGDkA== +SHA1-Digest-Manifest: HvfAQQLXphSZ9m8KBorJMX8MUnE= + diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/README b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/README new file mode 100644 index 00000000000..c8c1ce58823 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/README @@ -0,0 +1,3 @@ +The R-kiosk module has been downloaded from https://addons.mozilla.org/en-US/firefox/addon/r-kiosk/ +It is in the public domain as stated on https://addons.mozilla.org/en-US/firefox/addon/r-kiosk/eula/ +This mozilla module is shipped by Odoo to provide out of the box Client facing display to Odoo's Posbox
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/chrome.manifest b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/chrome.manifest new file mode 100644 index 00000000000..e4957b8d5e8 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/chrome.manifest @@ -0,0 +1,4 @@ +content RKiosk content/
+overlay chrome://browser/content/browser.xul chrome://rkiosk/content/rkioskbrowser.xul
+overlay chrome://mozapps/content/xpinstall/xpinstallConfirm.xul chrome://rkiosk/content/rkioskxpinstallConfirm.xul
+overlay chrome://mozapps/content/downloads/unknownContentType.xul chrome://rkiosk/content/rkioskunknownContentType.xul
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.js b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.js new file mode 100644 index 00000000000..5ece9a9e06b --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.js @@ -0,0 +1,34 @@ +function Rkiosk_donothing()
+{
+
+
+}
+
+function rkioskclose()
+{
+ close();
+}
+
+function Rkiosk_navbar_setting()
+{
+ var rkiosk_navbar_enable="true";
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch);
+ if (prefs.getPrefType("rkiosk.navbar") == prefs.PREF_BOOL){
+ if (prefs.getBoolPref("rkiosk.navbar")) rkiosk_navbar_enable = "false";
+ }
+ var rkiosk_element = document.getElementById("navigator-toolbox");
+ rkiosk_element.setAttribute("hidden", rkiosk_navbar_enable);
+}
+
+function RkioskBrowserStartup()
+{
+ Rkiosk_navbar_setting();
+ BrowserStartup();
+ setTimeout(RkioskdelayedStartup, 1000);
+}
+
+function RkioskdelayedStartup()
+{
+ window.fullScreen = true;
+}
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.xul b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.xul new file mode 100644 index 00000000000..d5fb0c140d1 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.xul @@ -0,0 +1,175 @@ +<?xml version="1.0"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<window id="main-window"
+ onload="RkioskBrowserStartup()">
+</window>
+
+<script type="application/x-javascript" src="rkioskbrowser.js"/>
+
+ <menubar id="main-menubar" hidden="true" fullscreentoolbar="false" disabled="true">
+ <menuitem id="menu_preferences" disabled="true"/>
+ </menubar>
+
+ <popup id="contentAreaContextMenu"
+ onpopupshowing="if (event.target != this) return true; return false;"
+ onpopuphiding="if (event.target == this) gContextMenu = null;">
+ </popup>
+
+ <commandset id="mainCommandSet">
+ <command id="cmd_newNavigator" disabled="true"/>
+ <command id="cmd_handleBackspace" disabled="true"/>
+ <command id="cmd_handleShiftBackspace" disabled="true"/>
+ <command id="cmd_newNavigatorTab" disabled="true"/>
+ <command id="Browser:OpenFile" disabled="true"/>
+ <command id="Browser:SavePage" disabled="true"/>
+ <command id="Browser:SaveFrame" disabled="true"/>
+ <command id="Browser:SendLink" disabled="true"/>
+ <command id="cmd_pageSetup" disabled="true"/>
+ <command id="cmd_print" oncommand="PrintUtils.print();"/>
+ <command id="cmd_printPreview" disabled="true"/>
+ <command id="cmd_close" disabled="true"/>
+ <command id="cmd_closeWindow" disabled="true"/>
+ <command id="cmd_ToggleTabsOnTop" disabled="true"/>
+ <command id="cmd_quitApplication" disabled="true"/>
+ <command id="cmd_toggleTaskbar" disabled="true"/>
+ <command id="cmd_CustomizeToolbars" disabled="true"/>
+ <commandset id="editMenuCommands"/>
+ <command id="View:PageSource" disabled="true"/>
+ <command id="View:PageInfo" disabled="true"/>
+ <command id="View:FullScreen" disabled="true"/>
+ <command id="cmd_find" disabled="true"/>
+ <command id="cmd_findAgain" disabled="true"/>
+ <command id="cmd_findPrevious" disabled="true"/>
+ <command id="Browser:AddBookmarkAs" disabled="true"/>
+ <command id="Browser:BookmarkAllTabs" disabled="true"/>
+ <command id="Browser:Home" oncommand="BrowserHome();"/>
+ <command id="Browser:Back" disabled="true"/>
+ <command id="Browser:Forward" disabled="true"/>
+ <command id="Browser:Stop" disabled="true"/>
+ <command id="Browser:Reload" disabled="true"/>
+ <command id="Browser:ReloadSkipCache" disabled="true"/>
+ <command id="Browser:BackOrBackDuplicate" disabled="true"/>
+ <command id="Browser:Forward" disabled="true"/>
+ <command id="Browser:ForwardOrForwardDuplicate" disabled="true"/>
+ <command id="Browser:ReloadOrDuplicate" disabled="true"/>
+ <command id="Browser:NextTab" disabled="true"/>
+ <command id="Browser:PrevTab" disabled="true"/>
+ <command id="Browser:ShowAllTabs" disabled="true"/>
+ <command id="Browser:ToggleTabView" disabled="true"/>
+ <command id="Browser:ToggleAddonBar" disabled="true"/>
+ <command id="cmd_fullZoomReduce" disabled="true"/>
+ <command id="cmd_fullZoomEnlarge" disabled="true"/>
+ <command id="cmd_fullZoomReset" disabled="true"/>
+ <command id="cmd_fullZoomToggle" disabled="true"/>
+ <command id="Browser:OpenLocation" disabled="true"/>
+ <command id="Tools:Search" disabled="true"/>
+ <command id="Tools:Downloads" disabled="true"/>
+ <command id="Tools:Addons" disabled="true"/>
+ <command id="Tools:Sanitize" disabled="true"/>
+ <command id="Tools:Inspect" disabled="true"/>
+ <command id="Tools:PrivateBrowsing" disabled="true"/>
+ <command id="History:UndoCloseTab" disabled="true"/>
+ <command id="History:UndoCloseWindow" disabled="true"/>
+ <command id="cmd_bm_open" disabled="true"/>
+ <command id="cmd_bm_openinnewwindow" disabled="true"/>
+ <command id="cmd_bm_openinnewtab" disabled="true"/>
+ <command id="cmd_bm_openfolder" disabled="true"/>
+ <command id="cmd_bm_managefolder" disabled="true"/>
+ <command id="cmd_bm_newfolder" disabled="true"/>
+ <command id="cmd_bm_newbookmark" disabled="true"/>
+ <command id="cmd_bm_newseparator" disabled="true"/>
+ <command id="cmd_bm_properties" disabled="true"/>
+ <command id="cmd_bm_refreshlivemark" disabled="true"/>
+ <command id="cmd_bm_refreshmicrosummary" disabled="true"/>
+ <command id="cmd_bm_rename" disabled="true"/>
+ <command id="cmd_bm_moveBookmark" disabled="true"/>
+ <command id="cmd_bm_sortbyname" disabled="true"/>
+ <command id="cmd_copyLink" disabled="true"/>
+ <command id="cmd_copyImageLocation" disabled="true"/>
+ <command id="cmd_copyImageContents" disabled="true"/>
+ <command id="cmd_undo" disabled="true"/>
+ <command id="cmd_redo" disabled="true"/>
+ <command id="cmd_cut" disabled="true"/>
+ <command id="cmd_copy" disabled="true"/>
+ <command id="cmd_paste" disabled="true"/>
+ <command id="cmd_delete" disabled="true"/>
+ <command id="cmd_selectAll" disabled="true"/>
+ <command id="cmd_switchTextDirection" disabled="true"/>
+ <command id="cmd_textZoomReduce" disabled="true"/>
+ <command id="cmd_textZoomEnlarge" disabled="true"/>
+ <command id="cmd_textZoomReset" disabled="true"/>
+ </commandset>
+ <commandset id="placesCommands">
+ <command id="Browser:ShowAllBookmarks" disabled="true"/>
+ <command id="Browser:ShowAllHistory" disabled="true"/>
+ </commandset>
+
+ <keyset id="mainKeyset">
+ <key id="rkiosk_f1" keycode="VK_F1" oncommand="Rkiosk_donothing();"/>
+ <key id="key_newNavigator" disabled="true"/>
+ <key id="key_newNavigatorTab" disabled="true"/>
+ <key id="focusURLBar" disabled="true"/>
+ <key id="focusURLBar2" disabled="true"/>
+ <key id="key_search" disabled="true"/>
+ <key id="key_search2" disabled="true"/>
+ <key id="key_openDownloads" disabled="true"/>
+ <key id="openFileKb" disabled="true"/>
+ <key id="key_savePage" disabled="true"/>
+ <key id="printKb" disabled="true"/>
+ <key id="key_close" disabled="true"/>
+ <key id="key_closeWindow" disabled="true"/>
+ <key id="key_undo" disabled="true"/>
+ <key id="key_redo" disabled="true"/>
+ <key id="key_cut" disabled="true"/>
+ <key id="key_copy" disabled="true"/>
+ <key id="key_paste" disabled="true"/>
+ <key id="key_delete" disabled="true"/>
+ <key id="key_selectAll" disabled="true"/>
+ <key id="goBackKb" disabled="true"/>
+ <key id="goForwardKb" disabled="true"/>
+ <key id="goHome" keycode="VK_HOME" command="Browser:Home" modifiers="alt"/>
+ <key id="key_viewSource" disabled="true"/>
+ <key id="key_find" disabled="true"/>
+ <key id="key_findAgain" disabled="true"/>
+ <key id="key_findPrevious" disabled="true"/>
+ <key id="addBookmarkAsKb" disabled="true"/>
+ <key id="bookmarkAllTabsKb" disabled="true"/>
+ <key id="key_stop" disabled="true"/>
+ <key id="key_gotoHistory" command="Rkiosk_donothing();"/>
+ <key id="key_switchTextDirection" disabled="true"/>
+ <key id="key_sanitize" disabled="true"/>
+ <key id="key_undoCloseTab" disabled="true"/>
+ <key id="viewBookmarksSidebarKb" command="Rkiosk_donothing();"/>
+ <key id="viewBookmarksSidebarWinKb" command="Rkiosk_donothing();"/>
+ <key id="key_fullScreen" disabled="true"/>
+ <key id="key_textZoomReduce" disabled="true"/>
+ <key id="key_textZoomEnlarge" disabled="true"/>
+ <key id="key_textZoomReset" disabled="true"/>
+ <key id="showAllHistoryKb" disabled="true"/>
+ <key id="key_errorConsole" disabled="true"/>
+ <key id="manBookmarkKb" disabled="true"/>
+ <key id="key_fullZoomReduce" disabled="true"/>
+ <key id="key_fullZoomEnlarge" disabled="true"/>
+ <key id="key_fullZoomReset" disabled="true"/>
+ <key id="key_openAddons" disabled="true"/>
+ <key id="key_webConsole" disabled="true"/>
+ <key id="key_inspect" disabled="true"/>
+ <key id="key_scratchpad" disabled="true"/>
+ <key id="key_showAllTabs" disabled="true"/>
+ <key id="key_tabview" disabled="true"/>
+ <key id="key_privatebrowsing" disabled="true"/>
+ <key id="key_undoCloseWindow" disabled="true"/>
+ <key id="key_selectTab1" disabled="true"/>
+ <key id="key_selectTab2" disabled="true"/>
+ <key id="key_selectTab3" disabled="true"/>
+ <key id="key_selectTab4" disabled="true"/>
+ <key id="key_selectTab5" disabled="true"/>
+ <key id="key_selectTab6" disabled="true"/>
+ <key id="key_selectTab7" disabled="true"/>
+ <key id="key_selectTab8" disabled="true"/>
+ <key id="key_selectLastTab" disabled="true"/>
+ <key id="key_toggleAddonBar" disabled="true"/>
+ </keyset>
+</overlay>
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskunknownContentType.xul b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskunknownContentType.xul new file mode 100644 index 00000000000..faf2381d1fa --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskunknownContentType.xul @@ -0,0 +1,9 @@ +<?xml version="1.0"?>
+
+<overlay>
+ <dialog id="unknownContentType"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="rkioskclose();">
+ <script src="rkioskbrowser.js"/>
+ </dialog>
+</overlay>
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskxpinstallConfirm.xul b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskxpinstallConfirm.xul new file mode 100644 index 00000000000..b96deadeee6 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskxpinstallConfirm.xul @@ -0,0 +1,9 @@ +<?xml version="1.0"?>
+
+<overlay>
+ <dialog id="xpinstallConfirm"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="rkioskclose();">
+ <script src="rkioskbrowser.js"/>
+ </dialog>
+</overlay>
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/install.rdf b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/install.rdf new file mode 100644 index 00000000000..5be400e52e8 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/install.rdf @@ -0,0 +1,19 @@ +<?xml version='1.0' encoding='utf-8'?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + + <Description about="urn:mozilla:install-manifest"> + + <em:id>{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}</em:id> + <em:name>R-kiosk</em:name> + <em:version>0.9.0.1-signed.1-signed</em:version> + <em:description>RKiosk (Real Kiosk), fullscreen kiosk mode: all menus, keys etc. disabled</em:description> + <em:creator>Kimmo Heinaaro</em:creator> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>2.0</em:minVersion> + <em:maxVersion>6.*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF>
\ 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 new file mode 100644 index 00000000000..8de5d5d60a4 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js @@ -0,0 +1,7 @@ +// Preferences to allow unattended install of R-Kiosk extension +// Needed for Odoo posbox Client display +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) 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 30be4bd26d3..4ab50a456a1 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_scale,hw_scanner,hw_escpos,hw_blackbox_be + 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_scale,hw_scanner,hw_escpos,hw_blackbox_be,hw_screen } function _stop() { 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 5c7895822a3..a9dfda63070 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 @@ -8,17 +8,25 @@ __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" __file="${__dir}/$(basename "${BASH_SOURCE[0]}")" __base="$(basename ${__file} .sh)" +# Since we are emulating, the real /boot is not mounted, +# leading to mismatch between kernel image and modules. +mount /dev/sda1 /boot + # Recommends: antiword, graphviz, ghostscript, postgresql, python-gevent, poppler-utils export DEBIAN_FRONTEND=noninteractive +echo "nameserver 8.8.8.8" >> /etc/resolv.conf -mount /dev/sda1 /boot apt-get update apt-get -y dist-upgrade +# Do not be too fast to upgrade to more recent firmware and kernel than 4.38 +# Firmware 4.44 seems to prevent the LED mechanism from working -PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-simplejson python-tz python-unittest2 python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg screen iw hostapd isc-dhcp-server git rsync console-data" +PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-simplejson python-tz python-unittest2 python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg screen iw hostapd isc-dhcp-server git rsync console-data lightdm xserver-xorg-video-fbdev xserver-xorg-input-evdev iceweasel xdotool unclutter x11-utils openbox python-netifaces rpi-update" -apt-get -y install ${PKGS_TO_INSTALL} +# KEEP OWN CONFIG FILES DURING PACKAGE CONFIGURATION +# http://serverfault.com/questions/259226/automatically-keep-current-version-of-config-files-when-apt-get-install +apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --force-yes install ${PKGS_TO_INSTALL} apt-get clean localepurge @@ -32,13 +40,20 @@ pip install pyusb==1.0.0b1 pip install qrcode pip install evdev +# --upgrade because websocket_client in wheezy is bad: +# https://github.com/docker/compose/issues/1288 +pip install --upgrade websocket_client + groupadd usbusers usermod -a -G usbusers pi usermod -a -G lp pi +usermod -a -G input lightdm sudo -u postgres createuser -s pi mkdir /var/log/odoo chown pi:pi /var/log/odoo +chown pi:pi -R /home/pi/odoo/ +chmod 770 -R /home/pi/odoo/ # logrotate is very picky when it comes to file permissions chown -R root:root /etc/logrotate.d/ @@ -54,6 +69,31 @@ update-rc.d -f isc-dhcp-server remove systemctl daemon-reload systemctl enable ramdisks.service systemctl disable dphys-swapfile.service +systemctl enable ssh + +# USER PI AUTO LOGIN (from nano raspi-config) +# We take the whole algorithm from raspi-config in order to stay compatible with raspbian infrastructure +if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then + SYSTEMD=1 +elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then + SYSTEMD=0 +else + echo "Unrecognised init system" + return 1 +fi +if [ $SYSTEMD -eq 1 ]; then + systemctl set-default graphical.target + ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service +else + update-rc.d lightdm enable 2 +fi + +# disable overscan in /boot/config.txt, we can't use +# overwrite_after_init because it's on a different device +# (/dev/mmcblk0p1) and we don't mount that afterwards. +# This option disables any black strips around the screen +# cf: https://www.raspberrypi.org/documentation/configuration/raspi-config.md +echo "disable_overscan=1" >> /boot/config.txt # https://www.raspberrypi.org/forums/viewtopic.php?p=79249 # to not have "setting up console font and keymap" during boot take ages @@ -68,5 +108,6 @@ create_ramdisk_dir "/var" create_ramdisk_dir "/etc" create_ramdisk_dir "/tmp" mkdir /root_bypass_ramdisks +umount /dev/sda1 reboot diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-z-input.rules b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-z-input.rules new file mode 100644 index 00000000000..aab19f2d1c7 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-z-input.rules @@ -0,0 +1,2 @@ +SUBSYSTEM=="input", GROUP="input", MODE="0660" +KERNEL=="tty[0-9]*", GROUP="tty", MODE="0660"
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/posbox_create_image.sh b/addons/point_of_sale/tools/posbox/posbox_create_image.sh index 1e4c9d1277c..a9ec8bc102d 100755 --- a/addons/point_of_sale/tools/posbox/posbox_create_image.sh +++ b/addons/point_of_sale/tools/posbox/posbox_create_image.sh @@ -36,20 +36,25 @@ fi cp -a *raspbian*.img posbox.img CLONE_DIR="${OVERWRITE_FILES_BEFORE_INIT_DIR}/home/pi/odoo" + rm -rf "${CLONE_DIR}" -mkdir "${CLONE_DIR}" -git clone -b 8.0 --no-checkout --depth 1 https://github.com/odoo/odoo.git "${CLONE_DIR}" -cd "${CLONE_DIR}" -git config core.sparsecheckout true -echo "addons/web + +if [ ! -d $CLONE_DIR ]; then + echo "Clone Github repo" + mkdir -p "${CLONE_DIR}" + git clone -b 8.0 --no-local --no-checkout --depth 1 https://github.com/odoo/odoo.git "${CLONE_DIR}" + cd "${CLONE_DIR}" + git config core.sparsecheckout true + echo "addons/web addons/web_kanban addons/hw_* addons/point_of_sale/tools/posbox/configuration openerp/ odoo.py" | tee --append .git/info/sparse-checkout > /dev/null -git read-tree -mu HEAD -cd "${__dir}" + git read-tree -mu HEAD +fi +cd "${__dir}" USR_BIN="${OVERWRITE_FILES_BEFORE_INIT_DIR}/usr/bin/" mkdir -p "${USR_BIN}" cd "/tmp" @@ -60,9 +65,11 @@ cd "${__dir}" mv /tmp/ngrok "${USR_BIN}" # zero pad the image to be around 3.5 GiB, by default the image is only ~1.3 GiB +echo "Enlarging the image..." dd if=/dev/zero bs=1M count=2048 >> posbox.img # resize partition table +echo "Fdisking" START_OF_ROOT_PARTITION=$(fdisk -l posbox.img | tail -n 1 | awk '{print $2}') (echo 'p'; # print echo 'd'; # delete @@ -75,7 +82,7 @@ START_OF_ROOT_PARTITION=$(fdisk -l posbox.img | tail -n 1 | awk '{print $2}') echo 'p'; # print echo 'w') | fdisk posbox.img # write and quit -LOOP_MAPPER_PATH=$(kpartx -av posbox.img | tail -n 1 | cut -d ' ' -f 3) +LOOP_MAPPER_PATH=$(kpartx -avs posbox.img | tail -n 1 | cut -d ' ' -f 3) LOOP_MAPPER_PATH="/dev/mapper/${LOOP_MAPPER_PATH}" sleep 5 diff --git a/addons/web/static/src/js/pyeval.js b/addons/web/static/src/js/pyeval.js index c132b8365fb..a651c7d8bfa 100644 --- a/addons/web/static/src/js/pyeval.js +++ b/addons/web/static/src/js/pyeval.js @@ -852,29 +852,60 @@ var eval_domains = function (domains, evaluation_context) { evaluation_context = _.extend(instance.web.pyeval.context(), evaluation_context || {}); var result_domain = []; + // Normalize only if the first domain is the array ["|"] or ["!"] + var need_normalization = ( + domains.length > 0 + && domains[0].length === 1 + && (domains[0][0] === "|" || domains[0][0] === "!") + ); _(domains).each(function (domain) { if (_.isString(domain)) { // wrap raw strings in domain domain = { __ref: 'domain', __debug: domain }; } + var domain_array_to_combine; switch(domain.__ref) { case 'domain': evaluation_context.context = evaluation_context; - result_domain.push.apply( - result_domain, py.eval(domain.__debug, wrap_context(evaluation_context))); + domain_array_to_combine = py.eval(domain.__debug, wrap_context(evaluation_context)); break; case 'compound_domain': var eval_context = eval_contexts([domain.__eval_context]); - result_domain.push.apply( - result_domain, eval_domains( - domain.__domains, _.extend( - {}, evaluation_context, eval_context))); + domain_array_to_combine = eval_domains( + domain.__domains, + _.extend({}, evaluation_context, eval_context) + ); break; default: - result_domain.push.apply(result_domain, domain); + domain_array_to_combine = domain; + } + if (need_normalization) { + domain_array_to_combine = get_normalized_domain(domain_array_to_combine); } + result_domain.push.apply(result_domain, domain_array_to_combine); }); return result_domain; + + /** + * Returns a normalized copy of the given domain array. Normalization is + * is making the implicit "&" at the start of the domain explicit, e.g. + * [A, B, C] would become ["&", "&", A, B, C]. + * + * @param {Array} domain_array + * @returns {Array} normalized copy of the given array + */ + function get_normalized_domain(domain_array) { + var expected = 1; // Holds the number of expected domain expressions + _.each(domain_array, function (item) { + if (item === "&" || item === "|") { + expected++; + } else if (item !== "!") { + expected--; + } + }); + var new_explicit_ands = _.times(-expected, _.constant("&")); + return new_explicit_ands.concat(domain_array); + } }; var eval_groupbys = function (contexts, evaluation_context) { evaluation_context = _.extend(instance.web.pyeval.context(), evaluation_context || {}); @@ -995,7 +1026,7 @@ instance.web._t("Local evaluation failure\n%s\n\n%s"), e.message, JSON.stringify(source)) } - }}; + }}; } d.resolve(result); }, 0); }); diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js index ff97086b019..8dd9a62497e 100644 --- a/addons/web/static/test/evals.js +++ b/addons/web/static/test/evals.js @@ -500,7 +500,7 @@ openerp.testing.section('eval.edc.nonliterals', { test('domain with time', {asserts: 1}, function (instance) { return instance.edc([ [['type', '=', 'contract']], - { "__domains": [["|"], [["state", "in", ["open", "draft"]]], [["state", "=", "pending"]]], + { "__domains": [["|"], [["state", "in", ["open", "draft"]]], [["type", "=", "contract"], ["state", "=", "pending"]]], "__eval_context": null, "__ref": "compound_domain" }, @@ -513,7 +513,8 @@ openerp.testing.section('eval.edc.nonliterals', { deepEqual(result.domain, [ ["type", "=", "contract"], "|", ["state", "in", ["open", "draft"]], - ["state", "=", "pending"], + "&", ["type", "=", "contract"], + ["state", "=", "pending"], "|", "&", ["date", "!=", false], ["date", "<=", today], diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js index c2b5a005c5a..6a3fc430c93 100644 --- a/addons/web_calendar/static/src/js/web_calendar.js +++ b/addons/web_calendar/static/src/js/web_calendar.js @@ -300,7 +300,7 @@ openerp.web_calendar = function(instance) { self.proxy('update_record')(event._id, data); }, eventRender: function (event, element, view) { - element.find('.fc-event-title').html(event.title); + element.find('.fc-event-title').html(event.title + event.attendee_avatars); }, eventAfterRender: function (event, element, view) { if ((view.name !== 'month') && (((event.end-event.start)/60000)<=30)) { @@ -592,7 +592,6 @@ openerp.web_calendar = function(instance) { if (attendee_other.length>2) { the_title_avatar += '<span class="attendee_head" title="' + attendee_other.slice(0, -2) + '">+</span>'; } - the_title = the_title_avatar + the_title; } } @@ -604,6 +603,7 @@ openerp.web_calendar = function(instance) { 'start': moment(date_start).format('YYYY-MM-DD HH:mm:ss'), 'end': moment(date_stop).format('YYYY-MM-DD HH:mm:ss'), 'title': the_title, + 'attendee_avatars': the_title_avatar, 'allDay': (this.fields[this.date_start].type == 'date' || (this.all_day && evt[this.all_day]) || false), 'id': evt.id, 'attendees':attendees diff --git a/demo_10.sql b/demo_10.sql new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/demo_10.sql diff --git a/openerp/http.py b/openerp/http.py index 69effa17798..255a530d695 100644 --- a/openerp/http.py +++ b/openerp/http.py @@ -1368,9 +1368,16 @@ class Root(object): httprequest.session.db = db_monodb(httprequest) def setup_lang(self, httprequest): - if not "lang" in httprequest.session.context: - lang = httprequest.accept_languages.best or "en_US" - lang = babel.core.LOCALE_ALIASES.get(lang, lang).replace('-', '_') + if "lang" not in httprequest.session.context: + alang = httprequest.accept_languages.best or "en-US" + try: + code, territory, _, _ = babel.core.parse_locale(alang, sep='-') + if territory: + lang = '%s_%s' % (code, territory) + else: + lang = babel.core.LOCALE_ALIASES[code] + except (ValueError, KeyError): + lang = 'en_US' httprequest.session.context["lang"] = lang def get_request(self, httprequest): |
