Files
Odoo-Modules/fusion_plating/fusion_plating/views/fp_migration_views.xml
gsinghpal 5cc1117f75 feat(plating-migration): dry-run + Owner-approval workflow
Phase H of permissions overhaul (LAST subagent phase).

New models:
- fp.migration.preview (state: pending/approved/cancelled/rolled_back)
- fp.migration.preview.line (one per active internal user)

On -u, post_init_hook creates a preview in 'pending' state, walks all
active non-share users through the 12-rule mapping predicate chain
(first match wins, highest precedence first), and schedules a
mail.activity on every Owner.

Mapping table (per spec Section 5):
  uid 1/2 / Administrator   -> owner
  CGP DO (existing)          -> owner + res.company DO field set
  CGP Officer                -> quality_manager
  Manager / Shop Mgr (old)   -> manager
  Accounting                 -> manager
  Estimator-without-Manager  -> sales_rep (flagged: loses confirm)
  Supervisor / Receiving     -> shop_manager
  Operator                   -> technician
  catchall                   -> 'no'

Owner clicks 'Approve & Run' on the preview form -> sudo write removes
old plating groups, adds new role's group, posts Markup chatter audit.
Optionally sets res.company.x_fc_cgp_designated_official_id for the DO.

30-day rollback window via JSON snapshot of groups_id per line. Daily
cron (Fusion Plating: Purge Expired Role Migrations) clears snapshots
+ unlinks old [DEPRECATED] groups after 30 days.

ACL: fp.migration.preview + .line both Owner-only (CRUD).
Menu: Plating > Configuration > Role Migrations (Owner-only).

Tests cover: only-Owner-can-approve, approve advances state, cancel
blocks after approval, rollback restores groups_id, Estimator warning
flagged, uid 2 maps to owner, rollback blocked after 30 days.

Per CLAUDE.md: ir.cron uses only Odoo-19-valid fields (no numbercall,
no doall). Post-init hook is idempotent — won't double-create previews
or re-fire if all users already migrated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 02:21:43 -04:00

93 lines
4.2 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="view_fp_migration_preview_form" model="ir.ui.view">
<field name="name">fp.migration.preview.form</field>
<field name="model">fp.migration.preview</field>
<field name="arch" type="xml">
<form>
<header>
<button name="action_approve_and_run" type="object"
string="Approve &amp; Run"
class="oe_highlight"
invisible="state != 'pending'"
confirm="This will apply role changes to all listed users. Continue?"/>
<button name="action_cancel" type="object"
string="Cancel"
invisible="state != 'pending'"/>
<button name="action_rollback" type="object"
string="Rollback"
invisible="state != 'approved'"
confirm="This will restore all users to their pre-migration groups. Continue?"/>
<field name="state" widget="statusbar"/>
</header>
<sheet>
<div class="oe_title">
<h1><field name="name"/></h1>
</div>
<group>
<group>
<field name="user_count"/>
<field name="warning_count"/>
</group>
<group>
<field name="approved_by_id"/>
<field name="approved_at"/>
<field name="rollback_deadline"/>
</group>
</group>
<notebook>
<page string="Users">
<field name="line_ids">
<list editable="bottom" decoration-warning="warning">
<field name="user_id"/>
<field name="current_groups"/>
<field name="proposed_role"/>
<field name="capability_delta"/>
<field name="warning" widget="boolean_toggle"/>
<field name="notes"/>
</list>
</field>
</page>
</notebook>
</sheet>
<chatter/>
</form>
</field>
</record>
<record id="view_fp_migration_preview_list" model="ir.ui.view">
<field name="name">fp.migration.preview.list</field>
<field name="model">fp.migration.preview</field>
<field name="arch" type="xml">
<list decoration-warning="state == 'pending'"
decoration-success="state == 'approved'"
decoration-muted="state in ('cancelled', 'rolled_back')">
<field name="name"/>
<field name="state" widget="badge"/>
<field name="user_count"/>
<field name="warning_count"/>
<field name="create_date"/>
<field name="approved_by_id"/>
<field name="approved_at"/>
</list>
</field>
</record>
<record id="action_fp_migration_preview" model="ir.actions.act_window">
<field name="name">Role Migrations</field>
<field name="res_model">fp.migration.preview</field>
<field name="view_mode">list,form</field>
</record>
<menuitem id="menu_fp_migration_preview"
name="Role Migrations"
parent="fusion_plating.menu_fp_config"
action="action_fp_migration_preview"
sequence="9"
groups="fusion_plating.group_fp_owner"/>
</data>
</odoo>