Skip to content

Commit

Permalink
[ADD] pos_odoo_driver_display
Browse files Browse the repository at this point in the history
  • Loading branch information
legalsylvain committed Sep 10, 2024
1 parent d532352 commit 9abc5a8
Show file tree
Hide file tree
Showing 24 changed files with 563 additions and 0 deletions.
Empty file.
1 change: 1 addition & 0 deletions pos_odoo_driver_display/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
25 changes: 25 additions & 0 deletions pos_odoo_driver_display/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (C) 2024 - 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).

{
"name": "Point of Sale - LED Customer Display (odoo-pos-driver)",
"version": "16.0.1.0.0",
"category": "Point Of Sale",
"summary": "Communicate with LEC Customer Display via odoo-pos-driver library",
"author": "GRAP",
"website": "https://github.com/grap/odoo-addons-pos",
"license": "AGPL-3",
"depends": ["point_of_sale"],
"assets": {
"point_of_sale.assets": [
"pos_odoo_driver_display/static/src/js/devices.esm.js",
"pos_odoo_driver_display/static/src/js/ProxyStatus.esm.js",
"pos_odoo_driver_display/static/src/js/models.esm.js",
"pos_odoo_driver_display/static/src/js/Chrome.esm.js",
"pos_odoo_driver_display/static/src/js/PaymentScreen.esm.js",
],
},
"data": ["views/view_pos_config.xml"],
"installable": True,
}
Empty file.
3 changes: 3 additions & 0 deletions pos_odoo_driver_display/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import pos_config
from . import res_config_settings
from . import pos_session
101 changes: 101 additions & 0 deletions pos_odoo_driver_display/models/pos_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# © 2014-2016 Aurélien DUMAINE
# © 2015-2016 Akretion (Alexis de Lattre <[email protected]>)
# 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,
default="2_20",
required=True,
)

customer_display_line_length = fields.Integer(
string="Line Length",
compute="_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_l2"),
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

Check warning on line 85 in pos_odoo_driver_display/models/pos_config.py

View check run for this annotation

Codecov / codecov/patch

pos_odoo_driver_display/models/pos_config.py#L85

Added line #L85 was not covered by tests
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)

Check warning on line 90 in pos_odoo_driver_display/models/pos_config.py

View check run for this annotation

Codecov / codecov/patch

pos_odoo_driver_display/models/pos_config.py#L90

Added line #L90 was not covered by tests
if value and len(value) > maxsize:
raise ValidationError(

Check warning on line 92 in pos_odoo_driver_display/models/pos_config.py

View check run for this annotation

Codecov / codecov/patch

pos_odoo_driver_display/models/pos_config.py#L92

Added line #L92 was not covered by tests
_(
"The message for customer display '%(field_name)s' is too "
"long: it has %(current_size)d chars whereas the maximum "
"is %(maxsize)d chars.",
field_name=self._fields[field_name].string,
current_size=len(value),
maxsize=maxsize,
)
)
16 changes: 16 additions & 0 deletions pos_odoo_driver_display/models/pos_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (C) 2024 - 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).

from odoo import models


class PosSession(models.Model):
_inherit = "pos.session"

def _get_pos_ui_pos_config(self, params):
config = super()._get_pos_ui_pos_config(params)
config["use_proxy"] = config["use_proxy"] or (

Check warning on line 13 in pos_odoo_driver_display/models/pos_session.py

View check run for this annotation

Codecov / codecov/patch

pos_odoo_driver_display/models/pos_session.py#L12-L13

Added lines #L12 - L13 were not covered by tests
config["is_posbox"] and config["iface_customer_display"]
)
return config

Check warning on line 16 in pos_odoo_driver_display/models/pos_session.py

View check run for this annotation

Codecov / codecov/patch

pos_odoo_driver_display/models/pos_session.py#L16

Added line #L16 was not covered by tests
30 changes: 30 additions & 0 deletions pos_odoo_driver_display/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (C) 2024 - 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).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

pos_iface_customer_display = fields.Boolean(
related="pos_config_id.iface_customer_display", readonly=False
)
pos_customer_display_format = fields.Selection(
related="pos_config_id.customer_display_format",
readonly=False,
required=True,
)
pos_customer_display_msg_next_l1 = fields.Char(
related="pos_config_id.customer_display_msg_next_l1", readonly=False
)
pos_customer_display_msg_next_l2 = fields.Char(
related="pos_config_id.customer_display_msg_next_l2", readonly=False
)
pos_customer_display_msg_closed_l1 = fields.Char(
related="pos_config_id.customer_display_msg_closed_l1", readonly=False
)
pos_customer_display_msg_closed_l2 = fields.Char(
related="pos_config_id.customer_display_msg_closed_l2", readonly=False
)
10 changes: 10 additions & 0 deletions pos_odoo_driver_display/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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 LED:

* In the IotBox section, activate the option *LED Customer Display*,
* configure the format of your LED screen. (2 lines of 20 characters, by default)

* optionaly, you can customize the *Next customer* message and the *POS closed* message

.. figure:: ../static/img/pos_config_form.png
7 changes: 7 additions & 0 deletions pos_odoo_driver_display/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module is a full refactor of the OCA V12 module ``pos_customer_display``.
Original authors and ideas are:

* Aurélien Dumaine
* Alexis de Lattre <[email protected]>
* Father Odilon (`Barroux Abbey <http://www.barroux.org/>`_)
* Daniel Kraft
Empty file.
30 changes: 30 additions & 0 deletions pos_odoo_driver_display/readme/USAGE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Once everything is configured, just start the POS as usual.
You will see the following messages on the device, depending
on the events.

'Welcome' message
~~~~~~~~~~~~~~~~~

* when cashier starts the PoS
* when cashier creates a new empty PoS Order

'Close' message
~~~~~~~~~~~~~~~

* when cashier Closes the PoS

'Order Line' message
~~~~~~~~~~~~~~~~~~~~

* when cashier adds a product
* when cashier changes the Unit Price, the discount or the quantity

'Product Removal' message
~~~~~~~~~~~~~~~~~~~~~~~~~

* when cashier removes an order line


* you press the Payment button: the device will display the total amount,
* you enter the amount of cash you receive: the device will display the amount of the change to give back,
* you close the POS.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions pos_odoo_driver_display/static/src/js/Chrome.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2024 - 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_odoo_driver_display.Chrome", function (require) {
const Chrome = require("point_of_sale.Chrome");
const Registries = require("point_of_sale.Registries");

const OverloadChrome = (OriginalChrome) =>
class extends OriginalChrome {
async start() {
await super.start();
this.env.proxy.customer_display_send_welcome_message();
}

async _closePos() {
await super._closePos();
this.env.proxy.customer_display_send_close_message();
}
};

Registries.Component.extend(Chrome, OverloadChrome);

return Chrome;
});
26 changes: 26 additions & 0 deletions pos_odoo_driver_display/static/src/js/PaymentScreen.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2024 - 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_odoo_driver_display.PaymentScreen", function (require) {
const {onRendered} = owl;
const PaymentScreen = require("point_of_sale.PaymentScreen");
const Registries = require("point_of_sale.Registries");

const OverloadPaymentScreen = (OriginalPaymentScreen) =>
class extends OriginalPaymentScreen {

setup() {
var self = this;
super.setup();

onRendered(() => {
self.env.proxy.customer_display_send_payment(self.currentOrder);
});
}

};

Registries.Component.extend(PaymentScreen, OverloadPaymentScreen);
return PaymentScreen;
});
37 changes: 37 additions & 0 deletions pos_odoo_driver_display/static/src/js/ProxyStatus.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (C) 2024 - 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_odoo_driver_display.ProxyStatus", function (require) {
var Registries = require("point_of_sale.Registries");
var ProxyStatus = require("point_of_sale.ProxyStatus");

const OverloadProxyStatus = (OriginalProxyStatus) =>
class extends OriginalProxyStatus {
_setStatus(newStatus) {
super._setStatus(newStatus);
if (
newStatus.status === "connected" &&
this.env.pos.config.iface_customer_display
) {
var displayStatus = newStatus.drivers.display
? newStatus.drivers.display.status
: false;
if (
displayStatus !== "connected" &&
displayStatus !== "connecting"
) {
if (this.state.msg) {
this.state.msg =
this.env._t("Display") + " & " + this.state.msg;
} else {
this.state.msg = this.env._t("Display Offline");
this.state.status = "warning";
}
}
}
}
};

Registries.Component.extend(ProxyStatus, OverloadProxyStatus);
});
53 changes: 53 additions & 0 deletions pos_odoo_driver_display/static/src/js/devices.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (C) 2024 - 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_odoo_driver_display.devices", function (require) {
var ProxyDevice = require("point_of_sale.devices").ProxyDevice;

ProxyDevice.include({
customer_display_send_welcome_message() {
this._customer_display_send_text([
this.pos.config.customer_display_msg_next_l1,
this.pos.config.customer_display_msg_next_l2,
]);
},

customer_display_send_close_message() {
this._customer_display_send_text([
this.pos.config.customer_display_msg_closed_l1,
this.pos.config.customer_display_msg_closed_l2,
]);
},

_customer_display_send_text: function (text_lines) {
var data = {
text_lines: text_lines,
action: "display_lines",
};
this.message("display_show", {data: JSON.stringify(data)});
},

customer_display_send_payment: function (order) {
var data = {
total: order.get_total_with_tax(),
total_paid: order.get_total_paid(),
total_due: order.get_due(),
action: "payment_balance",
};
this.message("display_show", {data: JSON.stringify(data)});
},

customer_display_send_order_line: function (orderline, action) {
var data = {
product_name: orderline.product.display_name,
quantity: orderline.quantity,
discount: orderline.discount,
unit_price: orderline.get_unit_price(),
total: orderline.get_display_price(),
action: action,
};
this.message("display_show", {data: JSON.stringify(data)});
},
});
});
Loading

0 comments on commit 9abc5a8

Please sign in to comment.