diff --git a/pos_odoo_driver_device_list/README.rst b/pos_odoo_driver_device_list/README.rst
new file mode 100644
index 0000000..e69de29
diff --git a/pos_odoo_driver_device_list/__init__.py b/pos_odoo_driver_device_list/__init__.py
new file mode 100644
index 0000000..0650744
--- /dev/null
+++ b/pos_odoo_driver_device_list/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/pos_odoo_driver_device_list/__manifest__.py b/pos_odoo_driver_device_list/__manifest__.py
new file mode 100644
index 0000000..efded3e
--- /dev/null
+++ b/pos_odoo_driver_device_list/__manifest__.py
@@ -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 - Devices List (odoo-pos-driver)",
+ "version": "16.0.1.0.0",
+ "category": "Point Of Sale",
+ "summary": "Get devices information from 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_device_list/static/src/js/devices.esm.js",
+ ],
+ },
+ "data": [
+ "security/ir.model.access.csv",
+ "security/ir_rule.xml",
+ "views/view_pos_device.xml",
+ ],
+ "installable": True,
+}
diff --git a/pos_odoo_driver_device_list/i18n/fr.po b/pos_odoo_driver_device_list/i18n/fr.po
new file mode 100644
index 0000000..6180a5a
--- /dev/null
+++ b/pos_odoo_driver_device_list/i18n/fr.po
@@ -0,0 +1,141 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * pos_odoo_driver_device_list
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 16.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-09-14 13:15+0000\n"
+"PO-Revision-Date: 2024-09-14 13:15+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__company_id
+msgid "Company"
+msgstr "Société"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__config_id
+msgid "Config"
+msgstr "Point de vente"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__create_uid
+msgid "Created by"
+msgstr "Créé par"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__create_date
+msgid "Created on"
+msgstr "Créé le"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields.selection,name:pos_odoo_driver_device_list.selection__pos_device__device_type__display
+msgid "Customer Display"
+msgstr "Afficheur client"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_config__device_ids
+msgid "Device"
+msgstr "Périphérique"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__device_type
+msgid "Device Type"
+msgstr "Type de périphérique"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__display_name
+msgid "Display Name"
+msgstr "Nom complet"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__id
+msgid "ID"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__last_connexion_date
+msgid "Last Connexion Date"
+msgstr "Date de dernière connexion"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device____last_update
+msgid "Last Modified on"
+msgstr "Dernière mise à jour le"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__write_uid
+msgid "Last Updated by"
+msgstr "Dernière mise à jour par"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__write_date
+msgid "Last Updated on"
+msgstr "Dernière mise à jour le"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__manufacturer
+msgid "Manufacturer"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__name
+msgid "Name"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields.selection,name:pos_odoo_driver_device_list.selection__pos_device__device_type__payment
+msgid "Payment Terminal"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.ui.menu,name:pos_odoo_driver_device_list.menu_pos_device
+msgid "PoS Devices"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model,name:pos_odoo_driver_device_list.model_pos_config
+msgid "Point of Sale Configuration"
+msgstr "Configuration du point de vente"
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model,name:pos_odoo_driver_device_list.model_pos_device
+msgid "Point of Sale Devices"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.actions.act_window,name:pos_odoo_driver_device_list.action_pos_device
+msgid "Pos Devices"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields.selection,name:pos_odoo_driver_device_list.selection__pos_device__device_type__printer
+msgid "Printer"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__product_name
+msgid "Product Name"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields.selection,name:pos_odoo_driver_device_list.selection__pos_device__device_type__scale
+msgid "Scale"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__serial_number
+msgid "Serial Number"
+msgstr ""
+
+#. module: pos_odoo_driver_device_list
+#: model:ir.model.fields,field_description:pos_odoo_driver_device_list.field_pos_device__vendor_product_code
+msgid "Vendor Product Code"
+msgstr ""
diff --git a/pos_odoo_driver_device_list/models/__init__.py b/pos_odoo_driver_device_list/models/__init__.py
new file mode 100644
index 0000000..9044dab
--- /dev/null
+++ b/pos_odoo_driver_device_list/models/__init__.py
@@ -0,0 +1,2 @@
+from . import pos_config
+from . import pos_device
diff --git a/pos_odoo_driver_device_list/models/pos_config.py b/pos_odoo_driver_device_list/models/pos_config.py
new file mode 100644
index 0000000..e115bd0
--- /dev/null
+++ b/pos_odoo_driver_device_list/models/pos_config.py
@@ -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).
+
+from datetime import datetime
+
+from odoo import api, fields, models
+
+
+class PosConfig(models.Model):
+ _inherit = "pos.config"
+
+ device_ids = fields.One2many(comodel_name="pos.device", inverse_name="config_id")
+
+ @api.model
+ def update_pos_device(self, config_id, changes):
+ PosDevice = self.env["pos.device"]
+ for device_type, device_info in changes.items():
+ existing_device = PosDevice.search(
+ [
+ ("config_id", "=", config_id),
+ ("device_type", "=", device_type),
+ ("name", "=", device_info.get("device_name", False)),
+ ("product_name", "=", device_info.get("product_name", False)),
+ ("manufacturer", "=", device_info.get("manufacturer", False)),
+ ("serial_number", "=", device_info.get("serial_number", False)),
+ (
+ "vendor_product_code",
+ "=",
+ device_info.get("vendor_product_code", False),
+ ),
+ ],
+ limit=1,
+ order="last_connexion_date desc",
+ )
+ if existing_device:
+ existing_device.write({"last_connexion_date": datetime.now()})
+ else:
+ PosDevice.create(
+ {
+ "config_id": config_id,
+ "device_type": device_type,
+ "name": device_info.get("device_name", False),
+ "product_name": device_info.get("product_name", False),
+ "manufacturer": device_info.get("manufacturer", False),
+ "serial_number": device_info.get("serial_number", False),
+ "vendor_product_code": device_info.get(
+ "vendor_product_code", False
+ ),
+ "last_connexion_date": datetime.now(),
+ }
+ )
+ return True
diff --git a/pos_odoo_driver_device_list/models/pos_device.py b/pos_odoo_driver_device_list/models/pos_device.py
new file mode 100644
index 0000000..43b0243
--- /dev/null
+++ b/pos_odoo_driver_device_list/models/pos_device.py
@@ -0,0 +1,39 @@
+# 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 PosDevice(models.Model):
+ _name = "pos.device"
+ _description = "Point of Sale Devices"
+ _order = "last_connexion_date desc, name"
+
+ device_type = fields.Selection(
+ selection=[
+ ("display", "Customer Display"),
+ ("payment", "Payment Terminal"),
+ ("scale", "Scale"),
+ ("printer", "Printer"),
+ ]
+ )
+
+ config_id = fields.Many2one(comodel_name="pos.config")
+
+ company_id = fields.Many2one(related="config_id.company_id")
+
+ name = fields.Char(readonly=True)
+
+ product_name = fields.Char(readonly=True)
+
+ vendor_product_code = fields.Char(readonly=True)
+
+ serial_number = fields.Char(readonly=True)
+
+ manufacturer = fields.Char(readonly=True)
+
+ last_connexion_date = fields.Datetime(readonly=True)
+
+ def _default_company_id(self):
+ return self.env.company
diff --git a/pos_odoo_driver_device_list/readme/CONTRIBUTORS.rst b/pos_odoo_driver_device_list/readme/CONTRIBUTORS.rst
new file mode 100644
index 0000000..ae6f43a
--- /dev/null
+++ b/pos_odoo_driver_device_list/readme/CONTRIBUTORS.rst
@@ -0,0 +1 @@
+* Sylvain LE GAL (https://twitter.com/legalsylvain)
diff --git a/pos_odoo_driver_device_list/readme/DESCRIPTION.rst b/pos_odoo_driver_device_list/readme/DESCRIPTION.rst
new file mode 100644
index 0000000..bc4d21a
--- /dev/null
+++ b/pos_odoo_driver_device_list/readme/DESCRIPTION.rst
@@ -0,0 +1,4 @@
+This module extends the Point of Sale odoo module, to add compatibility
+with the ``odoo-pos-driver`` python library.
+
+It will store connected devices information in Odoo for analysis.
diff --git a/pos_odoo_driver_device_list/readme/USAGE.rst b/pos_odoo_driver_device_list/readme/USAGE.rst
new file mode 100644
index 0000000..2104a27
--- /dev/null
+++ b/pos_odoo_driver_device_list/readme/USAGE.rst
@@ -0,0 +1,9 @@
+* Open the Point of sale, with usb devices connected.
+
+* Close the point of sale.
+
+* Go to " / Devices".
+
+you can see the devices information, with last usage date.
+
+.. figure:: ../static/img/pos_device_tree.png
diff --git a/pos_odoo_driver_device_list/security/ir.model.access.csv b/pos_odoo_driver_device_list/security/ir.model.access.csv
new file mode 100644
index 0000000..bc7e685
--- /dev/null
+++ b/pos_odoo_driver_device_list/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_pos_device_user,access_pos_device_user,pos_odoo_driver_device_list.model_pos_device,point_of_sale.group_pos_user,1,1,1,0
+access_pos_device_manager,access_pos_device_manager,pos_odoo_driver_device_list.model_pos_device,base.group_system,1,1,1,1
diff --git a/pos_odoo_driver_device_list/security/ir_rule.xml b/pos_odoo_driver_device_list/security/ir_rule.xml
new file mode 100644
index 0000000..b0a4acc
--- /dev/null
+++ b/pos_odoo_driver_device_list/security/ir_rule.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ PoS Device Rule
+
+
+ [('company_id', 'in', company_ids + [False])]
+
+
+
diff --git a/pos_odoo_driver_device_list/static/description/pos_device_tree.png b/pos_odoo_driver_device_list/static/description/pos_device_tree.png
new file mode 100644
index 0000000..2ee31ce
Binary files /dev/null and b/pos_odoo_driver_device_list/static/description/pos_device_tree.png differ
diff --git a/pos_odoo_driver_device_list/static/src/js/devices.esm.js b/pos_odoo_driver_device_list/static/src/js/devices.esm.js
new file mode 100644
index 0000000..b603c3b
--- /dev/null
+++ b/pos_odoo_driver_device_list/static/src/js/devices.esm.js
@@ -0,0 +1,41 @@
+// 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_device_list.devices", function (require) {
+
+ var ProxyDevice = require("point_of_sale.devices").ProxyDevice;
+
+ var set_connection_status_super = ProxyDevice.prototype.set_connection_status;
+
+ ProxyDevice.prototype.set_connection_status = function (status, drivers, msg='') {
+ if (status === 'connected' && drivers !== undefined) {
+ var old_drivers = this.get('status').drivers;
+ var changes = {};
+ Object.entries(drivers).forEach(([driver_name, driver_value]) => {
+ if (driver_value.status === "connected") {
+ if (JSON.stringify(driver_value) !== JSON.stringify(old_drivers[driver_name])) {
+ changes[driver_name] = driver_value;
+ }
+ }
+ })
+ if (Object.keys(changes).length !== 0) {
+ this.env.services.rpc({
+ model: 'pos.config',
+ method: 'update_pos_device',
+ args: [this.env.pos.config.id, changes],
+ kwargs: {context: this.env.session.user_context},
+ }, {})
+ .then(function (result) {
+ console.log("THEN: ", result)
+ }).catch(function (error){
+ console.warn('catch: ', error);
+ });
+
+ console.log("CHANGES: ", changes)
+ }
+ }
+ set_connection_status_super.call(this, status, drivers, msg);
+ };
+
+});
diff --git a/pos_odoo_driver_device_list/views/view_pos_device.xml b/pos_odoo_driver_device_list/views/view_pos_device.xml
new file mode 100644
index 0000000..84e73b7
--- /dev/null
+++ b/pos_odoo_driver_device_list/views/view_pos_device.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+ pos.device
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pos Devices
+ pos.device
+ tree
+
+
+
+
+
diff --git a/setup/.setuptools-odoo-make-default-ignore b/setup/.setuptools-odoo-make-default-ignore
new file mode 100644
index 0000000..207e615
--- /dev/null
+++ b/setup/.setuptools-odoo-make-default-ignore
@@ -0,0 +1,2 @@
+# addons listed in this file are ignored by
+# setuptools-odoo-make-default (one addon per line)
diff --git a/setup/README b/setup/README
new file mode 100644
index 0000000..a63d633
--- /dev/null
+++ b/setup/README
@@ -0,0 +1,2 @@
+To learn more about this directory, please visit
+https://pypi.python.org/pypi/setuptools-odoo
diff --git a/setup/pos_odoo_driver_device_list/odoo/addons/pos_odoo_driver_device_list b/setup/pos_odoo_driver_device_list/odoo/addons/pos_odoo_driver_device_list
new file mode 120000
index 0000000..0ddc385
--- /dev/null
+++ b/setup/pos_odoo_driver_device_list/odoo/addons/pos_odoo_driver_device_list
@@ -0,0 +1 @@
+../../../../pos_odoo_driver_device_list
\ No newline at end of file
diff --git a/setup/pos_odoo_driver_device_list/setup.py b/setup/pos_odoo_driver_device_list/setup.py
new file mode 100644
index 0000000..28c57bb
--- /dev/null
+++ b/setup/pos_odoo_driver_device_list/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+
+setuptools.setup(
+ setup_requires=['setuptools-odoo'],
+ odoo_addon=True,
+)