feat(fusion_clock): kiosk app + Kiosk Operator role, full-screen PWA, app-integrated permissions
- PWA manifest on the NFC kiosk page so it installs as a full-screen home-screen app (Chrome "Install" / Safari "Add to Home Screen"). - Dedicated "Kiosk Operator" permission + gated "Fusion Clock Kiosk" top-level app (act_url -> /fusion_clock/kiosk/nfc). Kiosk controllers accept Manager OR Kiosk Operator; all kiosk data ops already run sudo. - Fix 403: read the company kiosk location via sudo on page-load and tap (Kiosk Operator has no fusion.clock.location ACL). - Odoo 19 permissions UX: ir.module.category + res.groups.privilege so User/Team Lead/Manager and Kiosk Operator appear as application-access dropdowns on the user form (no developer mode). Short group display names. - Docs: note res.groups.privilege as the Odoo 19 category_id replacement. Deployed live to entech (odoo-entech / LXC 111 on pve-worker5). v19.0.3.6.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,12 @@ from odoo.addons.fusion_clock.models.tz_utils import get_local_today
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _is_kiosk_operator(user):
|
||||
"""Kiosk surfaces accept a full Clock Manager OR a dedicated Kiosk Operator."""
|
||||
return (user.has_group('fusion_clock.group_fusion_clock_manager')
|
||||
or user.has_group('fusion_clock.group_fusion_clock_kiosk_app'))
|
||||
|
||||
|
||||
class FusionClockKiosk(http.Controller):
|
||||
"""Kiosk mode controller for shared-device clock-in/out."""
|
||||
|
||||
@@ -17,7 +23,7 @@ class FusionClockKiosk(http.Controller):
|
||||
def kiosk_page(self, **kw):
|
||||
"""Kiosk clock-in/out page for shared tablets."""
|
||||
user = request.env.user
|
||||
if not user.has_group('fusion_clock.group_fusion_clock_manager'):
|
||||
if not _is_kiosk_operator(user):
|
||||
return request.redirect('/my')
|
||||
|
||||
ICP = request.env['ir.config_parameter'].sudo()
|
||||
@@ -34,7 +40,7 @@ class FusionClockKiosk(http.Controller):
|
||||
def kiosk_search(self, query='', **kw):
|
||||
"""Search employees for kiosk identification."""
|
||||
user = request.env.user
|
||||
if not user.has_group('fusion_clock.group_fusion_clock_manager'):
|
||||
if not _is_kiosk_operator(user):
|
||||
return {'error': 'Access denied.'}
|
||||
|
||||
employees = request.env['hr.employee'].sudo().search([
|
||||
@@ -55,7 +61,7 @@ class FusionClockKiosk(http.Controller):
|
||||
def kiosk_verify_pin(self, employee_id=0, pin='', **kw):
|
||||
"""Verify employee PIN for kiosk mode."""
|
||||
user = request.env.user
|
||||
if not user.has_group('fusion_clock.group_fusion_clock_manager'):
|
||||
if not _is_kiosk_operator(user):
|
||||
return {'error': 'Access denied.'}
|
||||
|
||||
employee = request.env['hr.employee'].sudo().browse(employee_id)
|
||||
@@ -75,7 +81,7 @@ class FusionClockKiosk(http.Controller):
|
||||
def kiosk_clock(self, employee_id=0, latitude=0, longitude=0, **kw):
|
||||
"""Perform clock action from kiosk on behalf of an employee."""
|
||||
user = request.env.user
|
||||
if not user.has_group('fusion_clock.group_fusion_clock_manager'):
|
||||
if not _is_kiosk_operator(user):
|
||||
return {'error': 'Access denied.'}
|
||||
|
||||
employee = request.env['hr.employee'].sudo().browse(employee_id)
|
||||
|
||||
Reference in New Issue
Block a user