fa82ce17dd9c41b91ef1abbfee5a7cead9db76a4
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
eed4dc8a78 |
fix(plating): chatter HTML rendering + workflow stage banner UX
Two fixes from a single SO walkthrough screenshot:
**1. "Current stage" banner**
- Was placed `inside sheet` so it rendered at the BOTTOM of the form
where users miss it. Moved to `before form/header` (same xpath
pattern as the Account Hold banner) — now it's the first thing
visible above the SO header.
- Was still showing "Shipped — awaiting invoice" after the invoice
was posted because `_compute_workflow_stage` only advanced to
`complete` when shipped + ALL paid; an unpaid posted invoice left
the SO stuck on `shipped`. Added an `invoicing` branch: shipped +
has_posted_invoice → invoicing. Banner invisible-list now also
includes `invoicing` and `paid`, so the banner only shows for
in-progress steps.
**2. Chatter messages rendering raw HTML tags as text**
Odoo 19 escapes any string passed to `message_post(body=...)`
unless wrapped in `markupsafe.Markup`. We had ~10 places posting
HTML (`<a href>`, `<b>`, `<br/>`, `<code>`, `<pre>`) that all
showed up as `<a href=...>` literal text in the chatter.
Wrapped each one with `Markup(_(...))` so the tags render. Files
touched:
- fusion_plating_bridge_mrp/models/sale_order.py
(auto-MO failure code block, "Draft MO created" link,
"Job assigned to <b>" message)
- fusion_plating_bridge_mrp/models/mrp_production.py
("Recipe steps" pre/br block on each WO)
- fusion_plating_bridge_mrp/models/fp_proficiency.py
(operator promotion announcement)
- fusion_plating_configurator/models/fp_quote_configurator.py
(SO link, 3D model attached, drawing attached, save to catalog)
- fusion_plating_configurator/models/fp_part_catalog.py
(3D/drawing change tracking + propagation to linked quotes)
- fusion_plating_portal/models/fp_quote_request.py
(RFQ → SO link)
- fusion_plating_quality/models/fp_quality_hold.py
(hold status change)
- fusion_plating_shopfloor/controllers/manager_controller.py
(worker / tank / manager-takeover assignments)
Verified on entech: SO S00038 stage now reads `invoicing` (banner
hidden), and a freshly posted message shows `<a href>` and `<b>`
as actual link + bold instead of escaped text.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
7ad7481195 |
fix(bol): bigger title, shipper info, uniform headers, cargo qty, taller signatures
Five fixes applied to the Bill of Lading and (where relevant) all
report templates:
1. **Bigger title + BoL #** — portrait now uses h2 24pt (was h4 16pt),
landscape h2 26pt; BoL # ticker is 13/14pt instead of body size.
2. **Shipper info missing** — root cause: `_fp_build_delivery_vals`
was creating deliveries without `company_id`, so the BoL's
`<span t-field="doc.company_id.name"/>` rendered empty. Two fixes:
- Hook now sets `company_id = mo.company_id.id or env.company.id`.
- Template falls back defensively to `env.company` when
`doc.company_id` is empty (covers any legacy delivery that
somehow slips through without it).
- Backfilled 14 existing deliveries via SQL on entech.
3. **Uniform header backgrounds** — replaced mixed `info-header`
(gray) + default-th (brand black) headers with a single
`fp-header-primary` (brand black) across all sub-tables for a
consistent look.
4. **Cargo description alignment + missing column** — added a QTY
column (matches landscape variant), pulled from the linked MO
via job_ref → mrp.production.product_qty. Added `.fp-cell-mid`
utility class with `vertical-align: middle !important;` and
applied it to every cargo + info cell so values sit centred
instead of jammed against the top border.
5. **Signature box too short** — bumped `.sig-box` from 70 → 110 px
(portrait) / 130 px (landscape), `.sig-line` from 28 → 60/70 px,
added flex layout so the label sits at the bottom and signers
have a real space to write in. Lives in the shared
`report_base_styles.xml` so EVERY FP template benefits, not just
the BoL.
Verified: BoL portrait renders cleanly at 140 KB with full shipper
block + uniform headers + middle-aligned cargo cells.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
633427bcf8 |
fix(plating): CoC + invoice PDFs render full content
Three reported PDF bugs from the customer-facing email package: 1. Invoice body was empty — Odoo 19 sets display_type='product' on regular invoice/SO lines (was empty string in 18.0). Both report_fp_invoice.xml and report_fp_sale.xml only matched `not line.display_type`, so every product line was skipped. Fixed both portrait + landscape variants to also match display_type == 'product'. 2. CoC PDF was a bare 30 KB header — _fp_generate_cert_pdf was rendering action_report_coc, which is bound to portal_job and has minimal content. Rewrote to use the rich fp.certificate-bound report (action_report_coc_en / action_report_coc_fr based on cert.partner_id.lang) and slugged the filename to CoC-<Customer>-<CertName>.pdf so the email attachment reads nicely instead of CERT-00123.pdf. 3. Thickness cert was an exact duplicate of the CoC — the CoC template already embeds thickness readings. Skip thickness cert creation entirely when the customer also wants CoC; only create a standalone thickness cert when the customer opted out of CoC. Also: dispatcher in fp_notification_template now prefers portal_job.coc_attachment_id (the rich one we just generated) and falls back to rendering action_report_coc_en against fp.certificate by partner.lang — never the bare portal-job report. Versions bumped: bridge_mrp 19.0.6.0.0, notifications 19.0.4.0.0, reports 19.0.4.0.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
167c423bf5 |
feat(plating): close 5 end-to-end automation gaps
E2E test (quote → SO → MO → WOs → ship → invoice → payment) ran clean but flagged five gaps where the operator was filling in data the system already knew. Closes all five. #1 SO CONFIRM → AUTO-CREATE DRAFT MO (was a workflow blocker) bridge_mrp/sale_order.py: action_confirm() override + new _fp_auto_create_mo helper. Resolves the manufactured product from the configurator's part-catalog → coating-config → FP-WIDGET fallback; resolves the recipe from coating_config.recipe_id → part_catalog.recipe_id → first installed recipe. Idempotent: skips if any MO already exists for the SO. Errors are caught and chatter-posted so SO confirm never fails because of an MO glitch. #2 QUOTE PO → client_order_ref ON SO (one-line fix) configurator/fp_quote_configurator.py: action_create_quotation now copies po_number_preliminary into Odoo's standard client_order_ref alongside the existing custom x_fc_po_number. Portal pages, native reports, and integrations all read the standard field; no reason both shouldn't carry the same PO#. #3 MO DONE → AUTO-RENDER CoC + THICKNESS PDFs bridge_mrp/mrp_production.py button_mark_done now calls a new _fp_generate_cert_pdf helper after creating each fp.certificate. Renders fusion_plating_reports.action_report_coc to PDF, stores as ir.attachment, links to cert.attachment_id, AND cross-links to portal_job.coc_attachment_id + delivery.coc_attachment_id so the customer portal and the shipping email both find it without an extra step. Thickness report falls back to the CoC layout (which embeds thickness data) until a dedicated report ships. Errors are logged but never block MO completion. #4 RECEIVING received_qty PREFILL receiving/fp_receiving.py: create() prefills received_qty from expected_qty on draft. Operator only types when the count is wrong (the rare case). Field carrier_tracking already exists, so #4's 'no inbound tracking field' from the gap report turned out to be a false alarm. #5 DELIVERY scheduled_date + driver PREFILL bridge_mrp/mrp_production.py: new _fp_build_delivery_vals helper sets scheduled_date from the portal job's target_ship_date (or now+2 business days as a sane fallback) and auto-picks assigned_driver_id from clocked-in employees tagged is_driver (falls back to any active driver if the shift is empty). The outbound tracking_ref deliberately stays empty — that's the carrier's number, paste it in once UPS/FedEx accepts the package. Module bumps: configurator 19.0.5.0.0, bridge_mrp 19.0.5.0.0, receiving 19.0.2.0.0. Verified on entech: re-ran the E2E test against a fresh quote. Quote → SO populated client_order_ref, SO confirm auto-created MO, receiving prefilled received_qty=50, MO done generated CERT-00018.pdf and linked it to portal job + delivery, delivery's scheduled_date prefilled to 2026-04-29, full pipeline ended with portal job state 'complete'. The remaining 'gaps' in the static report are script artefacts (e.g. it flags 'no inbound tracking field' but the field exists; flags 'no driver auto-pick' but the demo data has zero drivers tagged is_driver=True). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
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>
|
||
|
|
f340c87b6a |
feat(bridge_mrp): shop-role auto-routing + tablet worker mode (CHUNK 4/4)
Completes the worker-access story. Handoffs now route themselves.
New model fp.work.role with 8 seeded defaults (noupdate so shops can
rename/prune):
masking · racking · plating_op · demask · oven · derack ·
inspection · rework
Each one has a code, icon, description, sequence, active flag.
Config menu: Configuration → Shop Roles (manager-only).
Field additions:
hr.employee.x_fc_work_role_ids (Many2many) — tag workers with the
roles they perform. One-person shop: one employee, every role.
Specialised shop: one role per employee. Cross-trained: multiple.
fusion.plating.process.node.x_fc_work_role_id (Many2one) — tag
each recipe operation with the role that performs it.
mrp.workorder.x_fc_work_role_id (Many2one) — copied from the recipe
operation on WO generation.
Auto-assignment on WO generation:
_generate_workorders_from_recipe() now copies the operation's role
onto the WO, then calls _fp_pick_worker_for_role() which picks the
least-loaded employee (active WO count) with that role. WO lands in
their Tablet "My Queue" the moment the MO is confirmed. No manual
routing needed for the common case.
Tablet Station — worker mode:
/fp/shopfloor/tablet_overview now filters to WOs where
x_fc_assigned_user_id == env.user when the field is populated.
KPIs (WOs Ready / In Progress) reflect the logged-in worker's load,
not shop-wide totals. "My Queue" rows carry wo_state + can_start +
can_finish so inline Start/Finish buttons appear.
New JS handlers onStartWo / onFinishWo call /fp/shopfloor/start_wo
and /fp/shopfloor/stop_wo (finish=true). One-tap progression.
Views:
hr.employee form gets a "Shop Roles" notebook page with many2many_tags.
Process node form gets x_fc_work_role_id inline after work_center_id.
Work Order form shows role + assigned worker.
Smoke-tested end-to-end on WH/MO/00010:
Masking → Administrator (masking role)
Racking → Administrator (racking role)
E-Nickel → Andrew (plating_op, least-loaded tiebreaker)
Demask → Administrator (masking)
Oven bake → Andrew (oven)
Derack → Administrator (racking fallback)
Post-plate QA → Administrator (inspection)
80 existing WOs backfilled with role + worker via name-match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
adc27c637a |
feat(bridge_mrp): SO smart buttons for full production lifecycle
Sale Order form now hubs the full flow — Manufacturing, Work Orders, Portal Jobs, Quality Holds, Certificates, Deliveries — hidden when count == 0. Clicking each jumps to the filtered list/form so users can drill in without leaving the SO. Counts are computed on the fly from: mrp.production.origin == SO.name, production.workorder_ids, production.x_fc_portal_job_id, quality.hold production_id, fp.certificate.sale_order_id, fp.delivery.job_ref. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
6658544f85 |
feat(fusion_plating): Tier 2 (quality + audit) and Tier 3 (business) features
Tier 2 — Quality & audit readiness:
- T2.1 SPC on thickness readings (fp.certificate)
- spec_min_mils / spec_max_mils auto-pulled from coating config on create
- Computed: std_dev_mils, min/max, cpk, cpk_status (incapable/marginal/
capable/excellent/insufficient)
- Western Electric trend rules (rule 1: any point beyond 3σ; rule 4:
8 consecutive on one side of mean) → trend_alert + explanation
- New SPC group on certificate form with badge-coloured indicators
- T2.2 Operator certification enforcement (fp.operator.certification)
- Per (employee, process_type) records with issued/expires dates,
training record attachment, revocation workflow
- State auto-computed: active → expired when date passes
- MrpWorkorder.button_start() blocks with UserError if current user's
linked hr.employee lacks an active cert for the bath's process_type
- Managers bypass the check; expiring-soon filter in search view
- HR Employee form: "Plating Certifications" tab
- T2.3 Material traceability chain
- fusion.plating.batch.workorder_id (new Many2one) + production_id
(related through WO) for full chain
- fp.certificate gets computed batch_ids / bath_ids / batch_count
- "Batches" stat button → list of batches used for this cert's MO,
with their chemistry logs intact
- T2.4 Pre-treatment as first-class baths
- process_family selection on fusion.plating.process.type
(pre_treatment / plating / post_treatment / bake / strip / passivation /
masking / inspection)
- Bath search view: Pre-Treatments / Plating / Post-Treatments / Strip
quick filters
- Existing bath infra (logs, replenishment, SPC) now applies to pre-
treatment baths equally
Tier 3 — Business / revenue:
- T3.1 Customer-specific price lists (fp.customer.price.list)
- Per (customer, coating_config) with unit_price + basis (per_part /
sqin / sqft / lb)
- effective_from / effective_to for annual contract pricing
- min_quantity for volume breaks (cheapest price at requested qty wins)
- _find_price() helper resolves active entry by date + qty
- Direct Order wizard auto-fills unit_price on (partner, coating, qty)
change unless operator has typed an override
- Configurator menu → Customer Price Lists
- T3.2 Quote win/loss tracking (fp.quote.configurator)
- State values: draft → confirmed (won) / lost / expired / cancelled
- lost_reason selection (price / lead_time / tech / spec_mismatch /
no_bid / no_response / competitor / other) + lost_competitor_name
+ lost_details text
- Action buttons: Mark as Lost (requires reason), Mark as Expired
- won_date auto-set on SO creation; lost_date auto-set on mark_lost
- New "Win / Loss" tab on configurator form
- T3.3 Actuals vs. quoted margin (mrp.production)
- Computed monetary fields: x_fc_consumables_cost, x_fc_labour_cost,
x_fc_actual_cost, x_fc_quoted_revenue, x_fc_margin_actual,
x_fc_margin_pct
- Labour = sum(WO duration × workcentre cost_hour)
- Revenue = SO amount_untaxed via mo.origin lookup
- New "Job Costing" group on MO form with badge-coloured margin
- T3.4 Job consumables tracking (fp.job.consumption)
- One row per consumable event (bath replenisher, masking tape, PPE,
chemistry): product, qty, uom, unit_cost (snapshot), total_cost,
source, optional workorder link
- One2many x_fc_consumption_ids on mrp.production
- "Consumables" stat button on MO → filtered list
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
d3dd6376a6 |
feat(fusion_plating): quote-to-cash infra, notifications, wizards, Tier 1 plating features
Quote-to-cash PDF reports (portrait + landscape variants, 16 new actions): - Quotation / Sales Order, Work Order Traveller, Packing Slip, Bill of Lading, Certificate of Conformance (portrait added), Invoice, Payment Receipt - Shared fp_portrait_styles + fp_landscape_styles base templates Workflow gap fixes (fusion_plating_bridge_mrp): - Auto-assign recipe from SO coating config in MrpProduction.action_confirm - Auto-create draft CoC (fp.certificate) on MrpProduction.button_mark_done Notifications overhaul (fusion_plating_notifications v2.0): - Expanded TRIGGER_EVENTS to 7 (added quote_sent, mo_complete, shipped, payment_received) - Shared _dispatch method replaces three duplicated send helpers - Auto-attach PDF reports per template config (quote, SO, CoC, invoice, receipt, BoL) - Rebuilt 7 email templates with fusion_claims accent-bar design (info/success color-coded, theme-safe, 600px max-width) - New hooks: MrpProduction done, FpDelivery mark_delivered, AccountPayment post, SaleOrder action_quotation_send Wizards (fusion_plating_configurator): - fp.direct.order.wizard — skip quotation for repeat customers with PO in hand; optional new-revision drawing upload bumps fp.part.catalog revision and links new rev to the SO; creates + confirms the SO in one step - fp.part.catalog.import.wizard — 3-step CSV import with dry-run preview, tolerant parsing (customer by name/email/xmlid, human-readable selections), duplicate detection, create-missing-customers option, single transaction commit - Partner form stat buttons: Direct Order, Import Parts - CSV template download button Tier 1 practical plating features: - T1.1 Hydrogen bake window enforcement (fp.coating.config.requires_bake_relief, auto-create fusion.plating.bake.window on plating WO finish, FpDelivery lockout when window is open) - T1.2 Bath replenishment rules + pending suggestion queue (fusion.plating.bath.replenishment.rule + .suggestion, hook on bath log line create, operator Apply / Dismiss actions) - T1.3 Rack/fixture library (fusion.plating.rack with MTO counter, strip schedule, lifecycle: active → needs_strip → stripping → retired) - T1.4 Rework / strip-and-replate MOs (x_fc_is_rework, x_fc_original_production_id, Create Rework stat button on completed MOs) - T1.5 Parts location (x_fc_current_location computed on mrp.production — "In progress: Alkaline Clean" / "Queued: Bake Oven" / "Ready to Ship") Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
7c7ef06057 | folder rename |