changes
This commit is contained in:
@@ -13,6 +13,30 @@ from odoo import fields, models
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
def fp_customer_description(self):
|
||||
"""Strip the "[code] product_name" prefix from line.name.
|
||||
|
||||
Mirror of sale.order.line.fp_customer_description so the shared
|
||||
customer_line_description QWeb macro renders cleanly on invoice
|
||||
PDFs too.
|
||||
"""
|
||||
self.ensure_one()
|
||||
name = (self.name or '').strip()
|
||||
if not self.product_id or not name:
|
||||
return name
|
||||
code = self.product_id.default_code or ''
|
||||
pname = self.product_id.name or ''
|
||||
prefixes = []
|
||||
if code and pname:
|
||||
prefixes.append(f'[{code}] {pname}')
|
||||
if pname:
|
||||
prefixes.append(pname)
|
||||
for prefix in prefixes:
|
||||
if name.startswith(prefix):
|
||||
tail = name[len(prefix):]
|
||||
return tail.lstrip(' \t\r\n-—–:').strip()
|
||||
return name
|
||||
|
||||
x_fc_part_catalog_id = fields.Many2one(
|
||||
'fp.part.catalog',
|
||||
string='Part',
|
||||
|
||||
@@ -25,9 +25,26 @@ class FpCoatingThickness(models.Model):
|
||||
ondelete='cascade',
|
||||
)
|
||||
value = fields.Float(
|
||||
string='Nominal',
|
||||
digits=(10, 4),
|
||||
required=True,
|
||||
help='Target thickness value (magnitude only; UoM in the next field).',
|
||||
help='Target / nominal thickness value (the number printed on the cert). '
|
||||
'Magnitude only — UoM lives in the next field.',
|
||||
)
|
||||
# Hitting an exact thickness on plated parts is impossible — the spec
|
||||
# is always "X mils ± tolerance" or a min/max range. These fields
|
||||
# capture the acceptance band so QC can mark a reading pass/fail
|
||||
# against real customer specs (e.g. AMS-2404 Class 4 = 0.001"–0.0015").
|
||||
# Both optional: leave blank for legacy single-value entries.
|
||||
value_min = fields.Float(
|
||||
string='Min',
|
||||
digits=(10, 4),
|
||||
help='Lower acceptance bound. Readings below this fail QC.',
|
||||
)
|
||||
value_max = fields.Float(
|
||||
string='Max',
|
||||
digits=(10, 4),
|
||||
help='Upper acceptance bound. Readings above this fail QC.',
|
||||
)
|
||||
uom = fields.Selection(
|
||||
[('mils', 'mils (0.001 in)'),
|
||||
@@ -44,7 +61,7 @@ class FpCoatingThickness(models.Model):
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends('value', 'uom')
|
||||
@api.depends('value', 'value_min', 'value_max', 'uom')
|
||||
def _compute_display_name(self):
|
||||
uom_labels = dict(self._fields['uom'].selection)
|
||||
for rec in self:
|
||||
@@ -52,7 +69,22 @@ class FpCoatingThickness(models.Model):
|
||||
# Strip the bracketed clarification for a tighter dropdown row.
|
||||
if ' (' in label:
|
||||
label = label.split(' (')[0]
|
||||
if rec.value:
|
||||
# Range overrides single value when both bounds are set —
|
||||
# operators see the real spec, not a phantom-precise nominal.
|
||||
if rec.value_min and rec.value_max:
|
||||
rec.display_name = (
|
||||
f'{rec.value_min:g}–{rec.value_max:g} {label}'.strip()
|
||||
)
|
||||
elif rec.value:
|
||||
rec.display_name = f'{rec.value:g} {label}'.strip()
|
||||
else:
|
||||
rec.display_name = label
|
||||
|
||||
@api.constrains('value_min', 'value_max')
|
||||
def _check_range(self):
|
||||
for rec in self:
|
||||
if rec.value_min and rec.value_max and rec.value_min > rec.value_max:
|
||||
from odoo.exceptions import ValidationError
|
||||
raise ValidationError(_(
|
||||
'Thickness Min (%(mn)s) cannot exceed Max (%(mx)s).'
|
||||
) % {'mn': rec.value_min, 'mx': rec.value_max})
|
||||
|
||||
@@ -10,6 +10,36 @@ from odoo.exceptions import ValidationError
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
def fp_customer_description(self):
|
||||
"""Return line.name with the leading "[code] product_name" stripped.
|
||||
|
||||
Odoo's _compute_name re-prepends the product code + name on save,
|
||||
polluting customer-facing PDFs with internal-product noise like
|
||||
"[FP-SERVICE] Plating Service". This helper peels that prefix
|
||||
off so the QWeb macros print only what the estimator actually
|
||||
typed for the customer to see. Same logic mirrored on
|
||||
account.move.line for invoice rendering.
|
||||
"""
|
||||
self.ensure_one()
|
||||
name = (self.name or '').strip()
|
||||
if not self.product_id or not name:
|
||||
return name
|
||||
code = self.product_id.default_code or ''
|
||||
pname = self.product_id.name or ''
|
||||
# Try the bracketed form first ("[CODE] Name"), then bare name.
|
||||
# Whichever matches gets stripped along with any trailing
|
||||
# newline / dash / em-dash separator.
|
||||
prefixes = []
|
||||
if code and pname:
|
||||
prefixes.append(f'[{code}] {pname}')
|
||||
if pname:
|
||||
prefixes.append(pname)
|
||||
for prefix in prefixes:
|
||||
if name.startswith(prefix):
|
||||
tail = name[len(prefix):]
|
||||
return tail.lstrip(' \t\r\n-—–:').strip()
|
||||
return name
|
||||
|
||||
x_fc_part_catalog_id = fields.Many2one(
|
||||
'fp.part.catalog', string='Part',
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user