Two bugs caught by entech battle test on first deploy:
1. Manifest entry landed in the 'demo' list instead of 'data' because
my anchor (fp_demo_shopfloor_data.xml) was already in 'demo' —
the entry pattern-matched into the wrong section. Demo data
doesn't load on entech (no --load demo), so the mail.template
never existed. Moved fp_tablet_pin_reset_template.xml to 'data'.
2. The fp.notification.template wrapper record referenced a model
that doesn't exist until fusion_plating_notifications loads;
fusion_plating_shopfloor doesn't depend on notifications, so
the data load ParseError'd. Removed the wrapper — the controller
calls mail_template.send_mail() directly anyway, not via the
notification dispatcher. Added an inline comment explaining why
the wrapper isn't here.
Battle test updated to drop the (now removed) wrapper xmlid check.
Battle test ALL PASS on entech after fixes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mail template renders the 4-digit code in both subject (mobile
notification glance) and body (big bold display). Per Rule 25 only
core res.users fields referenced; the code itself comes from ctx.
fp.notification.template wrapper enables admin UI customization of
the body without touching code. tablet_pin_reset_requested added to
TRIGGER_EVENTS selection.
Daily ir.cron purges used/expired rows > 7 days old (audit trail
lives in fp.tablet.session.event, not here, so aggressive cleanup
is safe).
Manifest bump 19.0.34.2.0 -> 19.0.35.0.0 (triggers asset cache
invalidation on -u so the new template + SCSS load cleanly).
Phase 1 backend complete.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every 5 minutes, find active unlock events past 8-hour ceiling and
mark them force-locked. SQL bypass of the model's read-only ACL is
the only path that can update existing rows (no Python write() works
because the model override blocks even sudo writes without the
explicit fp_tablet_audit_admin_write context flag).
Ceiling configurable via ir.config_parameter[fp.tablet.session_ceiling_hours].
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
C1: Add placeholder fp_tablet_cron.xml + fp_tablet_session_event_views.xml
so the module is installable now (real content lands in Phase C task C4
and Phase E task E1 respectively).
I1: test_tablet_pin_auth_manager now passes {} (not self.env) as the
env arg to _check_credentials — matches what request.session.authenticate
provides and what the base implementation expects.
I2: Auth manager role check now uses user_sudo.all_group_ids (transitive)
instead of group_ids (direct) per CLAUDE.md rules 13l + 23. Owner users
who hold Owner directly still match all 5 shop-branch xmlids via the
implication chain.
I3: fp.tablet.session.event gains Python-layer write() + unlink()
overrides that always raise AccessError unless the explicit
fp_tablet_audit_admin_write / fp_tablet_audit_admin_purge context flag
is set. Closes the gap between the model's append-only docstring and
its actual enforcement (ACL-only previously).
M1: Hoisted 'from odoo.exceptions import AccessDenied' to top-of-file
imports next to existing UserError import.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Kiosk holds the tablet session when no tech is PIN-unlocked.
Password is auto-generated by the post-migrate hook (Task A5).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds two fields to fusion.plating.shopfloor.station:
- x_fc_authorised_user_ids (Many2many → res.users): restricts the
tablet lock-screen tile grid to a specific roster per station.
Empty = all operator-group users shown.
- x_fc_idle_lock_minutes (Integer, nullable): per-station override
for the auto-lock idle threshold; null = use system parameter.
Plus data/fp_tablet_config_data.xml registers four ir.config_parameter
defaults (noupdate=1 — manager can override via Settings → Technical
→ Parameters):
fp.shopfloor.tablet_idle_lock_minutes = 5
fp.shopfloor.tablet_pin_fail_threshold = 5
fp.shopfloor.tablet_pin_fail_lockout_minutes = 5
fp.shopfloor.tablet_warn_seconds_before_lock = 30
Form view surfaces both new fields in a dedicated 'Tablet PIN Gate'
group.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit of all 86 data XML files in the fusion_plating module set
turned up 3 more files that lacked noupdate=1 protection — every
module upgrade would re-import them and silently overwrite user
customisations. Following the ENP-ALUM-BASIC recovery (a68bf2e),
locked these too:
1. fusion_tasks/data/ir_cron_data.xml — 4 ir.cron records
(technician travel times, push notifications, late-arrival
checks, location cleanup). Users may disable / re-schedule.
2. fusion_plating_shopfloor/data/fp_cron_data.xml — 1 ir.cron
(Bake Window state updater). Same reasoning.
3. fusion_plating_bridge_maintenance/data/fp_maintenance_stage_data.xml
— 3 maintenance.stage records (kanban columns: New / Active /
Completed). Admin may rename, reorder, or add new stages.
Companion entech-side action (executed via SQL during the fix
session): 11 ir.model.data rows for these records were updated to
noupdate=true so the next module upgrade respects the new flag.
Files left explicitly noupdate=0 — verified safe:
- fusion_plating/data/fp_landing_data.xml — 1 ir.actions.server
(system action, code-defined; re-import is harmless)
- fusion_plating_reports/data/fp_hide_default_reports.xml —
re-asserts deletion of default Odoo report bindings; intentional
to re-run on every upgrade
Final audit confirmed 0 user-editable noupdate=false records remain.
ir.model.inherit + report.paperformat rows still noupdate=false but
those are system metadata (Odoo manages) and Odoo's standard
paperformat pattern, both safe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>