feat(plating): in-Odoo notifications, timer audit, presence-aware Manager Desk, auto-promotion

End-to-end workflow tightening + the team / skills system. Three
phases bundled because they share the same touchpoints (button_start /
button_finish / Manager Desk dropdown).

PHASE 1 — In-Odoo notifications + timer audit
=============================================
Workers now get a bell-icon notification (Odoo Discuss inbox) the
moment a manager assigns them a WO. No email — operators check Discuss
between jobs, and the customer-facing notification dispatcher stays
out of the worker loop.

- mrp.workorder.write() override fires message_notify(message_type=
  'user_notification') only when x_fc_assigned_user_id transitions to
  a non-empty value (clearing or no-op writes don't ping)
- 4 new fields on the WO header surface what was previously buried in
  time_ids: x_fc_started_by_user_id, x_fc_started_at,
  x_fc_finished_by_user_id, x_fc_finished_at
- button_start stamps started_* once (subsequent pause/resume cycles
  preserve the original); button_finish stamps finished_* every time
  the WO closes
- New "Timer Audit" group on the WO form (Time & Cost tab)

PHASE 2 — Presence-aware Manager Desk
=====================================
Manager Desk now knows who's clocked in. Works with vanilla
hr_attendance and fusion_clock — both expose hr.attendance with an
open record while the operator is on shift.

- bridge_mrp depends on hr_attendance
- hr.employee.x_fc_is_clocked_in computed field (batched query — one
  DB hit for the whole employee set, not N+1)
- hr.employee._fp_clocked_in_user_ids() classmethod for the dashboard
- manager_controller sends operators with is_clocked_in / role_ids /
  lead_hand_role_ids per worker, plus presence dict {clocked_in: N,
  total: M}; each WO carries role_id/role_name so the dropdown can
  match qualified operators

Manager Desk OWL:
- Header gets a "Present 7 / 12" pill chip; tap to toggle hideOffShift
  (off-shift hidden when active, accent colour when filter is on)
- New operatorsForWO(wo) helper sorts dropdown options into 4 buckets:
  qualified+clocked-in → lead-hand+clocked-in → clocked-in untrained
  (training mode) → off-shift (greyed; only shown when hideOffShift
  is false). Each option carries a ●/○ dot prefix and a soft suffix.

PHASE 3 — Skills, lead-hand-per-role, auto-promotion
====================================================
The team grows organically: managers assign training tasks, operators
finish them, the system auto-promotes after N successful runs.

- fp.work.role.mastery_required (integer, default reads from the
  company-level Default Mastery Threshold). Each role can override —
  masking might need 1 success, electroless nickel 5.
- res.company.x_fc_default_mastery_threshold + res.config.settings
  exposure under "Workforce Settings" in the Fusion Plating settings
  block (default 3)
- hr.employee.x_fc_lead_hand_role_ids m2m, separate from
  x_fc_work_role_ids — Sarah can be a lead hand for masking + racking
  even if those aren't her primary roles. Manager-only group access.
- New fp.operator.proficiency model (one row per employee+role) with
  completed_count, first/last_completed_at, promoted, promoted_at,
  progress_label compute. SQL-unique on (employee, role).
- mrp.workorder.button_finish increments the (employee, role)
  counter, then if count >= role.mastery_required AND not promoted,
  adds the role to x_fc_work_role_ids and posts a "🎉 Promoted"
  chatter line on the employee record. Wrapped in try/except so a
  tracker glitch never blocks production.
- Promotion uses the WO's assigned_user_id, NOT env.user — credit
  goes to the operator who was supposed to do it, even if a manager
  finished on their behalf.

Employee form gets a "Shop Roles" tab (supervisor+):
- "Tasks This Operator Can Do" m2m
- "Lead Hand For" m2m (manager-only)
- Read-only Task Proficiency list with progress / promotion badges

Verified on odoo-entech: all fields land, default threshold = 3,
asset bundle regenerated as 9f38f05.

Module bumps: fusion_plating 19.0.4.0.0,
fusion_plating_bridge_mrp 19.0.4.0.0,
fusion_plating_shopfloor 19.0.11.0.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-04-18 22:05:32 -04:00
parent c1d26f3168
commit 0d12902ee7
18 changed files with 744 additions and 42 deletions

View File

@@ -5,7 +5,7 @@
{
'name': 'Fusion Plating',
'version': '19.0.3.0.0',
'version': '19.0.4.0.0',
'category': 'Manufacturing/Plating',
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
'description': """

View File

@@ -29,6 +29,20 @@ class ResCompany(models.Model):
'Settings > Fusion Plating.',
)
# ----- Worker auto-promotion default -----------------------------------
# Default number of successful WO completions a worker needs on a role
# before it's auto-added to their Shop Roles. Each role can override
# via fp.work.role.mastery_required.
x_fc_default_mastery_threshold = fields.Integer(
string='Default Mastery Threshold',
default=3,
help='How many successful WO completions an operator needs on a '
"task before it's added to their Shop Roles automatically. "
'New roles inherit this number; managers can override per '
'role on the role form. 1 = promote on first success; 3 = '
'solid baseline; 5+ for tasks that need real practice.',
)
# ----- Facility footprint for this legal entity ----------------------
x_fc_facility_ids = fields.One2many(
'fusion.plating.facility',

View File

@@ -20,3 +20,8 @@ class ResConfigSettings(models.TransientModel):
readonly=False,
string='Fusion Plating Timezone',
)
x_fc_default_mastery_threshold = fields.Integer(
related='company_id.x_fc_default_mastery_threshold',
readonly=False,
string='Default Mastery Threshold',
)

View File

@@ -27,6 +27,16 @@
<field name="x_fc_default_tz"/>
</setting>
</block>
<block title="Workforce Settings"
name="fp_workforce_settings"
help="Defaults that govern how the shop tracks worker skills and promotions across recipes.">
<setting id="fp_default_mastery"
string="Default Mastery Threshold"
help="How many successful WO completions an operator needs on a new task before it's added to their Shop Roles automatically. Each role can override this on its own form (e.g. masking 1, electroless nickel 5).">
<field name="x_fc_default_mastery_threshold"/>
</setting>
</block>
</app>
</xpath>
</field>