Files
Odoo-Modules/fusion_repairs/security/security.xml
gsinghpal 44e5b391f9 fix(fusion_repairs): admin sees app + add placeholder icon
Two related issues that hid the Fusion Repairs app from the Apps menu
for admin users:

1. Custom security groups don't auto-include admin

   The Repairs User / Dispatcher / Manager groups are new custom groups.
   Having base.group_user or base.group_system on its own does NOT grant
   membership in custom child groups - implied chains only flow one way
   (child -> parent). Admin therefore had no Repairs groups, so the
   top-level "Fusion Repairs" menu (gated on group_fusion_repairs_user)
   was hidden from them.

   Fix: extend base.group_system with implied_ids that include
   group_fusion_repairs_manager. Manager already implies Dispatcher
   implies User, so admin (= base.group_system) now automatically gets
   the whole chain on install / upgrade with no manual user editing.

   Verified via odoo-shell:
     admin.has_group('fusion_repairs.group_fusion_repairs_user')       == True
     admin.has_group('fusion_repairs.group_fusion_repairs_dispatcher') == True
     admin.has_group('fusion_repairs.group_fusion_repairs_manager')    == True
     menu_fusion_repairs_root._filter_visible_menus()                 == ir.ui.menu(2735,)

2. Missing static/description/icon.png

   The manifest referenced fusion_repairs,static/description/icon.png
   via web_icon on the top-level menu but the file did not exist. Odoo
   handles missing icons gracefully but the apps list ends up rendering
   without a tile graphic. Copied fusion_tasks/static/description/icon.png
   as a placeholder; replace with a custom asset whenever desired.

   Verified: /fusion_repairs/static/description/icon.png returns
   HTTP 200 with 43989 bytes after restart.

Bumped manifest version to 19.0.1.0.1 to bust the asset bundle hash so
clients pick up the new icon without a manual cache clear.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 22:31:38 -04:00

100 lines
5.6 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- ==================================================================== -->
<!-- MODULE CATEGORY -->
<!-- ==================================================================== -->
<record id="module_category_fusion_repairs" model="ir.module.category">
<field name="name">Fusion Repairs</field>
<field name="sequence">47</field>
</record>
<!-- ==================================================================== -->
<!-- FUSION REPAIRS PRIVILEGE (Odoo 19 res.groups.privilege pattern) -->
<!-- ==================================================================== -->
<record id="res_groups_privilege_fusion_repairs" model="res.groups.privilege">
<field name="name">Fusion Repairs</field>
<field name="sequence">47</field>
<field name="category_id" ref="module_category_fusion_repairs"/>
</record>
<!-- ==================================================================== -->
<!-- GROUPS -->
<!-- ==================================================================== -->
<record id="group_fusion_repairs_user" model="res.groups">
<field name="name">Repairs: User (CS Intake)</field>
<field name="privilege_id" ref="res_groups_privilege_fusion_repairs"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
<field name="comment">CS / front-office staff who take repair intake calls and view repairs.</field>
</record>
<record id="group_fusion_repairs_dispatcher" model="res.groups">
<field name="name">Repairs: Dispatcher</field>
<field name="privilege_id" ref="res_groups_privilege_fusion_repairs"/>
<field name="implied_ids" eval="[(4, ref('group_fusion_repairs_user'))]"/>
<field name="comment">Assigns technicians to repairs, reschedules visits, manages parts pre-pull picklists.</field>
</record>
<record id="group_fusion_repairs_manager" model="res.groups">
<field name="name">Repairs: Manager</field>
<field name="privilege_id" ref="res_groups_privilege_fusion_repairs"/>
<field name="implied_ids" eval="[(4, ref('group_fusion_repairs_dispatcher'))]"/>
<field name="comment">Configures intake templates, pricing, maintenance contracts, on-call rotation, variance overrides.</field>
</record>
<!-- =====================================================================
Admin auto-membership: anyone with base.group_system (Settings /
Administration) automatically gets Repairs Manager, which implies
Dispatcher and User. So admin users see the Fusion Repairs app
and have full access without needing to be added manually.
===================================================================== -->
<record id="base.group_system" model="res.groups">
<field name="implied_ids" eval="[(4, ref('fusion_repairs.group_fusion_repairs_manager'))]"/>
</record>
<!-- ==================================================================== -->
<!-- RECORD RULES -->
<!-- ==================================================================== -->
<!-- Multi-company isolation on repair.order -->
<record id="rule_repair_order_company" model="ir.rule">
<field name="name">Repair Order: Multi-Company</field>
<field name="model_id" ref="repair.model_repair_order"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
<field name="global" eval="True"/>
</record>
<!-- Field technicians (from fusion_tasks) see only repairs they're assigned to as technician on a linked task.
Uses STORED fields (technician_id + additional_technician_ids) - not the computed all_technician_ids. -->
<record id="rule_repair_order_technician_own" model="ir.rule">
<field name="name">Repair Order: Technician sees own repairs</field>
<field name="model_id" ref="repair.model_repair_order"/>
<field name="domain_force">['|', ('x_fc_technician_task_ids.technician_id', '=', user.id), ('x_fc_technician_task_ids.additional_technician_ids', 'in', [user.id])]</field>
<field name="groups" eval="[(4, ref('fusion_tasks.group_field_technician'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<!-- Intake answer access scoped to repair access -->
<record id="rule_repair_intake_answer_company" model="ir.rule">
<field name="name">Repair Intake Answer: Multi-Company</field>
<field name="model_id" ref="model_fusion_repair_intake_answer"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
<field name="global" eval="True"/>
</record>
<!-- Sales Rep Portal: sees only repair orders they submitted -->
<record id="rule_repair_order_sales_rep_portal" model="ir.rule">
<field name="name">Repair Order: Sales Rep Portal - Own Repairs</field>
<field name="model_id" ref="repair.model_repair_order"/>
<field name="domain_force">[('x_fc_intake_user_id', '=', user.id)]</field>
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
</odoo>