H1+H2: Field technicians had perm_create=1 perm_write=1 on inspection certs (could forge or edit issued certs). Reduced to read-only - the visit-report wizard already sudos when creating new certs from a tech visit. Added rule_inspection_cert_readonly for the dispatcher group so even dispatchers cannot edit already-issued certs; only the manager can revoke/correct. Sealed audit trail. H3: Replaced display:flex / gap (which wkhtmltopdf 0.12 renders as a vertical stack) with inline-block + margin in the certificate PDF. Footer uses float left/right for the cert-number / inspector signature line so the layout survives wkhtmltopdf rendering. Bumped to 19.0.1.4.1. Co-authored-by: Cursor <cursoragent@cursor.com>
167 lines
9.3 KiB
XML
167 lines
9.3 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.
|
|
|
|
NOTE: per-group rules in Odoo are OR'd. A user who is BOTH a field
|
|
technician AND a Repairs User/Dispatcher/Manager will see all repairs
|
|
because the permissive Repairs rules below grant access via the OR. -->
|
|
<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>
|
|
|
|
<!-- Repairs office users (User / Dispatcher / Manager) see all repairs
|
|
across companies they have access to. OR'd with the technician rule
|
|
above so admin / dispatchers who happen to also be in field_technician
|
|
still see everything. -->
|
|
<record id="rule_repair_order_repairs_user_full" model="ir.rule">
|
|
<field name="name">Repair Order: Repairs Office Full Access</field>
|
|
<field name="model_id" ref="repair.model_repair_order"/>
|
|
<field name="domain_force">[(1, '=', 1)]</field>
|
|
<field name="groups" eval="[(4, ref('group_fusion_repairs_user'))]"/>
|
|
<field name="perm_read" eval="True"/>
|
|
<field name="perm_write" eval="True"/>
|
|
<field name="perm_create" eval="True"/>
|
|
<field name="perm_unlink" eval="False"/>
|
|
</record>
|
|
<record id="rule_repair_order_repairs_manager_unlink" model="ir.rule">
|
|
<field name="name">Repair Order: Repairs Manager Can Delete</field>
|
|
<field name="model_id" ref="repair.model_repair_order"/>
|
|
<field name="domain_force">[(1, '=', 1)]</field>
|
|
<field name="groups" eval="[(4, ref('group_fusion_repairs_manager'))]"/>
|
|
<field name="perm_read" eval="True"/>
|
|
<field name="perm_write" eval="True"/>
|
|
<field name="perm_create" eval="True"/>
|
|
<field name="perm_unlink" eval="True"/>
|
|
</record>
|
|
|
|
<!-- Repairs office users can read AND schedule technician tasks. This is
|
|
what makes "office can dispatch / reschedule" work without requiring
|
|
them to also be in the sales_team groups that fusion_tasks normally
|
|
keys off of. -->
|
|
<record id="rule_technician_task_repairs_office" model="ir.rule">
|
|
<field name="name">Technician Task: Repairs Office Access</field>
|
|
<field name="model_id" ref="fusion_tasks.model_fusion_technician_task"/>
|
|
<field name="domain_force">[(1, '=', 1)]</field>
|
|
<field name="groups" eval="[(4, ref('group_fusion_repairs_user'))]"/>
|
|
<field name="perm_read" eval="True"/>
|
|
<field name="perm_write" eval="True"/>
|
|
<field name="perm_create" eval="True"/>
|
|
<field name="perm_unlink" eval="False"/>
|
|
</record>
|
|
<record id="rule_technician_task_repairs_manager_unlink" model="ir.rule">
|
|
<field name="name">Technician Task: Repairs Manager Can Delete</field>
|
|
<field name="model_id" ref="fusion_tasks.model_fusion_technician_task"/>
|
|
<field name="domain_force">[(1, '=', 1)]</field>
|
|
<field name="groups" eval="[(4, ref('group_fusion_repairs_manager'))]"/>
|
|
<field name="perm_read" eval="True"/>
|
|
<field name="perm_write" eval="True"/>
|
|
<field name="perm_create" eval="True"/>
|
|
<field name="perm_unlink" eval="True"/>
|
|
</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>
|
|
|
|
<!-- Inspection certs: only manager can edit AFTER issue (everyone else read-only).
|
|
Visit-report wizard uses sudo() to create new certs from a tech visit. -->
|
|
<record id="rule_inspection_cert_readonly" model="ir.rule">
|
|
<field name="name">Inspection Certificate: Read-only for non-managers</field>
|
|
<field name="model_id" ref="model_fusion_repair_inspection_certificate"/>
|
|
<field name="domain_force">[(1, '=', 1)]</field>
|
|
<field name="groups" eval="[(4, ref('group_fusion_repairs_dispatcher'))]"/>
|
|
<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>
|
|
|
|
<!-- 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>
|