Ships the remaining items from the Sales UX Uplift plan:
D2 BOM Items kanban
New view_sale_order_line_bom_kanban grouped by x_fc_part_catalog_id.
Smart button 'BOM Items' on SO form opens it.
D5 Archive line
x_fc_archived Boolean on sale.order.line plus action_archive_line /
action_unarchive_line. Acknowledgement report filters out archived
lines.
D6 Add Quoted Lines sub-wizard
New fp.add.from.quote.wizard parallel to fp.add.from.so.wizard. Pick
quotes for this customer and clone them into direct-order lines
carrying part, coating, qty, unit price (from calculated or
override), and notes. Button '+ Add From Quotes' on wizard Lines tab.
D7 SO Acknowledgement PDF
New ir.actions.report + QWeb template in configurator/report/.
Header shows customer / contact / PO / Customer Job #, Bill-To,
Ship-To, planned start + customer deadline + ship-via. Line table
skips archived lines. Includes external notes, blanket-order
callout, and customer-signature + vendor-signature blocks.
Binding added to sale.order so it shows up under Print menu.
D9 Quick-nav chip bar
New smart buttons on SO form: Invoices / Pickings / NCRs / Files
with counts and icons. Each opens a filtered list. NCR button
appears only when fusion_plating_quality is installed.
D10 SO/WO perspective toggle
view_sale_order_line_wo_kanban grouped by x_fc_wo_group_tag. Smart
button 'By WO' on SO form.
D11 Assemblies minimal model
fp.sale.assembly + fp.sale.assembly.line with name, ship_to, count,
procured_count, completed_at. UX (forms / kanbans / integration
into receiving) deferred — model only for now.
D14 Uploaded Files
Files smart button on SO form opens ir.attachment kanban filtered
to this SO. Count appears in the chip bar.
F4 Signed tracking
x_fc_signed_at / x_fc_signed_by / x_fc_is_signed on sale.order +
action_mark_signed helper. Signed column on quotes list view.
F10 New Quote
Kept on existing action_fp_quotations (already surfaces the
default New button).
E5/F9 Action icons per row
Deferred — requires a custom widget; the native PDF action via the
Print menu covers 80% of the use case.
Bumped to 19.0.8.0.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two features from Phases B/C that were previously only data now do work:
1. WO GROUPING (x_fc_wo_group_tag)
_fp_auto_create_mo rewritten to iterate order_lines and group by
x_fc_wo_group_tag. Lines sharing a tag collapse into ONE MO with
product = first line's part.product_id, qty = Σ line qty,
recipe = first line's coating_config.recipe_id. Untagged lines
each get their own MO. Legacy path preserved for service-line SOs
with no plating data.
Idempotency is per (origin, tag): re-confirming an SO doesn't
create duplicate MOs for already-grouped lines.
New on mrp.production:
- x_fc_wo_group_tag (Char, tracking)
- x_fc_sale_order_line_ids (M2M back to sale.order.line)
- x_fc_start_at_node_id (Many2one fusion.plating.process.node)
2. START-AT-NODE (x_fc_start_at_node_id)
_generate_workorders_from_recipe pre-computes allowed_ids as the
set of {descendants of start_node} ∪ {ancestors of start_node}.
_is_node_included rejects any node outside that set. This skips
sibling branches earlier in the recipe while keeping the
container hierarchy so WO sequence numbers still make sense.
Smoke-tested S00070 (4 lines, 2 tagged groups + 1 untagged) -> 3 MOs:
WO#A qty=15 (2 lines batched), WO#B qty=50 (1 line), untagged qty=7
(1 line). Each got the ENP-ALUM-BASIC recipe.
Start-at-node smoke on the same recipe: full generation = 9 WOs,
partial with start_at='Ready for processing' = 1 WO.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
F1 follow-up: x_fc_follow_up_date + x_fc_follow_up_user_id fields on
sale.order, surfaced in the quotations list + a 'Needs Follow-Up'
preset filter.
F2 expires: native validity_date exposed as togglable column on the
quotes list + an 'Expired' preset filter.
F3 email status pills: x_fc_email_status computed (draft / sent /
opened / won). 'Opened' detects via mail.notification.is_read on any
email-type mail.message attached to this SO.
F5 part numbers summary: x_fc_part_numbers_summary ("PN1, PN2 (+3
more)") across order_line parts, togglable column.
F7 from-RFQ filter reuses existing x_fc_rfq_attachment_id.
Views:
- view_sale_order_list_fp_quotes (new list dedicated to quotes).
- view_sale_order_search_fp_quotes with filters Draft / Sent / Won /
From RFQ / Needs Follow-Up / Expired + group-bys.
- action_fp_quotations rewired to both of the above.
Bumped to 19.0.7.2.0. Closes all six phases originally planned.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
E1/E2/E3/E4: list view gets new togglable columns for
- x_fc_wo_completion (e.g. '3/5'): count of completed vs total WOs
- x_fc_invoiced_amount (Monetary): sum of posted customer invoices
minus credit notes
- x_fc_margin_amount + x_fc_margin_percent: reuses Phase D8 computes
- x_fc_is_blanket_order toggle
New sale.order.search view (sale.order.search.fp) with preset
filters: My Orders / Open / Confirmed / Done / Blanket / Has Rush /
Overdue, plus group-bys for Customer / Status / Customer Deadline.
Bumped to 19.0.7.1.0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
D3 first half: x_fc_workorder_count computes live count of active MRP
work orders linked to this SO (via mo.origin = so.name). Adds a
'Active WOs' smart button next to the existing PO / RFQ buttons on
the sale.order form. Clicking opens a filtered mrp.workorder list
grouped by MO.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase D first landing covers the quick-win Steelhead-parity fields on
the SO form / list:
- D1: x_fc_deadline_countdown ("in 2d 3h", "overdue 1d 4h") computed
from commitment_date. Surfaced in SO form scheduling group and as
togglable column on the SO list.
- D4: x_fc_internal_note + x_fc_external_note split (html). Existing
'note' field is left untouched for back-compat. External note is
intended for the SO acknowledgement + portal; internal note is
shop-floor only.
- D8: x_fc_margin_amount + x_fc_margin_percent, currently computed
against fp.coating.config.unit_cost if defined (else 0 -> 100%
margin). When cost rollup lands on fp.coating.config, margin will
reflect reality automatically.
- D12: x_fc_contact_phone related to partner.phone (readonly) on SO
header.
- D13: x_fc_ship_via Char on SO header (carrier name).
Smoke: S00066 shows 'in 9d 22h' countdown + \$3025 margin; S00069
shows 'in 24d 22h' + \$750. Contact phone pulls from partner.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase C complete on odoo-entech. Smoke-tested S00069:
- C1 x_fc_start_at_node_id = Ready for De-Masking (resume-rework)
- C2 x_fc_part_wo_description = internal rework note
- C5 x_fc_is_one_off = False
- C3 x_fc_quote_id slot wired (no quote picked in this smoke)
- C4 push-to-defaults wrote EN High-Phos back onto part catalog
Phase D (SO detail view), Phase E (SO list view), and Phase F
(Quotes list) are independent tracks — outlined in the plan doc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds quote_id (Many2one fp.quote.configurator) on the wizard line
with a domain scoped to the wizard's customer + quote states (sent /
accepted / won). Onchange auto-fills part, coating, and unit price
(final = estimator_override_price or calculated_price, per-part).
Mirrors x_fc_quote_id on sale.order.line for the audit trail. Surfaced
as a togglable column on the SO line tree and under "Qty & Price" on
the wizard line drill-in form.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds x_fc_default_coating_config_id and x_fc_default_treatment_ids
fields on fp.part.catalog. Wizard line gets a push_to_defaults
toggle. After action_create_order confirms the SO, any line with
push_to_defaults=True writes its coating + treatments back onto the
part catalog entry as the new defaults.
Reverse direction too: onchange on part_catalog_id in the wizard
line seeds coating + treatments from the part's defaults (if set and
the line doesn't already have them).
Part catalog form gets a new "Defaults" tab showing the stored
defaults. Smoke-tested: pushing default on order 1 populates the
catalog entry; new wizard line for that part auto-seeds the coating.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
C1: start_at_node_id per wizard line, mirrors to x_fc_start_at_node_id
on sale.order.line. Domain filters to nodes descending from the
coating_config's recipe so the estimator only picks valid resume
points. bridge_mrp will use this in a follow-up to skip ancestor
steps in the generated work order.
C2: part_wo_description (separate from customer-facing line_description)
lets the planner add internal-only notes that appear on the travelling
sheet only. Mirrors to x_fc_part_wo_description on sale.order.line.
C5: is_one_off flag for prototype / non-catalog parts. Mirrors to
x_fc_is_one_off. Actual skip-catalog behaviour will be wired in a
later pass.
All three fields appear in the wizard line drill-in form (under a new
"Work Order (internal)" group) and as togglable columns on the
sale.order.line tree.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase B complete on odoo-entech:
- B1/B2: Blanket + Block Partial flags on wizard header + sale.order
- B3: x_fc_wo_group_tag per SO line (bridge_mrp will use this to
batch MOs in a follow-up)
- B4: 'Add From Prior SO' sub-wizard for repeat orders
- B5: Per-line is_missing_info compute + amber row decoration
- B6: Rush already on line (added in Phase A)
Smoke-tested: wizard accepts 4 lines (1 with missing price, 3 WO-tagged
across 2 groups), banner shows correctly, missing row highlighted in
amber, after fix SO creates cleanly with all flags + tags persisted.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task B4. New fp.add.from.so.wizard transient model: given the current
direct-order wizard + customer, lists the customer's prior confirmed
sale orders, lets the estimator tick source lines, and clones them
into fp.direct.order.line rows (part, coating, treatments, qty,
price, deadline, rush, WO group, description).
Button "+ Add From Prior SO" lives on the Lines tab of the main
wizard, visible once the customer is picked. Sub-wizard rejects
source lines that predate the new plating fields (no x_fc_part_catalog_id).
Smoke-tested on odoo-entech: copying all 3 lines of S00066 onto a
fresh wizard reproduces part/coating/qty/price correctly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase B partial landing (B1, B2, B3, B5):
- B1/B2: x_fc_is_blanket_order and x_fc_block_partial_shipments on
sale.order; matching booleans on the wizard header.
- B3: x_fc_wo_group_tag Char on sale.order.line and wo_group_tag on
wizard line. Free-text tag; bridge_mrp will batch lines sharing a
tag into one MO in a follow-up.
- B5: is_missing_info computed Boolean on fp.direct.order.line;
tree uses decoration-warning to highlight incomplete rows in amber.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task A8. Closes Phase A of the direct-order rewrite.
Smoke-tested on odoo-entech: wizard accepts 3 lines (qty 65, total
\$3,025 + tax -> \$3,418.25), creates SO S00066 in state=sale with all
header fields (customer job #, three deadlines, bill/ship addresses)
and per-line fields (part, coating, qty, price) populated correctly.
Phase A complete. Phase B (blanket flag, block partial, WO grouping,
add-from-SO, missing-info banner polish) and Phase C (to-node picker,
quote link, push-defaults) outlined in the plan doc; Phases D/E/F
(SO detail, SO list, quotes list) are separate tracks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task A7. SO form Plating tab gets a new "Customer Reference /
Scheduling" block showing customer_job_number, planned_start_date,
internal_deadline, commitment_date (as Customer Deadline). Order line
tree in SO form now shows per-line part / coating / treatments /
deadline / rush. SO list view exposes customer job # and both
deadlines as togglable columns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tasks A3 + A6. Wizard rewritten as header + lines architecture:
- Header carries customer/addresses/PO/deadlines/invoicing/notes.
- One SO line created per fp.direct.order.line, carrying part,
coating, treatments M2M, qty, price, per-line deadline, rush flag,
and description.
- action_create_order loops wizard lines, invokes revision-bump
helper, and builds order_line tuples with x_fc_* fields.
- Form view uses notebook (Lines tab with editable tree + drill-in
form, Notes tab), amber missing-info banner at top, running totals
at bottom. Customer deadline maps to Odoo commitment_date on SO.
Single-line fields and their computes/onchanges removed from wizard;
moved to fp.direct.order.line in task A4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task A4. Expands fp.direct.order.line with: part related fields,
optional new-revision block, additional treatment M2M, per-line
deadline + rush flag, description template + free-text, onchange
auto-price-lookup from customer price list, onchange template
suggestion (part > customer > coating), and _get_or_bump_revision
helper that will be called by the SO-creation loop.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task A2 of the direct-order-wizard rewrite. Adds SO-header fields for
customer job #, three deadlines (planned start / internal / customer),
bill-to / ship-to address pickers, the line_ids O2M linking to
fp.direct.order.line, computed order totals, and a missing-info
warning banner. Partner onchange now also seeds default addresses.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task A1 of the direct-order-wizard rewrite. Adds the transient line
model that will hold per-part detail (part, coating, qty, price) when
the wizard moves from single-line to header+lines architecture.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds fusion_accounting_assets to the meta-module 'depends' so a single
install of fusion_accounting brings up the full Phase 1 + 2 + 3 stack.
Bumps version 19.0.1.0.2 -> 19.0.1.0.3.
Made-with: Cursor
Auto-detects LM Studio (:1234) or Ollama (:11434) on
host.docker.internal / localhost; skips silently when no server is
reachable so CI stays green. When a server is present it exercises the
full predict_useful_life path through the OpenAI-compatible adapter,
catching prompt / JSON-parsing regressions that mocked LLMs hide.
Tagged 'local_llm' so it can be selected explicitly when an LLM is
known-available.
Made-with: Cursor
Adds JSON-RPC controller benchmark to complement Task 23's engine-level
benchmarks: end-to-end /fusion/assets/get_detail timing through the HTTP
dispatch layer.
Captured locally on westin-v19:
controller.get_detail: median=2ms p95=40ms (target <500ms, 12x headroom)
Tagged 'benchmark' so it stays out of fast unit runs.
Made-with: Cursor
Mirrors Phase 1 + 2 tour pattern: HttpCase.start_tour wrappers tagged
'tour' so they skip cleanly when websocket-client is absent. Tours cover
smoke (/odoo loads), the asset list / category list / anomaly list views,
and the depreciation-run wizard form. Bundle is wired via
web.assets_tests.
Verified locally: 5 tests registered, all skip with
"websocket-client module is not installed" (expected — no chromium in
the dev container).
Made-with: Cursor