From b7d05158ed88eb6d569d8aadfaa3a13561efd9c1 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Thu, 4 Apr 2019 01:13:43 +0200 Subject: [PATCH 1/7] [ADD] iot_ras --- iot_ras_oca/README.rst | 73 ++++++++++++++++++++++++++ iot_ras_oca/__init__.py | 1 + iot_ras_oca/__manifest__.py | 19 +++++++ iot_ras_oca/data/ras_template.xml | 18 +++++++ iot_ras_oca/models/__init__.py | 3 ++ iot_ras_oca/models/hr_employee.py | 23 ++++++++ iot_ras_oca/models/iot_device_input.py | 12 +++++ iot_ras_oca/models/iot_template.py | 15 ++++++ 8 files changed, 164 insertions(+) create mode 100644 iot_ras_oca/README.rst create mode 100644 iot_ras_oca/__init__.py create mode 100644 iot_ras_oca/__manifest__.py create mode 100644 iot_ras_oca/data/ras_template.xml create mode 100644 iot_ras_oca/models/__init__.py create mode 100644 iot_ras_oca/models/hr_employee.py create mode 100644 iot_ras_oca/models/iot_device_input.py create mode 100644 iot_ras_oca/models/iot_template.py diff --git a/iot_ras_oca/README.rst b/iot_ras_oca/README.rst new file mode 100644 index 000000000..e27455951 --- /dev/null +++ b/iot_ras_oca/README.rst @@ -0,0 +1,73 @@ +======== +IoT Base +======== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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-OCA%2Fiot-lightgray.png?logo=github + :target: https://github.com/OCA/iot/tree/11.0/iot + :alt: OCA/iot +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/iot-11-0/iot-11-0-iot + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/269/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This addon is a base module used for all iot modules. + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* Creu Blanca + +Contributors +~~~~~~~~~~~~ + +* Enric Tobella + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/iot `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/iot_ras_oca/__init__.py b/iot_ras_oca/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/iot_ras_oca/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/iot_ras_oca/__manifest__.py b/iot_ras_oca/__manifest__.py new file mode 100644 index 000000000..cba47b078 --- /dev/null +++ b/iot_ras_oca/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright (C) 2018 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + 'name': 'IoT Templates', + 'version': '12.0.1.0.0', + 'category': 'IoT', + 'author': "Creu Blanca, " + "Odoo Community Association (OCA)", + 'license': 'AGPL-3', + 'installable': True, + 'summary': 'IoT base module', + 'depends': [ + 'iot_template', + 'hr_attendance_rfid', + ], + 'data': [ + 'data/ras_template.xml', + ], +} diff --git a/iot_ras_oca/data/ras_template.xml b/iot_ras_oca/data/ras_template.xml new file mode 100644 index 000000000..2d94d3006 --- /dev/null +++ b/iot_ras_oca/data/ras_template.xml @@ -0,0 +1,18 @@ + + + + eficent.ras + + + + serial + + + + rfid_read + + iot_ras_default_action + {'serial': '${key_serial}', 'passphrase': '${passphrase}'} + + + diff --git a/iot_ras_oca/models/__init__.py b/iot_ras_oca/models/__init__.py new file mode 100644 index 000000000..a7329d4c1 --- /dev/null +++ b/iot_ras_oca/models/__init__.py @@ -0,0 +1,3 @@ +from . import iot_template +from . import hr_employee +from . import iot_device_input diff --git a/iot_ras_oca/models/hr_employee.py b/iot_ras_oca/models/hr_employee.py new file mode 100644 index 000000000..4c3985190 --- /dev/null +++ b/iot_ras_oca/models/hr_employee.py @@ -0,0 +1,23 @@ +# Copyright 2017 Comunitea Servicios Tecnológicos S.L. +# Copyright 2018 Eficent Business and IT Consulting Services, S.L. +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +import logging +from odoo import api, fields, models, _ +_logger = logging.getLogger(__name__) + + +class HrEmployee(models.Model): + _inherit = "hr.employee" + + @api.model + def register_attendance(self, card_code): + res = super().register_attendance(card_code) + if 'action' in res: + if res['action'] == 'check_in': + res['action_msg'] = _('Checked in %s') % res['employee_name'] + elif res['action'] == 'check_out': + res['action_msg'] = _('Checked out %s') % res['employee_name'] + elif res['action'] == 'FALSE': + res['action_msg'] = _('Contact your admin') + return res diff --git a/iot_ras_oca/models/iot_device_input.py b/iot_ras_oca/models/iot_device_input.py new file mode 100644 index 000000000..ac05f66ca --- /dev/null +++ b/iot_ras_oca/models/iot_device_input.py @@ -0,0 +1,12 @@ +from odoo import api, models + + +class IotDeviceInput(models.Model): + _inherit = 'iot.device.input' + + @api.model + def iot_ras_default_action(self, message): + return { + 'action_msg': message, + 'action': 'check_in' + } \ No newline at end of file diff --git a/iot_ras_oca/models/iot_template.py b/iot_ras_oca/models/iot_template.py new file mode 100644 index 000000000..9d299f228 --- /dev/null +++ b/iot_ras_oca/models/iot_template.py @@ -0,0 +1,15 @@ +from odoo import models +from uuid import uuid4 + + +class IotTemplate(models.Model): + _inherit = 'iot.template' + + def auto_generate_key(self, serial): + res = super().auto_generate_key(serial) + if self == self.env.ref('iot_ras.ras_template'): + res.update({ + 'key_serial': uuid4(), + 'passphrase': uuid4(), + }) + return res From 8aa0b235d77c645130826c30b0c58154674ef173 Mon Sep 17 00:00:00 2001 From: Olga Marco Date: Thu, 10 Jun 2021 15:57:01 +0200 Subject: [PATCH 2/7] [IMP] iot_ras_oca: black, isort, prettier --- iot_ras_oca/__manifest__.py | 24 +++++++++--------------- iot_ras_oca/models/hr_employee.py | 18 ++++++++++-------- iot_ras_oca/models/iot_device_input.py | 7 ++----- iot_ras_oca/models/iot_template.py | 12 +++++------- 4 files changed, 26 insertions(+), 35 deletions(-) diff --git a/iot_ras_oca/__manifest__.py b/iot_ras_oca/__manifest__.py index cba47b078..d4f0c5260 100644 --- a/iot_ras_oca/__manifest__.py +++ b/iot_ras_oca/__manifest__.py @@ -1,19 +1,13 @@ # Copyright (C) 2018 Creu Blanca # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - 'name': 'IoT Templates', - 'version': '12.0.1.0.0', - 'category': 'IoT', - 'author': "Creu Blanca, " - "Odoo Community Association (OCA)", - 'license': 'AGPL-3', - 'installable': True, - 'summary': 'IoT base module', - 'depends': [ - 'iot_template', - 'hr_attendance_rfid', - ], - 'data': [ - 'data/ras_template.xml', - ], + "name": "IoT Templates", + "version": "13.0.1.0.0", + "category": "IoT", + "author": "Creu Blanca, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "summary": "IoT base module", + "depends": ["iot_template_oca", "hr_attendance_rfid"], + "data": ["data/ras_template.xml"], } diff --git a/iot_ras_oca/models/hr_employee.py b/iot_ras_oca/models/hr_employee.py index 4c3985190..0a62a9906 100644 --- a/iot_ras_oca/models/hr_employee.py +++ b/iot_ras_oca/models/hr_employee.py @@ -3,7 +3,9 @@ # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html import logging -from odoo import api, fields, models, _ + +from odoo import _, api, models + _logger = logging.getLogger(__name__) @@ -13,11 +15,11 @@ class HrEmployee(models.Model): @api.model def register_attendance(self, card_code): res = super().register_attendance(card_code) - if 'action' in res: - if res['action'] == 'check_in': - res['action_msg'] = _('Checked in %s') % res['employee_name'] - elif res['action'] == 'check_out': - res['action_msg'] = _('Checked out %s') % res['employee_name'] - elif res['action'] == 'FALSE': - res['action_msg'] = _('Contact your admin') + if "action" in res: + if res["action"] == "check_in": + res["action_msg"] = _("Checked in %s") % res["employee_name"] + elif res["action"] == "check_out": + res["action_msg"] = _("Checked out %s") % res["employee_name"] + elif res["action"] == "FALSE": + res["action_msg"] = _("Contact your admin") return res diff --git a/iot_ras_oca/models/iot_device_input.py b/iot_ras_oca/models/iot_device_input.py index ac05f66ca..31c341156 100644 --- a/iot_ras_oca/models/iot_device_input.py +++ b/iot_ras_oca/models/iot_device_input.py @@ -2,11 +2,8 @@ class IotDeviceInput(models.Model): - _inherit = 'iot.device.input' + _inherit = "iot.device.input" @api.model def iot_ras_default_action(self, message): - return { - 'action_msg': message, - 'action': 'check_in' - } \ No newline at end of file + return {"action_msg": message, "action": "check_in"} diff --git a/iot_ras_oca/models/iot_template.py b/iot_ras_oca/models/iot_template.py index 9d299f228..f0c5fad2b 100644 --- a/iot_ras_oca/models/iot_template.py +++ b/iot_ras_oca/models/iot_template.py @@ -1,15 +1,13 @@ -from odoo import models from uuid import uuid4 +from odoo import models + class IotTemplate(models.Model): - _inherit = 'iot.template' + _inherit = "iot.template" def auto_generate_key(self, serial): res = super().auto_generate_key(serial) - if self == self.env.ref('iot_ras.ras_template'): - res.update({ - 'key_serial': uuid4(), - 'passphrase': uuid4(), - }) + if self == self.env.ref("iot_ras_oca.ras_template"): + res.update({"key_serial": uuid4(), "passphrase": uuid4()}) return res From eb09cdf6f834b331abf4c070880a3fe8fa9be59a Mon Sep 17 00:00:00 2001 From: Olga Marco Date: Fri, 11 Jun 2021 11:19:20 +0200 Subject: [PATCH 3/7] [MIG] iot_ras_oca: Migration to 13.0 --- iot_ras_oca/data/ras_template.xml | 6 +- iot_ras_oca/models/__init__.py | 1 - iot_ras_oca/models/iot_template.py | 13 ----- iot_ras_oca/tests/__init__.py | 1 + iot_ras_oca/tests/test_ras.py | 89 ++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 19 deletions(-) delete mode 100644 iot_ras_oca/models/iot_template.py create mode 100644 iot_ras_oca/tests/__init__.py create mode 100644 iot_ras_oca/tests/test_ras.py diff --git a/iot_ras_oca/data/ras_template.xml b/iot_ras_oca/data/ras_template.xml index 2d94d3006..bdc9a2555 100644 --- a/iot_ras_oca/data/ras_template.xml +++ b/iot_ras_oca/data/ras_template.xml @@ -3,16 +3,12 @@ eficent.ras - - - serial - rfid_read iot_ras_default_action - {'serial': '${key_serial}', 'passphrase': '${passphrase}'} + {} diff --git a/iot_ras_oca/models/__init__.py b/iot_ras_oca/models/__init__.py index a7329d4c1..8a6d1c15f 100644 --- a/iot_ras_oca/models/__init__.py +++ b/iot_ras_oca/models/__init__.py @@ -1,3 +1,2 @@ -from . import iot_template from . import hr_employee from . import iot_device_input diff --git a/iot_ras_oca/models/iot_template.py b/iot_ras_oca/models/iot_template.py deleted file mode 100644 index f0c5fad2b..000000000 --- a/iot_ras_oca/models/iot_template.py +++ /dev/null @@ -1,13 +0,0 @@ -from uuid import uuid4 - -from odoo import models - - -class IotTemplate(models.Model): - _inherit = "iot.template" - - def auto_generate_key(self, serial): - res = super().auto_generate_key(serial) - if self == self.env.ref("iot_ras_oca.ras_template"): - res.update({"key_serial": uuid4(), "passphrase": uuid4()}) - return res diff --git a/iot_ras_oca/tests/__init__.py b/iot_ras_oca/tests/__init__.py new file mode 100644 index 000000000..5e2aa21fe --- /dev/null +++ b/iot_ras_oca/tests/__init__.py @@ -0,0 +1 @@ +from . import test_ras diff --git a/iot_ras_oca/tests/test_ras.py b/iot_ras_oca/tests/test_ras.py new file mode 100644 index 000000000..0ce8a7737 --- /dev/null +++ b/iot_ras_oca/tests/test_ras.py @@ -0,0 +1,89 @@ +from odoo.tests.common import HttpCase + + +class TestRas(HttpCase): + def setUp(self): + super().setUp() + self.card_code = "e313441e" + self.employee = self.env["hr.employee"].create( + {"name": "Anita", "rfid_card_code": self.card_code} + ) + self.template = self.env.ref("iot_ras_oca.ras_template") + + def _get_wizard(self): + wizard = self.env["iot.device.configure"].create({}) + self.assertFalse(wizard.serial) + self.assertFalse(wizard.generated) + self.assertFalse(wizard.url) + wizard.run() + self.assertTrue(wizard.serial) + self.assertTrue(wizard.generated) + self.assertTrue(wizard.url) + return wizard + + def test_generation(self): + wizard = self._get_wizard() + device_config = self.url_open( + wizard.url, data={"template": self.template.name} + ).json() + device = self.env["iot.device"].search([("name", "=", device_config["name"])]) + self.assertTrue(device) + ras_input = device.input_ids + self.assertTrue(ras_input) + self.assertTrue(ras_input.serial) + self.assertTrue(ras_input.passphrase) + res = self.url_open( + "/iot/%s/action" % ras_input.serial, + data={"passphrase": ras_input.passphrase, "value": "123"}, + ).json() + # This should work properly because it has not been assigned to + # Checking attendance + self.assertEqual(res["status"], "ok") + + ras_input.write( + { + "call_model_id": self.env.ref("hr.model_hr_employee").id, + "call_function": "register_attendance", + } + ) # We are assigning it to the proper function and model + + res = self.url_open( + "/iot/%s/action" % ras_input.serial, + data={"passphrase": ras_input.passphrase, "value": "123"}, + ).json() + # Now it must fail as the value is not correct + self.assertEqual(res["status"], "ok") + self.assertIn("error_message", res) + self.assertRegex(res["error_message"], ".*No employee found.*") + self.assertFalse( + self.env["hr.attendance"].search([("employee_id", "=", self.employee.id)]) + ) + res = self.url_open( + "/iot/%s/action" % ras_input.serial, + data={"passphrase": ras_input.passphrase, "value": self.card_code}, + ).json() + # The employee has checked in + self.assertEqual(res["status"], "ok") + self.assertEqual(res["action"], "check_in") + self.assertEqual(res["error_message"], "") + attendance = self.env["hr.attendance"].search( + [("employee_id", "=", self.employee.id)] + ) + self.assertTrue(attendance) + self.assertEqual(1, len(attendance)) + self.assertFalse(attendance.check_out) + res = self.url_open( + "/iot/%s/action" % ras_input.serial, + data={"passphrase": ras_input.passphrase, "value": self.card_code}, + ).json() + # The employee has checked out + self.assertEqual(res["status"], "ok") + self.assertEqual(res["action"], "check_out") + self.assertEqual(res["error_message"], "") + attendance = self.env["hr.attendance"].search( + [("employee_id", "=", self.employee.id)] + ) + attendance.refresh() + self.assertTrue(attendance) + self.assertEqual(1, len(attendance)) + self.assertTrue(attendance.check_out) From 8dc3106d0422adb3b36a7e2de21c377ac72cdd33 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Wed, 7 Dec 2022 16:29:25 +0100 Subject: [PATCH 4/7] [IMP] iot_ras_oca: black, isort, prettier --- iot_ras_oca/data/ras_template.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iot_ras_oca/data/ras_template.xml b/iot_ras_oca/data/ras_template.xml index bdc9a2555..94df528a0 100644 --- a/iot_ras_oca/data/ras_template.xml +++ b/iot_ras_oca/data/ras_template.xml @@ -4,9 +4,9 @@ eficent.ras - + rfid_read - + iot_ras_default_action {} From 21289307d2ba241538c6a917702cd3ac24513d59 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Wed, 7 Dec 2022 16:30:44 +0100 Subject: [PATCH 5/7] [MIG] iot_ras_oca: Migration to 14.0 --- iot_ras_oca/__manifest__.py | 5 +++-- iot_ras_oca/tests/test_ras.py | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/iot_ras_oca/__manifest__.py b/iot_ras_oca/__manifest__.py index d4f0c5260..1ce61d789 100644 --- a/iot_ras_oca/__manifest__.py +++ b/iot_ras_oca/__manifest__.py @@ -2,12 +2,13 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "IoT Templates", - "version": "13.0.1.0.0", + "version": "14.0.1.0.0", "category": "IoT", - "author": "Creu Blanca, Odoo Community Association (OCA)", + "author": "CreuBlanca", "license": "AGPL-3", "installable": True, "summary": "IoT base module", "depends": ["iot_template_oca", "hr_attendance_rfid"], "data": ["data/ras_template.xml"], + "website": "https://github.com/tegin/cb-addons", } diff --git a/iot_ras_oca/tests/test_ras.py b/iot_ras_oca/tests/test_ras.py index 0ce8a7737..25ce72e5b 100644 --- a/iot_ras_oca/tests/test_ras.py +++ b/iot_ras_oca/tests/test_ras.py @@ -12,12 +12,7 @@ def setUp(self): def _get_wizard(self): wizard = self.env["iot.device.configure"].create({}) - self.assertFalse(wizard.serial) - self.assertFalse(wizard.generated) - self.assertFalse(wizard.url) - wizard.run() self.assertTrue(wizard.serial) - self.assertTrue(wizard.generated) self.assertTrue(wizard.url) return wizard From 08f65d80bd99d69e35b0c79f931caa662591230a Mon Sep 17 00:00:00 2001 From: Kevin Luna Date: Tue, 18 Feb 2025 16:33:24 +0100 Subject: [PATCH 6/7] [IMP] iot_ras_oca: black, isort, prettier --- setup/iot_ras_oca/odoo/addons/iot_ras_oca | 1 + setup/iot_ras_oca/setup.py | 6 ++++++ 2 files changed, 7 insertions(+) create mode 120000 setup/iot_ras_oca/odoo/addons/iot_ras_oca create mode 100644 setup/iot_ras_oca/setup.py diff --git a/setup/iot_ras_oca/odoo/addons/iot_ras_oca b/setup/iot_ras_oca/odoo/addons/iot_ras_oca new file mode 120000 index 000000000..f230c6fdf --- /dev/null +++ b/setup/iot_ras_oca/odoo/addons/iot_ras_oca @@ -0,0 +1 @@ +../../../../iot_ras_oca \ No newline at end of file diff --git a/setup/iot_ras_oca/setup.py b/setup/iot_ras_oca/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/iot_ras_oca/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From a10c3f295ebec9fbfa9ecf8f0bf9902338d9a8fe Mon Sep 17 00:00:00 2001 From: Kevin Luna Date: Tue, 18 Feb 2025 16:40:12 +0100 Subject: [PATCH 7/7] [MIG] iot_ras_oca: migration to 16.0 --- iot_ras_oca/__manifest__.py | 2 +- iot_ras_oca/tests/test_ras.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iot_ras_oca/__manifest__.py b/iot_ras_oca/__manifest__.py index 1ce61d789..b41c253b4 100644 --- a/iot_ras_oca/__manifest__.py +++ b/iot_ras_oca/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "IoT Templates", - "version": "14.0.1.0.0", + "version": "16.0.1.0.0", "category": "IoT", "author": "CreuBlanca", "license": "AGPL-3", diff --git a/iot_ras_oca/tests/test_ras.py b/iot_ras_oca/tests/test_ras.py index 25ce72e5b..9531fa553 100644 --- a/iot_ras_oca/tests/test_ras.py +++ b/iot_ras_oca/tests/test_ras.py @@ -78,7 +78,7 @@ def test_generation(self): attendance = self.env["hr.attendance"].search( [("employee_id", "=", self.employee.id)] ) - attendance.refresh() + attendance.invalidate_recordset() self.assertTrue(attendance) self.assertEqual(1, len(attendance)) self.assertTrue(attendance.check_out)