feat(shopfloor): per-user 7-day tablet event smart button
Owner-only smart button on res.users form. Click opens the audit log filtered to that user (both user_id and attempted_user_id, so failed unlock attempts against a tile show up too). Compute is non-stored: search_count on the audit model per user on demand. Sudo'd because the audit model has Owner-only ACL — the compute fires for the form-viewing user (Owner) who would see the results anyway via the menu. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -140,6 +140,39 @@ class ResUsers(models.Model):
|
|||||||
'target': 'new',
|
'target': 'new',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x_fc_tablet_event_count_7d = fields.Integer(
|
||||||
|
string='Tablet Events (7d)',
|
||||||
|
compute='_compute_tablet_event_count_7d',
|
||||||
|
store=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _compute_tablet_event_count_7d(self):
|
||||||
|
from datetime import timedelta
|
||||||
|
cutoff = fields.Datetime.now() - timedelta(days=7)
|
||||||
|
for user in self:
|
||||||
|
user.x_fc_tablet_event_count_7d = self.env[
|
||||||
|
'fp.tablet.session.event'
|
||||||
|
].sudo().search_count([
|
||||||
|
'|',
|
||||||
|
('user_id', '=', user.id),
|
||||||
|
('attempted_user_id', '=', user.id),
|
||||||
|
('create_date', '>=', cutoff),
|
||||||
|
])
|
||||||
|
|
||||||
|
def action_view_tablet_events(self):
|
||||||
|
self.ensure_one()
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'name': _('Tablet Events: %s') % self.name,
|
||||||
|
'res_model': 'fp.tablet.session.event',
|
||||||
|
'view_mode': 'list,form',
|
||||||
|
'domain': [
|
||||||
|
'|',
|
||||||
|
('user_id', '=', self.id),
|
||||||
|
('attempted_user_id', '=', self.id),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
def _check_credentials(self, credential, env):
|
def _check_credentials(self, credential, env):
|
||||||
"""Custom auth manager: accept `type='fp_tablet_pin'` credential.
|
"""Custom auth manager: accept `type='fp_tablet_pin'` credential.
|
||||||
|
|
||||||
|
|||||||
@@ -55,4 +55,30 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- =================================================================
|
||||||
|
(c) res.users form — Owner-only smart button: Tablet Events (7d)
|
||||||
|
Counts unlock/lock/failed events for this user across the last
|
||||||
|
7 days. Clicking opens the audit log filtered to this user
|
||||||
|
(both user_id and attempted_user_id, so failed-tile-tap attempts
|
||||||
|
show up too).
|
||||||
|
================================================================= -->
|
||||||
|
<record id="view_users_form_tablet_event_smart_button" model="ir.ui.view">
|
||||||
|
<field name="name">res.users.form.tablet.event.smart.button</field>
|
||||||
|
<field name="model">res.users</field>
|
||||||
|
<field name="inherit_id" ref="base.view_users_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//div[@name='button_box']" position="inside">
|
||||||
|
<button name="action_view_tablet_events"
|
||||||
|
type="object"
|
||||||
|
class="oe_stat_button"
|
||||||
|
icon="fa-history"
|
||||||
|
groups="fusion_plating.group_fp_owner">
|
||||||
|
<field name="x_fc_tablet_event_count_7d"
|
||||||
|
widget="statinfo"
|
||||||
|
string="Tablet Events (7d)"/>
|
||||||
|
</button>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
Reference in New Issue
Block a user