From 012f95021c4f01b759d052a09643128ce85726f3 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Fri, 28 May 2021 10:08:25 +0200 Subject: [PATCH] [12.0][ADD] pos_self_service_base --- pos_self_service_base/README.rst | 101 ++++ pos_self_service_base/__init__.py | 1 + pos_self_service_base/__manifest__.py | 17 + pos_self_service_base/models/__init__.py | 1 + pos_self_service_base/models/pos_config.py | 9 + pos_self_service_base/readme/CONFIGURE.rst | 7 + pos_self_service_base/readme/CONTRIBUTORS.rst | 7 + pos_self_service_base/readme/DESCRIPTION.rst | 5 + pos_self_service_base/readme/ROADMAP.rst | 1 + pos_self_service_base/readme/USAGE.rst | 14 + pos_self_service_base/readme/cups | 52 ++ .../static/description/index.html | 488 ++++++++++++++++++ .../img/blue/empty_foodbox_on_scale.svg | 406 +++++++++++++++ .../static/src/css/pos_self_service.css | 150 ++++++ pos_self_service_base/static/src/js/chrome.js | 221 ++++++++ pos_self_service_base/static/src/js/models.js | 15 + .../static/src/js/screens.js | 130 +++++ .../static/src/xml/pos_self_service.xml | 50 ++ .../views/pos_config_view.xml | 25 + pos_self_service_base/views/templates.xml | 24 + 20 files changed, 1724 insertions(+) create mode 100644 pos_self_service_base/README.rst create mode 100644 pos_self_service_base/__init__.py create mode 100644 pos_self_service_base/__manifest__.py create mode 100644 pos_self_service_base/models/__init__.py create mode 100644 pos_self_service_base/models/pos_config.py create mode 100644 pos_self_service_base/readme/CONFIGURE.rst create mode 100644 pos_self_service_base/readme/CONTRIBUTORS.rst create mode 100644 pos_self_service_base/readme/DESCRIPTION.rst create mode 100644 pos_self_service_base/readme/ROADMAP.rst create mode 100644 pos_self_service_base/readme/USAGE.rst create mode 100644 pos_self_service_base/readme/cups create mode 100644 pos_self_service_base/static/description/index.html create mode 100644 pos_self_service_base/static/img/blue/empty_foodbox_on_scale.svg create mode 100644 pos_self_service_base/static/src/css/pos_self_service.css create mode 100644 pos_self_service_base/static/src/js/chrome.js create mode 100644 pos_self_service_base/static/src/js/models.js create mode 100644 pos_self_service_base/static/src/js/screens.js create mode 100644 pos_self_service_base/static/src/xml/pos_self_service.xml create mode 100644 pos_self_service_base/views/pos_config_view.xml create mode 100644 pos_self_service_base/views/templates.xml diff --git a/pos_self_service_base/README.rst b/pos_self_service_base/README.rst new file mode 100644 index 0000000000..444dc86ec8 --- /dev/null +++ b/pos_self_service_base/README.rst @@ -0,0 +1,101 @@ +============================ +Point Of Sale - Self-Service +============================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-coopiteasy%2Faddons-lightgray.png?logo=github + :target: https://github.com/coopiteasy/addons/tree/12.0/pos_self_service_base + :alt: coopiteasy/addons + +|badge1| |badge2| |badge3| + +This is the base module for the implementation of POS as a self-service weighing station. +This module handles weighing/container taring and barcode formatting. +It is aimed to be used by several other modules: + +* pos_self_service_print_zpl + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Setup the self-service POS +~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Create a new POS +2. Enable "Is Self-Service" +3. Setup hardware proxy + * Enable electronic scale +4. Enable barcode reader and its nomenclature + +Usage +===== + +This module should be used from a computer accessible to customers. +In order to limit the risk of unfortunate/malicious actions, you should: + +* **Use a dedicated odoo account with the least possible rights** +* Configure the web browser to be in kiosk mode (cf. "Launch Firefox" section) + +Those measures aren't sufficient *per se*, but should lower the risk significantly. + +Launch Firefox +~~~~~~~~~~~~~~ + +This self-service module can be used in kiosk mode. To launch Firefox in kiosk mode, run this command:: + + firefox -foreground --kiosk + +Known issues / Roadmap +====================== + +* Label printing using web print + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Coop IT Easy SCRLfs + +Contributors +~~~~~~~~~~~~ + +* `Coop IT Easy SCRLfs `_: + * Grégoire Leeuwerck + * Vincent Van Rossem +* `Le Nid `_: + * François Kawala +* `SPP `_ +* Icons made by Freepik from flaticon.com + +Maintainers +~~~~~~~~~~~ + +This module is part of the `coopiteasy/addons `_ project on GitHub. + +You are welcome to contribute. diff --git a/pos_self_service_base/__init__.py b/pos_self_service_base/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/pos_self_service_base/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/pos_self_service_base/__manifest__.py b/pos_self_service_base/__manifest__.py new file mode 100644 index 0000000000..9bbfc50d45 --- /dev/null +++ b/pos_self_service_base/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2021 - Today Coop IT Easy SCRLfs () +# - Grégoire Leeuwerck +# - Vincent Van Rossem +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Point Of Sale - Self-Service", + "summary": "POS Self-Service Base Module", + "version": "12.0.1.0.0", + "category": "Point of Sale", + "author": "Coop IT Easy SCRLfs, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/pos", + "license": "AGPL-3", + "depends": ["point_of_sale", "pos_tare"], + "data": ["views/templates.xml", "views/pos_config_view.xml"], + "qweb": ["static/src/xml/pos_self_service.xml"], + "installable": True, +} diff --git a/pos_self_service_base/models/__init__.py b/pos_self_service_base/models/__init__.py new file mode 100644 index 0000000000..db8634ade1 --- /dev/null +++ b/pos_self_service_base/models/__init__.py @@ -0,0 +1 @@ +from . import pos_config diff --git a/pos_self_service_base/models/pos_config.py b/pos_self_service_base/models/pos_config.py new file mode 100644 index 0000000000..7ffd78bf60 --- /dev/null +++ b/pos_self_service_base/models/pos_config.py @@ -0,0 +1,9 @@ +from odoo import fields, models + + +class PosConfig(models.Model): + _inherit = "pos.config" + + iface_self_service = fields.Boolean( + string="Is Self-Service", help="Use that POS as self-service point" + ) diff --git a/pos_self_service_base/readme/CONFIGURE.rst b/pos_self_service_base/readme/CONFIGURE.rst new file mode 100644 index 0000000000..a6c85b45ed --- /dev/null +++ b/pos_self_service_base/readme/CONFIGURE.rst @@ -0,0 +1,7 @@ +Setup the self-service POS +~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Create a new POS +2. Enable "Is Self-Service" +3. Setup hardware proxy + * Enable electronic scale +4. Enable barcode reader and its nomenclature diff --git a/pos_self_service_base/readme/CONTRIBUTORS.rst b/pos_self_service_base/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..de0bfec5c0 --- /dev/null +++ b/pos_self_service_base/readme/CONTRIBUTORS.rst @@ -0,0 +1,7 @@ +* `Coop IT Easy SCRLfs `_: + * Grégoire Leeuwerck + * Vincent Van Rossem +* `Le Nid `_: + * François Kawala +* `SPP `_ +* Icons made by Freepik from flaticon.com diff --git a/pos_self_service_base/readme/DESCRIPTION.rst b/pos_self_service_base/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..51859a4af5 --- /dev/null +++ b/pos_self_service_base/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This is the base module for the implementation of POS as a self-service weighing station. +This module handles weighing/container taring and barcode formatting. +It is aimed to be used by several other modules: + +* pos_self_service_print_zpl diff --git a/pos_self_service_base/readme/ROADMAP.rst b/pos_self_service_base/readme/ROADMAP.rst new file mode 100644 index 0000000000..6912042b39 --- /dev/null +++ b/pos_self_service_base/readme/ROADMAP.rst @@ -0,0 +1 @@ +* Label printing using web print diff --git a/pos_self_service_base/readme/USAGE.rst b/pos_self_service_base/readme/USAGE.rst new file mode 100644 index 0000000000..34e2edf5c7 --- /dev/null +++ b/pos_self_service_base/readme/USAGE.rst @@ -0,0 +1,14 @@ +This module should be used from a computer accessible to customers. +In order to limit the risk of unfortunate/malicious actions, you should: + +* **Use a dedicated odoo account with the least possible rights** +* Configure the web browser to be in kiosk mode (cf. "Launch Firefox" section) + +Those measures aren't sufficient *per se*, but should lower the risk significantly. + +Launch Firefox +~~~~~~~~~~~~~~ + +This self-service module can be used in kiosk mode. To launch Firefox in kiosk mode, run this command:: + + firefox -foreground --kiosk diff --git a/pos_self_service_base/readme/cups b/pos_self_service_base/readme/cups new file mode 100644 index 0000000000..002082b375 --- /dev/null +++ b/pos_self_service_base/readme/cups @@ -0,0 +1,52 @@ +upstream cups-reverse-proxy { + server 127.0.0.1:631 weight=1 fail_timeout=60s; +} + +server { + # server port and name + listen 8631; + listen [::]:8631; + server_name _; + + # ssl log files + access_log /var/log/nginx/cups-access.log; + error_log /var/log/nginx/cups-error.log; + + + # increase proxy buffer to handle some Odoo web requests + proxy_buffers 16 64k; + proxy_buffer_size 128k; + + location / { + proxy_pass http://cups-reverse-proxy; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + + add_header 'Access-Control-Allow-Origin' "http://localhost:8000" always; + add_header 'Access-Control-Allow-Credentials' * always; + add_header 'Access-Control-Allow-Methods' * always; + add_header 'Access-Control-Allow-Headers' * always; + # required to be able to read Authorization header in frontend + add_header 'Access-Control-Expose-Headers' * always; + + if ($request_method = 'OPTIONS') { + # Tell client that this pre-flight info is valid for 20 days + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + add_header 'Access-Control-Allow-Origin' "http://localhost:8000" always; + add_header 'Access-Control-Allow-Credentials' * always; + add_header 'Access-Control-Allow-Methods' * always; + add_header 'Access-Control-Allow-Headers' * always; + # required to be able to read Authorization header in frontend + add_header 'Access-Control-Expose-Headers' * always; + + return 204; + } + + # by default, do not forward anything + proxy_redirect off; + } +} diff --git a/pos_self_service_base/static/description/index.html b/pos_self_service_base/static/description/index.html new file mode 100644 index 0000000000..e3550fba8f --- /dev/null +++ b/pos_self_service_base/static/description/index.html @@ -0,0 +1,488 @@ + + + + + + +Point Of Sale - Self-Service + + + +
+

Point Of Sale - Self-Service

+ + +

Beta License: AGPL-3 coopiteasy/addons

+

This is the base module for the implementation of POS as a self-service weighing station. +This module handles weighing/container taring and barcode formatting. +It is aimed to be used by several other modules:

+
    +
  • pos_self_service_print_zpl
  • +
+

Table of contents

+ +
+

Configuration

+
+

Setup the self-service POS

+
    +
  1. Create a new POS
  2. +
  3. Enable “Is Self-Service”
  4. +
  5. +
    Setup hardware proxy
    +
      +
    • Enable electronic scale
    • +
    +
    +
    +
  6. +
  7. Enable barcode reader and its nomenclature
  8. +
+
+
+
+

Usage

+

This module should be used from a computer accessible to customers. +In order to limit the risk of unfortunate/malicious actions, you should:

+
    +
  • Use a dedicated odoo account with the least possible rights
  • +
  • Configure the web browser to be in kiosk mode (cf. “Launch Firefox” section)
  • +
+

Those measures aren’t sufficient per se, but should lower the risk significantly.

+
+

Launch Firefox

+

This self-service module can be used in kiosk mode. To launch Firefox in kiosk mode, run this command:

+
+firefox <url> -foreground --kiosk
+
+
+
+
+

Known issues / Roadmap

+
    +
  • Label printing using web print
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Coop IT Easy SCRLfs
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the coopiteasy/addons project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/pos_self_service_base/static/img/blue/empty_foodbox_on_scale.svg b/pos_self_service_base/static/img/blue/empty_foodbox_on_scale.svg new file mode 100644 index 0000000000..d5ad2368c5 --- /dev/null +++ b/pos_self_service_base/static/img/blue/empty_foodbox_on_scale.svg @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pos_self_service_base/static/src/css/pos_self_service.css b/pos_self_service_base/static/src/css/pos_self_service.css new file mode 100644 index 0000000000..abb83ffc77 --- /dev/null +++ b/pos_self_service_base/static/src/css/pos_self_service.css @@ -0,0 +1,150 @@ +/* --- POS Self Service Specific CSS --- */ + +/* *** The self-service control buttons *** */ +.pos .self-service-control-buttons { + display: -webkit-flex; + display: flex; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + padding: 8px 16px 0px 11px; +} + +.pos .self-service-control-button { + -webkit-flex-grow: 1; + flex-grow: 1; + background: #e2e2e2; + border: solid 1px #bfbfbf; + display: inline-block; + line-height: 76px; + min-width: 80px; + text-align: center; + border-radius: 3px; + padding: 0px 10px; + font-size: 36px; + margin-left: 6px; + margin-bottom: 6px; + cursor: pointer; + overflow: hidden; + transition: all linear 150ms; +} + +.pos .self-service-control-button:hover { + background: #efefef; +} + +.pos .self-service-control-button:active { + background: black; + color: white; + border-color: black; +} + +.pos .self-service-control-button .fa { + margin-right: 4px; +} + +.pos .self-service-control-button.highlight { + background: #6ec89b !important; + border: solid 1px #64af8a !important; + color: white !important; +} + +.pos .self-service-control-button.altlight { + background: #7f82ac !important; + border: solid 1px #756a99 !important; + color: white !important; +} + +.pos .self-service-control-button.disabled, +.pos .self-service-control-button.disabled:active { + background: #e2e2e2; + border: solid 1px #bebebe; + opacity: 0.5; + cursor: default; + color: inherit; +} + +/* ------ Self Service Screen Widget -------*/ +.centered { + display: flex; + justify-content: center; + align-items: center; + overflow: auto; + width: 100%; + height: 100%; +} + +.big-button { + display: flex; + text-align: center; + flex-direction: column; + justify-content: center; + align-items: center; + width: 90%; + height: 45%; + font-size: 55px; + cursor: pointer; + transition: background-color, border-color, color 150ms linear; +} + +.big-button .ico { + display: flex; + background-size: contain; + width: 170px; + height: 170px; + order: 2; +} + +.foodbox { + background-image: url("../../img/blue/empty_foodbox_on_scale.svg"); +} + +.self-service-screen .green { + background: rgb(110, 200, 155); + border: solid 1px rgb(73, 186, 130); +} + +.self-service-screen .green:hover { + background: rgb(73, 186, 130); +} + +.self-service-screen .grey { + background: lightgrey; + border: solid 1px darkgrey; +} + +.self-service-screen .grey:hover { + background: darkgrey; +} + +/* ------ Self Service Scale Widget ------- */ + +.pos .self-service-scale-container { + position: absolute; + top: 0px; + width: 100%; + height: 100%; + /*background: white;*/ +} + +.pos .self-service-scale-scroller { + width: 100%; + height: 100%; + overflow: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; +} + +.pos .self-service-scale .weight { + display: block; + position: relative; + text-align: center; + border-style: solid; + border-color: #787878; + border-width: 0 0 3px 0; + background: white; + padding: 40px; + font-size: 56px; + font-family: Inconsolata; + text-shadow: 0px 2px 0px rgb(210, 210, 210); + box-shadow: 0px 2px 0px rgb(225, 225, 225) inset; +} diff --git a/pos_self_service_base/static/src/js/chrome.js b/pos_self_service_base/static/src/js/chrome.js new file mode 100644 index 0000000000..9159be326d --- /dev/null +++ b/pos_self_service_base/static/src/js/chrome.js @@ -0,0 +1,221 @@ +odoo.define("pos_self_service_base.chrome", function(require) { + "use strict"; + // This file contains the different widgets available to all self-service screens + // They are contained in a left-pane + + var PosBaseWidget = require("point_of_sale.BaseWidget"); + var chrome = require("point_of_sale.chrome"); + var core = require("web.core"); + var _t = core._t; + + /* ----- The Self Service Action Buttons ----- */ + + // buttons for extra actions and controls + // by pos_self_service extensions modules. + + var self_service_action_button_classes = []; + var define_self_service_action_button = function(classe, options) { + options = options || {}; + + var classes = self_service_action_button_classes; + var index = classes.length; + var i; + + if (options.after) { + for (i = 0; i < classes.length; i++) { + if (classes[i].name === options.after) { + index = i + 1; + } + } + } else if (options.before) { + for (i = 0; i < classes.length; i++) { + if (classes[i].name === options.after) { + index = i; + break; + } + } + } + classes.splice(i, 0, classe); + }; + + var SelfServiceActionButtonWidget = PosBaseWidget.extend({ + template: "SelfServiceActionButtonWidget", + label: _t("Button"), + renderElement: function() { + var self = this; + this._super(); + this.$el.click(function() { + self.button_click(); + }); + }, + button_click: function() {}, + highlight: function(highlight) { + this.$el.toggleClass("highlight", !!highlight); + }, + // alternative highlight color + altlight: function(altlight) { + this.$el.toggleClass("altlight", !!altlight); + }, + }); + + /* -------- The Self-Service Home Button -------- */ + + // The home button allows the user to go to the startup screen. + // It clears the navigation history stack + var SelfServiceHomeButton = SelfServiceActionButtonWidget.extend({ + template: "SelfServiceHomeButton", + home_screen: "selfservice", + + button_click: function() { + this._super(); + this.gui.show_screen(this.home_screen); + }, + }); + + define_self_service_action_button({ + name: "home_button", + widget: SelfServiceHomeButton, + }); + + /* -------- The Self-Service Scale Widget -------- */ + + var SelfServiceScaleWidget = PosBaseWidget.extend({ + template: "SelfServiceScaleWidget", + + init: function(parent, options) { + this._super(parent, options); + this.weight = 0; + this.observers = []; + this.renderElement(); + }, + start: function() { + var self = this; + this._super(); + var queue = this.pos.proxy_queue; + this.set_weight(0); + this.renderElement(); + + queue.schedule( + function() { + return self.pos.proxy.scale_read().then(function(weight) { + self.set_weight(weight.weight); + self.notify_all(weight.weight); + }); + }, + {duration: 500, repeat: true} + ); + }, + add_observer: function(observer) { + this.observers.push(observer); + }, + notify_all: function(data) { + var observers = this.observers; + if (observers.length > 0) { + for (var i = 0; i < observers.length; i++) { + var observer = observers[i]; + observer.update(data); + } + } + }, + set_weight: function(weight) { + this.weight = weight; + this.$(".weight").text(this.get_weight_string()); + }, + get_weight: function() { + return this.weight; + }, + get_weight_string: function() { + var defaultstr = (this.weight || 0).toFixed(3) + " kg"; + return defaultstr; + }, + }); + + // Add the self-service widgets to the Chrome + chrome.Chrome.include({ + build_widgets: function() { + if (this.pos.config.iface_self_service) { + // here we add widgets available to all self-service screens + this.widgets.push({ + name: "self_service_scale_widget", + widget: SelfServiceScaleWidget, + replace: ".placeholder-SelfServiceScaleWidget", + }); + this._super(); + this.self_service_action_buttons = {}; + var classes = self_service_action_button_classes; + for (var i = 0; i < classes.length; i++) { + var classe = classes[i]; + if (!classe.condition || classe.condition.call(this)) { + var widget = new classe.widget(this, {}); + widget.appendTo(this.$(".self-service-control-buttons")); + this.self_service_action_buttons[classe.name] = widget; + } + } + if (_.size(this.self_service_action_buttons)) { + this.$(".self-service-control-buttons").removeClass("oe_hidden"); + } + this.gui.set_startup_screen("selfservice"); + this.gui.set_default_screen("selfservice"); + } else { + this._super(); + } + }, + build_chrome: function() { + // workaround to split Chrome in leftpane/rightpane as it doesn't seem possible in QWeb + this._super(); + if (this.pos.config.iface_self_service) { + this.split_content(); + } + }, + split_content: function() { + var $window = this.$el.find(".window"); + $window.remove(); + + var $leftpane = $("
", {class: "leftpane"}); + $leftpane.append( + $("
", {class: "window"}) + .append( + $("
", {class: "subwindow"}).append( + $("
", {class: "subwindow-container"}).append( + $("
", {class: "subwindow-container-fix"}).append( + $("
", { + class: "placeholder-SelfServiceScaleWidget", + }) + ) + ) + ) + ) + .append( + $("
", {class: "subwindow"}).append( + $("
", {class: "subwindow-container"}).append( + $("
", { + class: "subwindow-container-fix pads", + }).append( + $("
", { + class: "self-service-control-buttons oe_hidden", + }) + ) + ) + ) + ) + ); + + var $rightpane = $("
", {class: "rightpane"}); + $rightpane.html($window); + + var $pos_content = this.$el.find(".pos-content"); + $pos_content.append($leftpane, $rightpane); + + // workaround to hide .pos-topheader + // and fully display .pos-content + $pos_content.css("top", "0"); + }, + }); + + return { + define_self_service_action_button: define_self_service_action_button, + SelfServiceActionButtonWidget: SelfServiceActionButtonWidget, + SelfServiceHomeButton: SelfServiceHomeButton, + SelfServiceScaleWidget: SelfServiceScaleWidget, + }; +}); diff --git a/pos_self_service_base/static/src/js/models.js b/pos_self_service_base/static/src/js/models.js new file mode 100644 index 0000000000..2e8f74a94d --- /dev/null +++ b/pos_self_service_base/static/src/js/models.js @@ -0,0 +1,15 @@ +odoo.define("pos_self_service_base.models", function(require) { + "use strict"; + + var models = require("point_of_sale.models"); + + // We need to change the way the regular UI sees the orders + var _super_posmodel = models.PosModel.prototype; + models.PosModel = models.PosModel.extend({ + set_start_order: function() { + if (!this.config.iface_self_service) { + _super_posmodel.set_start_order.apply(this, arguments); + } + }, + }); +}); diff --git a/pos_self_service_base/static/src/js/screens.js b/pos_self_service_base/static/src/js/screens.js new file mode 100644 index 0000000000..cd6aec7a8e --- /dev/null +++ b/pos_self_service_base/static/src/js/screens.js @@ -0,0 +1,130 @@ +odoo.define("pos_self_service_base.screens", function(require) { + "use strict"; + // This file contains the base screen where user actions will be included. + // Those actions will be defined in seperated modules. + // e.g.: `pos_self_service_printing` defines UI and business logic for printing labels, + + var gui = require("point_of_sale.gui"); + var screens = require("point_of_sale.screens"); + var core = require("web.core"); + var QWeb = core.qweb; + var _t = core._t; + + /* -------- The Self-Service Screen -------- */ + // This is the home screen with the call to action buttons. + var SelfServiceScreenWidget = screens.ScreenWidget.extend({ + template: "SelfServiceScreenWidget", + scale_weight: 0, + + // Ignore products, discounts, and client barcodes + barcode_product_action: function(code) {}, + barcode_discount_action: function(code) {}, + barcode_client_action: function(code) {}, + start: function() { + var self = this; + this._super(); + this.self_service_scale_widget = this.pos.chrome.widget.self_service_scale_widget; + this.self_service_scale_widget.add_observer(this); + this.barcode_parser = this.pos.barcode_reader.barcode_parser; + }, + show: function() { + var self = this; + this._super(); + this.chrome.widget.order_selector.hide(); + this.$(".tare").click(function() { + self.click_print(); + }); + this.render_button(); + }, + get_tare_button_render_env: function() { + return { + widget: this, + pos: this.pos, + scale_weight: this.scale_weight, + }; + }, + update: function(data) { + this.scale_weight = data; + this.render_button(); + }, + renderElement() { + var self = this; + this._super(); + }, + click_print: function() { + if (this.scale_weight <= 0) { + this.gui.show_popup("alert", { + title: _t("No Weight"), + body: _t("Please put your container on the scale"), + }); + } + }, + format_barcode: function(weight) { + // We use EAN13 barcode, it looks like `07 00000 12345 x`. First there + // is the prefix, here 07, that is used to decide which type of + // barcode we're dealing with. A weight barcode has then two groups + // of five digits. The first group encodes the product id. Here the + // product id is 00000. The second group encodes the weight in + // grams. Here the weight is 12.345kg. The last digit of the barcode + // is a checksum, here symbolized by x. + var padding_size = 5; + var void_product_id = "0".repeat(padding_size); + var weight_in_gram = weight * 1e3; + + if (weight_in_gram >= Math.pow(10, padding_size)) { + throw new RangeError(_t("Maximum tare weight is 99.999 kg")); + } + + // Weight has to be padded with zeroes. + var weight_with_padding = "0".repeat(padding_size) + weight_in_gram; + var padded_weight = weight_with_padding.substr( + weight_with_padding.length - padding_size + ); + // Builds the barcode using a placeholder checksum. + var barcode = this.get_barcode_prefix() + .concat(void_product_id, padded_weight) + .concat(0); + // Compute checksum + var ean_checksum = this.barcode_parser.ean_checksum(barcode); + // Replace checksum placeholder by the actual checksum. + return barcode.substr(0, 12).concat(ean_checksum); + }, + get_barcode_prefix: function() { + var barcode_pattern = this.get_barcode_pattern(); + return barcode_pattern.substr(0, 2); + }, + get_barcode_pattern: function() { + var rules = this.get_nomenclature_rules(); + var rule = rules.filter(function(r) { + // We select the first (smallest sequence ID) barcode rule + // with the expected type. + return r.type === "tare"; + })[0]; + return rule.pattern; + }, + get_nomenclature_rules: function() { + return this.barcode_parser.nomenclature.rules; + }, + get_barcode: function() { + return this.format_barcode(this.scale_weight); + }, + render_button: function() { + this.$(".tare-button-container").html( + QWeb.render("TareButton", this.get_tare_button_render_env()) + ); + }, + }); + + // Add the self-service screen to the GUI + gui.define_screen({ + name: "selfservice", + widget: SelfServiceScreenWidget, + condition: function() { + return this.pos.config.iface_self_service; + }, + }); + + return { + SelfServiceScreenWidget: SelfServiceScreenWidget, + }; +}); diff --git a/pos_self_service_base/static/src/xml/pos_self_service.xml b/pos_self_service_base/static/src/xml/pos_self_service.xml new file mode 100644 index 0000000000..2e8ec43532 --- /dev/null +++ b/pos_self_service_base/static/src/xml/pos_self_service.xml @@ -0,0 +1,50 @@ + + + + +
+
+
+
+ +
+
+
+
+
+ + +
+ +
+
+ + +
+ + + Home + +
+
+ + +
+
+
+ +
+
+
+
+
+
+ + + +
+ Print container tare + +
+
+ diff --git a/pos_self_service_base/views/pos_config_view.xml b/pos_self_service_base/views/pos_config_view.xml new file mode 100644 index 0000000000..f015b85e49 --- /dev/null +++ b/pos_self_service_base/views/pos_config_view.xml @@ -0,0 +1,25 @@ + + + + + pos.config + + + +
+
+
+ +
+
+
+
+
+
+
+
+
diff --git a/pos_self_service_base/views/templates.xml b/pos_self_service_base/views/templates.xml new file mode 100644 index 0000000000..060a4ea39b --- /dev/null +++ b/pos_self_service_base/views/templates.xml @@ -0,0 +1,24 @@ + +