From f05cacec222f9467817fd17ebd2102d09b60918d Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Thu, 14 May 2026 00:53:03 -0400 Subject: [PATCH] feat(fusion_clock): NFC kiosk page render route Controller scaffold with GET /fusion_clock/kiosk/nfc, placeholder QWeb template, and HttpCase tests (10 pass, 0 failures). Fixed Odoo 19 res.users create API: groups_id -> group_ids. Co-Authored-By: Claude Sonnet 4.6 --- fusion_clock/__manifest__.py | 1 + fusion_clock/controllers/__init__.py | 1 + fusion_clock/controllers/clock_nfc_kiosk.py | 36 +++++++++++++++++++ fusion_clock/tests/__init__.py | 1 + fusion_clock/tests/test_clock_nfc_kiosk.py | 38 +++++++++++++++++++++ fusion_clock/views/kiosk_nfc_templates.xml | 20 +++++++++++ 6 files changed, 97 insertions(+) create mode 100644 fusion_clock/controllers/clock_nfc_kiosk.py create mode 100644 fusion_clock/tests/test_clock_nfc_kiosk.py create mode 100644 fusion_clock/views/kiosk_nfc_templates.xml diff --git a/fusion_clock/__manifest__.py b/fusion_clock/__manifest__.py index 0e5fe43b..63846568 100644 --- a/fusion_clock/__manifest__.py +++ b/fusion_clock/__manifest__.py @@ -76,6 +76,7 @@ Integrates natively with Odoo's hr.attendance module for full payroll compatibil 'views/portal_timesheet_templates.xml', 'views/portal_report_templates.xml', 'views/kiosk_templates.xml', + 'views/kiosk_nfc_templates.xml', ], 'assets': { 'web.assets_frontend': [ diff --git a/fusion_clock/controllers/__init__.py b/fusion_clock/controllers/__init__.py index f9a21dd5..5ed5d851 100644 --- a/fusion_clock/controllers/__init__.py +++ b/fusion_clock/controllers/__init__.py @@ -3,3 +3,4 @@ from . import portal_clock from . import clock_api from . import clock_kiosk +from . import clock_nfc_kiosk diff --git a/fusion_clock/controllers/clock_nfc_kiosk.py b/fusion_clock/controllers/clock_nfc_kiosk.py new file mode 100644 index 00000000..9abc9947 --- /dev/null +++ b/fusion_clock/controllers/clock_nfc_kiosk.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) + +import logging +from odoo import http +from odoo.http import request + +_logger = logging.getLogger(__name__) + + +class FusionClockNfcKiosk(http.Controller): + """NFC tap-to-clock kiosk controller. Reuses FusionClockAPI helpers.""" + + @http.route('/fusion_clock/kiosk/nfc', type='http', auth='user', website=True) + def nfc_kiosk_page(self, **kw): + """Render the NFC kiosk page for a wall-mounted tablet.""" + user = request.env.user + if not user.has_group('fusion_clock.group_fusion_clock_manager'): + return request.redirect('/my') + + ICP = request.env['ir.config_parameter'].sudo() + if ICP.get_param('fusion_clock.enable_nfc_kiosk', 'False') != 'True': + return request.redirect('/my') + + company = request.env.company + location = company.x_fclk_nfc_kiosk_location_id + values = { + 'page_name': 'nfc_kiosk', + 'company_name': company.name, + 'location_name': location.name if location else 'No location configured', + 'location_configured': bool(location), + 'photo_required': ICP.get_param('fusion_clock.nfc_photo_required', 'True') == 'True', + 'debug_enabled': ICP.get_param('fusion_clock.nfc_kiosk_debug', 'False') == 'True', + } + return request.render('fusion_clock.nfc_kiosk_page', values) diff --git a/fusion_clock/tests/__init__.py b/fusion_clock/tests/__init__.py index b18efb5d..2426bdb7 100644 --- a/fusion_clock/tests/__init__.py +++ b/fusion_clock/tests/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- from . import test_nfc_models +from . import test_clock_nfc_kiosk diff --git a/fusion_clock/tests/test_clock_nfc_kiosk.py b/fusion_clock/tests/test_clock_nfc_kiosk.py new file mode 100644 index 00000000..0cc118eb --- /dev/null +++ b/fusion_clock/tests/test_clock_nfc_kiosk.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +from odoo.tests.common import HttpCase, tagged + + +@tagged('-at_install', 'post_install', 'fusion_clock') +class TestNfcKioskController(HttpCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.ICP = cls.env['ir.config_parameter'].sudo() + cls.location = cls.env['fusion.clock.location'].create({ + 'name': 'Test Plant', + 'latitude': 43.65, + 'longitude': -79.38, + 'radius': 100, + }) + cls.env.company.x_fclk_nfc_kiosk_location_id = cls.location.id + cls.kiosk_user = cls.env['res.users'].create({ + 'name': 'NFC Kiosk User', + 'login': 'nfc-kiosk-test', + 'password': 'kioskpass123', + 'group_ids': [(4, cls.env.ref('fusion_clock.group_fusion_clock_manager').id)], + }) + + def test_kiosk_page_redirects_when_disabled(self): + self.ICP.set_param('fusion_clock.enable_nfc_kiosk', 'False') + self.authenticate('nfc-kiosk-test', 'kioskpass123') + response = self.url_open('/fusion_clock/kiosk/nfc', allow_redirects=False) + self.assertIn(response.status_code, (301, 302, 303)) + + def test_kiosk_page_renders_when_enabled(self): + self.ICP.set_param('fusion_clock.enable_nfc_kiosk', 'True') + self.authenticate('nfc-kiosk-test', 'kioskpass123') + response = self.url_open('/fusion_clock/kiosk/nfc') + self.assertEqual(response.status_code, 200) + self.assertIn('NFC Clock Kiosk', response.text) diff --git a/fusion_clock/views/kiosk_nfc_templates.xml b/fusion_clock/views/kiosk_nfc_templates.xml new file mode 100644 index 00000000..d01d472a --- /dev/null +++ b/fusion_clock/views/kiosk_nfc_templates.xml @@ -0,0 +1,20 @@ + + + + + +