Commit Graph

126 Commits

Author SHA1 Message Date
gsinghpal
0f2ed5cc16 feat(configurator): OWL widgets + Express form polish to match mockup
NEW OWL widgets:
- FpExpressPartCell (static/src/js/express_part_cell.js + .xml) — multi-row
  Part cell. Wraps Many2OneField for the part picker (row 1: part# / rev,
  bold). Below it: row 2 part description (italic muted), row 3 serial #s
  joined + '+ bulk' button that triggers the existing bulk-add wizard.
- FpExpressBakePill (static/src/js/express_bake_pill.js + .xml) — click-
  to-edit Bake pill. Renders amber pill when set, italic muted 'no bake'
  when empty. Click swaps to inline textarea + Save / Clear / Cancel.

NEW fields:
- fp.direct.order.line.part_number_display / part_revision_display /
  part_name_display (related Char from fp.part.catalog) — fed to the
  Part cell widget so it can render multi-row without RPC.
- fp.direct.order.wizard.tooling_charge (Monetary) — surfaced in the
  Totals card on the Express form.
- fp.direct.order.wizard.po_status (computed Selection
  received/pending/missing) — drives the PO Block status badge.
- sale.order.x_fc_tooling_charge (Monetary) — receives wizard.tooling_charge
  at confirm.

View updates (fp_express_order_views.xml):
- PO block header now shows the PO status pill (green Received,
  amber Pending, red Missing)
- Order Lines legend bar (Mask / Bake pill / DWG / OPEN explainers)
- Part Number column uses widget='fp_express_part_cell' — single cell
  with 3 internal rows
- Bake column uses widget='fp_express_bake_pill' — interactive pill
- Totals card now has Subtotal / Tooling Charge / Total Lines / Total
  Quantity / Grand Total + currency pill

SCSS adds:
- Multi-row part cell styles (internal borders, bold/italic/muted rows)
- Bake pill (has-bake amber, no-bake italic muted) + inline editor
- Legend bar (section background, gap-spaced explainer chips)
- PO status pill colour scheme
- Bulk button styling

Wizard's action_create_order now carries tooling_charge to the SO at
confirm so it persists on the resulting sale.order.
2026-05-26 22:13:54 -04:00
gsinghpal
1d674e587c feat(configurator): Express form CSS-Grid rebuild — match mockup pixel layout
Previous rebuild used Odoo's <group col='4'> which renders as an HTML
table — colspan+nesting broke into a vertical stack. Replaced entirely
with raw <div> + CSS Grid (display: grid; grid-template-columns:
repeat(4, 1fr)) so the header layout matches the mockup exactly:

- Row 1: Customer (span 2) + Shipping Address (span 2)
- Row 2: PO block (span 2, accent-bordered card with PO#/PDF/Pending
  toggle/Expected date stacked + chase warning) + Customer Job # + Job Sorting
- Row 3: Material/Process Tag + Lead Time (inline X to Y) + Payment
  Terms + Delivery Method
- Row 4: Blanket SO + Currency/Pricelist + Quote Validity + Invoice Strategy

Footer also rebuilt as CSS Grid (1fr 320px) — Notes/Terms cards
stacked in the left column, Totals card with Grand Total + currency
pill in the right column. Each card has a title + subtitle + body
matching the mockup's card chrome.

SCSS overrides Odoo's default field chrome inside .o_fp_xpr_cell so
inputs render with the mockup's underline style (no Bootstrap form-
control border, just a 1px bottom-border that thickens on focus).
2026-05-26 21:51:02 -04:00
gsinghpal
713ba17e37 feat(configurator): Express form layout rebuild — match mockup
Restructures the Express form to align with the brainstorming mockup:

Header (4-column grid via <group col='4'>):
- Row 1: Customer (colspan=2) + Shipping Address (colspan=2)
- Row 2: Consolidated PO Block (colspan=2 with PO#/PDF/Pending toggle/
  Expected date stacked + chase warning inline) + Customer Job # + Job Sorting
- Row 3: Material/Process Tag + Lead Time (X to Y inline) + Payment Terms + Delivery Method
- Row 4: Blanket SO + Currency/Pricelist + Quote Validity + Invoice Strategy

Lines: 13 inline columns including the Express-specific Line Job #,
masking toggle, bake text, plus per-line action buttons (DWG, OPEN,
+ bulk) wired to the Phase B helpers.

Footer: side-by-side cards — Notes + Terms stacked in the left card,
Totals card on the right with Total Lines / Total Qty / Grand Total
+ currency pill.

SCSS adds:
- PO block: accent-bordered card-within-card
- Lines: tight spreadsheet borders, hover row highlight
- Bake column: amber pill style, italic 'no bake' for empty
- Customer Line Job #: bold, uppercase, narrow column
- Inline action buttons: small uppercase bordered chips
- Footer cards with prominent Grand Total + currency pill

OWL multi-row Part cell (FpExpressPartCell) and click-to-edit Bake
pill (FpExpressBakePill) are still deferred — they need real OWL
components, separate pass.
2026-05-26 21:35:54 -04:00
gsinghpal
43abb8ef25 feat(configurator): C1+C3 - pricelist currency picker + Express SCSS (light + dark)
C1: product.pricelist._compute_display_name override gated by the
'fp_express_currency_picker' context flag (set on the Express form's
pricelist_id field). When active, prefixes the dropdown label with
the currency code: 'CAD — Public Pricelist (CAD)'. Elsewhere the
standard display name is unchanged.

C3: SCSS tokens + base styles for the Express form. Tokens use the
compile-time @if $o-webclient-color-scheme branch per the project's
'Dark Mode' rule — same SCSS compiles into both bundles with different
hex values. Token vars wrapped in CSS custom properties so downstream
modules can override for per-shop branding without recompiling.
Base styles: spreadsheet-feel table borders, bake-cell inset-pill,
customer line ref bold/uppercase, accent section markers.
2026-05-26 21:25:59 -04:00
gsinghpal
27af984f28 docs(configurator): E1 - Express Orders smoke test runbook 2026-05-26 21:22:43 -04:00
gsinghpal
aab842d6d3 feat(configurator): D1+D2 - drafts dual-routing + legacy deprecation banner
D1: action_open_draft method routes drafts-list click to the matching
form view by view_source. view_source badge column added to the drafts
list (Express=blue, Legacy=muted).

D2: Deprecation banner on the legacy direct-order form pointing operators
to the new Express view, plus a Switch-to-Express header button. Legacy
action context defaults new drafts to view_source='legacy' (Express
action defaults to 'express') so newly-created drafts open in the right
view automatically.
2026-05-26 21:21:23 -04:00
gsinghpal
a9256dbed7 feat(configurator): B5+B6 - SO line carry-through + part-default write-back on confirm 2026-05-26 21:11:15 -04:00
gsinghpal
200a2efeb8 feat(configurator): B4+B8 - Express onchange auto-fill cascade + DWG/OPEN on direct-order line 2026-05-26 21:11:15 -04:00
gsinghpal
299cae8a4e feat(configurator): B2+B7+B8 - Express override helper + serial-bulk + DWG/OPEN buttons on sale.order.line 2026-05-26 21:11:15 -04:00
gsinghpal
01df46f79f feat(configurator): C6 - Express Orders form view + menu (v1, stock widgets)
Spreadsheet-style flat entry view on the existing fp.direct.order.wizard
model. Renders:
- Customer + Shipping prominent (row 1)
- PO block (PO# + attachment + Pending toggle + Expected date)
- Scheduling/Lead Time + Pricing/Pricelist (row 2)
- Order Lines spreadsheet with: Part #, Specification, Line Job #,
  Thickness, Mask toggle, Bake text, Internal Notes, Serials, Qty,
  Price, Subtotal, Process/Recipe (optional-show)
- Notes + Terms split (internal vs customer-facing)
- View-switch buttons to bounce between Express and Legacy on a draft

New menu: Plating > Sales > '+ New Express Order' (sequence 3).
Same DB rows as legacy view (view_source='express' for routing).

v1 deferments: OWL FpExpressPartCell (multi-row part cell), OWL
FpExpressBakePill (click-to-edit), DWG/OPEN/+bulk inline buttons,
custom SCSS, quick-create part view, pricelist display_name override.
These come in later iterations.
2026-05-26 21:03:47 -04:00
gsinghpal
92b690aef1 feat(configurator): A5 - wizard schema (rename notes, add Express fields, retire manual currency_id) 2026-05-26 20:58:23 -04:00
gsinghpal
08bc2b6a89 feat(configurator): A4 - add Express header fields to sale.order 2026-05-26 20:58:23 -04:00
gsinghpal
ad3d6261af feat(configurator): A3 - add Express x_fc_* flags to sale.order.line 2026-05-26 20:58:23 -04:00
gsinghpal
f04b31cec7 feat(configurator): A2 - add Express flags to fp.direct.order.line 2026-05-26 20:58:23 -04:00
gsinghpal
5f898d4209 feat(configurator): A1 - add Express Orders per-part defaults to fp.part.catalog 2026-05-26 20:58:23 -04:00
gsinghpal
807ed86ef6 chore(configurator): bump to 19.0.22.0.0 for Express Orders 2026-05-26 20:06:19 -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
de3ec7d97a feat(plating-sec): SO confirm gate + fix _administrator typo + Python sweep
Phase G of permissions overhaul.

G2: sale.order.action_confirm now requires group_fp_sales_manager
(spec Section 2.B). Sales Reps can save drafts but cannot move SOs
to 'sale' state. UserError raised with clear message if attempted.

G3: Fixed audit-finding-11 typo bug in 2 files. The original code
checked has_group('fusion_plating.group_fusion_plating_administrator'),
an xmlid that has NEVER existed - so the gate always returned False
and only the Manager-side check actually fired. Fixed both:
  - fusion_plating_invoicing/models/res_partner.py:34
  - fusion_plating_configurator/wizard/fp_direct_order_wizard.py:467
Both now check has_group('fusion_plating.group_fp_manager') which
transitively includes Owner via implied_ids.

G4: Swept all Python has_group() calls to reference new group xmlids.
Backward-compat keeps old refs working today (Phase A's implied_ids),
but the sweep ensures correctness after the 30-day rollback window
deletes old groups. Replacements:
  group_fusion_plating_operator    -> group_fp_technician
  group_fusion_plating_supervisor  -> group_fp_shop_manager_v2
  group_fusion_plating_manager     -> group_fp_manager
  group_fusion_plating_admin       -> group_fp_owner
  group_fusion_plating_cgp_officer -> group_fp_quality_manager
  group_fusion_plating_cgp_designated_official -> group_fp_owner
  group_fp_estimator               -> group_fp_sales_rep
  group_fp_accounting              -> group_fp_manager
  group_fp_receiving               -> group_fp_shop_manager_v2
  group_fp_shop_manager (legacy)   -> group_fp_manager

G1: test_sales_manager_gate.py covers the new confirm gate (SR
blocked, SMg allowed, Manager allowed via diamond implication).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 02:11:35 -04:00
gsinghpal
269f9984ef feat(plating-views): Layer 3 — field/button gates per role
Phase D Task D5 of permissions overhaul. Adds explicit groups= to
form-level elements so non-matching roles don't even SEE the buttons
they can't use:

- SO Confirm button → group_fp_sales_manager (Sales Rep sees the SO
  in draft but no Confirm button — matches model-level gate from Phase G)
- SO pricing fields (price_unit/subtotal/total/untaxed/tax) →
  group_fp_sales_rep (Technician/Shop Manager don't see pricing if
  they navigate to an SO)
- Partner Account Hold tab → group_fp_manager (was the fold-in
  group_fp_accounting; the audit-finding-11 _administrator typo lives
  in res_partner.py and is Phase G's fix)
- CAPA Close + all state-transition buttons → group_fp_quality_manager;
  edit fields use readonly="not user_has_groups(...)" so Manager
  retains read+comment per spec section 2.C
- Audit Start/Findings/Close buttons → group_fp_quality_manager
- AVL Approve/Suspend/Reinstate/Remove → group_fp_quality_manager
  (model uses Suspend+Remove instead of spec's literal 'Disqualify';
  both surfaces gated, semantics match)
- Customer Spec edit fields → readonly for non-QM (Manager keeps
  read access per spec; only inputs lock)
- FAIR Approve/Reject buttons → group_fp_quality_manager (Submit-
  for-Review and Reset stay open to whoever created the FAIR)
- Certificate Issue button — Strategy B chosen: single button hidden
  when cert_type=nadcap_cert AND user is not QM. Cleaner than splitting
  into two buttons; no separate action_sign exists on fp.certificate
  (Issue is the sign+publish action). FAIR lives in its own model;
  fp.certificate only has nadcap_cert as a special type. The ir.rule
  from Phase C enforces model-level writes independently.
- CGP form buttons (7 view files: ai, controlled_good, psa,
  receipt_shipment, registration, security_incident, visitor) →
  group_fp_quality_manager on every action button

Defense in depth: ir.rules and ACLs (from Phases B + C) already
restrict model access. These view gates are the UI layer that
matches.

Concerns:
- Spec line 192 names 'sale.order view — x_fc_account_hold_override'
  but no such field exists in the codebase. Closest practical match
  was the partner-side Account Hold management tab, which already had
  a group= attribute. Re-gated there; no SO-side field to gate.
- AVL model has no action_disqualify per spec; uses suspend+remove.
  Both gated to QM.
- fp.certificate has no action_sign (only action_issue). FAIR's
  approve/reject covers the FAIR side; nadcap-cert Issue covers the
  cert side via Strategy B.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 01:45:39 -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
8eb2c2de95 refactor(plating-sec): sweep all ACL CSVs to new role group xmlids
Phase B of permissions overhaul. Mechanical text replacement across
11 ir.model.access.csv files:
  - group_fusion_plating_operator    -> fusion_plating.group_fp_technician
  - group_fusion_plating_supervisor  -> fusion_plating.group_fp_shop_manager_v2
  - group_fusion_plating_manager     -> fusion_plating.group_fp_manager
  - group_fusion_plating_admin       -> fusion_plating.group_fp_owner
  - group_fp_estimator (configurator)-> fusion_plating.group_fp_sales_rep
  - group_fp_accounting              -> fusion_plating.group_fp_manager
  - group_fp_receiving               -> fusion_plating.group_fp_shop_manager_v2
  - group_fp_shop_manager (legacy)   -> fusion_plating.group_fp_manager
  - group_fusion_plating_cgp_officer -> fusion_plating.group_fp_quality_manager
  - group_fusion_plating_cgp_designated_official -> fusion_plating.group_fp_owner

Backward-compat: old group xmlids still resolve (Phase A's implied_ids
chains keep old ACLs working for users still holding old groups).
This sweep ensures future-state correctness: when old groups are deleted
after the 30-day rollback window, ACLs continue resolving via the new
group xmlids.

Also adds fusion_plating/tests/test_acl_migration.py with sample-based
per-role access checks. The 2 CAPA tests are expected to fail until
Phase C implements the Manager/QM quality split.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 01:14:02 -04:00
gsinghpal
6c7e11db4d fix(plating-sec): move cross-module implied_ids out of fp_security_v2.xml
The previous commit (a53b0326) added implied_ids in fp_security_v2.xml
that referenced 5 xmlids from downstream modules (configurator/receiving/
invoicing/cgp). Since fusion_plating is the BASE module and loads first
at fresh install, those refs raised External-ID-not-found at install.

Fix: relocate the 5 cross-module implications into each downstream module's
own security file via additive (4, ref()) writes to the core group's
implied_ids. Odoo's XML data loader treats these as additive updates so
they stack cleanly across install + -u cycles.

Also: drop redundant <data noupdate="0"> wrapper in fp_security_v2.xml
to match sibling fp_security.xml's bare <odoo> shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 00:59:20 -04:00
gsinghpal
a53b03265d feat(plating-sec): add 8 consolidated role groups + mark old groups deprecated
Phase A of permissions overhaul (see docs/superpowers/specs/2026-05-23-*).
New groups (technician/sales_rep/shop_manager_v2/sales_manager/manager/
quality_manager/owner) defined in fp_security_v2.xml with implied_ids
chains that include old groups for backward-compat during 30-day rollback
window. Old groups display as [DEPRECATED] in user form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 00:47:54 -04:00
gsinghpal
f661724c72 changes 2026-05-22 18:01:31 -04:00
gsinghpal
d127e19b45 changes 2026-05-21 21:00:10 -04:00
gsinghpal
b395600a1c changes 2026-05-21 05:18:32 -04:00
gsinghpal
d6d6249857 changes 2026-05-21 04:47:45 -04:00
gsinghpal
1314f4581d changes 2026-05-21 03:37:25 -04:00
gsinghpal
d7bee9e854 fix(configurator): widen Template dropdown in Add Variant strip
Reported 2026-05-20: the Template dropdown in the Part > Process
Composer's 'Add Variant from Template' row truncated long recipe
names to 4 characters ("Cher" instead of "Chemical Conversion …").
The hard-coded max-width: 280px was set before the curated template
catalog grew names like "Chemical Conversion — Iridite Type II Cl 3"
and "ENP-STEEL-BASIC — Standard Heavy Phos".

Fix: replace the rigid max-width with a flex sizing that gives the
dropdown room to grow:
  - min-width: 360px (full common recipe name fits)
  - flex: 1 1 360px  (grows to fill available space)
  - max-width: 560px (cap so it doesn't push the buttons off-screen)

Same flex pattern applied to the Variant label input (slightly
narrower min/max).

Also: pulled the entech-side version of fp_part_process_composer.xml
back into the local repo — local was stale (one 'Add Variant' button;
entech had the dual 'Add — Tree' / 'Add — Simple' buttons that
landed in an out-of-band edit).

Module: fusion_plating_configurator 19.0.21.5.0 → 19.0.21.5.1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 08:27:04 -04:00
gsinghpal
091f98e1f9 changes 2026-05-18 22:33:23 -04:00
gsinghpal
d3c5c25865 changes
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
2026-05-17 03:20:33 -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
1ed414c6fb chore(menu): retire Configurator top-level — fold survivors into Configuration hub
After Phase E removed Coating Config + Treatments + Customer Price List
+ Coating Thickness from the Configurator submenu, only 3 admin items
remained — not enough to justify a top-level menu just for an
estimator.

Re-homed:
- Pricing Rules                → Configuration → Pricing & Billing
                                  (sequence 40, joins Invoice Strategy
                                   Defaults + Account Holds)
- Materials                    → Configuration → Materials & Tanks
                                  (sequence 40, joins Bath Parameters,
                                   Replenishment Rules, Chemicals,
                                   Rack Tags, Calibration Equipment)
- Line Description Templates   → Configuration → Quality & Documents
                                  (sequence 90, joins Notification
                                   Templates — same "templates" pattern)

All three keep estimator visibility (group_fp_estimator) plus manager
access. Top-level menu count under "Plating" drops from 9 visible to 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 07:52:53 -04:00
gsinghpal
7d27db69c6 fix(promote-customer-spec): leftover has_cost_data ref in _compute_margin
Phase E removed the coating-rollup loop but left a stale `has_cost_data`
reference in the percent computation. NameError on every SO list /
form load.

Margin is "not available" until recipe-level cost data exists
(backlog item). Set all three margin fields to 0 / False explicitly
so no stale references remain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 07:11:41 -04:00
gsinghpal
d891002c84 feat(promote-customer-spec): Phase E — final removal of coating + treatment
DELETED entirely (model + view + ACL + data file + menu):
- fp.coating.config (configurator)
- fp.treatment (configurator + seeded data)
- fp.coating.thickness (configurator) — replaced by fp.recipe.thickness in Phase A
- fp.customer.price.list (configurator) — coating-keyed, no replacement

Field deletions:
- sale.order.x_fc_coating_config_id
- sale.order.line.x_fc_coating_config_id + x_fc_treatment_ids
- account.move.line.x_fc_coating_config_id
- fp.part.catalog.x_fc_default_coating_config_id + x_fc_default_treatment_ids
- fp.job.coating_config_id
- fp.pricing.rule.coating_config_id
- fp.quality.point.coating_config_ids
- fp.direct.order.line.coating_config_id + treatment_ids
- fp.sale.description.template.coating_config_id

Refactored:
- fp.quote.configurator.coating_config_id → recipe_id (now points at
  fusion.plating.process.node, the actual recipe). All compute, onchange,
  and matcher logic updated to use recipe directly. Quality inherit
  extends matcher with spec-tier scoring.
- fp.job._fp_create_certificates now reads spec from job.customer_spec_id
  and formats spec_reference as "code Rev rev". Same for thickness
  source — bake fields read from recipe_root (Phase A).
- fp.job.step.button_finish bake-window auto-spawn reads bake settings
  from recipe_root instead of coating.
- fp.certificate auto-fill spec_min_mils/max_mils from recipe (Phase A
  thickness fields) instead of coating.
- jobs/sale_order.py: job creation reads x_fc_customer_spec_id from
  line, drops coating refs and the legacy header-coating fallback.
- Wizards drop coating + treatment fields and refs.
- Configurator views drop x_fc_coating_config_id + x_fc_treatment_ids
  fields entirely. Quality inherits re-anchor on stable fields
  (x_fc_part_catalog_id, x_fc_internal_description, default_process_id,
  process_variant_id, substrate_material) so they keep working.
- Reports drop coating fallback elifs; print recipe / spec.
- Tablet payload drops coating_config_id from job.read fields.

Skipped (deferred to backlog):
- fusion_plating_bridge_mrp — module is uninstalled per Sub 11; source
  files retain coating refs but no runtime impact.
- fusion_plating_portal — circular dep (portal → quality → certs →
  portal). Customer-facing portal coating picker stays for now;
  promote-spec polish is a separate sub-project.

Verification: grep for "coating_config_id|fp.coating.config|
fp.treatment|fp.coating.thickness" in live (non-bridge_mrp,
non-portal, non-script, non-test) Python/XML/CSV returns 3 hits,
all in module / class docstrings explaining Phase E history.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 02:00:41 -04:00
gsinghpal
7cafab1b9f feat(promote-customer-spec): Phase B — two-picker SO line UX
Spec-side picker (x_fc_customer_spec_id / customer_spec_id) added on:
- sale.order.line (via quality inherit — onchange autofill, create()
  fallback to part default, _prepare_invoice_line carry)
- account.move.line (via quality inherit — invoice rendering)
- fp.part.catalog (via quality inherit — x_fc_default_customer_spec_id)
- fp.direct.order.line (via quality inherit — wizard picker + autofill)
- fp.direct.order.wizard (action_create_order post-creates spec on SO line)

Thickness picker switched to fp.recipe.thickness (replaces coating-scoped):
- sale.order.line.x_fc_thickness_id comodel + domain rewired to recipe
- account.move.line + fp.delivery same
- fp.direct.order.line.thickness_id same

View inherits in quality add Specification picker next to legacy
Primary Treatment column on:
- SO form line tree
- part catalog Default Treatments block
- direct-order wizard line tree + drawer

Wizard files (fp.contract.review.client.email.wizard) pulled from
entech into the repo — they were ahead of the repo. Quality __init__
now imports wizards/.

Legacy x_fc_coating_config_id + treatment_ids remain visible during
transition; Phase E removes them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 01:16:25 -04:00
gsinghpal
5b399fbdda fix(configurator): copy operator-input prompts when cloning recipe to part
_clone_subtree() in fp_part_composer_controller built node vals
manually and never copied source.input_ids — so 'Load Template'
copied the recipe tree structure but dropped every custom prompt,
leaving operators with empty data-capture screens. The fix iterates
input_ids and calls .copy({'node_id': new_node.id}) so kind,
target_min/max/unit, compliance_tag, hint, selection_options,
sequence — every field on the input model — flows through.

Verified on entech: ENP-ALUM-BASIC clone now shows all 105 prompts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:58:11 -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
6b7b44264a changes 2026-05-10 10:25:12 -04:00
gsinghpal
1da27ed6bf changes 2026-05-01 00:20:40 -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
a2fe1fcbcc changes 2026-04-29 03:35:33 -04:00
gsinghpal
13e300d90e changes 2026-04-28 19:39:37 -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
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
f08f328688 changes 2026-04-27 00:11:18 -04:00