Browse Source
[MIG] pos_customer_display: Migration to 12.0
[MIG] pos_customer_display: Migration to 12.0
[REF] OCA Convention - rename files. - split js file into many files. (models, screens, etc.) [FIX] make default "welcome" and "good bye" message translatable [REF] add the possibility to have other format of LCD Customer display. fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! [MIG] pos_customer_display: Migration to 12.0 [REF] OCA Convention. rename files. fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! [MIG] pos_customer_display: Migration to 12.0 [REF] OCA Convention. rename files. fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! [MIG] pos_customer_display: Migration to 12.0 [REF] OCA Convention. rename files. fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! [MIG] pos_customer_display: Migration to 12.0 [REF] OCA Convention. rename files. fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! [MIG] pos_customer_display: Migration to 12.0 [REF] OCA Convention. rename files. fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! [MIG] pos_customer_display: Migration to 12.0 [REF] OCA Convention. rename files.pull/437/head
Sylvain LE GAL
5 years ago
26 changed files with 708 additions and 592 deletions
-
98pos_customer_display/README.rst
-
2pos_customer_display/__init__.py
-
15pos_customer_display/__manifest__.py
-
9pos_customer_display/demo/pos_config.xml
-
11pos_customer_display/demo/pos_customer_display_demo.xml
-
136pos_customer_display/i18n/pos_customer_display.pot
-
4pos_customer_display/models/__init__.py
-
102pos_customer_display/models/pos_config.py
-
80pos_customer_display/models/pos_customer_display.py
-
8pos_customer_display/readme/CONFIGURE.rst
-
5pos_customer_display/readme/CONTRIBUTORS.rst
-
10pos_customer_display/readme/DESCRIPTION.rst
-
7pos_customer_display/readme/INSTALL.rst
-
0pos_customer_display/readme/ROADMAP.rst
-
9pos_customer_display/readme/USAGE.rst
-
BINpos_customer_display/static/description/icon.png
-
309pos_customer_display/static/src/js/customer_display.js
-
111pos_customer_display/static/src/js/customer_display_2_20.js
-
90pos_customer_display/static/src/js/devices.js
-
24pos_customer_display/static/src/js/gui.js
-
128pos_customer_display/static/src/js/models.js
-
51pos_customer_display/static/src/js/screens.js
-
14pos_customer_display/views/assets.xml
-
26pos_customer_display/views/customer_display_view.xml
-
10pos_customer_display/views/pos_customer_display.xml
-
41pos_customer_display/views/view_pos_config.xml
@ -1,90 +1,8 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
==================== |
|||
POS Customer Display |
|||
==================== |
|||
|
|||
This module adds support for Customer Display in the Point of Sale. As incredible as it may seem, the Odoo POS doesn't have native support for a customer display, even on Odoo 10. So, if the customer cannot see the screen of the cashier, he will not be able to check the price of each product scanned by the cashier, he won't be able to see the total amount, etc. This module provides a solution to this problem by adding support for good old POS LCDs, which are often made of 2 lines of 20 caracters. |
|||
|
|||
This module is designed to be installed on the *main Odoo server*. On the |
|||
*POSbox*, you should install the module *hw_customer_display*. But you will certainly prefer to use `pywebdriver <https://github.com/akretion/pywebdriver>`__ instead of the POSbox. Compared to the POSbox, Pywebdriver has several advantages: |
|||
|
|||
* smaller footprint: no need to have a full-blown Odoo with PostgreSQL on the computer of the cashier (or his small Linux-based PC connected to the hardware, like the RaspberryPi for the POSbox), |
|||
* availability of an Ubuntu package, for easier deployment, |
|||
* native support for the customer display, payment terminal, etc. |
|||
* nice test/diagnosis Web interface. |
|||
|
|||
It has been tested with a Bixolon BCD-1100 |
|||
(http://www.bixolon.com/html/en/product/product_detail.xhtml?prod_id=61), |
|||
but should support most serial and USB-serial LCD displays |
|||
out-of-the-box or with minor adaptations in the source code: |
|||
|
|||
* of the module *hw_customer_display* if you use the POSbox, |
|||
* or of the Python lib `pyposdisplay <https://github.com/akretion/pyposdisplay>`__ if you use `pywebdriver <https://github.com/akretion/pywebdriver>`__. |
|||
|
|||
This module has been developped during a POS code sprint at |
|||
`Akretion France <http://www.akretion.com/>`_ from July 7th to July 10th 2014. |
|||
|
|||
Configuration |
|||
============= |
|||
|
|||
To configure this module, go to the menu *Point of Sale > Configuration > Point |
|||
of Sale* and edit the point of sale for which you want to enable the LCD: |
|||
|
|||
* make sure you have configured the *IP address* and port of the POSbox or pywebdriver in the section *Hardware Proxy / PosBox*, |
|||
* activate the option *Customer Display*, |
|||
* configure the number of caracters on each line of your LCD (20 by default). |
|||
|
|||
At the end of the page, in the *Customer Display* section, you can customize the *Next customer* message and the *POS closed* message. |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
Once everything is configured, just start the POS as usual. You will see messages on the LCD when: |
|||
|
|||
* you start the POS, |
|||
* you add or remove a product, |
|||
* you press the Payment button: the LCD will display the total amount, |
|||
* you enter the amount of cash you receive: the LCD will display the amount of the change to give back, |
|||
* you validate an order and go to the next customer, |
|||
* you close the POS. |
|||
|
|||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
|||
:alt: Try me on Runbot |
|||
:target: https://runbot.odoo-community.org/runbot/184/10.0 |
|||
|
|||
Bug Tracker |
|||
=========== |
|||
|
|||
Bugs are tracked on `GitHub Issues |
|||
<https://github.com/OCA/pos/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. |
|||
|
|||
Credits |
|||
======= |
|||
|
|||
Contributors |
|||
------------ |
|||
|
|||
* Aurélien Dumaine |
|||
* Alexis de Lattre <alexis.delattre@akretion.com> |
|||
* Father Odilon (`Barroux Abbey <http://www.barroux.org/>`_) |
|||
* Daniel Kraft |
|||
|
|||
Maintainer |
|||
---------- |
|||
|
|||
.. image:: https://odoo-community.org/logo.png |
|||
:alt: Odoo Community Association |
|||
:target: https://odoo-community.org |
|||
|
|||
This module is maintained by the OCA. |
|||
|
|||
OCA, or the Odoo Community Association, is a nonprofit organization whose |
|||
mission is to support the collaborative development of Odoo features and |
|||
promote its widespread use. |
|||
|
|||
To contribute to this module, please visit https://odoo-community.org. |
|||
==================================== |
|||
Point of Sale - LCD Customer Display |
|||
==================================== |
|||
|
|||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|||
!! This file is generated by oca-gen-addon-readme !! |
|||
!! changes will be overwritten. !! |
|||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
@ -1,3 +1 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import models |
@ -1,20 +1,19 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2016 Aurélien DUMAINE |
|||
# © 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
{ |
|||
"name": "POS Customer Display", |
|||
"version": "10.0.1.0.1", |
|||
"name": "Point of Sale - LCD Customer Display", |
|||
"version": "12.0.1.0.0", |
|||
"category": "Point Of Sale", |
|||
"summary": "Manage Customer Display device from POS front end", |
|||
"author": "Aurélien DUMAINE,Akretion,Odoo Community Association (OCA)", |
|||
"summary": "Manage LCD Customer Display device from POS front end", |
|||
"author": "Aurélien DUMAINE,GRAP,Akretion,Odoo Community Association (OCA)", |
|||
"license": "AGPL-3", |
|||
"depends": ["point_of_sale"], |
|||
"data": [ |
|||
"views/pos_customer_display.xml", |
|||
"views/customer_display_view.xml", |
|||
"views/assets.xml", |
|||
"views/view_pos_config.xml", |
|||
], |
|||
"demo": ["demo/pos_customer_display_demo.xml"], |
|||
"demo": ["demo/pos_config.xml"], |
|||
"installable": True, |
|||
} |
@ -0,0 +1,9 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
|
|||
<odoo noupdate="1"> |
|||
|
|||
<record id="point_of_sale.pos_config_main" model="pos.config"> |
|||
<field name="iface_customer_display" eval="True"/> |
|||
</record> |
|||
|
|||
</odoo> |
@ -1,11 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
|
|||
<odoo noupdate="1"> |
|||
|
|||
|
|||
<record id="point_of_sale.pos_config_main" model="pos.config"> |
|||
<field name="iface_customer_display" eval="True"/> |
|||
</record> |
|||
|
|||
|
|||
</odoo> |
@ -1,3 +1 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from . import pos_customer_display |
|||
from . import pos_config |
@ -0,0 +1,102 @@ |
|||
# © 2014-2016 Aurélien DUMAINE |
|||
# © 2015-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from odoo import _, api, fields, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class PosConfig(models.Model): |
|||
_inherit = "pos.config" |
|||
|
|||
_CUSTOMER_DISPLAY_FORMAT_SELECTION = [ |
|||
("2_20", "2 Lines of 20 Characters"), |
|||
] |
|||
|
|||
iface_customer_display = fields.Boolean( |
|||
string="LED Customer Display", |
|||
help="Display data on the customer display" |
|||
) |
|||
|
|||
customer_display_format = fields.Selection( |
|||
selection=_CUSTOMER_DISPLAY_FORMAT_SELECTION, |
|||
string="Customer Display Format", |
|||
default="2_20", required=True) |
|||
|
|||
customer_display_line_length = fields.Integer( |
|||
string="Line Length", |
|||
compute="_customer_display_line_length", |
|||
store=True, |
|||
help="Length of the LEDs lines of the customer display", |
|||
) |
|||
customer_display_msg_next_l1 = fields.Char( |
|||
string="Next Customer (Line 1)", |
|||
default=lambda x: x._default_customer_display_msg("next_l1"), |
|||
help="First line of the message on the customer display which is " |
|||
"displayed after starting POS and also after validation of an order", |
|||
) |
|||
customer_display_msg_next_l2 = fields.Char( |
|||
string="Next Customer (Line 2)", |
|||
default=lambda x: x._default_customer_display_msg("next_l2"), |
|||
help="Second line of the message on the customer display which is " |
|||
"displayed after starting POS and also after validation of an order", |
|||
) |
|||
customer_display_msg_closed_l1 = fields.Char( |
|||
string="PoS Closed (Line 1)", |
|||
default=lambda x: x._default_customer_display_msg("closed_l1"), |
|||
help="First line of the message on the customer display which " |
|||
"is displayed when POS is closed", |
|||
) |
|||
customer_display_msg_closed_l2 = fields.Char( |
|||
string="PoS Closed (Line 2)", |
|||
default=lambda x: x._default_customer_display_msg("closed_l1"), |
|||
help="Second line of the message on the customer display which " |
|||
"is displayed when POS is closed", |
|||
) |
|||
|
|||
@api.model |
|||
def _default_customer_display_msg(self, line): |
|||
if line == "next_l1": |
|||
return _("Point of Sale Open") |
|||
elif line == "next_l2": |
|||
return _("Welcome!") |
|||
elif line == "closed_l1": |
|||
return _("Point of Sale Closed") |
|||
elif line == "closed_l2": |
|||
return _("See you soon!") |
|||
|
|||
@api.depends("customer_display_format") |
|||
def _compute_customer_display_line_length(self): |
|||
for config in self: |
|||
config.customer_display_line_length = int( |
|||
config.customer_display_format.split("_")[1]) |
|||
|
|||
@api.constrains( |
|||
"iface_customer_display", |
|||
"customer_display_format", |
|||
"customer_display_msg_next_l1", |
|||
"customer_display_msg_next_l2", |
|||
"customer_display_msg_closed_l1", |
|||
"customer_display_msg_closed_l2", |
|||
) |
|||
def _check_customer_display_length(self): |
|||
for config in self.filtered(lambda x: x.customer_display_line_length): |
|||
maxsize = config.customer_display_line_length |
|||
fields_to_check = [ |
|||
x for x in self._fields.keys() |
|||
if 'customer_display_msg_' in x |
|||
] |
|||
for field_name in fields_to_check: |
|||
value = getattr(config, field_name) |
|||
if value and len(value) > maxsize: |
|||
raise ValidationError( |
|||
_( |
|||
"The message for customer display '%s' is too " |
|||
"long: it has %d chars whereas the maximum " |
|||
"is %d chars." |
|||
) |
|||
% ( |
|||
self._fields[field_name].string, |
|||
len(value), |
|||
maxsize) |
|||
) |
@ -1,80 +0,0 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# © 2014-2016 Aurélien DUMAINE |
|||
# © 2015-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
|||
|
|||
from odoo import models, fields, api, _ |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class PosConfig(models.Model): |
|||
_inherit = "pos.config" |
|||
|
|||
iface_customer_display = fields.Boolean( |
|||
string="Customer Display", help="Display data on the customer display" |
|||
) |
|||
customer_display_line_length = fields.Integer( |
|||
string="Line Length of the Customer Display", |
|||
default=20, |
|||
help="Length of the LEDs lines of the customer display", |
|||
) |
|||
customer_display_msg_next_l1 = fields.Char( |
|||
string="Next Customer (top line)", |
|||
default="Welcome!", |
|||
help="Top line of the message on the customer display which is " |
|||
"displayed after starting POS and also after validation of an order", |
|||
) |
|||
customer_display_msg_next_l2 = fields.Char( |
|||
string="Next Customer (bottom line)", |
|||
default="Point of Sale Open", |
|||
help="Bottom line of the message on the customer display which is " |
|||
"displayed after starting POS and also after validation of an order", |
|||
) |
|||
customer_display_msg_closed_l1 = fields.Char( |
|||
string="POS Closed (top line)", |
|||
default="Point of Sale Closed", |
|||
help="Top line of the message on the customer display which " |
|||
"is displayed when POS is closed", |
|||
) |
|||
customer_display_msg_closed_l2 = fields.Char( |
|||
string="POS Closed (bottom line)", |
|||
default="See you soon!", |
|||
help="Bottom line of the message on the customer display which " |
|||
"is displayed when POS is closed", |
|||
) |
|||
|
|||
@api.constrains( |
|||
"customer_display_line_length", |
|||
"customer_display_msg_next_l1", |
|||
"customer_display_msg_next_l2", |
|||
"customer_display_msg_closed_l1", |
|||
"customer_display_msg_closed_l2", |
|||
) |
|||
def _check_customer_display_length(self): |
|||
self.ensure_one() |
|||
if self.customer_display_line_length: |
|||
maxsize = self.customer_display_line_length |
|||
to_check = { |
|||
_( |
|||
"Next Customer (top line)" |
|||
): self.customer_display_msg_next_l1, |
|||
_( |
|||
"Next Customer (bottom line)" |
|||
): self.customer_display_msg_next_l2, |
|||
_( |
|||
"POS Closed (top line)" |
|||
): self.customer_display_msg_closed_l1, |
|||
_( |
|||
"POS Closed (bottom line)" |
|||
): self.customer_display_msg_closed_l2, |
|||
} |
|||
for field, msg in to_check.iteritems(): |
|||
if msg and len(msg) > maxsize: |
|||
raise ValidationError( |
|||
_( |
|||
"The message for customer display '%s' is too " |
|||
"long: it has %d chars whereas the maximum " |
|||
"is %d chars." |
|||
) |
|||
% (field, len(msg), maxsize) |
|||
) |
@ -0,0 +1,8 @@ |
|||
To configure this module, |
|||
* go to the menu Point of Sale > Configuration > Point of Sale |
|||
* edit the point of sale for which you want to enable the LCD: |
|||
|
|||
* In the IotBox section, activate the option *LCD Customer Display*, |
|||
* configure the format of your LCD screen. (2 lines of 20 characters, by default) |
|||
|
|||
* optionaly, you can customize the *Next customer* message and the *POS closed* message |
@ -0,0 +1,5 @@ |
|||
* Aurélien Dumaine |
|||
* Alexis de Lattre <alexis.delattre@akretion.com> |
|||
* Father Odilon (`Barroux Abbey <http://www.barroux.org/>`_) |
|||
* Daniel Kraft |
|||
* Sylvain LE GAL ((https://twitter.com/legalsylvain)) |
@ -0,0 +1,10 @@ |
|||
This module adds support for LCD Customer Display in the Point of Sale. |
|||
|
|||
It has been tested with |
|||
|
|||
* Bixolon BCD-1100 (http://www.bixolon.com/html/en/product/product_detail.xhtml?prod_id=61), |
|||
* Aures OCD 300 (https://www.aures.com/point-de-vente-equipment-solutions-systemes/ecrans-tactiles-afficheurs/ocd-300-350-afficheur-client-graphique) |
|||
|
|||
But it should support most serial and USB-serial LCD displays out-of-the-box or with minor adaptations in the source code |
|||
* of the module *hw_customer_display* if you use the POSbox, |
|||
* or of the Python lib `pyposdisplay <https://github.com/akretion/pyposdisplay>`__ if you use `pywebdriver <https://github.com/akretion/pywebdriver>`__. |
@ -0,0 +1,7 @@ |
|||
This module is designed to be installed on the *main Odoo server*. On the |
|||
*POSbox*, you should install the module *hw_customer_display*. But you will certainly prefer to use `pywebdriver <https://github.com/akretion/pywebdriver>`__ instead of the POSbox. Compared to the POSbox, Pywebdriver has several advantages: |
|||
|
|||
* smaller footprint: no need to have a full-blown Odoo with PostgreSQL on the computer of the cashier (or his small Linux-based PC connected to the hardware, like the RaspberryPi for the POSbox), |
|||
* availability of an Ubuntu package, for easier deployment, |
|||
* native support for the customer display, payment terminal, etc. |
|||
* nice test/diagnosis Web interface. |
@ -0,0 +1,9 @@ |
|||
Once everything is configured, just start the POS as usual. You will see messages on the LCD when: |
|||
|
|||
* you start the POS, |
|||
* you add or remove a product, |
|||
* you select or deselect a customer, |
|||
* you press the Payment button: the LCD will display the total amount, |
|||
* you enter the amount of cash you receive: the LCD will display the amount of the change to give back, |
|||
* you validate an order and go to the next customer, |
|||
* you close the POS. |
Before Width: 128 | Height: 128 | Size: 9.2 KiB After Width: 200 | Height: 200 | Size: 18 KiB |
@ -1,309 +0,0 @@ |
|||
/* |
|||
© 2014-2016 Aurélien DUMAINE |
|||
© 2014-2016 Barroux Abbey (www.barroux.org) |
|||
© 2014-2016 Akretion (www.akretion.com) |
|||
@author: Aurélien DUMAINE |
|||
@author: Alexis de Lattre <alexis.delattre@akretion.com> |
|||
@author: Father Odilon (Barroux Abbey) |
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|||
*/ |
|||
|
|||
odoo.define('pos_customer_display', function(require) { |
|||
"use strict"; |
|||
var chrome = require('point_of_sale.chrome'); |
|||
var core = require('web.core'); |
|||
var devices = require('point_of_sale.devices'); |
|||
var gui = require('point_of_sale.gui'); |
|||
var models = require('point_of_sale.models'); |
|||
var screens = require('point_of_sale.screens'); |
|||
var _t = core._t; |
|||
var PosModelSuper = models.PosModel; |
|||
|
|||
models.PosModel = models.PosModel.extend({ |
|||
prepare_text_customer_display: function(type, data){ |
|||
if (this.config.iface_customer_display != true) |
|||
return; |
|||
var line_length = this.config.customer_display_line_length || 20; |
|||
var currency_rounding = this.currency.decimals; |
|||
|
|||
if (type == 'add_update_line'){ |
|||
var line = data['line']; |
|||
var price_unit = line.get_unit_price(); |
|||
var discount = line.get_discount(); |
|||
if (discount) { |
|||
price_unit = price_unit * (1.0 - (discount / 100.0)); |
|||
} |
|||
price_unit = price_unit.toFixed(currency_rounding); |
|||
var qty = line.get_quantity(); |
|||
// only display decimals when qty is not an integer
|
|||
if (qty.toFixed(0) == qty) { |
|||
qty = qty.toFixed(0); |
|||
} |
|||
// only display unit when != Unit(s)
|
|||
var unit = line.get_unit(); |
|||
var unit_display = ''; |
|||
if (unit && !unit.is_unit) { |
|||
unit_display = unit.name; |
|||
} |
|||
var l21 = qty + unit_display + ' x ' + price_unit; |
|||
var l22 = ' ' + line.get_display_price().toFixed(currency_rounding); |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_left(line.get_product().display_name, line_length), |
|||
this.proxy.align_left(l21, line_length - l22.length) + l22 |
|||
); |
|||
|
|||
} else if (type == 'remove_orderline') { |
|||
// first click on the backspace button set the amount to 0 => we can't precise the deleted qunatity and price
|
|||
var line = data['line']; |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_left(_t("Delete Item"), line_length), |
|||
this.proxy.align_right(line.get_product().display_name, line_length) |
|||
); |
|||
|
|||
} else if (type == 'add_paymentline') { |
|||
var total = this.get('selectedOrder').get_total_with_tax().toFixed(currency_rounding); |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_left(_t("TOTAL: "), line_length), |
|||
this.proxy.align_right(total, line_length) |
|||
); |
|||
|
|||
} else if (type == 'remove_paymentline') { |
|||
var line = data['line']; |
|||
var amount = line.get_amount().toFixed(currency_rounding); |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_left(_t("Cancel Payment"), line_length), |
|||
this.proxy.align_right(line.cashregister.journal_id[1] , line_length - 1 - amount.length) + ' ' + amount |
|||
); |
|||
|
|||
} else if (type == 'update_payment') { |
|||
var change = data['change']; |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_left(_t("Your Change:"), line_length), |
|||
this.proxy.align_right(change, line_length) |
|||
); |
|||
|
|||
} else if (type == 'push_order') { |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_center(this.config.customer_display_msg_next_l1, line_length), |
|||
this.proxy.align_center(this.config.customer_display_msg_next_l2, line_length) |
|||
); |
|||
|
|||
} else if (type == 'openPOS') { |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_center(this.config.customer_display_msg_next_l1, line_length), |
|||
this.proxy.align_center(this.config.customer_display_msg_next_l2, line_length) |
|||
); |
|||
|
|||
} else if (type = 'closePOS') { |
|||
var lines_to_send = new Array( |
|||
this.proxy.align_center(this.config.customer_display_msg_closed_l1, line_length), |
|||
this.proxy.align_center(this.config.customer_display_msg_closed_l2, line_length) |
|||
); |
|||
} else { |
|||
console.warn('Unknown message type'); |
|||
return; |
|||
} |
|||
|
|||
this.proxy.send_text_customer_display(lines_to_send, line_length); |
|||
}, |
|||
|
|||
push_order: function(order){ |
|||
var res = PosModelSuper.prototype.push_order.call(this, order); |
|||
if (order) { |
|||
this.prepare_text_customer_display('push_order', {'order' : order}); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
devices.ProxyDevice = devices.ProxyDevice.extend({ |
|||
send_text_customer_display: function(data, line_length){ |
|||
//FIXME : this function is call twice. The first time, it is not called by prepare_text_customer_display : WHY ?
|
|||
if (_.isEmpty(data) || data.length != 2 || data[0].length != line_length || data[1].length != line_length){ |
|||
console.warn("send_text_customer_display: Bad Data argument. Data=" + data + ' line_length=' + line_length); |
|||
} else { |
|||
// alert(JSON.stringify(data));
|
|||
return this.message('send_text_customer_display', {'text_to_display' : JSON.stringify(data)}); |
|||
} |
|||
}, |
|||
|
|||
align_left: function(string, length){ |
|||
if (string) { |
|||
if (string.length > length) |
|||
{ |
|||
string = string.substring(0,length); |
|||
} |
|||
else if (string.length < length) |
|||
{ |
|||
while(string.length < length) |
|||
string = string + ' '; |
|||
} |
|||
} |
|||
else { |
|||
string = ' ' |
|||
while(string.length < length) |
|||
string = ' ' + string; |
|||
} |
|||
return string; |
|||
}, |
|||
|
|||
align_right: function(string, length){ |
|||
if (string) { |
|||
if (string.length > length) |
|||
{ |
|||
string = string.substring(0,length); |
|||
} |
|||
else if (string.length < length) |
|||
{ |
|||
while(string.length < length) |
|||
string = ' ' + string; |
|||
} |
|||
} |
|||
else { |
|||
string = ' ' |
|||
while(string.length < length) |
|||
string = ' ' + string; |
|||
} |
|||
return string; |
|||
}, |
|||
|
|||
align_center: function(string, length){ |
|||
if (string) { |
|||
if (string.length > length) |
|||
{ |
|||
string = string.substring(0, length); |
|||
} |
|||
else if (string.length < length) |
|||
{ |
|||
var ini = (length - string.length) / 2; |
|||
while(string.length < length - ini) |
|||
string = ' ' + string; |
|||
while(string.length < length) |
|||
string = string + ' '; |
|||
} |
|||
} |
|||
else { |
|||
string = ' ' |
|||
while(string.length < length) |
|||
string = ' ' + string; |
|||
} |
|||
return string; |
|||
}, |
|||
}); |
|||
|
|||
var OrderlineSuper = models.Orderline; |
|||
|
|||
models.Orderline = models.Orderline.extend({ |
|||
/* set_quantity() is called when you force the qty via the dedicated button |
|||
AND when you create a new order line via add_product(). |
|||
So, when you add a product, we call prepare_text_customer_display() twice... |
|||
but I haven't found any good solution to avoid this -- Alexis */ |
|||
set_quantity: function(quantity){ |
|||
var res = OrderlineSuper.prototype.set_quantity.call(this, quantity); |
|||
if (quantity != 'remove') { |
|||
var line = this; |
|||
if(this.selected){ |
|||
this.pos.prepare_text_customer_display('add_update_line', {'line': line}); |
|||
} |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
set_discount: function(discount){ |
|||
var res = OrderlineSuper.prototype.set_discount.call(this, discount); |
|||
if (discount) { |
|||
var line = this; |
|||
if(this.selected){ |
|||
this.pos.prepare_text_customer_display('add_update_line', {'line': line}); |
|||
} |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
set_unit_price: function(price){ |
|||
var res = OrderlineSuper.prototype.set_unit_price.call(this, price); |
|||
var line = this; |
|||
if(this.selected){ |
|||
this.pos.prepare_text_customer_display('add_update_line', {'line': line}); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
var OrderSuper = models.Order; |
|||
|
|||
models.Order = models.Order.extend({ |
|||
add_product: function(product, options){ |
|||
var res = OrderSuper.prototype.add_product.call(this, product, options); |
|||
if (product) { |
|||
var line = this.get_last_orderline(); |
|||
this.pos.prepare_text_customer_display('add_update_line', {'line' : line}); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
remove_orderline: function(line){ |
|||
if (line) { |
|||
this.pos.prepare_text_customer_display('remove_orderline', {'line' : line}); |
|||
} |
|||
return OrderSuper.prototype.remove_orderline.call(this, line); |
|||
}, |
|||
|
|||
remove_paymentline: function(line){ |
|||
if (line) { |
|||
this.pos.prepare_text_customer_display('remove_paymentline', {'line' : line}); |
|||
} |
|||
return OrderSuper.prototype.remove_paymentline.call(this, line); |
|||
}, |
|||
|
|||
add_paymentline: function(cashregister){ |
|||
var res = OrderSuper.prototype.add_paymentline.call(this, cashregister); |
|||
if (cashregister) { |
|||
this.pos.prepare_text_customer_display('add_paymentline', {'cashregister' : cashregister}); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
screens.PaymentScreenWidget.include({ |
|||
render_paymentlines: function(){ |
|||
var res = this._super(); |
|||
var currentOrder = this.pos.get_order(); |
|||
if (currentOrder) { |
|||
var paidTotal = currentOrder.get_total_paid(); |
|||
var dueTotal = currentOrder.get_total_with_tax(); |
|||
var change = paidTotal > dueTotal ? paidTotal - dueTotal : 0; |
|||
if (change) { |
|||
var change_rounded = change.toFixed(2); |
|||
this.pos.prepare_text_customer_display('update_payment', {'change': change_rounded}); |
|||
} |
|||
} |
|||
return res; |
|||
}, |
|||
}); |
|||
|
|||
gui.Gui.include({ |
|||
close: function(){ |
|||
this._super(); |
|||
this.pos.prepare_text_customer_display('closePOS', {}); |
|||
}, |
|||
}); |
|||
|
|||
chrome.ProxyStatusWidget.include({ |
|||
start: function(){ |
|||
this._super(); |
|||
this.pos.prepare_text_customer_display('openPOS', {}); |
|||
}, |
|||
}); |
|||
|
|||
screens.PaymentScreenWidget.include({ |
|||
show: function(){ |
|||
this._super(); |
|||
this.pos.prepare_text_customer_display('add_paymentline', {}); |
|||
}, |
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,111 @@ |
|||
/* |
|||
Copyright (C) 2015-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
|
|||
odoo.define('pos_customer_display.customer_display_2_20', function (require) { |
|||
"use strict"; |
|||
|
|||
var core = require('web.core'); |
|||
var _t = core._t; |
|||
|
|||
var CustomerDisplay_2_20 = function(proxy_device){ |
|||
this.pos = proxy_device.pos; |
|||
this._prepare_line = proxy_device._prepare_line; |
|||
|
|||
this._prepare_message_welcome = function(){ |
|||
return new Array( |
|||
this._prepare_line(this.pos.config.customer_display_msg_next_l1, ""), |
|||
this._prepare_line(this.pos.config.customer_display_msg_next_l2, ""), |
|||
); |
|||
}; |
|||
|
|||
this._prepare_message_close = function(){ |
|||
return new Array( |
|||
this._prepare_line(this.pos.config.customer_display_msg_closed_l1, ""), |
|||
this._prepare_line(this.pos.config.customer_display_msg_closed_l2, ""), |
|||
); |
|||
}; |
|||
|
|||
this._prepare_message_orderline = function(order_line, action){ |
|||
var currency_rounding = this.pos.currency.decimals; |
|||
|
|||
var product_name = order_line.product.display_name; |
|||
var unit_price_str = order_line.get_unit_price().toFixed(currency_rounding); |
|||
var total_amount_str = order_line.get_display_price().toFixed(currency_rounding); |
|||
var qty = order_line.get_quantity(); |
|||
// only display decimals when qty is not an integer
|
|||
if (qty.toFixed(0) == qty) { |
|||
qty = qty.toFixed(0); |
|||
} |
|||
var discount = order_line.get_discount(); |
|||
var discount_str = ""; |
|||
if ([ |
|||
'add_line', |
|||
'update_quantity', |
|||
'update_unit_price', |
|||
'update_discount', |
|||
].indexOf(action) !== -1){ |
|||
var second_line = String(qty) + " * " + unit_price_str; |
|||
if (discount){ |
|||
discount_str = " -" + String(discount) + "%"; |
|||
} |
|||
return new Array( |
|||
this._prepare_line(product_name, discount_str), |
|||
this._prepare_line(second_line, total_amount_str), |
|||
); |
|||
} else if (action === 'delete_line'){ |
|||
return new Array( |
|||
this._prepare_line(_t("Deleting Line ..."), ""), |
|||
this._prepare_line(order_line.product.display_name, ""), |
|||
); |
|||
} |
|||
}; |
|||
|
|||
this._prepare_message_payment = function(action){ |
|||
var currency_rounding = this.pos.currency.decimals; |
|||
var order = this.pos.get_order() |
|||
var total = order.get_total_with_tax().toFixed(currency_rounding); |
|||
var total_paid = order.get_total_paid().toFixed(currency_rounding); |
|||
var total_change = order.get_due().toFixed(currency_rounding); |
|||
var total_to_pay = (total - total_paid).toFixed(currency_rounding); |
|||
|
|||
var remaining_operation_str = ""; |
|||
|
|||
if (total_paid != 0) { |
|||
if (total_to_pay > 0) { |
|||
remaining_operation_str = _t("To Pay: ") + String(total_to_pay); |
|||
} else if (total_change < 0) { |
|||
remaining_operation_str = _t("Returned: ") + String(- total_change); |
|||
} |
|||
} |
|||
|
|||
return new Array( |
|||
this._prepare_line(_t("Total"), String(total)), |
|||
this._prepare_line(remaining_operation_str, ""), |
|||
); |
|||
}; |
|||
|
|||
this._prepare_message_client = function(client){ |
|||
if ( client ) { |
|||
return new Array( |
|||
this._prepare_line(_t("Customer Account"), ""), |
|||
this._prepare_line(client.name, ""), |
|||
); |
|||
} else { |
|||
return new Array( |
|||
this._prepare_line(_t("No Customer Account"), ""), |
|||
this._prepare_line("", ""), |
|||
); |
|||
} |
|||
}; |
|||
|
|||
}; |
|||
|
|||
return { |
|||
CustomerDisplay_2_20: CustomerDisplay_2_20, |
|||
}; |
|||
|
|||
}); |
@ -0,0 +1,90 @@ |
|||
/* |
|||
Copyright (C) 2015-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
|
|||
odoo.define('pos_customer_display.devices', function (require) { |
|||
"use strict"; |
|||
|
|||
var devices = require('point_of_sale.devices'); |
|||
|
|||
var customer_display_2_20 = require('pos_customer_display.customer_display_2_20'); |
|||
|
|||
var ProxyDeviceSuper = devices.ProxyDevice; |
|||
|
|||
devices.ProxyDevice = devices.ProxyDevice.extend({ |
|||
|
|||
|
|||
init: function(parent, options){ |
|||
var res = ProxyDeviceSuper.prototype.init.call(this, parent, options); |
|||
this.customer_display_proxy = false; |
|||
return res; |
|||
}, |
|||
|
|||
load_customer_display_format_file: function(){ |
|||
// console.log(this.config.customer_display_format);
|
|||
if (this.pos.config.customer_display_format == "2_20") { |
|||
this.customer_display_proxy = new customer_display_2_20.CustomerDisplay_2_20(this); |
|||
} else { |
|||
console.warn("No Javascript file found for the Customer Display format" + this.config.customer_display_format); |
|||
} |
|||
}, |
|||
|
|||
send_text_customer_display: function(data){ |
|||
console.log(data); |
|||
if (this.customer_display_proxy) { |
|||
return this.message( |
|||
'send_text_customer_display', |
|||
{'text_to_display' : JSON.stringify(data)} |
|||
); |
|||
} |
|||
}, |
|||
|
|||
_prepare_line: function(left_part, right_part){ |
|||
var line_length = this.pos.config.customer_display_line_length; |
|||
var max_left_length = line_length; |
|||
if (right_part.length !== 0) { |
|||
max_left_length -= right_part.length; |
|||
} |
|||
var result = left_part.substring(0, max_left_length - 1); |
|||
result = result.padEnd(max_left_length); |
|||
if (right_part.length !== 0) { |
|||
result += right_part.padStart(line_length - result.length); |
|||
} |
|||
return result; |
|||
}, |
|||
|
|||
prepare_message_orderline: function(order_line, action){ |
|||
if (this.customer_display_proxy) { |
|||
return this.customer_display_proxy._prepare_message_orderline(order_line, action); |
|||
} |
|||
}, |
|||
|
|||
prepare_message_payment: function(action){ |
|||
if (this.customer_display_proxy) { |
|||
return this.customer_display_proxy._prepare_message_payment(action); |
|||
} |
|||
}, |
|||
|
|||
prepare_message_welcome: function(){ |
|||
if (this.customer_display_proxy) { |
|||
return this.customer_display_proxy._prepare_message_welcome(); |
|||
} |
|||
}, |
|||
|
|||
prepare_message_close: function(){ |
|||
if (this.customer_display_proxy) { |
|||
return this.customer_display_proxy._prepare_message_close(); |
|||
} |
|||
}, |
|||
|
|||
prepare_message_client: function(client){ |
|||
if (this.customer_display_proxy) { |
|||
return this.customer_display_proxy._prepare_message_client(client); |
|||
} |
|||
} |
|||
|
|||
}); |
|||
}); |
@ -0,0 +1,24 @@ |
|||
/* |
|||
Copyright (C) 2020-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
|
|||
odoo.define('pos_customer_display.gui', function (require) { |
|||
"use strict"; |
|||
|
|||
var gui = require('point_of_sale.gui'); |
|||
|
|||
gui.Gui.include({ |
|||
|
|||
close: function(){ |
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_closed() |
|||
); |
|||
return this._super(); |
|||
}, |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,128 @@ |
|||
/* |
|||
Copyright (C) 2015-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
odoo.define('pos_customer_display.models', function (require) { |
|||
"use strict"; |
|||
|
|||
var models = require('point_of_sale.models'); |
|||
var OrderSuper = models.Order; |
|||
var OrderlineSuper = models.Orderline; |
|||
var PosModelSuper = models.PosModel; |
|||
|
|||
// //////////////////////////////////
|
|||
// Overload models.PosModel
|
|||
// //////////////////////////////////
|
|||
models.PosModel = models.PosModel.extend({ |
|||
|
|||
initialize: function(session, attributes) { |
|||
var res = PosModelSuper.prototype.initialize.call(this, session, attributes); |
|||
// send_message_customer_display is a variable that allow
|
|||
// to disable the send of the message to the customer display
|
|||
// This desing is due to the current design of Odoo PoS.
|
|||
// 1) during the call_of_init_from_JSON, a call to
|
|||
// add_product and remove_orderline is done.
|
|||
// 2) during the call of add_product, a call
|
|||
// to set_price, set_discount, set_quantity is done.
|
|||
// To avoid multiple useless messages sends.
|
|||
// it fixed this @via-alexis comment:
|
|||
// https://github.com/OCA/pos/blob/10.0/pos_customer_display/
|
|||
// static/src/js/customer_display.js#L198
|
|||
this.send_message_customer_display = true; |
|||
return res; |
|||
}, |
|||
|
|||
after_load_server_data: function(){ |
|||
this.proxy.load_customer_display_format_file(); |
|||
return PosModelSuper.prototype.after_load_server_data.call(this); |
|||
}, |
|||
}); |
|||
|
|||
|
|||
// //////////////////////////////////
|
|||
// Overload models.Order
|
|||
// //////////////////////////////////
|
|||
models.Order = models.Order.extend({ |
|||
|
|||
init_from_JSON: function(json) { |
|||
this.pos.send_message_customer_display = false; |
|||
var res = OrderSuper.prototype.init_from_JSON.call(this, json); |
|||
this.pos.send_message_customer_display = true; |
|||
return res; |
|||
}, |
|||
|
|||
add_product: function(product, options){ |
|||
var send_message = this.pos.send_message_customer_display; |
|||
this.pos.send_message_customer_display = false; |
|||
var res = OrderSuper.prototype.add_product.call(this, product, options); |
|||
if (send_message){ |
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_orderline( |
|||
this.get_last_orderline(), 'add_line')); |
|||
this.pos.send_message_customer_display = true; |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
//////////////////////////////////
|
|||
// Overload models.Orderline
|
|||
//////////////////////////////////
|
|||
models.Orderline = models.Orderline.extend({ |
|||
|
|||
set_quantity: function(quantity, keep_price){ |
|||
var send_message = this.pos.send_message_customer_display; |
|||
var message; |
|||
this.pos.send_message_customer_display = false; |
|||
|
|||
// In the current Odoo design, set_quantity is call to remove line
|
|||
// so we prepare the message before because after the call
|
|||
// of super, the line is delete.
|
|||
if (send_message){ |
|||
if (quantity === 'remove') { |
|||
message = this.pos.proxy.prepare_message_orderline(this, 'delete_line'); |
|||
} |
|||
} |
|||
var res = OrderlineSuper.prototype.set_quantity.call(this, quantity, keep_price); |
|||
if (send_message) { |
|||
if (quantity !== 'remove'){ |
|||
message = this.pos.proxy.prepare_message_orderline(this, 'update_quantity'); |
|||
} |
|||
this.pos.send_message_customer_display = true; |
|||
this.pos.proxy.send_text_customer_display(message); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
set_discount: function(discount){ |
|||
var send_message = this.pos.send_message_customer_display; |
|||
this.pos.send_message_customer_display = false; |
|||
|
|||
var res = OrderlineSuper.prototype.set_discount.call(this, discount); |
|||
if (send_message) { |
|||
this.pos.send_message_customer_display = true; |
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_orderline(this, 'update_discount')); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
set_unit_price: function(price){ |
|||
var send_message = this.pos.send_message_customer_display; |
|||
this.pos.send_message_customer_display = false; |
|||
|
|||
var res = OrderlineSuper.prototype.set_unit_price.call(this, price); |
|||
if (send_message) { |
|||
this.pos.send_message_customer_display = true; |
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_orderline(this, 'update_unit_price')); |
|||
} |
|||
return res; |
|||
}, |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,51 @@ |
|||
/* |
|||
Copyright (C) 2015-Today GRAP (http://www.grap.coop)
|
|||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
|||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
*/ |
|||
|
|||
odoo.define('pos_customer_display.screens', function (require) { |
|||
"use strict"; |
|||
|
|||
var screens = require('point_of_sale.screens'); |
|||
|
|||
screens.PaymentScreenWidget.include({ |
|||
|
|||
render_paymentlines: function() { |
|||
if (this.pos.get_order().get_total_with_tax() === 0) { |
|||
// Render payment is called each time a new order is created
|
|||
// (and so when lauching the PoS)
|
|||
// in that case, we display the welcome message
|
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_welcome() |
|||
); |
|||
} else { |
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_payment() |
|||
); |
|||
} |
|||
return this._super(); |
|||
}, |
|||
|
|||
}); |
|||
|
|||
screens.ClientListScreenWidget.include({ |
|||
|
|||
save_changes: function(){ |
|||
if(this.has_client_changed()){ |
|||
this.pos.proxy.send_text_customer_display( |
|||
this.pos.proxy.prepare_message_client(this.new_client) |
|||
); |
|||
} |
|||
// we disable the send of message, during the call of _super()
|
|||
// because when selecting customer, all lines are recomputed
|
|||
// and so a message is sent for each lines
|
|||
// causing useless flashes
|
|||
this.pos.send_message_customer_display = false; |
|||
var res = this._super(); |
|||
this.pos.send_message_customer_display = true; |
|||
return res; |
|||
}, |
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,14 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<template id="assets" inherit_id="point_of_sale.assets"> |
|||
<xpath expr="." position="inside"> |
|||
<script type="text/javascript" src="/pos_customer_display/static/src/js/models.js" /> |
|||
<script type="text/javascript" src="/pos_customer_display/static/src/js/screens.js" /> |
|||
<script type="text/javascript" src="/pos_customer_display/static/src/js/gui.js" /> |
|||
<script type="text/javascript" src="/pos_customer_display/static/src/js/devices.js" /> |
|||
<script type="text/javascript" src="/pos_customer_display/static/src/js/customer_display_2_20.js" /> |
|||
</xpath> |
|||
</template> |
|||
|
|||
</odoo> |
@ -1,26 +0,0 @@ |
|||
<?xml version="1.0"?> |
|||
<odoo> |
|||
|
|||
<record id="view_pos_config_form" model="ir.ui.view"> |
|||
<field name="name">pos_customer_display.pos.config.form</field> |
|||
<field name="model">pos.config</field> |
|||
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"/> |
|||
<field name="arch" type="xml"> |
|||
<field name="iface_cashdrawer" position="after"> |
|||
<field name="iface_customer_display"/> |
|||
<field name="customer_display_line_length"/> |
|||
</field> |
|||
<group name="receipt" position="after"> |
|||
<group name="customer_display" string="Customer Display"> |
|||
<label string="Next Customer Message" name="next_customer" colspan="2"/> |
|||
<field name="customer_display_msg_next_l1" string="Top Line"/> |
|||
<field name="customer_display_msg_next_l2" string="Bottom Line"/> |
|||
<label string="POS Closed Message" name="pos_closed" colspan="2"/> |
|||
<field name="customer_display_msg_closed_l1" string="Top Line"/> |
|||
<field name="customer_display_msg_closed_l2" string="Bottom Line"/> |
|||
</group> |
|||
</group> |
|||
</field> |
|||
</record> |
|||
|
|||
</odoo> |
@ -1,10 +0,0 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<template id="assets" name="pos_customer_display assets" inherit_id="point_of_sale.assets"> |
|||
<xpath expr="." position="inside"> |
|||
<script type="text/javascript" src="/pos_customer_display/static/src/js/customer_display.js"></script> |
|||
</xpath> |
|||
</template> |
|||
|
|||
</odoo> |
@ -0,0 +1,41 @@ |
|||
<?xml version="1.0"?> |
|||
<odoo> |
|||
|
|||
<record id="view_pos_config_form" model="ir.ui.view"> |
|||
<field name="model">pos.config</field> |
|||
<field name="inherit_id" ref="point_of_sale.pos_config_view_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='iface_cashdrawer']/.." position="after"> |
|||
<div class="row"> |
|||
<label string="LED Customer Display" for="iface_customer_display" class="col-lg-3 o_light_label"/> |
|||
<field name="iface_customer_display"/> |
|||
</div> |
|||
|
|||
<div class="row" attrs="{'invisible': [('iface_customer_display', '=', False)]}"> |
|||
<label string="Line Length" for="customer_display_line_length" class="col-lg-3 o_light_label"/> |
|||
<field name="customer_display_line_length"/> |
|||
</div> |
|||
|
|||
<div class="row" attrs="{'invisible': [('iface_customer_display', '=', False)]}"> |
|||
<label string="Next Customer (Line 1)" for="customer_display_msg_next_l1" class="col-lg-3 o_light_label"/> |
|||
<field name="customer_display_msg_next_l1"/> |
|||
</div> |
|||
<div class="row" attrs="{'invisible': [('iface_customer_display', '=', False)]}"> |
|||
<label string="Next Customer (Line 2)" for="customer_display_msg_next_l2" class="col-lg-3 o_light_label"/> |
|||
<field name="customer_display_msg_next_l2"/> |
|||
</div> |
|||
|
|||
<div class="row" attrs="{'invisible': [('iface_customer_display', '=', False)]}"> |
|||
<label string="PoS Closed (Line 1)" for="customer_display_msg_closed_l1" class="col-lg-3 o_light_label"/> |
|||
<field name="customer_display_msg_closed_l1"/> |
|||
</div> |
|||
<div class="row" attrs="{'invisible': [('iface_customer_display', '=', False)]}"> |
|||
<label string="Pos Closed (Line 2)" for="customer_display_msg_closed_l2" class="col-lg-3 o_light_label"/> |
|||
<field name="customer_display_msg_closed_l2"/> |
|||
</div> |
|||
|
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
|
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue