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:
gsinghpal
2026-05-24 13:08:30 -04:00
parent 87e924d1d8
commit 8f6302b446
5 changed files with 130 additions and 18 deletions

View File

@@ -16,9 +16,11 @@ import logging
from datetime import timedelta
from odoo import _, fields, http
from odoo.exceptions import UserError
from odoo.exceptions import AccessDenied, UserError
from odoo.http import request
from ._tablet_session_audit import write_event, _sha256_session_sid
_logger = logging.getLogger(__name__)
@@ -226,8 +228,6 @@ class FpTabletController(http.Controller):
Spec: docs/superpowers/specs/2026-05-24-tablet-pin-session-redesign-design.md
"""
from odoo.exceptions import AccessDenied
from ._tablet_session_audit import write_event, _sha256_session_sid
env = request.env
Users = env['res.users'].sudo()
target = Users.browse(int(user_id))
@@ -336,7 +336,6 @@ class FpTabletController(http.Controller):
ceiling -> ceiling_lock
Anything else falls back to manual_lock.
"""
from ._tablet_session_audit import write_event, _sha256_session_sid
env = request.env
now = fields.Datetime.now()
sid = request.session.sid
@@ -376,6 +375,18 @@ class FpTabletController(http.Controller):
session_started_at=session_started_at,
session_ended_at=now,
duration_seconds=duration_seconds)
# Close the original unlock event (mirror what the cron does
# for stale sessions) so the cron doesn't re-process it later.
# The Python write override blocks updates without the explicit
# admin context flag, so use parameterized SQL (consistent with
# _cron_force_lock_stale_sessions in fp_tablet_session_event.py).
if open_event:
self.env.cr.execute(
"""UPDATE fp_tablet_session_event
SET session_ended_at = %s, duration_seconds = %s
WHERE id = %s""",
(now, duration_seconds or 0, open_event.id),
)
_logger.info(
'Tablet locked (reason=%s) for uid %s (sid %s..) duration=%ss',
reason, tech_id, sid[:8] if sid else '', duration_seconds,