fix(shopfloor): tablet tile grid includes shop-branch role holders

Previously only direct Technicians appeared on the lock-screen tile
grid because env.ref('group_fp_technician').user_ids returns DIRECT
members only — Odoo's implication chain (Owner -> ... -> Technician)
is read-time only, not stored in res_groups_users_rel.

Search res.users with ('groups_id', 'in', shop_branch_ids) where
shop_branch_ids covers all 5 shop-branch role groups (Technician,
Shop Manager v2, Manager, Quality Manager, Owner). Sales branch
intentionally excluded — they don't operate the tablet.

Verified on entech: 18 technicians + 1 shop_manager + 2 managers
+ 1 quality_manager + 2 owners = 24 tiles (was 18).

CLAUDE.md rule 13l corrected — previous version wrongly claimed
res.groups.user_ids surfaced implied members. Now documents the
search-based query as the canonical 'enumerate role X or higher'
pattern.

Module version: 19.0.32.0.11 -> 19.0.32.0.12

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-24 10:47:01 -04:00
parent 0f751d82cc
commit 839a7f0abc
3 changed files with 51 additions and 15 deletions

View File

@@ -217,22 +217,36 @@ class FpTabletController(http.Controller):
@http.route('/fp/tablet/tiles', type='jsonrpc', auth='user')
def tiles(self, station_id=None):
env = request.env
# Phase 1 permissions overhaul (2026-05-24): post-migration users
# hold the new group_fp_technician (old group_fusion_plating_operator
# is still reachable via implication but DIRECT memberships moved to
# the new group). Point the tile grid at Technician — higher roles
# (Shop Manager / Manager / QM / Owner) imply Technician and so
# are included automatically via res.groups.user_ids (which surfaces
# both direct AND implied memberships).
op_group = env.ref(
# Phase 1 permissions overhaul (2026-05-24): show everyone on the
# SHOP branch — Technician, Shop Manager, Manager, Quality Manager,
# Owner. Managers/Owners need to "chip in" on the floor occasionally.
# Search-based query because res.groups.user_ids returns DIRECT
# memberships only — implied groups (Owner → ... → Technician) don't
# get stored in user.groups_id by Odoo's group-write propagation.
# OR across the 5 shop-branch role group ids; sales-branch users
# (Sales Rep / Sales Manager directly held without any shop-branch
# role) are intentionally excluded — they don't operate the tablet.
shop_branch_xmlids = (
'fusion_plating.group_fp_technician',
raise_if_not_found=False,
'fusion_plating.group_fp_shop_manager_v2',
'fusion_plating.group_fp_manager',
'fusion_plating.group_fp_quality_manager',
'fusion_plating.group_fp_owner',
)
if not op_group:
return {'ok': False, 'error': 'technician group missing'}
group_ids = [
g.id for g in (
env.ref(x, raise_if_not_found=False) for x in shop_branch_xmlids
) if g
]
if not group_ids:
return {'ok': False, 'error': 'shop-branch role groups missing'}
# Determine candidate users — station roster wins if non-empty
users = op_group.user_ids
Users = env['res.users'].sudo()
users = Users.search([
('groups_id', 'in', group_ids),
('share', '=', False),
('active', '=', True),
])
if station_id:
Station = env['fusion.plating.shopfloor.station']
station = Station.browse(int(station_id))