fix(shopfloor): Phase C review findings — lock_session closes unlock event + cron test
Important 1: lock_session now closes the original unlock event's session_ended_at via the same parameterized-SQL bypass pattern used by the force-lock cron. Without this, every Hand-Off click became a duplicate force_lock event 8 hours later (cron saw the unlock still open and re-processed). Important 2: test_unlock_lock_session_endpoints setUp now unconditionally overrides the kiosk password (was gated on 'if not get_param(...)' which broke on entech where the post-migrate hook already generated a random password — tests failed against the real value). HttpCase rolls back per test so no persistence. Minor 4: _cron_force_lock_stale_sessions now routes the force_lock create through write_event helper for consistency (single audit-write path; helper captures acting_uid/ip/ua uniformly). Minor 5: Hoisted local imports inside method bodies to top-of-file in tablet_controller.py (AccessDenied, _tablet_session_audit) and fp_tablet_session_event.py (timedelta, write_event). Minor 6: New test_force_lock_cron.py with 3 tests: stale session emits force_lock + closes original; recent session unaffected; already-closed session not re-processed. Would have caught Important 1 if it had existed during Phase C review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,11 @@ write/unlink/edit are forbidden to anyone except root via direct SQL.
|
||||
|
||||
Spec section 4: docs/superpowers/specs/2026-05-24-tablet-pin-session-redesign-design.md
|
||||
"""
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import AccessError
|
||||
from odoo.addons.fusion_plating_shopfloor.controllers._tablet_session_audit import write_event
|
||||
|
||||
|
||||
class FpTabletSessionEvent(models.Model):
|
||||
@@ -124,7 +127,6 @@ class FpTabletSessionEvent(models.Model):
|
||||
|
||||
Runs every 5 minutes per fp_tablet_cron.xml.
|
||||
"""
|
||||
from datetime import timedelta
|
||||
ceiling_hours = int(self.env['ir.config_parameter'].sudo().get_param(
|
||||
'fp.tablet.session_ceiling_hours', 8))
|
||||
cutoff = fields.Datetime.now() - timedelta(hours=ceiling_hours)
|
||||
@@ -136,15 +138,15 @@ class FpTabletSessionEvent(models.Model):
|
||||
now = fields.Datetime.now()
|
||||
for event in stale:
|
||||
duration = int((now - event.session_started_at).total_seconds())
|
||||
self.sudo().create({
|
||||
'event_type': 'force_lock',
|
||||
'user_id': event.user_id.id,
|
||||
'session_id_hash': event.session_id_hash,
|
||||
'session_started_at': event.session_started_at,
|
||||
'session_ended_at': now,
|
||||
'duration_seconds': duration,
|
||||
'notes': 'Cron force-lock: session exceeded %d-hour ceiling' % ceiling_hours,
|
||||
})
|
||||
write_event(self.env,
|
||||
event_type='force_lock',
|
||||
user_id=event.user_id.id,
|
||||
session_id_hash=event.session_id_hash,
|
||||
session_started_at=event.session_started_at,
|
||||
session_ended_at=now,
|
||||
duration_seconds=duration,
|
||||
notes='Cron force-lock: session exceeded %d-hour ceiling' % ceiling_hours,
|
||||
)
|
||||
# Mark the original unlock event closed so it's not reprocessed
|
||||
# next tick. write() is blocked by the model override — use
|
||||
# direct SQL bypass (this is the documented escape hatch for
|
||||
|
||||
Reference in New Issue
Block a user