Commit Graph

55 Commits

Author SHA1 Message Date
gsinghpal
7b90f210b9 feat(fusion_plating): kind.area_kind drives Shop Floor column routing
Add required area_kind Selection to fp.step.kind so each kind
self-declares which plant-view column its steps belong in. Replaces
the hardcoded _STEP_KIND_TO_AREA dict (removed in fp_job_step.py
in the follow-up commit).

- New `blast` kind for the Blasting column (sequence=35)
- 26 existing kind records seeded with area_kind in XML
- Pre-migrate 19.0.21.2.0 seeds existing rows BEFORE NOT NULL hits
  the schema; also activates derack/demask/gating that were
  deactivated in 19.0.20.6.0 but are needed for the full taxonomy
- Step Kind form + list views surface area_kind (badge + chip)
- Step Kind search adds Group By Shop Floor Column
- Simple Editor kind picker shows "Masking — Masking column"
  suffix so authors see the routing at pick time
- Add Hot Water Porosity Test (A-15) + Final Inspection / Packaging
  templates (used by 7+3 recipe nodes that previously had no
  library entry)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:02:02 -04:00
gsinghpal
7bcbcb4008 fix(plating-perms): deploy-time cascade fixes from entech I3
5 fixes discovered during the live deploy to entech LXC 111:

1. pre-migrate.py to rename old configurator's 'Shop Manager' group BEFORE
   new core 'Shop Manager v2' XML loads (cross-module name collision on
   res_groups_name_uniq).

2. res_company_views.xml: dropped ref() inside <field domain=> attribute
   (Odoo 19 view validator interprets it as a field name).

3. sale_order_views.xml: replaced 3 separate xpaths for amount_total /
   amount_untaxed / amount_tax with a single xpath on tax_totals widget
   (Odoo 19 sale.view_order_form uses one widget instead of separate fields).

4. fp_cert_security.xml: certificate_type field, not cert_type. FAIR is a
   separate model so the rule only restricts cert_type='nadcap_cert' now.

5. fp_certificate_views.xml + fp_capa_views.xml + fp_customer_spec_views.xml:
   stripped user_has_groups() from invisible= / readonly= attrs (Odoo 19
   view validator interprets as field name). Model-layer ACLs and ir.rules
   already enforce the same restrictions.

Also fixed res.groups.users -> user_ids in fp_migration.py (Odoo 19 rename,
caught when manually invoking _fp_notify_owners post-deploy).

CLAUDE.md updated with 4 new rules (13e cross-module name collisions,
13f ref() in domain, 13g tax_totals widget, 13h user_has_groups in attrs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 09:07:13 -04:00
gsinghpal
0047f49d2c fix(plating-perms): address final-reviewer critical + important issues
Pre-deploy fixes for Phase 1 permissions overhaul branch (catches by
final-reviewer subagent + main session).

CRITICAL FIXES:

C1: groups_id -> group_ids (Odoo 19 field rename). Affected ~30 sites
    across 4 model files, 1 view, 7 test files. Documented project
    gotcha (feedback_odoo19_groups_id_renamed.md) that the implementer
    subagents missed because they don't see user memory.

C2: action_fp_resolve_plating_landing server action now calls
    env['ir.actions.act_window'].sudo()._fp_resolve_landing_for_current_user()
    instead of the old inline priority chain. Phase E's role-based
    dispatch was previously dead code.

C3: New migrations/19.0.21.1.0/post-migrate.py triggers
    _fp_post_init_role_migration(env) on -u. post_init_hook only fires
    on INSTALL in Odoo 19, not UPGRADE -- so Phase H's preview creation
    wouldn't have auto-fired on entech without this script. Module
    version bumped to 19.0.21.1.0 to match the migration directory.

C4: Team kanban template rewritten for Odoo 19 (<t t-name='card'> with
    semantic <aside>/<main>) instead of legacy <t t-name='kanban-box'>.
    Previous template threw 'Missing card template' at render.

IMPORTANT FIXES:

I1: SO state=sent Confirm button (id='action_confirm') now also gated
    to group_fp_sales_manager. Previously only the state=draft button
    was gated; Sales Reps could send-and-confirm via the secondary path.

I2: Designated Officials picker domain uses all_group_ids (transitive)
    instead of group_ids (explicit only). Owner users now correctly
    appear as eligible CGP DO candidates via the implied_ids chain.

I3: test_menu_visibility.py compliance hub xmlid corrected to
    fusion_plating.menu_fp_compliance_hub (was
    fusion_plating_compliance.menu_fp_compliance_hub which doesn't exist
    -- the hub menu is defined in core's fp_menu.xml). Tests were
    silently skipTest-ing.

I4: _inverse_plating_role chatter audit reads old role from DB via SQL
    (bypasses cache) so 'old -> new' displays actual values, and
    short-circuits no-op writes.

I5: _FP_ROLE_MAPPING_RULES reordered: cgp_designated_official fires
    BEFORE admin/uid_1_or_2 so admin+DO users keep the capability_delta
    marker that triggers res.company.x_fc_cgp_designated_official_id
    auto-set during migration.

I6: _cron_purge_expired_migrations skips groups with active users
    instead of unlink-ing unconditionally. Defense against rollback
    safety being bypassed by manual role assignments post-migration.

CLAUDE.md updated with 3 new durable rules (13b kanban card template,
13c group_ids vs all_group_ids, 13d post_init_hook only on install).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 08:37:13 -04:00
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
gsinghpal
89a937fb32 feat(plating-team): Owner-only Team kanban + Designated Official fields
Phase F of permissions overhaul.

Adds res.users.x_fc_plating_role Selection field (8 options matching
the role hierarchy). Compute reads highest plating group from
groups_id (precedence: owner > QM > manager > sales_manager >
shop_manager > sales_rep > technician). Inverse uses sudo().write()
to clear all plating-role groups (additive-by-default m2m (3, id))
then adds the chosen one, and posts a Markup-wrapped chatter audit
naming the actor.

New Owner-only menu: Plating > Configuration > Team. Standard
res.users kanban grouped by x_fc_plating_role with records_draggable
for drag-and-drop role changes. Domain hides shared/portal users
and archived users.

res.company gains two Designated Official fields:
- x_fc_cgp_designated_official_id (CGP DO per Defence Production Act §22)
- x_fc_nadcap_authority_user_id (Nadcap signer)

Both tracking=True for audit. View-level domain restricts picker to
Owner or Quality Manager users via [(ref('...'), ref('...'))] xmlid
domains. New 'Plating Designated Officials' page on res.company form,
Owner-only visibility.

Tests in test_team_page.py cover compute/inverse/chatter/menu.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 02:03:44 -04:00
gsinghpal
36cd4341a7 feat(plating-menu): Layer 1+2 — explicit groups on top-level menus + submenus
Phase D Tasks D1-D4 of permissions overhaul. Adds explicit groups=
attributes to:
- 9 top-level Plating menus (matrix per spec Section 2.E)
- Quality submenus: Audits, Customer Specs, AVL → QM-only
- Compliance hub child submenus (CGP, General, Safety, Aerospace,
  Nuclear) → QM-only
- Operations submenus: Maintenance, Move Log, Labor History → Shop
  Manager+; Replenishment Suggestions → Manager+

Replaces fragile inheritance + action-ACL-based visibility with
explicit per-menu gates. Now every role's menu tree is deterministic.

Also adds fusion_plating/tests/test_menu_visibility.py — per-role
matrix tests using ir.ui.menu.search_count with the test user.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 01:35:11 -04:00
gsinghpal
06dc6a62b9 feat(fusion_plating): long_running flag on process node (auto-pause opt-out)
Plan task P2.1. Boolean on fusion.plating.process.node that exempts
steps generated from this node from the shop-floor auto-pause cron
(added in P2.4/P2.5). Use for 24h bakes, multi-shift soaks, and
similar long-but-legitimate operations.

Toggle visible on the process-node form for operation/step types,
grouped with parallel_start in the Behaviour section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 22:01:13 -04:00
gsinghpal
152ed86c3a feat(thickness): single Char range field — drop fp.recipe.thickness picker
Per client direction: every order is a thickness RANGE (e.g.
"0.0005-0.0008 mils" or "5-10 mils"), never a single value. The
old picker model (fp.recipe.thickness with a single 'value' Float)
was modelling the wrong concept and overcrowding the order entry
UI. Replaced with one free-text Char field that auto-fills from
last-used or part default.

DELETED entirely:
- fp.recipe.thickness model (file + view + ACL + manifest entry)
- recipe.thickness_option_ids One2many (the picker source)
- "Thickness Options" inline list on the recipe form
- sale.order.line.x_fc_thickness_id (M2O picker)
- account.move.line.x_fc_thickness_id
- fp.delivery.x_fc_thickness_id
- fp.direct.order.line.thickness_id

ADDED:
- sale.order.line.x_fc_thickness_range (Char) — operator types range
- account.move.line.x_fc_thickness_range — for invoice rendering
- fp.delivery.x_fc_thickness_range — for packing slip
- fp.direct.order.line.thickness_range — for the wizard
- fp.part.catalog.x_fc_default_thickness_range — part default

AUTO-FILL CHAIN (sale.order.line + wizard line):
1. Operator already typed → keep
2. Most recent SO line for (this part, this customer) with a
   non-empty thickness_range → copy that
3. part.x_fc_default_thickness_range → copy
4. Blank — operator types

Implemented as both an @api.onchange (interactive) AND a
create() override (programmatic — wizard, sale_mrp bridge,
imports). Same logic in both paths.

WIZARD push-to-defaults: when "Save as Default" toggle is ticked
on a wizard line, persist the line's thickness_range to
part.x_fc_default_thickness_range so future first-customer orders
get a sensible starting point.

REPORTS: customer_line_header.xml + report_fp_wo_sticker.xml now
print the Char range as-typed (no display_name lookup needed).

KEPT (admin documentation only — doesn't affect order entry):
- recipe.thickness_min, thickness_max, thickness_uom on the recipe
  root: documents the recipe's CAPABILITY range. No UI gate; just
  for spec authors to record what the chemistry can produce.

JOB GROUPING: fp.job auto-create groups SO lines by (recipe, part,
spec, thickness, serial). Updated to key on the thickness_range
Char (stripped) instead of the deleted thickness_id integer.

DB cleanup: --update=base ran on the upgrade, dropping the
fp_recipe_thickness table + the four x_fc_thickness_id columns.
Existing data was already nulled in earlier dev work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:54:40 -04:00
gsinghpal
bc7c771f20 chore(menu): promote Specifications + clarify misleading menu names
Specifications menu (urgent — workflow blocker for estimators):
- Moved from Configuration → Quality & Documents (manager-only) up
  to Plating → Quality (sequence 70). Now visible to estimator,
  supervisor, and manager.
- Renamed "Customer Specs" → "Specifications" — the seeded library
  includes industry standards (AMS, MIL, ASTM, BAC) not just
  customer-private specs.
- Action display name updated: "Customer Specifications" → "Specifications".
- Added action.help HTML so the empty-state placeholder explains
  the Specifications library purpose to first-time users.
- Old xmlid (menu_fp_config_customer_spec) preserved so existing
  links / breadcrumbs / search references continue to resolve.

Other clarifying renames:
- Safety: "JHSC" / "JHSC Meetings" → "H&S Committee (JHSC)" /
  "H&S Committee Meetings" — acronym was opaque to non-Canadian
  H&S folks.
- Operations: "Move Log" → "Parts & Rack Move Log" — generic name
  could be confused with chatter messages or stock moves.
- Configuration → Recipes & Steps: "Workflow States" →
  "Job Workflow Stages" — generic name; clarifies these are job
  state milestones (passed-stage tracking), not generic workflow.
- Compliance → General: child folder "Configuration" → "Reference
  Data" — three levels of "Configuration" nesting (Plating>Config
  vs Plating>Compliance>General>Config) was confusing.

No model / data changes. Pure menu metadata.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:05:19 -04:00
gsinghpal
c96f27b96c feat(promote-customer-spec): NADCAP recipe lock (Phase A+)
Per client review: NADCAP-qualified recipes need manager-only edit
permission. Word-doc external approval workflow stays outside ERP;
this is the in-app enforcement.

- New field fp.process.node.is_locked (recipe root)
- write() override blocks non-manager edits when recipe root is_locked
  Lock checks via recipe_root_id so child ops/steps are also protected
  Manager bypass via group + env.su (sudo) bypass for system jobs
- Amber "LOCKED — Manager Edit Only" ribbon at top of recipe form
- Toggle on Specification & Bake page under "Change Control (NADCAP)"
- Spec doc updated with Decision 6.5 + backlog from client review:
  approvals list, doc control auto-sync, oven recorder sync, SOP
  word-doc workflow, final-inspection signoff on cert

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 00:55:07 -04:00
gsinghpal
406cac1362 feat(promote-customer-spec): Phase A — recipe + spec foundation
- Add fp.recipe.thickness model (replaces fp.coating.thickness, scoped to recipe root)
- Add spec metadata + bake-relief fields to fusion.plating.process.node (recipe root):
  phosphorus_level, thickness_min/max/uom, thickness_option_ids,
  requires_bake_relief + bake_window_hours/temperature/duration
- Add recipe_ids M2M + print_on_cert to fusion.plating.customer.spec
- Add applicable_spec_ids reverse M2M as inherit in fusion_plating_quality
  (avoids circular dep — core can't reference customer.spec which lives in quality)
- Surface new fields on recipe form ("Specification & Bake" notebook page)
- Surface recipe linkage on customer spec form

Pure additive. Foundation for Phases B-E.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 00:50:17 -04:00
gsinghpal
2d9779047b fix(jobs): registry load failure after Tier 2/3 persistence patches
Two compounding issues introduced by the persistence audit work:

1. fields.Text mismatch: sale.order.x_fc_internal_note and
   x_fc_external_note are actually fields.Html. I declared the
   sale.order.line related mirrors and the fp.job stored copies as
   fields.Text, so setup_related raised:
     TypeError: Type of related field
     sale.order.line.x_fc_internal_note is inconsistent with
     sale.order.x_fc_internal_note
   Fixed by switching both Note fields on fp.job and sale.order.line
   to fields.Html.

2. Module-load-order: Tier 3 fields (x_fc_delivery_method,
   x_fc_ship_via, x_fc_invoice_strategy) are defined in
   fusion_plating_jobs (related to sale.order via _inherit), but I
   referenced them in fusion_plating core's fp_job_views.xml — which
   loads BEFORE fusion_plating_jobs registers the fields. View
   validator raised "Field x_fc_delivery_method does not exist".
   Fixed by removing those 3 fields from the core view group and
   adding them via xpath in fusion_plating_jobs's fp_job_form_inherit
   (which loads after the fields are registered).

Both fixes deployed and verified — registry loads in 2s, all field
types match, related path resolves correctly. No data loss; the
fp.job rows that already had stored Text content for internal_note /
external_note will carry over into the Html field intact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:45:59 -04:00
gsinghpal
cba9a6da6b feat(jobs): mirror delivery_method/ship_via/invoice_strategy on fp.job
Tier 3 of the SO->fp.job persistence audit. Three logistics/billing
fields surface on fp.job as related read-only (not stored) mirrors:

- x_fc_delivery_method - Local Delivery / Shipping Partner / Customer
  Pickup. Cargo classification used by logistics planning.
- x_fc_ship_via - Carrier name (UPS, FedEx, customer pickup, etc.).
- x_fc_invoice_strategy - Deposit / Progress / Net Terms / COD-Prepay.
  Read by the invoicing module's hooks; mirroring on the WO is for
  manager visibility only.

These were intentionally chosen as related (not stored persisted)
because the SO is the authoritative source - the existing downstream
code (delivery + invoicing modules) already reads them off SO directly.
A stored copy would risk drift. Related auto-follows SO updates.

Same three fields also mirrored on sale.order.line as stored related
for per-line list visibility.

Closes the SO->fp.job persistence audit. All 10 operational fields
identified now flow through to the WO (7 stored + populated at confirm,
3 related read-only).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:39:12 -04:00
gsinghpal
15eac309ee feat(jobs): persist deadlines + planned start + notes on fp.job
Tier 2 of the SO->fp.job persistence audit. Four operational metadata
fields mirrored from sale.order:

- x_fc_internal_deadline (Date) - shop's internal target finish date,
  ahead of the customer-facing deadline. Kept separate from
  date_deadline (which scheduling code may adjust).
- x_fc_planned_start_date (Date) - customer-quoted planned start date.
  Kept separate from date_planned_start (Datetime, capacity-adjusted).
- x_fc_internal_note (Text) - shop-internal notes from the order.
- x_fc_external_note (Text) - customer-facing notes, printed on
  traveller / BoL / cert.

All four populate at SO confirm via _fp_auto_create_job, and surface
on sale.order.line as stored related fields for per-line visibility.
fp.job form view gets a Notes group alongside the Customer References
group from Tier 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:37:19 -04:00
gsinghpal
7d37f5713c feat(jobs): persist Customer Job # + PO # + Rush Order on fp.job
Tier 1 of the SO->fp.job persistence audit. Three customer-reference
fields entered on sale.order's Plating tab were not flowing through
to fp.job (or SO lines), so the shop floor and printed paperwork
(traveller, BoL, cert) had to round-trip via sale_order_id every time.

Changes:
- fp.job: new x_fc_customer_job_number (Char, tracking), x_fc_po_number
  (Char, tracking), x_fc_rush_order (Boolean, tracking). All three
  populated by _fp_auto_create_job at SO confirm time.
- sale.order.line: x_fc_customer_job_number / x_fc_po_number added as
  stored related fields off order_id so per-line list views show the
  customer's references without navigating to the order header
  (x_fc_rush_order was already on lines).
- fp.job form view: small Customer References group under the title
  surfaces the three fields where the user expects them.

Verified end-to-end: SO -> SO line related fields -> fp.job direct
fields all carry the same value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:34:56 -04:00
gsinghpal
cd2584d6ee ui(rename): "Plating Job" -> "Work Order" / display "WO # 01368"
Standardise user-facing terminology across 5 modules (27 files):
  - display_name compute: 'Work Order # 01368' -> 'WO # 01368'
  - _description on 5 models: Plating Job{," Step"," Step Time Log"," Margin Report"," Recipe Node Override"} -> Work Order equivalents
  - field labels (string=...) on 13 Many2one / One2many fields
    across fp.batch, fp.thickness_reading, fp.quality.hold,
    fp.job_consumption, fp.portal.job, fp.certificate, fp.delivery,
    fp.quality.check, fp.racking.inspection, res.partner, sale.order
  - XML view labels: action names, list/form/search strings,
    portal template names, dashboard tile titles

What's deliberately preserved:
  - DB model name 'fp.job' (technical identifier — used by
    sale_order.x_fc_plating_job_ids and all comodel refs)
  - Module name 'fusion_plating_jobs' (directory / import path)
  - Settings -> Apps display label 'Fusion Plating Jobs' (module
    identity for Odoo's app picker)
  - 'Use Native Plating Jobs' migration toggle (internal mechanism
    flag, not user-facing terminology)

Verified on entech: WH/JOB/01368 now displays as 'WO # 01368'
everywhere humans look (form header, breadcrumbs, M2O dropdowns,
error messages, smart-button titles).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:22:09 -04:00
gsinghpal
b0070afc1b feat(jobs): step qty gate + partial-qty + display rename
Three coupled shop-floor corrections:
- fp.job._compute_display_name: renders "Work Order # 00011" in
  form header, breadcrumbs, M2O dropdowns, and error messages.
  DB name stays as WH/JOB/00011 - existing chatter/cert/delivery
  references unchanged.
- fp.job.step.button_finish: refuses if qty_at_step > 0 AND a
  downstream pending/ready step exists. Last runnable step is
  exempt (parts complete in place). Manager bypass via
  fp_skip_qty_gate=True context key.
- fp.job.step.action_complete_one_to_next: new per-row button
  "Complete 1 -> Next" for streaming flow (large parts going
  one-by-one). Records move(qty=1) to next step; if drain takes
  qty_at_step to 0, auto-finishes source + auto-starts destination
  via existing action_finish_and_advance.
- fp.job.step._fp_record_one_piece_auto_move: auto-move shim
  wired into action_finish_and_advance. qty=1 + downstream =>
  silently record move(1). qty>1 + downstream => raise pointing
  at Complete 1 -> Next. Last step always allowed.
- 16 new TestQtyGate tests covering gate / shim / auto-finish /
  last-step exemption / display rename / Move wizard zero-qty.

Spec: docs/superpowers/specs/2026-05-12-step-qty-gate-and-display-rename-design.md
Plan: docs/superpowers/plans/2026-05-12-step-qty-gate-and-display-rename.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 23:31:56 -04:00
gsinghpal
6b7b44264a changes 2026-05-10 10:25:12 -04:00
gsinghpal
586f05d567 chnages 2026-05-04 02:14:34 -04:00
gsinghpal
9794a98de9 feat(jobs): Sub 13 sequential step enforcement + Sub 12e v3 wizard
Two coherent feature drops shipping together because their fp_job_step
edits overlap. Both target operator workflow correctness.

## Sub 13 — Sequential step enforcement (recipe + per-step)

Background:
  Investigation on WH/JOB/00339 showed operators starting Incoming
  Inspection while Contract Review was still in_progress. Audit:
  98.7% of recipe operations system-wide had requires_predecessor_done
  = false (the legacy per-step opt-in defaults off, recipe authors
  rarely tick the box).

Architecture:
  Recipe-level toggle + per-step opt-out (Option A from /investigate).
  * fusion.plating.process.node.enforce_sequential — Boolean on the
    recipe root. Default True. When True, every operation under this
    recipe waits for earlier-sequence steps to finish before it can
    start.
  * fusion.plating.process.node.parallel_start — Boolean on operation
    nodes. When True, this step bypasses the sequential gate (e.g.
    paperwork or QA review that runs alongside production).
  * Mirrored on fp.step.template (parallel_start) so library steps
    carry the flag into snapshots.
  * fp.job.enforce_sequential — related from recipe_id. Snapshotted
    at job creation so a recipe author flipping the recipe's flag
    AFTER job generation does NOT change behaviour mid-run.
  * fp.job.step.parallel_start — related from recipe_node_id.
  * Decision matrix (encapsulated in
    fp.job.step._fp_should_block_predecessors):
        recipe.enforce_sequential | step.parallel_start | step.req_pred_done | block?
        --------------------------|---------------------|--------------------|------
                 True             |       False         |        any         |  YES
                 True             |       True          |        any         |   no
                 False            |        any          |       True         |  YES
                 False            |        any          |       False        |   no
  * Manager bypass via context fp_skip_predecessor_check=True (existing).

Runtime gates:
  * fp.job.step.button_start — calls _fp_should_block_predecessors;
    raises UserError naming the blocking earlier step(s).
  * fp.job.step.can_start — computed Boolean for view-side disable.
  * Move wizard predecessor check
    (fusion_plating_shopfloor/controllers/move_controller.py) — uses
    the same helper so tablet + backend behave identically.

UI surface:
  * Recipe form (fp_process_node_views.xml) — enforce_sequential
    toggle on recipe root, parallel_start checkbox on operations.
  * Step template form — parallel_start checkbox.
  * Simple Recipe Editor (inline library form) — Parallel Start
    checkbox + legacy flag demoted with muted styling + supervisor
    group gate.
  * Recipe Tree Editor (properties panel) — both flags exposed,
    only-show on the right node_type.
  * Controllers updated to allowlist + payload the new fields.

Migration:
  fusion_plating/migrations/19.0.18.12.0/post-migrate.py — sets
  enforce_sequential = TRUE on every existing recipe-root node.
  Idempotent. User confirmed dev-stage data, so retroactive flip
  is safe (no production jobs to disrupt).

Tests:
  TestSequentialEnforcement (10 tests) covering:
    * sequential mode blocks out-of-order start
    * first step always startable
    * predecessor finish/skip unlocks next
    * parallel_start opts out of gate
    * free-flow mode bypasses gate
    * legacy requires_predecessor_done still honoured in free-flow
    * manager bypass via context
    * can_start compute reflects state correctly
    * library template parallel_start snapshots into recipe-node

## Sub 12e — Record Inputs Wizard v3 (card layout, dark-mode aware)

Background:
  v2 wizard was a 17-column wide editable table. Operators got lost
  finding which value column applied to their row's type, horizontal
  scroll required on tablets, composite types crammed into one row.

New layout:
  * Each measurement renders as a stacked card (CSS Grid + display
    transformation on the existing list widget — preserves inline
    editing, no JS rewrite).
  * Card header: prompt name (large, bold) + type/unit pills.
  * Card body: ONLY the value widget for this row's type
    (number / boolean / date / text / photo / multi-point / panel).
  * Composite types (multi-point thickness 5x reading + avg, bath
    panel 4 fields) get inline sub-grid inside the card.
  * Empty state ("no measurement prompts") with friendly CTA.

Dark mode:
  * SCSS branches at compile time on $o-webclient-color-scheme
    (per fusion-plating/CLAUDE.md note).
  * Tokens: 7 surface colours + 4 ink levels with light/dark hex
    pairs, all behind var(--fp-*) custom properties for per-deploy
    override.
  * Registered in BOTH web.assets_backend AND web.assets_web_dark
    so each bundle compiles its own palette.

Tablet polish:
  @media (max-width: 900px) — collapse meta below prompt + bump
  numeric input min-height to 56px.

Defensive:
  * v2 view kept in the XML file (instant rollback by changing one
    view_id ref).
  * `:has(.o_invisible_modifier)` rule drops empty cells out of the
    grid so Odoo's invisible="..." doesn't punch holes in layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 21:24:12 -04:00
gsinghpal
1da27ed6bf changes 2026-05-01 00:20:40 -04:00
gsinghpal
f990f29019 feat(plating-jobs): state-aware sort + default Open filter on Plating Jobs
The Plating Jobs list was sorted priority-desc, deadline-asc, id-desc — which
mixed Done (closed) jobs in with Confirmed (open) jobs and made the list look
chaotic to managers. Done jobs from weeks ago surfaced above active work.

Two changes:

1. New stored compute fp.job.state_priority (Integer, indexed) ranks states
   by managerial relevance: in_progress=0, confirmed=1, draft=2, on_hold=3,
   done=4, cancelled=5. _order now leads with state_priority asc, then
   priority desc, then date_deadline asc, then id desc. Active work bubbles
   to the top automatically.

2. Plating Jobs action defaults to a new 'Open' filter
   (state not in done, cancelled). Managers see only active work by default;
   they untick the filter to see history. Added On Hold + Cancelled filters
   too for full state coverage.

Verified on entech: top 10 jobs are now all in_progress, sorted by deadline
ascending. Existing 26-row list goes from chaotic to focused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 23:48:34 -04:00
gsinghpal
b187192c58 feat(step-library): full plating workflow coverage + per-recipe configurability + audit
Implements 2026-04-29-step-library-audit-design.md. Bumps fusion_plating
to 19.0.18.7.0, fusion_plating_jobs to 19.0.8.12.0, fusion_plating_reports
to 19.0.10.2.0.

LIBRARY EXPANSION
- 8 new Step Kinds: Receiving, Electroclean, Strike, Salt Spray,
  Adhesion Test, Hardness Test, Packaging, Tank Replenishment
- 4 new input types: photo, multi_point_thickness, bath_chemistry_panel, ph
- DEFAULT_INPUTS_BY_KIND rewritten to seed audit-grade prompts on every
  kind (bath IDs, photos, multi-point thickness, signatures, etc.)
- + Common Audit Fields one-click button on the library template form
- Default Operator Instructions relabel + alert callout

PER-RECIPE CONFIGURABILITY
- collect (Boolean) per recipe-step input prompt — opt out without delete
- collect_measurements (Boolean) master switch on recipe step — when off,
  wizard skips entirely
- template_input_id (Many2one) traceability link from recipe to library
- Recipe-step backend form view exposes the new fields with handle drag,
  toggle, target range, and library-source column

RUNTIME WIRING
- Step input wizard filters node.input_ids to step_input AND collect=True;
  short-circuits on collect_measurements=False
- New input types: photo (image widget + ir.attachment), multi-point
  thickness (5 readings + auto avg, skips empty cells), bath chemistry
  panel (pH/conc/temp/bath bundle), pH (0-14 numeric)
- Composite values JSON-serialized into value_text; photo via attachment

CoC REPORT
- Filters captured prompts to collect=True only
- Renders new input types with appropriate format

MIGRATION (post-migrate.py for 19.0.18.7.0)
- Backfills collect=True on recipe-step inputs
- Backfills collect_measurements=True on recipe steps
- Re-runs action_seed_default_inputs on every existing template
  (idempotent, preserves user edits)
- Backfills template_input_id by name-matching against source library
  template (handles JSONB vs varchar name columns)

SEED DATA
- 8 example templates (one per new kind) in fp_step_template_data.xml
  with noupdate=1

BATTLE TEST
- bt_step_library_audit.py: 29 assertions all PASS on entech

OWL EDITOR EXTENSION DEFERRED
- The simple recipe editor's per-step Instructions/Measurements
  expansions were not implemented in this pass; users configure via the
  backend recipe-step form. Track follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:13:54 -04:00
gsinghpal
13e300d90e changes 2026-04-28 19:39:37 -04:00
gsinghpal
afcd128f83 fix: rename ambiguous 'Work Center' / 'Work Centres' menus
Two distinct entities were both labelled 'Work Centre' (US/UK spelling
the only differentiator — confusing). Renamed by purpose, model IDs
unchanged so all 12+9 existing cross-refs keep working:

fusion.plating.work.center → 'Production Line'
  Physical shop-layout grouping that owns tanks. Examples: 'Line 1 —
  EN', 'Anodize Line', 'Prep Bay'. Has tank_ids (O2M),
  supported_process_ids (M2M), capacity_per_day. The thing tanks live
  in.

fp.work.centre → 'Routing Station'
  Per-job-step routing entity (post-Sub-11 mrp.workcenter replacement).
  Has 'kind' selection (wet_line / bake / mask / rack / inspect),
  cost_per_hour for fp.job.step rollup, default_bath_id +
  default_tank_id for release-ready validation. The thing a job step
  routes through.

Conceptually a Production Line CONTAINS many Routing Stations (e.g.
'EN Line' production line has wet-line, bake, inspect routing
stations on it).

Updated:
- _description on both models
- string= on the name fields
- list/form/search view strings
- act_window names ('Production Lines' / 'Routing Stations')
- menu items in fp_menu.xml + fp_jobs_menu.xml
- doc comments in both model files explaining the distinction

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:55:39 -04:00
gsinghpal
5f6c7af2a7 feat(phase3): tighten group-gating on operator-irrelevant top-levels
Three targeted gates so operators no longer see admin/audit views:

- KPIs (menu_fp_dashboard) → supervisor+. Operators don't need
  dashboards; their tablet shows what they need to do next.
- Move Log (menu_fp_job_step_move) → supervisor+. Operators see
  their own moves on the tablet; this top-level menu is the
  audit-of-everyone-else view.
- Replenishment Suggestions (menu_fp_replenishment_suggestions) →
  supervisor+. Purchasing decision, not operator concern.

Other top-levels were already correctly gated:
- Sales / Configurator → estimator
- Shipping & Receiving → group_fp_receiving
- Compliance hub → supervisor+
- Configuration → manager
- Shop Floor / Quality → operator (correctly visible to floor staff)
- Operations parent stays open; child menus enforce per-action gates

Net effect: a fresh operator now sees ~5 top-level menus instead of
the previous ~10. Supervisors see ~8. Managers see all.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:51:30 -04:00
gsinghpal
46715410a9 fix(phase2): restructure fp_menu.xml so buckets defined before children
Within fp_menu.xml itself, the menu_fp_replenishment_rules entry
referenced menu_fp_config_materials_tanks which was defined later in
the same file. Odoo's data loader is strictly top-down within a file.

Reorganized by section: 1) root, 2) Configuration + 7 buckets,
3) Compliance hub, 4) Operations parent, 5) all child menus (referencing
parents already defined above).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:48:06 -04:00
gsinghpal
3641b78a66 feat(phase2): Configuration grouped into 7 themed folders
Collapses the flat ~36-entry Configuration list into 7 navigable
folders + Settings (sibling, stays at top of Configuration). Existing
menu IDs unchanged so bookmarks + cross-module data refs still work
— only parent-id moves.

New folder menus (defined in fusion_plating core):
  menu_fp_config_shop_setup       Shop Setup
  menu_fp_config_recipes_steps    Recipes & Steps
  menu_fp_config_materials_tanks  Materials & Tanks
  menu_fp_config_workforce        Workforce
  menu_fp_config_quality_docs     Quality & Documents
  menu_fp_config_pricing_billing  Pricing & Billing
  menu_fp_config_reference_data   Reference Data

Routing per item (sources updated in their owning module):
  Shop Setup       Facilities, Work Centers, Work Centres, Process
                   Categories, Process Types, Bake Ovens, Shopfloor
                   Stations, Vehicles
  Recipes & Steps  Step Library, QC Checklist Templates, Quality Points
  Materials & Tanks  Bath Parameters, Replenishment Rules, Chemicals,
                     Rack Tags, Calibration Equipment, Calibration Events
  Workforce        Operator Certifications, Shop Roles, Training Types,
                   Quality Teams
  Quality & Documents  Customer Specs, Approved Vendor List, Quality
                       Tags, Quality Reasons, Quality Stages, N299
                       Levels, Notification Templates, Notification Log
  Pricing & Billing  Invoice Strategy Defaults, Account Holds
  Reference Data   Value Sets, Value Rotations
  (Settings remains as a sibling at top of Configuration, manager-gated)

Versions bumped: fusion_plating, fusion_plating_quality, _safety,
_shopfloor, _logistics, _culture, _invoicing, _notifications, _nuclear.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:45:21 -04:00
gsinghpal
0ad382e1a6 feat(phase1): top-level menu consolidation + landing-page resolver
Phase 1 collapses the Plating app's 17 top-level menus down to 6
domains (Sales, Operations, Receiving & Shipping, Quality,
Compliance, Configuration) so users no longer scroll a 17-item
sidebar to find one thing.

Re-parented (no XML id changes — bookmarks still work):
- fusion_plating_compliance.menu_fp_compliance_root
    → menu_fp_compliance_hub  (renamed 'General')
- fusion_plating_safety.menu_fp_safety_root
    → menu_fp_compliance_hub  (renamed 'Safety / WHMIS')
- fusion_plating_aerospace.menu_fp_aerospace
    → menu_fp_compliance_hub  (renamed 'Aerospace (AS9100 / Nadcap)')
- fusion_plating_nuclear.menu_fp_nuclear
    → menu_fp_compliance_hub  (renamed 'Nuclear (CSA N299 / CNSC)')
- fusion_plating_cgp.menu_fp_cgp
    → menu_fp_compliance_hub  (renamed 'Controlled Goods (CGP)')
- fusion_plating_certificates.menu_fp_certificates
    → menu_fp_quality (Certs are a Quality output, not a separate
      top-level concern)
- fusion_plating_bridge_maintenance.menu_fp_maintenance
    → menu_fp_operations
- fusion_plating.menu_fp_job_step_move (Move Log)
    → menu_fp_operations
- fusion_plating.menu_fp_job_step_timelog (Labor History)
    → menu_fp_operations

The new menu_fp_compliance_hub is supervisor-gated; underlying
verticals retain their own group locks (CGP officer, etc.).

Settings menu remains manager-gated through inheritance from
menu_fp_config (already in place).

NEW — Plating landing-page resolver:
- ir.actions.act_window.x_fc_pickable_landing  (Boolean tag for
  curated picklist; flagged on Sale Orders, Quotations, Process
  Recipes for Phase 1; more in Phase 2)
- res.company.x_fc_default_landing_action_id (admin sets fallback)
- res.users.x_fc_plating_landing_action_id (per-user override)
- ir.actions.server action_fp_resolve_plating_landing — picks
  user → company → Sale Orders fallback at click time
- menu_fp_root rewired to call the resolver
- User profile + Settings tabs surface the dropdowns

Configurator's earlier menu_fp_root override (action_fp_sale_orders
direct) removed — core's resolver now owns the routing.

Versions bumped: fusion_plating 19.0.11.0.0, configurator
19.0.17.16.0, plus 7 dependent modules patched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:33:37 -04:00
gsinghpal
504c8f34db feat(sub12c): Labor History views + Plating menu (Task 4)
Plating → Labor History (sequence 64, between Move Log 62 and
Aerospace 65). List view colour-coded by state (info/warning/
success/muted), with billed_pct progressbar and rich field optionals.

Search filters: My Timers (default), Today, Running, Paused, Pending
Reconciliation, Reconciled. Group-by: Operator, Job, Date.

Form view (read-only header with statusbar): identity fields readonly,
billed_hrs/min/sec editable for supervisors+ until state=reconciled.
Notes group at bottom. create=false (timers are runtime-produced;
manual creation goes through the tablet flow).

ACL rows for fp.job.step.timelog already shipped in Sub 12b's CSV
(operator/supervisor/manager) — no security changes needed here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:43:07 -04:00
gsinghpal
0794f7e3c9 feat(sub12b): move-log list/form/search + Plating menu
Plating → Move Log (sequence 62, between Logistics 60 and Aerospace 65).
Form is read-only (create=false) since moves are produced by the
tablet flow, not the desktop UI.

Search filters: Today, Scrap/Rework, Racked. Group-by: Job, Operator,
Transfer Type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:05:28 -04:00
gsinghpal
d9ae45ce9b feat(sub12b): extend fusion.plating.rack — racking_state + tags + capacity
The existing 'state' field tracks wear (active/needs_strip/stripping/
retired). Sub 12b adds an orthogonal 'racking_state' (empty/loading/
loaded/in_use/awaiting_unrack/out_of_service) for the load lifecycle
— a rack can be wear-active AND racking-loaded simultaneously.

New fields:
  racking_state        — operational lifecycle
  tag_ids (M2M)        — fp.rack.tag chips on plant overview
  capacity_count       — soft warn (distinct from existing 'capacity')
  current_job_step_id  — compute, derived from latest fp.job.step.move
  current_tank_id      — compute
  current_part_count   — compute

Form view picks up the new fields under Sub-12b group + a 'Current
Use' panel that hides when racking_state is empty / out_of_service.

The compute references fp.job.step.move which lands in Task 4 — the
module won't load cleanly on entech until Tasks 4-5 ship; that's
expected for batch deployment at the end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:03:09 -04:00
gsinghpal
86c0e230a1 feat(sub12b): fp.rack.tag — rack-label registry + 4 starter tags
M2M tag registry: Rush / Hold for QC / Damaged / Customer Sample.
Each rack can carry many tags; tags surface as coloured chips on the
plant-overview rack rows + Move Rack dialog (Task 13).

Plating → Configuration → Rack Tags menu (sequence 48).
post_init_hook seeds 4 starters — idempotent (no-op if any exist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:01:49 -04:00
gsinghpal
5494684181 fix(sub12a): rename _seed_default_inputs → action_seed_default_inputs
Odoo 19 rejects view buttons that call private (underscore-prefixed)
methods. Renamed the public entry point. The post_init_hook callers
follow.

Caught by entech upgrade (ParseError on the form view).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:43:26 -04:00
gsinghpal
a892a7b20e feat(sub12a): recipe form — buttons + is_template + Step Authoring tab
Process node form:
- Header: keep 'Open Tree Editor' (primary, existing); add 'Open Simple
  Editor' (secondary). Both visible only for recipe-type nodes.
- Recipe Settings group: add preferred_editor + is_template (the latter
  supervisor-only).
- New 'Step Authoring' notebook page (visible for step/operation):
  Stations, default_kind, material_callout, predecessor/rack/transition
  flags, time/temp targets, voltage/viscosity, readonly
  source_template_id.

Model:
- New action_open_simple_editor (sibling of action_open_tree_editor).
- New _resolve_preferred_editor() — per-recipe preferred_editor wins,
  'auto' falls back to company.x_fc_default_recipe_editor, final
  fallback 'tree'.
- New action_open_recipe_with_preferred_editor() — one-click route
  through the resolver. Reserved for menu-list / context-menu callers
  that want the simple-loving foreman path.

Tree editor + every existing battle test path untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:40:08 -04:00
gsinghpal
0862e55de6 feat(sub12a): Plating → Configuration → Step Library menu
Sequence 45 — between Process Types (40) and Bath Parameters (50).
Inherits the manager-only group from menu_fp_config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:36:08 -04:00
gsinghpal
738f3fcfd5 feat(sub12a): step library list/form/search views
Form: Title + Code + Classification (kind/icon/process/material) +
Stations & Flags + 4 notebook tabs (Instructions / Operation
Measurements / Transition Form / Advanced).

Operation Measurements + Transition Form are inline-editable o2m
lists with handle widget for drag reorder.

Header button: 'Seed Default Inputs' (visible only when default_kind
is set). Triggers the idempotent seeding helper.

NB: I removed `string=` from <search> per Odoo 19 rule (CLAUDE.md
critical rule 4 — no string attr on search).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:35:33 -04:00
gsinghpal
95debabc28 feat(sub12a): res.company.x_fc_default_recipe_editor setting
Per-company default for which editor opens for new recipes / recipes
with preferred_editor=auto. Defaults to 'tree' to preserve existing
behavior. Surfaces in Settings → Fusion Plating → Recipe Editor.

Naming follows the existing x_fc_* convention used throughout
res_company.py for company-level Fusion Plating defaults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:34:12 -04:00
gsinghpal
cfe776be4c chore: session housekeeping — tank UX, plating menu defaults, WO label
- fusion_plating: tank field labels (Code → Tank Number, Tank → Tank Name)
  + state-control header buttons (Mark Empty/Filled/In Use/Draining/
  Maintenance/Out of Service) with chatter audit logging.
- fusion_plating_configurator: Plating app default landing screen = Sale
  Orders, while keeping menu name as 'Plating'.
- fusion_plating_jobs: SO smart-button label 'Plating Jobs' → 'WO'.

Already deployed and verified on entech earlier in the session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:27:35 -04:00
gsinghpal
d9f58b9851 changes 2026-04-26 15:05:17 -04:00
gsinghpal
de47d2ceb1 refactor(menus): collapse separate Jobs submenu into Shop Floor
Move 'All Jobs' and 'Steps' under fusion_plating_shopfloor's
existing 'Shop Floor' submenu (between Tablet Station and Bake
Windows). The standalone 'Jobs' parent menu is gone — it was
redundant once the operator UIs (Plant Overview / Tablet /
Manager Desk) consolidated under Shop Floor.

Final structure under Plating:
  Sales / *
  Configurator / *
  Shop Floor
    Manager Desk
    Plant Overview
    Tablet Station
    All Jobs       ← moved here (seq 15)
    Steps          ← moved here (seq 17, supervisor+)
    Bake Windows
    First-Piece Gates
  Receiving & Inspection
  Operations / *
  Configuration → Work Centres (manager)
  ...rest

Work Centres stays under Configuration (no shopfloor equivalent).

New menu file lives in fusion_plating_jobs/views (jobs depends on
shopfloor; core can't reference shopfloor xmlids).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:01:49 -04:00
gsinghpal
667654bd4e refactor(jobs): drop (Native) suffix + promote Jobs to top of Plating app
The (Native) suffix was a temporary distinguisher during parallel
coexistence with bridge_mrp. Now that fp.job is THE primary
system, the suffix is just noise. Removed across all 5 menus and
both client-action labels.

Also restructured the Jobs submenu under Plating:
- Renamed root from 'Plating Jobs (Native)' (seq=4, manager-only)
  to just 'Jobs' (seq=2, operator-visible). Now appears right
  below the Plating app header — first-click access for operators.
- All Jobs (was 'Jobs') at seq=20
- Tablet Station at seq=5 (operator entry point)
- Plant Overview at seq=10
- Manager Dashboard at seq=15 (supervisor+ only)
- Steps (renamed from 'Steps (Admin)') at seq=30 (supervisor+ only)
- Work Centres (was 'Work Centres (Native)') in Configuration

Hidden one more legacy menu: bridge_mrp's 'Production Priorities'
(mrp.workorder ordering UI — fp.job has its own priority field).

Manifest unchanged (no new files); skipping version bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 06:19:14 -04:00
gsinghpal
47a54eac8f feat(jobs): cutover - bridge_mrp gate, menu nesting, migration robustness
Three changes to support live cutover on entech (2026-04-25):

1. Bridge_mrp gate: sale.order.action_confirm in
   fusion_plating_bridge_mrp now skips _fp_auto_create_mo when the
   x_fc_use_native_jobs config flag is True. Without this, every SO
   confirm would create both an mrp.production AND an fp.job
   (duplicate work). The gate is the only modification to bridge_mrp
   during the migration — the rest stays untouched.

2. Menu nesting: Plating Jobs (Native) now lives INSIDE the existing
   Plating app (parent=menu_fp_root) instead of as a separate
   top-level app. Two parallel 'Plating' apps was confusing UX. Work
   Centres (Native) goes under the existing Configuration sub-menu.
   '(Native)' suffix is temporary — drops at full legacy removal.

3. Migration script robustness: per-MO savepoints (so one bad MO
   doesn't abort the whole transaction with cascading 'transaction
   aborted' errors) + extended partner resolver fallback chain
   (warehouse partner → company partner) for orphan demo MOs without
   SO link or x_fc_customer_id. Verified: 43 MOs + 297 WOs migrated
   on entech with 0 errors after these fixes.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 04:05:02 -04:00
gsinghpal
1491f2367b refactor(jobs): address code review feedback on Task 1.8 admin views
- I1: Lock time_log_ids list inside step Audit tab to read-only
  (no create/edit/delete on the nested list). Audit timelog rows
  are produced exclusively by button_start / button_finish; if a
  manager could hand-edit them, cost_total rollups would silently
  drift.
- I2: Add explicit list view (decoration on state) and search view
  (filters by state/kind, group_by state/work_centre/job) for
  fp.job.step. The Steps (Admin) menu was using Odoo's default
  auto-list with no filter, which would be unusable after a few
  weeks of step accumulation. Action now references the search
  view explicitly.

Manifest 19.0.8.7.0 -> 19.0.8.7.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:44:16 -04:00
gsinghpal
b2ae79b61f feat(jobs): add admin views and menu for Phase 1 models
Manager-only views during Phase 1 — operator UI rebuilt in Phase 6.
Top-level menu 'Plating Jobs (new)' (seq=47) groups the three
new act_window actions (Jobs, Steps Admin, Work Centres) so the
foundational models can be exercised through the UI without
touching the operator-facing menus that still serve mrp.production
and mrp.workorder.

Job form has Steps/Source/Costs notebook tabs. Step form has
Equipment/Plating Spec/Audit/Instructions tabs (Audit shows
the time log rows from Task 1.7). Search filters by state,
priority, partner, facility.

Manifest 19.0.8.6.1 → 19.0.8.7.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:38:36 -04:00
gsinghpal
625f6560f1 feat(plating): split templates vs part-scoped processes + Process smart button
Two user-reported gaps:

1. The Process Recipes list was about to be flooded by part-scoped
   clones as soon as parts started carrying customised processes —
   thousands of clones would bury the handful of real shared
   templates (General Processing, Anodize, etc.).

   Fix: the main Process Recipes action now narrows to
   part_catalog_id = False so shared templates stay alone in that
   view. A sibling menu "Part Processes" (Plating → Operations →
   Part Processes) shows the inverse list — every part-cloned
   process, grouped by part — so admins can audit clones without
   cluttering the templates list.

   Search view gains two toggle filters (Shared Templates /
   Part-Scoped) and a "Group by Part" option. The node list gains
   an optional "Part" column.

   Split across modules: core owns the base search / tree / action
   (unchanged); configurator owns all the part_catalog_id-dependent
   pieces (filter extensions, list column, narrower domain,
   "Part Processes" action + menu). Keeps the dependency direction
   clean — configurator always depends on core, never the other way.

2. Added a "Process" smart button to the part form's button box.
   Shows either a green check (composed) or "None" (not yet
   composed) and opens the part-scoped Composer on click. Gives
   users one-tap access from any part form without hunting through
   the Process tab.

fusion_plating → 19.0.8.0.0
fusion_plating_configurator → 19.0.13.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:45:24 -04:00
gsinghpal
54e56ed0e6 changes 2026-04-20 01:16:12 -04:00
gsinghpal
41336b179f feat(plating): company-level UoM defaults — F/C, mils/microns, etc.
Different facilities use different measurement systems. North-American
aerospace shops live in °F + mils + gallons + lb; ROW + most metric
shops use °C + microns + litres + kg. Add company-level defaults so
each shop picks its units once; new records inherit them automatically.

**Settings on res.company** (7 Selection fields):
  • x_fc_default_temp_uom            — °F / °C
  • x_fc_default_thickness_uom       — mils / microns / inches / mm
  • x_fc_default_volume_uom          — US gal / litres / Imp gal
  • x_fc_default_mass_uom            — lb / kg / oz / g
  • x_fc_default_pressure_uom        — psi / bar / kPa
  • x_fc_default_current_density_uom — A/ft² (ASF) / A/dm² (ASD)
  • x_fc_default_area_uom            — sq in / sq ft / cm² / m²

All default to North-American aerospace conventions (F, mils, gal, lb,
psi, asf, sq_in) — admins flip them once during onboarding via
Settings → Fusion Plating → Units of Measure.

**Per-record use** (this round)
  • mrp.workorder.x_fc_bake_temp_uom (°F / °C) — defaults from company,
    operator can override per WO if a specific bake needs a different
    unit (rare but allowed).
  • Bake-finish gate error message now reports the actual unit:
    "Bake Temp (°F)" or "Bake Temp (°C)" instead of hard-coded F.
  • Form: Bake Temp + Temp Unit picker side-by-side in the bake group.

**Settings UI** — new "Units of Measure" block on Settings → Fusion
Plating page with help text per unit explaining where each is used.

**Verified end-to-end** (scripts/fp_uom_smoke.py):
  • All 7 defaults populate with NA-aerospace defaults
  • Switching company default to °C makes a NEW WO inherit °C
  • Existing WOs keep their stored °F (no surprise mutation)

**Roadmap (deferred to next round)** — wire the same default-from-company
inheritance to:
  • fp.bake.oven.target_temp (currently no UoM)
  • fp.bake.window.bake_temp (currently no UoM)
  • fp.coating.config.bake_temperature (currently no UoM)
  • fp.tank.volume already has volume_uom; default from company
  • fp.bath.log chemistry readings already use parameter.uom; align
    with company default for new params

The settings + framework are now in place — adding more per-record uom
fields is mechanical from here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 12:01:44 -04:00
gsinghpal
f5f25f5716 fix(employee): rename 'Plating Certifications' tab to 'Operator Training'
The old label was easy to confuse with the customer-facing
Certificate of Conformance (fp.certificate). Operators kept asking
why a customer cert appeared on their employee profile. The tab is
actually the operator's process-level training record (EN, chrome,
anodize, etc.) that gates WO start in mrp_workorder.button_start —
nothing to do with customer documents.

Renamed the page string and added a one-line muted description
so anyone landing on the tab understands what it's for. Also
distinguishes it from the new 'Shop Roles' tab (coarser task tags
used by Manager Desk auto-routing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 23:20:38 -04:00
gsinghpal
0d12902ee7 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>
2026-04-18 22:05:32 -04:00