fix(plating): UAT-caught UX annoyances + lurking bugs
Five fixes from the end-to-end UAT debrief: 1. Menu discoverability (HIGH) Added a prominent "+ New Direct Order" button in the Sale Orders list header toolbar (class=btn-primary, display=always). The existing menuitem at Plating > Sales > New Direct Order was buried in a submenu that didn't always expand; the toolbar button is a guaranteed entry point from the most common screen. 2. Escape/X destroys wizard state (HIGH) Added a prominent info banner at the top of the wizard form: "Changes are not saved until you click Create & Confirm Order. Closing this window (Esc or X) discards your entries." The Cancel button now has confirm="Discard this order? All header data and line items will be lost." so the intentional-cancel path also prompts. 3. Shell/cron crash in _fp_auto_create_mo (MEDIUM) bridge_mrp/models/sale_order.py:232-264 used _() inside list comprehensions to format the internal chatter summary of newly created / adopted MOs. _() resolves language from env.context, which is empty in odoo-shell and cron contexts — triggering a translate.get_text_alias crash AFTER the MOs had been created. These strings are internal audit log text, not user-facing UI; dropped the _() wrappers so the message builds safely from any context. Same for the per-group error-message on savepoint rollback. 4. Misleading "100%" margin (MEDIUM) x_fc_margin_percent displayed 100% on every SO because the cost rollup from fp.coating.config.unit_cost isn't populated yet. Added x_fc_margin_available Boolean (True only when at least one line's coating has a non-zero unit_cost). The SO Plating tab now hides the margin numbers when margin_available=False and shows an inline muted note: "Margin n/a — coating cost rollup not yet populated on any line's treatment." 5. Account Hold banner too loud (LOW) fusion_plating_invoicing was injecting a full-height danger alert above every SO header. Slimmed it to a one-line compact alert with icon: "Account Hold — SO confirmation, invoicing and shipping are blocked for non-managers." Half the vertical footprint, less visual competition with the Plating chip bar. Verified via UAT on S00071. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,12 @@ class SaleOrder(models.Model):
|
||||
string='Margin %',
|
||||
compute='_compute_margin',
|
||||
)
|
||||
x_fc_margin_available = fields.Boolean(
|
||||
string='Margin Available',
|
||||
compute='_compute_margin',
|
||||
help='False when no order line has a costed coating — the '
|
||||
'margin fields should render "n/a" in the UI.',
|
||||
)
|
||||
|
||||
x_fc_workorder_count = fields.Integer(
|
||||
string='Active WOs',
|
||||
@@ -486,24 +492,34 @@ class SaleOrder(models.Model):
|
||||
|
||||
@api.depends('order_line.price_subtotal', 'amount_untaxed')
|
||||
def _compute_margin(self):
|
||||
"""Simple margin: untaxed total minus rolled-up cost from coating configs.
|
||||
"""Margin = untaxed total − rolled-up cost from coating configs.
|
||||
|
||||
x_fc_margin_percent is stored as a fraction (0.0 - 1.0) so the
|
||||
widget='percentage' formats it correctly (a 100% margin reads
|
||||
as 100%, not 10000%).
|
||||
widget='percentage' formats 100% as 100%, not 10000%.
|
||||
|
||||
x_fc_margin_available is False when NO line has a costed coating
|
||||
(i.e. fp.coating.config.unit_cost isn't populated anywhere). The
|
||||
UI should render margin fields as "n/a" in that case rather than
|
||||
showing a misleading 100%.
|
||||
"""
|
||||
for rec in self:
|
||||
has_cost_data = False
|
||||
cost = 0.0
|
||||
for line in rec.order_line:
|
||||
if line.x_fc_coating_config_id:
|
||||
cost_per_unit = getattr(
|
||||
line.x_fc_coating_config_id, 'unit_cost', 0.0,
|
||||
) or 0.0
|
||||
cost += cost_per_unit * (line.product_uom_qty or 0)
|
||||
cc = line.x_fc_coating_config_id
|
||||
if not cc:
|
||||
continue
|
||||
if 'unit_cost' not in cc._fields:
|
||||
continue
|
||||
if cc.unit_cost:
|
||||
has_cost_data = True
|
||||
cost_per_unit = cc.unit_cost or 0.0
|
||||
cost += cost_per_unit * (line.product_uom_qty or 0)
|
||||
rec.x_fc_margin_available = has_cost_data
|
||||
rec.x_fc_margin_amount = (rec.amount_untaxed or 0) - cost
|
||||
rec.x_fc_margin_percent = (
|
||||
(rec.x_fc_margin_amount / rec.amount_untaxed)
|
||||
if rec.amount_untaxed else 0.0
|
||||
if (rec.amount_untaxed and has_cost_data) else 0.0
|
||||
)
|
||||
|
||||
@api.onchange('upload_rfq_file')
|
||||
|
||||
Reference in New Issue
Block a user