[REM] core: remove name_get API

Rationale
=========

Since v8, the `display_name` field is present on all models. By default,
`display_name` uses `name_get` which has pretty much the same purpose
(return record name used by the web client). Gradually, many (backend)
developers (and the ORM: https://github.com/odoo/odoo/commit/6da1c3ac4c036eac289597602976538e243cb939)
started using `display_name` (more convenient than
`record.name_get()[0][1]`) but it still had the `name_get` override.
It becomes more complex than necessary and poeple start to misunderstand
the two (and sometimes override both, leading to inconstiencies between
`display_name`/`name_get`).

To simplify the ORM and the API, we decided to keep only one of them,
the `display_name` field:
- It is much more convenient from a backend point of view
(`record.name_get()[0][1]` vs `record.display_name`)
- It is cached during the same transaction (and invalidated if
its dependencies change)
- It can be overridden like any other compute field (override
`_compute_display_name` with any extra dependencies)
- `name_get` is replaced by `read(['display_name'])`
(API perceptive), which can actually be more efficient
(if `display_name`'s depends are correct, the ORM will only fetch the
fields it needs instead of every prefetchable field)

Changes
=======

- Deprecates `name_get` for the v17 and based the method on
`display_name` (the opposite of before)
- Converts all usage of `name_get`
- Overrides of `name_get` are now overrides of `_compute_display_name`
- For `res.partner`, rename the field store `display_name` into
`complete_name` because `display_name` context-dependent and it makes
no sense to have a compute store that is context-dependent.
- Previously, it was possible to return multiple names for the same
record with `name_get`, but it was tricky and most of the usage of
this `name_get` didn't take this into account. The only example of
this is the `name_get` of `product.product`
(now use `", ".join(<names>)`).

Part-of: odoo/odoo#122085
This commit is contained in:
Rémy Voet (ryv)
2023-06-28 17:41:19 +02:00
parent 067f9255a6
commit 3c62ca1eb9
176 changed files with 860 additions and 1325 deletions
+7 -10
View File
@@ -597,12 +597,9 @@ class AccountAccount(models.Model):
self.name = name
self.code = code
def name_get(self):
result = []
def _compute_display_name(self):
for account in self:
name = account.code + ' ' + account.name
result.append((account.id, name))
return result
account.display_name = f"{account.code} {account.name}"
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
@@ -701,7 +698,8 @@ class AccountAccount(models.Model):
"""
if 'import_file' in self.env.context:
code, name = self._split_code_name(name)
return self.create({'code': code, 'name': name}).name_get()[0]
record = self.create({'code': code, 'name': name})
return record.id, record.display_name
raise ValidationError(_("Please create new accounts from the Chart of Accounts menu."))
@api.model_create_multi
@@ -828,15 +826,14 @@ class AccountGroup(models.Model):
if not group.code_prefix_start or group.code_prefix_start > group.code_prefix_end:
group.code_prefix_start = group.code_prefix_end
def name_get(self):
result = []
def _compute_display_name(self):
for group in self:
prefix = group.code_prefix_start and str(group.code_prefix_start)
if prefix and group.code_prefix_end != group.code_prefix_start:
prefix += '-' + str(group.code_prefix_end)
name = (prefix and (prefix + ' ') or '') + group.name
result.append((group.id, name))
return result
group.display_name = name
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
+3 -6
View File
@@ -14,18 +14,15 @@ class AccountAccountTag(models.Model):
tax_negate = fields.Boolean(string="Negate Tax Balance", help="Check this box to negate the absolute value of the balance of the lines associated with this tag in tax report computation.")
country_id = fields.Many2one(string="Country", comodel_name='res.country', help="Country for which this tag is available, when applied on taxes.")
def name_get(self):
def _compute_display_name(self):
if not self.env.company.multi_vat_foreign_country_ids:
return super().name_get()
return super()._compute_display_name()
res = []
for tag in self:
name = tag.name
if tag.applicability == "taxes" and tag.country_id and tag.country_id != self.env.company.account_fiscal_country_id:
name = _("%s (%s)", tag.name, tag.country_id.code)
res.append((tag.id, name,))
return res
tag.display_name = name
@api.model
def _get_tax_tags(self, tag_name, country_id):
+3 -3
View File
@@ -18,6 +18,6 @@ class AccountIncoterms(models.Model):
'Active', default=True,
help="By unchecking the active field, you may hide an INCOTERM you will not use.")
def name_get(self):
return [(incoterm.id, '%s%s' % (incoterm.code and '[%s] ' % incoterm.code or '', incoterm.name))
for incoterm in self]
def _compute_display_name(self):
for incoterm in self:
incoterm.display_name = '%s%s' % (incoterm.code and '[%s] ' % incoterm.code or '', incoterm.name)
+3 -5
View File
@@ -696,14 +696,12 @@ class AccountJournal(models.Model):
'journal_id': self,
}).id
def name_get(self):
res = []
def _compute_display_name(self):
for journal in self:
name = journal.name
if journal.currency_id and journal.currency_id != journal.company_id.currency_id:
name = "%s (%s)" % (name, journal.currency_id.name)
res += [(journal.id, name)]
return res
name = f"{name} ({journal.currency_id.name})"
journal.display_name = name
def action_configure_bank_journal(self):
""" This function is called by the "configure" button of bank journals,
+2 -4
View File
@@ -2387,11 +2387,9 @@ class AccountMove(models.Model):
self.line_ids.unlink()
return super().unlink()
def name_get(self):
result = []
def _compute_display_name(self):
for move in self:
result.append((move.id, move._get_move_display_name(show_ref=True)))
return result
move.display_name = move._get_move_display_name(show_ref=True)
def onchange(self, values, field_name, field_onchange):
if field_name in ('line_ids', 'invoice_line_ids'):
+9 -8
View File
@@ -1525,14 +1525,15 @@ class AccountMoveLine(models.Model):
return res
def name_get(self):
return [(line.id, " ".join(
element for element in (
line.move_id.name,
line.ref and f"({line.ref})",
line.name or line.product_id.display_name,
) if element
)) for line in self]
def _compute_display_name(self):
for line in self:
line.display_name = " ".join(
element for element in (
line.move_id.name,
line.ref and f"({line.ref})",
line.name or line.product_id.display_name,
) if element
)
def copy_data(self, default=None):
data_list = super().copy_data(default=default)
+3 -2
View File
@@ -740,8 +740,9 @@ class AccountPayment(models.Model):
return res
@api.depends('move_id.name')
def name_get(self):
return [(payment.id, payment.move_id.name != '/' and payment.move_id.name or _('Draft Payment')) for payment in self]
def _compute_display_name(self):
for payment in self:
payment.display_name = payment.move_id.name if payment.move_id.name != '/' else _('Draft Payment')
# -------------------------------------------------------------------------
# SYNCHRONIZATION account.payment <-> account.move
@@ -119,10 +119,11 @@ class AccountPaymentMethodLine(models.Model):
company_id = fields.Many2one(related='journal_id.company_id')
available_payment_method_ids = fields.Many2many(related='journal_id.available_payment_method_ids')
def name_get(self):
if self.env.context.get('show_payment_journal_id'):
return [(method.id, "%s (%s)" % (method.name, method.journal_id.name)) for method in self]
return super().name_get()
def _compute_display_name(self):
if not self.env.context.get('show_payment_journal_id'):
return super()._compute_display_name()
for method in self:
method.display_name = f"{method.name} ({method.journal_id.name})"
@api.depends('payment_method_id.name')
def _compute_name(self):
+6 -6
View File
@@ -203,11 +203,9 @@ class AccountReport(models.Model):
return name
@api.depends('name', 'country_id')
def name_get(self):
result = []
def _compute_display_name(self):
for report in self:
result.append((report.id, report.name + (f' ({report.country_id.code})' if report.country_id else '')))
return result
report.display_name = report.name + (f' ({report.country_id.code})' if report.country_id else '')
class AccountReportLine(models.Model):
@@ -561,8 +559,10 @@ class AccountReportExpression(models.Model):
tags_to_archive.active = False
tags_to_unlink.unlink()
def name_get(self):
return [(expr.id, f'{expr.report_line_name} [{expr.label}]') for expr in self]
def _compute_display_name(self):
for expr in self:
expr.display_name = f'{expr.report_line_name} [{expr.label}]'
def _expand_aggregations(self):
"""Return self and its full aggregation expression dependency"""
+2 -4
View File
@@ -362,8 +362,7 @@ class AccountTax(models.Model):
default['name'] = _("%s (Copy)") % self.name
return super(AccountTax, self).copy(default=default)
def name_get(self):
name_list = []
def _compute_display_name(self):
type_tax_use = dict(self._fields['type_tax_use']._description_selection(self.env))
tax_scope = dict(self._fields['tax_scope']._description_selection(self.env))
for record in self:
@@ -372,8 +371,7 @@ class AccountTax(models.Model):
name += ' (%s)' % type_tax_use.get(record.type_tax_use)
if record.tax_scope:
name += ' (%s)' % tax_scope.get(record.tax_scope)
name_list += [(record.id, name)]
return name_list
record.display_name = name
@api.onchange('amount')
def onchange_amount(self):
+5 -7
View File
@@ -307,15 +307,13 @@ class ResPartnerBank(models.Model):
account.partner_id._message_log(body=msg)
return super().unlink()
def name_get(self):
res = super().name_get()
def _compute_display_name(self):
super()._compute_display_name()
if self.env.context.get('display_account_trust'):
res = []
for acc in self:
trusted_label = _('trusted') if acc.allow_out_payment else _('untrusted')
if acc.bank_id:
name = '{} - {} ({})'.format(acc.acc_number, acc.bank_id.name, trusted_label)
name = f'{acc.acc_number} - {acc.bank_id.name} ({trusted_label})'
else:
name = '{} ({})'.format(acc.acc_number, trusted_label)
res.append((acc.id, name))
return res
name = f'{acc.acc_number} ({trusted_label})'
acc.display_name = name
+2 -4
View File
@@ -115,16 +115,14 @@ class AccountAnalyticAccount(models.Model):
if self._cr.fetchone():
raise UserError(_("You can't set a different company on your analytic account since there are some analytic items linked to it."))
def name_get(self):
res = []
def _compute_display_name(self):
for analytic in self:
name = analytic.name
if analytic.code:
name = f'[{analytic.code}] {name}'
if analytic.partner_id.commercial_partner_id.name:
name = f'{name} - {analytic.partner_id.commercial_partner_id.name}'
res.append((analytic.id, name))
return res
analytic.display_name = name
def copy_data(self, default=None):
default = dict(default or {})
@@ -15,9 +15,7 @@ class City(models.Model):
country_id = fields.Many2one(comodel_name='res.country', string='Country', required=True)
state_id = fields.Many2one(comodel_name='res.country.state', string='State', domain="[('country_id', '=', country_id)]")
def name_get(self):
res = []
def _compute_display_name(self):
for city in self:
name = city.name if not city.zipcode else '%s (%s)' % (city.name, city.zipcode)
res.append((city.id, name))
return res
name = city.name if not city.zipcode else f'{city.name} ({city.zipcode})'
city.display_name = name
+1 -1
View File
@@ -59,7 +59,7 @@ def _compute_sparse(self, records):
def _inverse_sparse(self, records):
for record in records:
values = record[self.sparse]
value = self.convert_to_read(record[self.name], record, use_name_get=False)
value = self.convert_to_read(record[self.name], record, use_display_name=False)
if value:
if values.get(self.name) != value:
values[self.name] = value
+3 -6
View File
@@ -645,7 +645,7 @@ class Meeting(models.Model):
return True
def name_get(self):
def _compute_display_name(self):
""" Hide private events' name for events which don't belong to the current user
"""
hidden = self.filtered(
@@ -654,11 +654,8 @@ class Meeting(models.Model):
evt.user_id.id != self.env.uid and
self.env.user.partner_id not in evt.partner_ids
)
shown = self - hidden
shown_names = super(Meeting, shown).name_get()
obfuscated_names = [(eid, _('Busy')) for eid in hidden.ids]
return shown_names + obfuscated_names
hidden.display_name = _('Busy')
super(Meeting, self - hidden)._compute_display_name()
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
@@ -18,8 +18,9 @@ class PeopleRole(models.Model):
]
@api.depends('name')
def name_get(self):
return [(role.id, role.name.replace('_', ' ').title()) for role in self]
def _compute_display_name(self):
for role in self:
role.display_name = role.name.replace('_', ' ').title()
class PeopleSeniority(models.Model):
@@ -35,5 +36,6 @@ class PeopleSeniority(models.Model):
]
@api.depends('name')
def name_get(self):
return [(seniority.id, seniority.name.replace('_', ' ').title()) for seniority in self]
def _compute_display_name(self):
for seniority in self:
seniority.display_name = seniority.name.replace('_', ' ').title()
@@ -17,5 +17,6 @@ class PeopleSeniority(models.Model):
]
@api.depends('name')
def name_get(self):
return [(seniority.id, seniority.name.replace('_', ' ').title()) for seniority in self]
def _compute_display_name(self):
for seniority in self:
seniority.display_name = seniority.name.replace('_', ' ').title()
+3 -5
View File
@@ -589,11 +589,10 @@ class EventEvent(models.Model):
self.message_subscribe([vals['organizer_id']])
return res
def name_get(self):
def _compute_display_name(self):
"""Adds ticket seats availability if requested by context."""
if not self.env.context.get('name_with_seats_availability'):
return super().name_get()
res = []
return super()._compute_display_name()
for event in self:
# event or its tickets are sold out
if event.event_registrations_sold_out:
@@ -606,8 +605,7 @@ class EventEvent(models.Model):
)
else:
name = event.name
res.append((event.id, name))
return res
event.display_name = name
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
+4 -3
View File
@@ -162,10 +162,11 @@ class EventRegistration(models.Model):
return ret
def name_get(self):
""" Custom name_get in case a registration is nott linked to an attendee
def _compute_display_name(self):
""" Custom display_name in case a registration is nott linked to an attendee
"""
return [(registration.id, registration.name or f"#{registration.id}") for registration in self]
for registration in self:
registration.display_name = registration.name or f"#{registration.id}"
def toggle_active(self):
pre_inactive = self - self.filtered(self._active_name)
+3 -5
View File
@@ -163,11 +163,10 @@ class EventTicket(models.Model):
raise ValidationError(_('There are not enough seats available for:')
+ '\n%s\n' % '\n'.join(sold_out_tickets))
def name_get(self):
def _compute_display_name(self):
"""Adds ticket seats availability if requested by context."""
if not self.env.context.get('name_with_seats_availability'):
return super().name_get()
res = []
return super()._compute_display_name()
for ticket in self:
if not ticket.seats_max:
name = ticket.name
@@ -179,8 +178,7 @@ class EventTicket(models.Model):
ticket_name=ticket.name,
count=formatLang(self.env, ticket.seats_available, digits=0),
)
res.append((ticket.id, name))
return res
ticket.display_name = name
def _get_ticket_multiline_description(self):
""" Compute a multiline description of this ticket. It is used when ticket
@@ -14,5 +14,6 @@ class FleetVehicleAssignationLog(models.Model):
date_start = fields.Date(string="Start Date")
date_end = fields.Date(string="End Date")
def name_get(self):
return [(rec.id, f'{rec.vehicle_id.name} - {rec.driver_id.name}') for rec in self]
def _compute_display_name(self):
for rec in self:
rec.display_name = f'{rec.vehicle_id.name} - {rec.driver_id.name}'
+3 -5
View File
@@ -53,14 +53,12 @@ class FleetVehicleModel(models.Model):
domain = expression.AND([name_domain, domain])
return self._search(domain, limit=limit, order=order)
def name_get(self):
res = []
def _compute_display_name(self):
for record in self:
name = record.name
if record.brand_id.name:
name = record.brand_id.name + '/' + name
res.append((record.id, name))
return res
name = f"{record.brand_id.name}/{name}"
record.display_name = name
def _compute_vehicle_count(self):
group = self.env['fleet.vehicle']._read_group(
@@ -698,11 +698,10 @@ class Challenge(models.Model):
message_body = _("The challenge %s is finished.", challenge.name)
if rewarded_users:
user_names = rewarded_users.name_get()
message_body += Markup("<br/>") + _(
"Reward (badge %(badge_name)s) for every succeeding user was sent to %(users)s.",
badge_name=challenge.reward_id.name,
users=", ".join(name for (user_id, name) in user_names)
users=", ".join(rewarded_users.mapped('display_name'))
)
else:
message_body += Markup("<br/>") + _("Nobody has succeeded to reach every goal, no badge is rewarded for this challenge.")
+7 -5
View File
@@ -31,14 +31,16 @@ class Department(models.Model):
master_department_id = fields.Many2one(
'hr.department', 'Master Department', compute='_compute_master_department_id', store=True)
def name_get(self):
if not self.env.context.get('hierarchical_naming', True):
return [(record.id, record.name) for record in self]
return super(Department, self).name_get()
def _compute_display_name(self):
if self.env.context.get('hierarchical_naming', True):
return super()._compute_display_name()
for record in self:
record.display_name = record.name
@api.model
def name_create(self, name):
return self.create({'name': name}).name_get()[0]
record = self.create({'name': name})
return record.id, record.display_name
@api.depends('name', 'parent_id.complete_name')
def _compute_complete_name(self):
+4 -3
View File
@@ -191,10 +191,11 @@ class HrEmployeePrivate(models.Model):
})
}
def name_get(self):
def _compute_display_name(self):
if self.check_access_rights('read', raise_exception=False):
return super(HrEmployeePrivate, self).name_get()
return self.env['hr.employee.public'].browse(self.ids).name_get()
return super()._compute_display_name()
for employee_private, employee_public in zip(self, self.env['hr.employee.public'].browse(self.ids)):
employee_private.display_name = employee_public.display_name
def search_fetch(self, domain, field_names, offset=0, limit=None, order=None):
if self.check_access_rights('read', raise_exception=False):
+3 -3
View File
@@ -13,17 +13,17 @@ class Partner(models.Model):
help="Related employees based on their private address")
employees_count = fields.Integer(compute='_compute_employees_count', groups="hr.group_hr_user")
def name_get(self):
def _compute_display_name(self):
""" Override to allow an employee to see its private address in his profile.
This avoids to relax access rules on `res.parter` and to add an `ir.rule`.
(advantage in both security and performance).
Use a try/except instead of systematically checking to minimize the impact on performance.
"""
try:
return super(Partner, self).name_get()
super()._compute_display_name()
except AccessError as e:
if len(self) == 1 and self in self.env.user.employee_ids.mapped('address_home_id'):
return super(Partner, self.sudo()).name_get()
super(Partner, self.sudo())._compute_display_name()
raise e
def _compute_employees_count(self):
+12 -12
View File
@@ -31,21 +31,21 @@ class HrAttendance(models.Model):
check_out = fields.Datetime(string="Check Out")
worked_hours = fields.Float(string='Worked Hours', compute='_compute_worked_hours', store=True, readonly=True)
def name_get(self):
result = []
def _compute_display_name(self):
for attendance in self:
if not attendance.check_out:
result.append((attendance.id, _("%(empl_name)s from %(check_in)s") % {
'empl_name': attendance.employee_id.name,
'check_in': format_datetime(self.env, attendance.check_in, dt_format=False),
}))
attendance.display_name = _(
"%s from %s",
attendance.employee_id.name,
format_datetime(self.env, attendance.check_in, dt_format=False)
)
else:
result.append((attendance.id, _("%(empl_name)s from %(check_in)s to %(check_out)s") % {
'empl_name': attendance.employee_id.name,
'check_in': format_datetime(self.env, attendance.check_in, dt_format=False),
'check_out': format_datetime(self.env, attendance.check_out, dt_format=False),
}))
return result
attendance.display_name = _(
"%s from %s to %s",
attendance.employee_id.name,
format_datetime(self.env, attendance.check_in, dt_format=False),
format_datetime(self.env, attendance.check_out, dt_format=False),
)
def _get_employee_calendar(self):
self.ensure_one()
@@ -17,7 +17,6 @@ class ContractHistory(models.Model):
# to the employee. That's why we will use this id (employee_id) as the id of the hr.contract.history.
contract_id = fields.Many2one('hr.contract', readonly=True)
display_name = fields.Char(compute='_compute_display_name')
name = fields.Char('Contract Name', readonly=True)
date_hired = fields.Date('Hire Date', readonly=True)
date_start = fields.Date('Start Date', readonly=True)
+1 -1
View File
@@ -61,7 +61,7 @@ class Department(models.Model):
**self._get_action_context(),
'search_default_active_time_off': 3,
'hide_employee_name': 1,
'holiday_status_name_get': False
'holiday_status_display_name': False
}
return action
+46 -77
View File
@@ -82,7 +82,7 @@ class HolidaysRequest(models.Model):
defaults = super(HolidaysRequest, self).default_get(fields_list)
defaults = self._default_get_request_parameters(defaults)
if self.env.context.get('holiday_status_name_get', True) and 'holiday_status_id' in fields_list and not defaults.get('holiday_status_id'):
if self.env.context.get('holiday_status_display_name', True) and 'holiday_status_id' in fields_list and not defaults.get('holiday_status_id'):
lt = self.env['hr.leave.type'].search(['|', ('requires_allocation', '=', 'no'), ('has_valid_allocation', '=', True)], limit=1, order='sequence')
if lt:
@@ -774,19 +774,6 @@ class HolidaysRequest(models.Model):
@api.depends('employee_id', 'holiday_status_id')
def _compute_display_name(self):
super()._compute_display_name()
def onchange(self, values, field_name, field_onchange):
# Try to force the leave_type name_get when creating new records
# This is called right after pressing create and returns the name_get for
# most fields in the view.
if field_onchange.get('employee_id') and 'employee_id' not in self._context and values:
employee_id = get_employee_from_context(values, self._context, self.env.user.employee_id.id)
self = self.with_context(employee_id=employee_id)
return super().onchange(values, field_name, field_onchange)
def name_get(self):
res = []
for leave in self:
user_tz = timezone(leave.tz)
date_from_utc = leave.date_from and leave.date_from.astimezone(user_tz).date()
@@ -795,13 +782,9 @@ class HolidaysRequest(models.Model):
if self.env.context.get('short_name'):
short_leave_name = leave.name or time_off_type_display or _('Time Off')
if leave.leave_type_request_unit == 'hour':
res.append((
leave.id,
_("%s: %.2f hours") % (short_leave_name, leave.number_of_hours_display)))
leave.display_name = _("%s: %.2f hours", short_leave_name, leave.number_of_hours_display)
else:
res.append((
leave.id,
_("%s: %.2f days") % (short_leave_name, leave.number_of_days)))
leave.display_name = _("%s: %.2f days", short_leave_name, leave.number_of_days)
else:
if leave.holiday_type == 'company':
target = leave.mode_company_id.name
@@ -816,65 +799,55 @@ class HolidaysRequest(models.Model):
display_date = format_date(self.env, date_from_utc) or ""
if leave.leave_type_request_unit == 'hour':
if self.env.context.get('hide_employee_name') and 'employee_id' in self.env.context.get('group_by', []):
res.append((
leave.id,
_("%(leave_type)s: %(duration).2f hours on %(date)s",
leave_type=time_off_type_display,
duration=leave.number_of_hours_display,
date=fields.Date.to_string(date_from_utc) or "",
)
))
leave.display_name = _("%(leave_type)s: %(duration).2f hours on %(date)s",
leave_type=time_off_type_display,
duration=leave.number_of_hours_display,
date=fields.Date.to_string(date_from_utc) or "",
)
elif not time_off_type_display:
res.append((
leave.id,
_("%(person)s: %(duration).2f hours on %(date)s",
person=target,
duration=leave.number_of_hours_display,
date=display_date,
)
))
leave.display_name = _("%(person)s: %(duration).2f hours on %(date)s",
person=target,
duration=leave.number_of_hours_display,
date=display_date,
)
else:
res.append((
leave.id,
_("%(person)s on %(leave_type)s: %(duration).2f hours on %(date)s",
person=target,
leave_type=time_off_type_display,
duration=leave.number_of_hours_display,
date=display_date,
)
))
leave.display_name = _("%(person)s on %(leave_type)s: %(duration).2f hours on %(date)s",
person=target,
leave_type=time_off_type_display,
duration=leave.number_of_hours_display,
date=display_date,
)
else:
if leave.number_of_days > 1 and date_from_utc and date_to_utc:
display_date += ' / %s' % format_date(self.env, date_to_utc) or ""
if not target or self.env.context.get('hide_employee_name') and 'employee_id' in self.env.context.get('group_by', []):
res.append((
leave.id,
_("%(leave_type)s: %(duration).2f days (%(start)s)",
leave_type=time_off_type_display,
duration=leave.number_of_days,
start=display_date,
)
))
leave.display_name = _("%(leave_type)s: %(duration).2f days (%(start)s)",
leave_type=time_off_type_display,
duration=leave.number_of_days,
start=display_date,
)
elif not time_off_type_display:
res.append((
leave.id,
_("%(person)s: %(duration).2f days (%(start)s)",
person=target,
duration=leave.number_of_days,
start=display_date,
)
))
leave.display_name = _("%(person)s: %(duration).2f days (%(start)s)",
person=target,
duration=leave.number_of_days,
start=display_date,
)
else:
res.append((
leave.id,
_("%(person)s on %(leave_type)s: %(duration).2f days (%(start)s)",
person=target,
leave_type=time_off_type_display,
duration=leave.number_of_days,
start=display_date,
)
))
return res
leave.display_name = _("%(person)s on %(leave_type)s: %(duration).2f days (%(start)s)",
person=target,
leave_type=time_off_type_display,
duration=leave.number_of_days,
start=display_date,
)
def onchange(self, values, field_name, field_onchange):
# Try to force the leave_type display_name when creating new records
# This is called right after pressing create and returns the display_name for
# most fields in the view.
if field_onchange.get('employee_id') and 'employee_id' not in self._context and values:
employee_id = get_employee_from_context(values, self._context, self.env.user.employee_id.id)
self = self.with_context(employee_id=employee_id)
return super().onchange(values, field_name, field_onchange)
def add_follower(self, employee_id):
employee = self.env['hr.employee'].browse(employee_id)
@@ -1373,18 +1346,16 @@ class HolidaysRequest(models.Model):
def _notify_manager(self):
leaves = self.filtered(lambda hol: (hol.validation_type == 'both' and hol.state in ['validate1', 'validate']) or (hol.validation_type == 'manager' and hol.state == 'validate'))
holiday_names = self.name_get()
for holiday in leaves:
responsible = holiday.employee_id.leave_manager_id.partner_id.ids
if responsible:
holiday_name = list(filter(lambda h: holiday.id in h, holiday_names))[0][1]
self.env['mail.thread'].sudo().message_notify(
partner_ids=responsible,
model_description='Time Off',
subject=_('Refused Time Off'),
body=_(
'%(holiday_name)s has been refused.',
holiday_name=holiday_name,
holiday_name=holiday.display_name,
),
email_layout_xmlid='mail.mail_notification_light',
)
@@ -1397,7 +1368,6 @@ class HolidaysRequest(models.Model):
self._force_cancel(reason, 'mail.mt_note')
def _force_cancel(self, reason, msg_subtype='mail.mt_comment'):
leave_names = self.name_get()
recs = self.browse() if self.env.context.get(MODULE_UNINSTALL_FLAG) else self
for leave in recs:
leave.message_post(
@@ -1418,14 +1388,13 @@ class HolidaysRequest(models.Model):
responsibles |= leave.holiday_status_id.responsible_ids.partner_id
if responsibles:
leave_name = list(filter(lambda h: leave.id in h, leave_names))[0][1]
self.env['mail.thread'].sudo().message_notify(
partner_ids=responsibles.ids,
model_description='Time Off',
subject=_('Canceled Time Off'),
body=_(
"%(leave_name)s has been cancelled with the justification: <br/> %(reason)s.",
leave_name=leave_name,
leave_name=leave.display_name,
reason=reason
),
email_layout_xmlid='mail.mail_notification_light',
@@ -520,16 +520,15 @@ class HolidaysAllocation(models.Model):
####################################################
def onchange(self, values, field_name, field_onchange):
# Try to force the leave_type name_get when creating new records
# This is called right after pressing create and returns the name_get for
# Try to force the leave_type display_name when creating new records
# This is called right after pressing create and returns the display_name for
# most fields in the view.
if field_onchange.get('employee_id') and 'employee_id' not in self._context and values:
employee_id = get_employee_from_context(values, self._context, self.env.user.employee_id.id)
self = self.with_context(employee_id=employee_id)
return super().onchange(values, field_name, field_onchange)
def name_get(self):
res = []
def _compute_display_name(self):
for allocation in self:
if allocation.holiday_type == 'company':
target = allocation.mode_company_id.name
@@ -542,16 +541,12 @@ class HolidaysAllocation(models.Model):
else:
target = ', '.join(allocation.employee_ids.sudo().mapped('name'))
res.append(
(allocation.id,
_("Allocation of %(allocation_name)s: %(duration).2f %(duration_type)s to %(person)s",
allocation_name=allocation.holiday_status_id.sudo().name,
duration=allocation.number_of_hours_display if allocation.type_request_unit == 'hour' else allocation.number_of_days,
duration_type=_('hours') if allocation.type_request_unit == 'hour' else _('days'),
person=target
))
allocation.display_name = _("Allocation of %s: %.2f %s to %s",
allocation.holiday_status_id.sudo().name,
allocation.number_of_hours_display if allocation.type_request_unit == 'hour' else allocation.number_of_days,
_('hours') if allocation.type_request_unit == 'hour' else _('days'),
target,
)
return res
def add_follower(self, employee_id):
employee = self.env['hr.employee'].browse(employee_id)
+13 -13
View File
@@ -537,26 +537,26 @@ class HolidaysType(models.Model):
if leave_type.employee_requests == 'no':
leave_type.allocation_validation_type = 'officer'
def requested_name_get(self):
return self._context.get('holiday_status_name_get', True) and self._context.get('employee_id')
def requested_display_name(self):
return self._context.get('holiday_status_display_name', True) and self._context.get('employee_id')
def name_get(self):
if not self.requested_name_get():
@api.depends('requires_allocation', 'virtual_remaining_leaves', 'max_leaves', 'request_unit')
@api.depends_context('holiday_status_display_name', 'employee_id', 'from_manager_leave_form')
def _compute_display_name(self):
if not self.requested_display_name():
# leave counts is based on employee_id, would be inaccurate if not based on correct employee
return super(HolidaysType, self).name_get()
res = []
return super()._compute_display_name()
for record in self:
name = record.name
if record.requires_allocation == "yes" and not self._context.get('from_manager_leave_form'):
name = "%(name)s (%(count)s)" % {
'name': name,
'count': _('%g remaining out of %g') % (
name = "{name} ({count})".format(
name=name,
count=_('%g remaining out of %g') % (
float_round(record.virtual_remaining_leaves, precision_digits=2) or 0.0,
float_round(record.max_leaves, precision_digits=2) or 0.0,
) + (_(' hours') if record.request_unit == 'hour' else _(' days'))
}
res.append((record.id, name))
return res
) + (_(' hours') if record.request_unit == 'hour' else _(' days')),
)
record.display_name = name
@api.model
def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None):
+2 -2
View File
@@ -679,7 +679,7 @@
'search_default_active_employee': 3,
'search_default_active_time_off': 4,
'hide_employee_name': 1,
'holiday_status_name_get': False}
'holiday_status_display_name': False}
</field>
<field name="domain">['|', ('employee_id.company_id', 'in', allowed_company_ids),
'&amp;', ('multi_employee', '=', True),
@@ -701,7 +701,7 @@
<field name="search_view_id" ref="hr_holidays.hr_leave_view_search_manager"/>
<field name="context">{
'hide_employee_name': 1,
'holiday_status_name_get': False}
'holiday_status_display_name': False}
</field>
<field name="domain">[('holiday_allocation_id', '=', active_id)]</field>
<field name="help" type="html">
@@ -13,27 +13,24 @@ class HRLeaveType(models.Model):
"Deduct Extra Hours", default=False,
help="Once a time off of this type is approved, extra hours in attendances will be deducted.")
def name_get(self):
@api.depends_context('request_type', 'leave', 'holiday_status_display_name', 'employee_id')
def _compute_display_name(self):
# Exclude hours available in allocation contexts, it might be confusing otherwise
if not self.requested_name_get() or self._context.get('request_type', 'leave') == 'allocation':
return super().name_get()
employee_id = False
overtime_leaves = self.env['hr.leave.type']
res = []
for leave_type in self:
if leave_type.overtime_deductible and leave_type.requires_allocation == 'no':
if not employee_id:
employee_id = self.env['hr.employee'].browse(self._context.get('employee_id')).sudo()
if employee_id.total_overtime > 0:
overtime_leaves |= leave_type
name = "%(name)s (%(count)s)" % {
'name': leave_type.name,
'count': _('%s hours available',
format_duration(employee_id.total_overtime)),
}
res.append((leave_type.id, name))
res += super(HRLeaveType, self - overtime_leaves).name_get()
return res
if not self.requested_display_name() or self._context.get('request_type', 'leave') == 'allocation':
return super()._compute_display_name()
employee = self.env['hr.employee'].browse(self._context.get('employee_id')).sudo()
if employee.total_overtime <= 0:
return super()._compute_display_name()
overtime_leaves = self.filtered(lambda l_type: l_type.overtime_deductible and l_type.requires_allocation == 'no')
for leave_type in overtime_leaves:
leave_type.display_name = "%(name)s (%(count)s)" % {
'name': leave_type.name,
'count': _('%s hours available',
format_duration(employee.total_overtime)),
}
super(HRLeaveType, self - overtime_leaves)._compute_display_name()
def get_employees_days(self, employee_ids, date=None):
res = super().get_employees_days(employee_ids, date)
+5 -7
View File
@@ -505,13 +505,11 @@ class Applicant(models.Model):
applicant._message_add_suggested_recipient(recipients, email=email_from, reason=_('Contact Email'))
return recipients
def name_get(self):
if self.env.context.get('show_partner_name'):
return [
(applicant.id, applicant.partner_name or applicant.name)
for applicant in self
]
return super().name_get()
def _compute_display_name(self):
if not self.env.context.get('show_partner_name'):
return super()._compute_display_name()
for applicant in self:
applicant.display_name = applicant.partner_name or applicant.name
@api.model
def message_new(self, msg, custom_values=None):
+4 -3
View File
@@ -13,7 +13,8 @@ class Skill(models.Model):
sequence = fields.Integer(default=10)
skill_type_id = fields.Many2one('hr.skill.type', required=True, ondelete='cascade')
def name_get(self):
def _compute_display_name(self):
if not self._context.get('from_skill_dropdown'):
return super().name_get()
return [(record.id, f"{record.name} ({record.skill_type_id.name})") for record in self]
return super()._compute_display_name()
for record in self:
record.display_name = f"{record.name} ({record.skill_type_id.name})"
+4 -3
View File
@@ -19,10 +19,11 @@ class SkillLevel(models.Model):
('check_level_progress', 'CHECK(level_progress BETWEEN 0 AND 100)', "Progress should be a number between 0 and 100."),
]
def name_get(self):
def _compute_display_name(self):
if not self._context.get('from_skill_level_dropdown'):
return super().name_get()
return [(record.id, f"{record.name} ({record.level_progress}%)") for record in self]
return super()._compute_display_name()
for record in self:
record.display_name = f"{record.name} ({record.level_progress}%)"
@api.model_create_multi
def create(self, vals_list):
+4 -6
View File
@@ -23,13 +23,12 @@ class HrEmployee(models.Model):
for employee in self:
employee.has_timesheet = result.get(employee.id, False)
def name_get(self):
res = super().name_get()
def _compute_display_name(self):
super()._compute_display_name()
allowed_company_ids = self.env.context.get('allowed_company_ids', [])
if len(allowed_company_ids) <= 1:
return res
return
name_mapping = dict(res)
employees_count_per_user = {
user.id: count
for user, count in self.env['hr.employee'].sudo()._read_group(
@@ -40,8 +39,7 @@ class HrEmployee(models.Model):
}
for employee in self:
if employees_count_per_user.get(employee.user_id.id, 0) > 1:
name_mapping[employee.id] = f'{name_mapping[employee.id]} - {employee.company_id.name}'
return list(name_mapping.items())
employee.display_name = f'{employee.display_name} - {employee.company_id.name}'
def action_unlink_wizard(self):
wizard = self.env['hr.employee.delete.wizard'].create({
+8 -17
View File
@@ -65,23 +65,14 @@ class AccountAnalyticLine(models.Model):
partner_id = fields.Many2one(compute='_compute_partner_id', store=True, readonly=False)
readonly_timesheet = fields.Boolean(string="Readonly Timesheet", compute="_compute_readonly_timesheet")
def name_get(self):
result = super().name_get()
timesheets_read = self.env[self._name].search_read([('project_id', '!=', False), ('id', 'in', self.ids)], ['id', 'project_id', 'task_id'])
if not timesheets_read:
return result
def _get_display_name(project_id, task_id):
""" Get the display name of the timesheet based on the project and task
:param project_id: tuple containing the id and the display name of the project
:param task_id: tuple containing the id and the display name of the task if a task exists in the timesheet
otherwise False.
:returns: the display name of the timesheet
"""
if task_id:
return '%s - %s' % (project_id[1], task_id[1])
return project_id[1]
timesheet_dict = {res['id']: _get_display_name(res['project_id'], res['task_id']) for res in timesheets_read}
return list({**dict(result), **timesheet_dict}.items())
def _compute_display_name(self):
analytic_line_with_project = self.filtered('project_id')
super(AccountAnalyticLine, self - analytic_line_with_project)._compute_display_name()
for analytic_line in analytic_line_with_project:
if analytic_line.task_id:
analytic_line.display_name = f"{analytic_line.project_id.display_name} - {analytic_line.task_id.display_name}"
else:
analytic_line.display_name = analytic_line.project_id.display_name
def _is_readonly(self):
self.ensure_one()
@@ -164,15 +164,14 @@ class Project(models.Model):
project._create_analytic_account()
return super(Project, self).write(values)
def name_get(self):
res = super().name_get()
def _compute_display_name(self):
super()._compute_display_name()
if len(self.env.context.get('allowed_company_ids', [])) <= 1:
return res
name_mapping = dict(res)
return
for project in self:
if project.is_internal_project:
name_mapping[project.id] = f'{name_mapping[project.id]} - {project.company_id.name}'
return list(name_mapping.items())
project.display_name = f'{project.display_name} - {project.company_id.name}'
@api.model
def _init_data_analytic_account(self):
+4 -6
View File
@@ -181,13 +181,13 @@ class Task(models.Model):
return res
def name_get(self):
def _compute_display_name(self):
super()._compute_display_name()
if self.env.context.get('hr_timesheet_display_remaining_hours'):
name_mapping = dict(super().name_get())
for task in self:
if task.allow_timesheets and task.planned_hours > 0 and task.encode_uom_in_days:
days_left = _("(%s days remaining)") % task._convert_hours_to_days(task.remaining_hours)
name_mapping[task.id] = name_mapping.get(task.id, '') + u"\u00A0" + days_left
task.display_name = task.display_name + "\u00A0" + days_left
elif task.allow_timesheets and task.planned_hours > 0:
hours, mins = (str(int(duration)).rjust(2, '0') for duration in divmod(abs(task.remaining_hours) * 60, 60))
hours_left = _(
@@ -196,9 +196,7 @@ class Task(models.Model):
hours=hours,
minutes=mins,
)
name_mapping[task.id] = name_mapping.get(task.id, '') + u"\u00A0" + hours_left
return list(name_mapping.items())
return super().name_get()
task.display_name = task.display_name + "\u00A0" + hours_left
@api.model
def _get_view_cache_key(self, view_id=None, view_type='form', **options):
-1
View File
@@ -88,7 +88,6 @@ def slug(value):
try:
if not value.id:
raise ValueError("Cannot slug non-existent record %s" % value)
# [(id, name)] = value.name_get()
identifier, name = value.id, getattr(value, 'seo_name', False) or value.display_name
except AttributeError:
# assume name_search result tuple
@@ -21,21 +21,15 @@ class ChatbotScriptAnswer(models.Model):
'chatbot.script.step', string='Script Step', required=True, ondelete='cascade')
chatbot_script_id = fields.Many2one(related='script_step_id.chatbot_script_id')
def name_get(self):
def _compute_display_name(self):
if self._context.get('chatbot_script_answer_display_short_name'):
return super().name_get()
return super()._compute_display_name()
result = []
for answer in self:
answer_message = answer.script_step_id.message.replace('\n', ' ')
shortened_message = textwrap.shorten(answer_message, width=26, placeholder=" [...]")
result.append((
answer.id,
"%s: %s" % (shortened_message, answer.name)
))
return result
answer.display_name = f"{shortened_message}: {answer.name}"
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
@@ -22,11 +22,7 @@ class EWayBillType(models.Model):
)
active = fields.Boolean("Active", default=True)
def name_get(self):
def _compute_display_name(self):
"""Show name and sub_type in name"""
result_dict = dict()
for ewaybill_type in self:
name = ewaybill_type.name
name += _(" (Sub-Type: %s)", ewaybill_type.sub_type)
result_dict[ewaybill_type.id] = name
return list(result_dict.items())
ewaybill_type.display_name = _("%s (Sub-Type: %s)", ewaybill_type.name, ewaybill_type.sub_type)
+2 -4
View File
@@ -11,8 +11,6 @@ class L10nItDdt(models.Model):
name = fields.Char(string="Numero DDT", size=20, help="Transport document number", required=True)
date = fields.Date(string="Data DDT", help="Transport document date", required=True)
def name_get(self):
res = []
def _compute_display_name(self):
for ddt in self:
res.append((ddt.id, ("%s (%s)") % (ddt.name, ddt.date)))
return res
ddt.display_name = f"{ddt.name} ({ddt.date})"
@@ -16,7 +16,7 @@ class L10nLatamIdentificationType(models.Model):
is_vat = fields.Boolean()
country_id = fields.Many2one('res.country')
def name_get(self):
def _compute_display_name(self):
multi_localization = len(self.search([]).mapped('country_id')) > 1
return [(rec.id, '%s%s' % (
rec.name, multi_localization and rec.country_id and ' (%s)' % rec.country_id.code or '')) for rec in self]
for rec in self:
rec.display_name = '{}{}'.format(rec.name, multi_localization and rec.country_id and ' (%s)' % rec.country_id.code or '')
@@ -283,13 +283,12 @@ class AccountPayment(models.Model):
})
return res
def name_get(self):
def _compute_display_name(self):
""" Add check number to display_name on check_id m2o field """
res_names = super().name_get()
for i, (res_name, rec) in enumerate(zip(res_names, self)):
super()._compute_display_name()
for rec in self:
if rec.check_number and rec.payment_method_line_id.code == 'new_third_party_checks':
res_names[i] = (res_name[0], "%s %s" % (res_name[1], _("(Check %s)", rec.check_number)))
return res_names
rec.display_name = "{} {}".format(rec.display_name, _("(Check %s)", rec.check_number))
def button_open_check_operations(self):
''' Redirect the user to the invoice(s) paid by this payment.
@@ -35,11 +35,9 @@ class L10nLatamDocumentType(models.Model):
self.ensure_one()
return document_number
def name_get(self):
result = []
def _compute_display_name(self):
for rec in self:
name = rec.name
if rec.code:
name = '(%s) %s' % (rec.code, name)
result.append((rec.id, name))
return result
name = f'({rec.code}) {name}'
rec.display_name = name
+3 -2
View File
@@ -19,8 +19,9 @@ class LoyaltyCard(models.Model):
"""
return '044' + str(uuid4())[7:-18]
def name_get(self):
return [(card.id, f'{card.program_id.name}: {card.code}') for card in self]
def _compute_display_name(self):
for card in self:
card.display_name = f'{card.program_id.name}: {card.code}'
program_id = fields.Many2one('loyalty.program', ondelete='restrict', default=lambda self: self.env.context.get('active_id', None))
program_type = fields.Selection(related='program_id.program_type')
+3 -2
View File
@@ -38,8 +38,9 @@ class LoyaltyReward(models.Model):
('per_order', _('%s per order', symbol))
]
def name_get(self):
return [(reward.id, '%s - %s' % (reward.program_id.name, reward.description)) for reward in self]
def _compute_display_name(self):
for reward in self:
reward.display_name = f'{reward.program_id.name} - {reward.description}'
active = fields.Boolean(default=True)
program_id = fields.Many2one('loyalty.program', required=True, ondelete='cascade')
+3 -2
View File
@@ -18,8 +18,9 @@ class LunchCashMove(models.Model):
amount = fields.Float('Amount', required=True)
description = fields.Text('Description')
def name_get(self):
return [(cashmove.id, '%s %s' % (_('Lunch Cashmove'), '#%d' % cashmove.id)) for cashmove in self]
def _compute_display_name(self):
for cashmove in self:
cashmove.display_name = '{} {}'.format(_('Lunch Cashmove'), '#%d' % cashmove.id)
@api.model
def get_wallet_balance(self, user, include_config=True):
+3 -5
View File
@@ -117,14 +117,12 @@ class LunchSupplier(models.Model):
'Automatic Email Sending Time should be between 0 and 12'),
]
def name_get(self):
res = []
def _compute_display_name(self):
for supplier in self:
if supplier.phone:
res.append((supplier.id, '%s %s' % (supplier.name, supplier.phone)))
supplier.display_name = f'{supplier.name} {supplier.phone}'
else:
res.append((supplier.id, supplier.name))
return res
supplier.display_name = supplier.name
def _sync_cron(self):
for supplier in self:
+2 -4
View File
@@ -17,10 +17,8 @@ class LunchTopping(models.Model):
supplier_id = fields.Many2one('lunch.supplier', ondelete='cascade')
topping_category = fields.Integer('Topping Category', required=True, default=1)
def name_get(self):
def _compute_display_name(self):
currency_id = self.env.company.currency_id
res = dict(super(LunchTopping, self).name_get())
for topping in self:
price = formatLang(self.env, topping.price, currency_obj=currency_id)
res[topping.id] = '%s %s' % (topping.name, price)
return list(res.items())
topping.display_name = f'{topping.name} {price}'
+3 -2
View File
@@ -17,8 +17,9 @@ class CashmoveReport(models.Model):
user_id = fields.Many2one('res.users', string='User')
description = fields.Text('Description')
def name_get(self):
return [(cashmove.id, '%s %s' % (_('Lunch Cashmove'), '#%d' % cashmove.id)) for cashmove in self]
def _compute_display_name(self):
for cashmove in self:
cashmove.display_name = '{} {}'.format(_('Lunch Cashmove'), '#%d' % cashmove.id)
def init(self):
tools.drop_view_if_exists(self._cr, self._table)
@@ -59,8 +59,9 @@ class ChannelMember(models.Model):
else:
self.message_unread_counter = 0
def name_get(self):
return [(record.id, record.partner_id.name or record.guest_id.name) for record in self]
def _compute_display_name(self):
for record in self:
record.display_name = record.partner_id.name or record.guest_id.name
def init(self):
self.env.cr.execute("CREATE UNIQUE INDEX IF NOT EXISTS discuss_channel_member_partner_unique ON %s (channel_id, partner_id) WHERE partner_id IS NOT NULL" % self._table)
+2 -4
View File
@@ -404,12 +404,10 @@ class MailActivity(models.Model):
)
return activities._as_query(order)
def name_get(self):
res = []
def _compute_display_name(self):
for record in self:
name = record.summary or record.activity_type_id.display_name
res.append((record.id, name))
return res
record.display_name = name
# ------------------------------------------------------
# Business Methods
+4 -6
View File
@@ -147,20 +147,18 @@ class Alias(models.Model):
vals['alias_name'] = self._clean_and_check_unique([vals.get('alias_name')])[0]
return super(Alias, self).write(vals)
def name_get(self):
def _compute_display_name(self):
"""Return the mail alias display alias_name, including the implicit
mail catchall domain if exists from config otherwise "New Alias".
e.g. `jobs@mail.odoo.com` or `jobs` or 'New Alias'
"""
res = []
for record in self:
if record.alias_name and record.alias_domain:
res.append((record['id'], "%s@%s" % (record.alias_name, record.alias_domain)))
record.display_name = f"{record.alias_name}@{record.alias_domain}"
elif record.alias_name:
res.append((record['id'], "%s" % (record.alias_name)))
record.display_name = record.alias_name
else:
res.append((record['id'], _("Inactive Alias")))
return res
record.display_name = _("Inactive Alias")
def _clean_and_check_unique(self, names):
"""When an alias name appears to already be an email, we keep the local
+3 -3
View File
@@ -103,7 +103,7 @@ class Message(models.Model):
# related document
model = fields.Char('Related Document Model')
res_id = fields.Many2oneReference('Related Document ID', model_field='model')
record_name = fields.Char('Message Record Name') # name_get() of the related document
record_name = fields.Char('Message Record Name') # display_name of the related document
link_preview_ids = fields.One2many('mail.link.preview', 'message_id', string='Link Previews', groups="base.group_erp_manager")
# characteristics
message_type = fields.Selection([
@@ -993,7 +993,7 @@ class Message(models.Model):
'email_from': 'sacha@pokemon.com' # email address or False
'subtype_id': (1, u'Discussions'),
'date': '2015-06-30 08:22:33',
'partner_ids': [[7, "Sacha Du Bourg-Palette"]], # list of partner name_get
'partner_ids': [[7, "Sacha Du Bourg-Palette"]], # list of partner convert_to_read
'message_type': u'comment',
'id': 59,
'subject': False
@@ -1194,7 +1194,7 @@ class Message(models.Model):
@api.model
def _get_record_name(self, values):
""" Return the related document name, using name_get. It is done using
""" Return the related document name, using display_name. It is done using
SUPERUSER_ID, to be sure to have the record name correctly stored. """
model = values.get('model', self.env.context.get('default_model'))
res_id = values.get('res_id', self.env.context.get('default_res_id'))
+1 -1
View File
@@ -2712,7 +2712,7 @@ class MailThread(models.AbstractModel):
:return str: default subject """
self.ensure_one()
return self.name_get()[0][1]
return self.display_name
def _message_create(self, values_list):
""" Low-level helper to create mail.message records. It is mainly used
+2 -2
View File
@@ -78,8 +78,8 @@ class MailTracking(models.Model):
values.update({
'old_value_integer': initial_value and initial_value.id or 0,
'new_value_integer': new_value and new_value.id or 0,
'old_value_char': initial_value and initial_value.sudo().name_get()[0][1] or '',
'new_value_char': new_value and new_value.sudo().name_get()[0][1] or ''
'old_value_char': initial_value and initial_value.sudo().display_name or '',
'new_value_char': new_value and new_value.sudo().display_name or ''
})
elif col_info['type'] in ['many2many', 'one2many']:
values.update({
@@ -22,8 +22,9 @@ class ResUsersSettingsVolumes(models.Model):
("partner_or_guest_exists", "CHECK((partner_id IS NOT NULL AND guest_id IS NULL) OR (partner_id IS NULL AND guest_id IS NOT NULL))", "A volume setting must have a partner or a guest."),
]
def name_get(self):
return [(rec.id, f'{rec.user_setting_id.user_id.name} - {rec.partner_id.name or rec.guest_id.name}') for rec in self]
def _compute_display_name(self):
for rec in self:
rec.display_name = f'{rec.user_setting_id.user_id.name} - {rec.partner_id.name or rec.guest_id.name}'
def _discuss_users_settings_volume_format(self):
return [{
@@ -60,7 +60,7 @@ patch(Message.prototype, "mail/core/web", {
case "boolean":
return trackingValue.value ? _t("Yes") : _t("No");
/**
* many2one formatter exists but is expecting id/name_get or data
* many2one formatter exists but is expecting id/display_name or data
* object but only the target record name is known in this context.
*
* Selection formatter exists but requires knowing all
@@ -193,7 +193,7 @@ class MailPluginController(http.Controller):
if normalized_email:
filter_domain = [('email_normalized', 'ilike', search_term)]
else:
filter_domain = ['|', '|', ('display_name', 'ilike', search_term), ('ref', '=', search_term),
filter_domain = ['|', '|', ('complete_name', 'ilike', search_term), ('ref', '=', search_term),
('email', 'ilike', search_term)]
# Search for the partner based on the email.
+3 -5
View File
@@ -92,14 +92,12 @@ class MaintenanceEquipment(models.Model):
return self.env.ref('maintenance.mt_mat_assign')
return super(MaintenanceEquipment, self)._track_subtype(init_values)
def name_get(self):
result = []
def _compute_display_name(self):
for record in self:
if record.name and record.serial_no:
result.append((record.id, record.name + '/' + record.serial_no))
record.display_name = record.name + '/' + record.serial_no
if record.name and not record.serial_no:
result.append((record.id, record.name))
return result
record.display_name = record.name
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
@@ -129,13 +129,13 @@ class MassMailingContact(models.Model):
def name_create(self, name):
name, email = self.get_name_email(name)
contact = self.create({'name': name, 'email': email})
return contact.name_get()[0]
return contact.id, contact.display_name
@api.model
def add_to_list(self, name, list_id):
name, email = self.get_name_email(name)
contact = self.create({'name': name, 'email': email, 'list_ids': [(4, list_id)]})
return contact.name_get()[0]
return contact.id, contact.display_name
def _message_get_default_recipients(self):
return {r.id: {
+3 -2
View File
@@ -120,8 +120,9 @@ class MassMailingList(models.Model):
return super(MassMailingList, self).write(vals)
def name_get(self):
return [(list.id, "%s (%s)" % (list.name, list.contact_count)) for list in self]
def _compute_display_name(self):
for mailing_list in self:
mailing_list.display_name = f"{mailing_list.name} ({mailing_list.contact_count})"
def copy(self, default=None):
self.ensure_one()
+1 -2
View File
@@ -52,7 +52,6 @@ class MailingTrace(models.Model):
_order = 'create_date DESC'
trace_type = fields.Selection([('mail', 'Email')], string='Type', default='mail', required=True)
display_name = fields.Char(compute='_compute_display_name')
# mail data
mail_mail_id = fields.Many2one('mail.mail', string='Mail', index='btree_not_null')
mail_mail_id_int = fields.Integer(
@@ -117,7 +116,7 @@ class MailingTrace(models.Model):
@api.depends('trace_type', 'mass_mailing_id')
def _compute_display_name(self):
for trace in self:
trace.display_name = '%s: %s (%s)' % (trace.trace_type, trace.mass_mailing_id.name, trace.id)
trace.display_name = f'{trace.trace_type}: {trace.mass_mailing_id.name} ({trace.id})'
@api.model_create_multi
def create(self, values_list):
+3 -2
View File
@@ -253,8 +253,9 @@ class MrpBom(models.Model):
self.with_context({'active_test': False}).operation_ids.toggle_active()
return super().toggle_active()
def name_get(self):
return [(bom.id, '%s%s' % (bom.code and '%s: ' % bom.code or '', bom.product_tmpl_id.display_name)) for bom in self]
def _compute_display_name(self):
for bom in self:
bom.display_name = f"{bom.code + ': ' if bom.code else ''}{bom.product_tmpl_id.display_name}"
def action_compute_bom_days(self):
company_id = self.env.context.get('default_company_id', self.env.company.id)
+3 -5
View File
@@ -328,15 +328,13 @@ class MrpWorkcenterProductivityLossType(models.Model):
_rec_name = 'loss_type'
@api.depends('loss_type')
def name_get(self):
def _compute_display_name(self):
""" As 'category' field in form view is a Many2one, its value will be in
lower case. In order to display its value capitalized 'name_get' is
lower case. In order to display its value capitalized 'display_name' is
overrided.
"""
result = []
for rec in self:
result.append((rec.id, rec.loss_type.title()))
return result
rec.display_name = rec.loss_type.title()
loss_type = fields.Selection([
('availability', 'Availability'),
+3 -5
View File
@@ -272,14 +272,12 @@ class MrpWorkorder(models.Model):
if not self._check_m2m_recursion('blocked_by_workorder_ids'):
raise ValidationError(_("You cannot create cyclic dependency."))
def name_get(self):
res = []
def _compute_display_name(self):
for wo in self:
if len(wo.production_id.workorder_ids) == 1:
res.append((wo.id, "%s - %s - %s" % (wo.production_id.name, wo.product_id.name, wo.name)))
wo.display_name = f"{wo.production_id.name} - {wo.product_id.name} - {wo.name}"
else:
res.append((wo.id, "%s - %s - %s - %s" % (wo.production_id.workorder_ids.ids.index(wo._origin.id) + 1, wo.production_id.name, wo.product_id.name, wo.name)))
return res
wo.display_name = f"{wo.production_id.workorder_ids.ids.index(wo._origin.id) + 1} - {wo.production_id.name} - {wo.product_id.name} - {wo.name}"
def unlink(self):
# Removes references to workorder to avoid Validation Error
@@ -21,13 +21,6 @@ class MrpProduction(models.Model):
incoming_picking = fields.Many2one(related='move_finished_ids.move_dest_ids.picking_id')
@api.depends('name')
def name_get(self):
return [
(record.id, "%s (%s)" % (record.incoming_picking.name, record.name)) if record.bom_id.type == 'subcontract'
else (record.id, record.name) for record in self
]
@api.depends('move_raw_ids.move_line_ids')
def _compute_move_line_raw_ids(self):
for production in self:
@@ -65,7 +65,7 @@ class ResCompany(models.Model):
company_data = {field: value for field, value in company_data.items()
if field in self.partner_id._fields and value and (field == 'image_1920' or not self.partner_id[field])}
# for company and childs: from state_id / country_id name_get like to IDs
# for company and childs: from state_id / country_id display_name like to IDs
company_data.update(self._enrich_extract_m2o_id(company_data, ['state_id', 'country_id']))
if company_data.get('child_ids'):
company_data['child_ids'] = [
+6 -3
View File
@@ -27,6 +27,12 @@ class PaymentToken(models.Model):
verified = fields.Boolean(string="Verified")
active = fields.Boolean(string="Active", default=True)
#=== COMPUTE METHODS ===#
def _compute_display_name(self):
for token in self:
token.display_name = token._build_display_name()
#=== CRUD METHODS ===#
@api.model_create_multi
@@ -91,9 +97,6 @@ class PaymentToken(models.Model):
"""
return
def name_get(self):
return [(token.id, token._build_display_name()) for token in self]
#=== BUSINESS METHODS ===#
def _get_available_tokens(self, providers_ids, partner_id, is_validation=False, **kwargs):
@@ -100,14 +100,15 @@ class PaymentLinkWizard(models.TransientModel):
partner_id = related_document.partner_id
currency_id = related_document.currency_id
selection.extend(
self._get_payment_provider_available(
(payment_provider.id, payment_provider.display_name)
for payment_provider in self._get_payment_provider_available(
res_model=res_model,
res_id=res_id,
company_id=company_id.id,
partner_id=partner_id.id,
amount=related_document.amount_total,
currency_id=currency_id.id,
).name_get()
)
)
return selection
+2 -2
View File
@@ -15,7 +15,7 @@ class Bill(models.Model):
def name_create(self, name):
try:
value = float(name)
except:
except ValueError:
raise UserError(_("The name of the Coins/Bills must be a number."))
result = super().create({"name": name, "value": value})
return result.name_get()[0]
return result.id, result.display_name
+3 -2
View File
@@ -32,8 +32,9 @@ class PosCategory(models.Model):
self.ensure_one()
return (self.parent_id._get_hierarchy() if self.parent_id else []) + [self.name]
def name_get(self) -> List[Tuple[int, str]]:
return [(category.id, " / ".join(category._get_hierarchy())) for category in self if category.name]
def _compute_display_name(self):
for cat in self:
cat.display_name = " / ".join(cat._get_hierarchy())
@api.ondelete(at_uninstall=False)
def _unlink_except_session_open(self):
+3 -5
View File
@@ -366,15 +366,13 @@ class PosConfig(models.Model):
if trusted_config.currency_id != config.currency_id:
raise ValidationError(_("You cannot share open orders with configuration that does not use the same currency."))
def name_get(self):
result = []
def _compute_display_name(self):
for config in self:
last_session = self.env['pos.session'].search([('config_id', '=', config.id)], limit=1)
if (not last_session) or (last_session.state == 'closed'):
result.append((config.id, _("%(pos_name)s (not used)", pos_name=config.name)))
config.display_name = _("%(pos_name)s (not used)", pos_name=config.name)
else:
result.append((config.id, "%s (%s)" % (config.name, last_session.user_id.name)))
return result
config.display_name = f"{config.name} ({last_session.user_id.name})"
@api.model_create_multi
def create(self, vals_list):
+3 -5
View File
@@ -33,14 +33,12 @@ class PosPayment(models.Model):
is_change = fields.Boolean(string='Is this payment change?', default=False)
account_move_id = fields.Many2one('account.move')
def name_get(self):
res = []
def _compute_display_name(self):
for payment in self:
if payment.name:
res.append((payment.id, '%s %s' % (payment.name, formatLang(self.env, payment.amount, currency_obj=payment.currency_id))))
payment.display_name = f'{payment.name} {formatLang(self.env, payment.amount, currency_obj=payment.currency_id)}'
else:
res.append((payment.id, formatLang(self.env, payment.amount, currency_obj=payment.currency_id)))
return res
payment.display_name = formatLang(self.env, payment.amount, currency_obj=payment.currency_id)
@api.constrains('payment_method_id')
def _check_payment_method_id(self):
@@ -587,7 +587,7 @@ export class TicketScreen extends Component {
PARTNER: {
repr: (order) => order.get_partner_name(),
displayName: this.env._t("Customer"),
modelField: "partner_id.display_name",
modelField: "partner_id.complete_name",
},
};
@@ -9,12 +9,12 @@ import { usePos } from "@point_of_sale/app/store/pos_hook";
const VALID_SEARCH_TAGS = new Set(["date", "customer", "client", "name", "order"]);
const FIELD_MAP = {
date: "date_order",
customer: "partner_id.display_name",
client: "partner_id.display_name",
customer: "partner_id.complete_name",
client: "partner_id.complete_name",
name: "name",
order: "name",
};
const SEARCH_FIELDS = ["name", "partner_id.display_name", "date_order"];
const SEARCH_FIELDS = ["name", "partner_id.complete_name", "date_order"];
/**
* @emits search
@@ -64,7 +64,7 @@ export class SaleOrderManagementControlPanel extends Component {
* '|',
* '|',
* ['pos_reference', 'ilike', '%Customer 1%'],
* ['partner_id.display_name', 'ilike', '%Customer 1%'],
* ['partner_id.complete_name', 'ilike', '%Customer 1%'],
* ['date_order', 'ilike', '%Customer 1%']
* ]
* ```
@@ -81,7 +81,7 @@ export class SaleOrderManagementControlPanel extends Component {
* ```
* searchString = 'customer: Steward, date: 2020-05-01'
* result = [
* ['partner_id.display_name', 'ilike', '%Steward%'],
* ['partner_id.complete_name', 'ilike', '%Steward%'],
* ['date_order', 'ilike', '%2020-05-01%']
* ]
* ```
@@ -27,8 +27,8 @@ class PrivacyLookupWizard(models.TransientModel):
for wizard in self:
wizard.line_count = len(wizard.line_ids)
def name_get(self):
return [(w.id, _('Privacy Lookup')) for w in self]
def _compute_display_name(self):
self.display_name = _('Privacy Lookup')
def _get_query_models_blacklist(self):
return [
@@ -286,8 +286,8 @@ class PrivacyLookupWizardLine(models.TransientModel):
record = self.env[line.res_model].sudo().browse(line.res_id)
if not record.exists():
continue
name = record.name_get()
line.res_name = name[0][1] if name else ('%s/%s') % (line.res_model_id.name, line.res_id)
name = record.display_name
line.res_name = name if name else f'{line.res_model_id.name}/{line.res_id}'
@api.onchange('is_active')
def _onchange_is_active(self):
@@ -55,7 +55,7 @@ class ProductAttributeValue(models.Model):
for pav in self:
pav.is_used_on_products = bool(pav.pav_attribute_line_ids)
def name_get(self):
def _compute_display_name(self):
"""Override because in general the name of the value is confusing if it
is displayed without the name of the corresponding attribute.
Eg. on product list & kanban views, on BOM form view
@@ -65,8 +65,9 @@ class ProductAttributeValue(models.Model):
on every value.
"""
if not self.env.context.get('show_attribute', True):
return super().name_get()
return [(value.id, "%s: %s" % (value.attribute_id.name, value.name)) for value in self]
return super()._compute_display_name()
for value in self:
value.display_name = f"{value.attribute_id.name}: {value.name}"
def write(self, values):
if 'attribute_id' in values:
+7 -5
View File
@@ -48,12 +48,14 @@ class ProductCategory(models.Model):
@api.model
def name_create(self, name):
return self.create({'name': name}).name_get()[0]
category = self.create({'name': name})
return category.id, category.display_name
def name_get(self):
if not self.env.context.get('hierarchical_naming', True):
return [(record.id, record.name) for record in self]
return super().name_get()
def _compute_display_name(self):
if self.env.context.get('hierarchical_naming', True):
return super()._compute_display_name()
for record in self:
record.display_name = record.name
@api.ondelete(at_uninstall=False)
def _unlink_except_default_category(self):
+3 -2
View File
@@ -64,8 +64,9 @@ class Pricelist(models.Model):
],
copy=True)
def name_get(self):
return [(pricelist.id, '%s (%s)' % (pricelist.name, pricelist.currency_id.name)) for pricelist in self]
def _compute_display_name(self):
for pricelist in self:
pricelist.display_name = f'{pricelist.name} ({pricelist.currency_id.name})'
def _get_products_price(self, products, *args, **kwargs):
"""Compute the pricelist prices for the specified products, quantity & uom.
+15 -33
View File
@@ -8,6 +8,7 @@ from odoo import api, fields, models, tools, _
from odoo.exceptions import ValidationError
from odoo.osv import expression
from odoo.tools import float_compare
from odoo.tools.misc import unique
class ProductProduct(models.Model):
@@ -415,21 +416,13 @@ class ProductProduct(models.Model):
domain.append((('categ_id', 'child_of', self._context['search_default_categ_id'])))
return super()._search(domain, offset, limit, order, access_rights_uid)
@api.depends_context('display_default_code', 'seller_id')
@api.depends_context('display_default_code', 'seller_id', 'company_id')
def _compute_display_name(self):
# `display_name` is calling `name_get()`` which is overidden on product
# to depend on `display_default_code` and `seller_id`
return super()._compute_display_name()
def name_get(self):
# TDE: this could be cleaned a bit I think
def _name_get(d):
name = d.get('name', '')
code = self._context.get('display_default_code', True) and d.get('default_code', False) or False
if code:
name = '[%s] %s' % (code,name)
return (d['id'], name)
def get_display_name(name, code):
if self._context.get('display_default_code', True) and code:
return f'[{code}] {name}'
return name
partner_id = self._context.get('partner_id')
if partner_id:
@@ -443,15 +436,13 @@ class ProductProduct(models.Model):
self.check_access_rights("read")
self.check_access_rule("read")
result = []
# prefetch the fields used by the `name_get`
# prefetch the fields used by the `display_name`
self.sudo().fetch(['name', 'default_code', 'product_tmpl_id'])
product_template_ids = self.sudo().product_tmpl_id.ids
if partner_ids:
# prefetch the fields used by the `name_get`
# prefetch the fields used by the `display_name`
supplier_info = self.env['product.supplierinfo'].sudo().search_fetch(
[('product_tmpl_id', 'in', product_template_ids), ('partner_id', 'in', partner_ids)],
['product_tmpl_id', 'product_id', 'company_id', 'product_name', 'product_code'],
@@ -476,27 +467,18 @@ class ProductProduct(models.Model):
if company_id:
sellers = [x for x in sellers if x.company_id.id in [company_id, False]]
if sellers:
temp = []
for s in sellers:
seller_variant = s.product_name and (
variant and "%s (%s)" % (s.product_name, variant) or s.product_name
) or False
mydict = {
'id': product.id,
'name': seller_variant or name,
'default_code': s.product_code or product.default_code,
}
temp = _name_get(mydict)
if temp not in result:
result.append(temp)
else:
mydict = {
'id': product.id,
'name': name,
'default_code': product.default_code,
}
result.append(_name_get(mydict))
temp.append(get_display_name(seller_variant or name, s.product_code or product.default_code))
return result
# => Feature drop here, one record can only have one display_name now, instead separate with `,`
# Remove this comment
product.display_name = ", ".join(unique(temp))
else:
product.display_name = get_display_name(name, product.default_code)
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
+5 -5
View File
@@ -485,11 +485,11 @@ class ProductTemplate(models.Model):
default['name'] = _("%s (copy)", self.name)
return super(ProductTemplate, self).copy(default=default)
def name_get(self):
# Prefetch the fields used by the `name_get`, so `browse` doesn't fetch other fields
def _compute_display_name(self):
# Prefetch the fields used by the `display_name`, so `browse` doesn't fetch other fields
self.fetch(['name', 'default_code'])
return [(template.id, '%s%s' % (template.default_code and '[%s] ' % template.default_code or '', template.name))
for template in self]
for template in self:
template.display_name = '{}{}'.format(template.default_code and '[%s] ' % template.default_code or '', template.name)
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
@@ -529,7 +529,7 @@ class ProductTemplate(models.Model):
domain2 = expression.AND([domain, [('id', 'in', tmpl_without_variant.ids)]])
searched_ids |= set(super()._name_search(name, domain2, operator, limit, order))
# re-apply product.template order + name_get
# re-apply product.template order + display_name
domain = [('id', 'in', list(searched_ids))]
return super()._name_search('', domain, 'ilike', limit, order)
@@ -147,12 +147,13 @@ class ProductTemplateAttributeValue(models.Model):
ptav_to_archive.write({'ptav_active': False})
return True
def name_get(self):
def _compute_display_name(self):
"""Override because in general the name of the value is confusing if it
is displayed without the name of the corresponding attribute.
Eg. on exclusion rules form
"""
return [(value.id, "%s: %s" % (value.attribute_id.name, value.name)) for value in self]
for value in self:
value.display_name = f"{value.attribute_id.name}: {value.name}"
def _only_active(self):
return self.filtered(lambda ptav: ptav.ptav_active)
+9 -15
View File
@@ -48,26 +48,20 @@ class TestSeller(TransactionCase):
(0, 0, {'partner_id': self.asustec.id, 'product_code': 'NO', 'company_id': False}),
]})
names = self.product_consu.with_context(
name = self.product_consu.with_context(
partner_id=self.asustec.id,
).name_get()
ref = set([x[1] for x in names])
self.assertEqual(len(names), 3, "3 vendor references should have been found")
self.assertEqual(ref, {'[A] Boudin', '[B] Boudin', '[NO] Boudin'}, "Incorrect vendor reference list")
names = self.product_consu.with_context(
).display_name
self.assertEqual(name, '[A] Boudin, [B] Boudin, [NO] Boudin', "Incorrect vendor reference list")
name = self.product_consu.with_context(
partner_id=self.asustec.id,
company_id=company_a.id,
).name_get()
ref = set([x[1] for x in names])
self.assertEqual(len(names), 2, "2 vendor references should have been found")
self.assertEqual(ref, {'[A] Boudin', '[NO] Boudin'}, "Incorrect vendor reference list")
names = self.product_consu.with_context(
).display_name
self.assertEqual(name, '[A] Boudin, [NO] Boudin', "Incorrect vendor reference list")
name = self.product_consu.with_context(
partner_id=self.asustec.id,
company_id=company_b.id,
).name_get()
ref = set([x[1] for x in names])
self.assertEqual(len(names), 2, "2 vendor references should have been found")
self.assertEqual(ref, {'[B] Boudin', '[NO] Boudin'}, "Incorrect vendor reference list")
).display_name
self.assertEqual(name, '[B] Boudin, [NO] Boudin', "Incorrect vendor reference list")
def test_30_select_seller(self):
self.res_partner_1 = self.asustec
@@ -16,9 +16,10 @@ class ProjectCollaborator(models.Model):
('unique_collaborator', 'UNIQUE(project_id, partner_id)', 'A collaborator cannot be selected more than once in the project sharing access. Please remove duplicate(s) and try again.'),
]
def name_get(self):
collaborator_search_read = self.search_read([('id', 'in', self.ids)], ['id', 'project_id', 'partner_id'])
return [(collaborator['id'], '%s - %s' % (collaborator['project_id'][1], collaborator['partner_id'][1])) for collaborator in collaborator_search_read]
def _compute_display_name(self):
self.fetch(['project_id', 'partner_id'])
for collaborator in self:
collaborator.display_name = f'{collaborator.project_id.display_name} - {collaborator.partner_id.display_name}'
@api.model_create_multi
def create(self, vals_list):
+1 -1
View File
@@ -121,5 +121,5 @@ class ProjectTags(models.Model):
def name_create(self, name):
existing_tag = self.search([('name', '=ilike', name.strip())], limit=1)
if existing_tag:
return existing_tag.name_get()[0]
return existing_tag.id, existing_tag.display_name
return super().name_create(name)
+2 -4
View File
@@ -193,16 +193,14 @@ class PurchaseOrder(models.Model):
order.date_planned = False
@api.depends('name', 'partner_ref')
def name_get(self):
result = []
def _compute_display_name(self):
for po in self:
name = po.name
if po.partner_ref:
name += ' (' + po.partner_ref + ')'
if self.env.context.get('show_total_amount') and po.amount_total:
name += ': ' + formatLang(self.env, po.amount_total, currency_obj=po.currency_id)
result.append((po.id, name))
return result
po.display_name = name
@api.depends('order_line.taxes_id', 'order_line.price_subtotal', 'amount_total', 'amount_untaxed')
def _compute_tax_totals(self):
+2 -4
View File
@@ -40,8 +40,7 @@ class PurchaseBillUnion(models.Model):
invoice_status in ('to invoice', 'no')
)""")
def name_get(self):
result = []
def _compute_display_name(self):
for doc in self:
name = doc.name or ''
if doc.reference:
@@ -50,5 +49,4 @@ class PurchaseBillUnion(models.Model):
if doc.purchase_order_id and doc.purchase_order_id.invoice_status == 'no':
amount = 0.0
name += ': ' + formatLang(self.env, amount, monetary=True, currency_obj=doc.currency_id)
result.append((doc.id, name))
return result
doc.display_name = name
+4 -4
View File
@@ -59,8 +59,8 @@ class Rating(models.Model):
@api.depends('res_model', 'res_id')
def _compute_res_name(self):
for rating in self:
name = self.env[rating.res_model].sudo().browse(rating.res_id).name_get()
rating.res_name = name and name[0][1] or ('%s/%s') % (rating.res_model, rating.res_id)
name = self.env[rating.res_model].sudo().browse(rating.res_id).display_name
rating.res_name = name or f'{rating.res_model}/{rating.res_id}'
@api.depends('res_model', 'res_id')
def _compute_resource_ref(self):
@@ -83,8 +83,8 @@ class Rating(models.Model):
for rating in self:
name = False
if rating.parent_res_model and rating.parent_res_id:
name = self.env[rating.parent_res_model].sudo().browse(rating.parent_res_id).name_get()
name = name and name[0][1] or ('%s/%s') % (rating.parent_res_model, rating.parent_res_id)
name = self.env[rating.parent_res_model].sudo().browse(rating.parent_res_id).display_name
name = name or f'{rating.parent_res_model}/{rating.parent_res_id}'
rating.parent_res_name = name
def _get_rating_image_filename(self):
@@ -70,7 +70,7 @@ class ResourceCalendarAttendance(models.Model):
section_names = {'0': _('First week'), '1': _('Second week')}
section_info = {True: _('this week'), False: _('other week')}
for record in self.filtered(lambda l: l.display_type == 'line_section'):
section_name = "%s (%s)" % (section_names[record.week_type], section_info[this_week_type == record.week_type])
section_name = f"{section_names[record.week_type]} ({section_info[this_week_type == record.week_type]})"
record.display_name = section_name
def _copy_attendance_vals(self):
+12 -11
View File
@@ -295,6 +295,18 @@ class SaleOrder(models.Model):
#=== COMPUTE METHODS ===#
@api.depends_context('sale_show_partner_name')
def _compute_display_name(self):
if not self._context.get('sale_show_partner_name'):
return super()._compute_display_name()
for order in self:
name = order.name
if order.partner_id.name:
name = f'{name} - {order.partner_id.name}'
order.display_name = name
@api.depends('company_id')
def _compute_require_signature(self):
for order in self:
@@ -1557,17 +1569,6 @@ class SaleOrder(models.Model):
upselling_orders = filtered_self.filtered(lambda so: so.invoice_status == 'upselling')
upselling_orders._create_upsell_activity()
def name_get(self):
if self._context.get('sale_show_partner_name'):
res = []
for order in self:
name = order.name
if order.partner_id.name:
name = f'{name} - {order.partner_id.name}'
res.append((order.id, name))
return res
return super().name_get()
#=== BUSINESS METHODS ===#
def _create_upsell_activity(self):
+9 -11
View File
@@ -263,6 +263,15 @@ class SaleOrderLine(models.Model):
#=== COMPUTE METHODS ===#
def _compute_display_name(self):
name_per_id = self._additional_name_per_id()
for so_line in self.sudo():
name = '{} - {}'.format(so_line.order_id.name, so_line.name and so_line.name.split('\n')[0] or so_line.product_id.name)
additional_name = name_per_id.get(so_line.id)
if additional_name:
name = f'{name} {additional_name}'
so_line.display_name = name
@api.depends('product_id')
def _compute_product_template_id(self):
for line in self:
@@ -1157,17 +1166,6 @@ class SaleOrderLine(models.Model):
if so_line.order_partner_id.ref or so_line.order_partner_id.name
}
def name_get(self):
result = []
name_per_id = self._additional_name_per_id()
for so_line in self.sudo():
name = '%s - %s' % (so_line.order_id.name, so_line.name and so_line.name.split('\n')[0] or so_line.product_id.name)
additional_name = name_per_id.get(so_line.id)
if additional_name:
name = '%s %s' % (name, additional_name)
result.append((so_line.id, name))
return result
#=== HOOKS ===#
def _is_delivery(self):
+2 -2
View File
@@ -290,7 +290,7 @@ class TestSaleOrder(SaleCommon):
"No validity date must be specified if the company validity duration is 0")
def test_so_names(self):
"""Test custom context key for name_get & name_search.
"""Test custom context key for display_name & name_search.
Note: this key is used in sale_expense & sale_timesheet modules.
"""
@@ -302,7 +302,7 @@ class TestSaleOrder(SaleCommon):
self.assertNotIn(self.sale_order.partner_id.name, self.sale_order.display_name)
self.assertIn(
self.sale_order.partner_id.name,
self.sale_order.with_context(sale_show_partner_name=True).name_get()[0][1])
self.sale_order.with_context(sale_show_partner_name=True).display_name)
def test_state_changes(self):
"""Test some untested state changes methods & logic."""
+1 -1
View File
@@ -13,7 +13,7 @@ class SaleOrder(models.Model):
@api.model
def _name_search(self, name, domain=None, operator='ilike', limit=None, order=None):
""" For expense, we want to show all sales order but only their name_get (no ir.rule applied), this is the only way to do it. """
""" For expense, we want to show all sales order but only their display_name (no ir.rule applied), this is the only way to do it. """
if (
self._context.get('sale_expense_all_order')
and self.user_has_groups('sales_team.group_sale_salesman')
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<!-- Required simply to set SO on expense before submitting. Used to avoid crash on name_get/name_search -->
<!-- Required simply to set SO on expense before submitting. Used to avoid crash on display_name/name_search -->
<record id="sale_order_rule_expense_user" model="ir.rule">
<field name="name">Expense Employee can read confirmed SO</field>
<field ref="sale.model_sale_order" name="model_id"/>
@@ -37,7 +37,6 @@ class ProjectUpdate(models.Model):
('is_downpayment', '=', False),
]),
)
name_by_sol = dict(sols.with_context(with_price_unit=True).name_get())
product_uom_unit = self.env.ref('uom.product_uom_unit')
product_uom_hour = self.env.ref('uom.product_uom_hour')
company_uom = self.env.company.timesheet_encode_uom_id
@@ -50,7 +49,7 @@ class ProjectUpdate(models.Model):
qty_invoiced = sol.product_uom._compute_quantity(sol.qty_invoiced, company_uom, raise_if_failure=False)
unit = sol.product_uom if is_unit else company_uom
services.append({
'name': name_by_sol[sol.id],
'name': sol.with_context(with_price_unit=True).display_name,
'sold_value': product_uom_qty,
'effective_value': qty_delivered,
'remaining_value': product_uom_qty - qty_delivered,

Some files were not shown because too many files have changed in this diff Show More