[MERGE] tools: better placeholder support for _

Support two new syntaxes with `_()` method:

_("This is so %s") % 2019
_("Text with %s placeholders", 42)
_("Text with %(num)s placeholders %(symbol)s", num=42, symbol="🧀")

The main benefit is to have a fallback on the source string if formating the
translated string fails (e.g. "Foo %s" translated "Foo s%").

This PR converted most (but not all) calls to _ using placeholders to use the
new syntax. Hopefully, the remaining ones will be converted in the future and
avoid technical debt.

Use named placeholders when needed. If more than one placeholder is present in a
string, using named placeholder can be beneficial to reorder the placehodler
position (for languages like Japanese that do not use the same phrase
construction). On some sentences, it also brings clarity on the meaning of the
placeholders.

closes odoo/odoo#52155

Task-id: 1853119
Signed-off-by: Martin Trigaux (mat) <mat@odoo.com>
This commit is contained in:
Odoo's Mergebot
2020-06-18 13:51:48 +02:00
committed by GitHub
153 changed files with 695 additions and 408 deletions
+8 -4
View File
@@ -42,7 +42,7 @@ class AccountAccount(models.Model):
def _check_reconcile(self):
for account in self:
if account.internal_type in ('receivable', 'payable') and account.reconcile == False:
raise ValidationError(_('You cannot have a receivable/payable account that is not reconcilable. (account code: %s)') % account.code)
raise ValidationError(_('You cannot have a receivable/payable account that is not reconcilable. (account code: %s)', account.code))
@api.constrains('user_type_id')
def _check_user_type_id(self):
@@ -52,7 +52,7 @@ class AccountAccount(models.Model):
if res.get('company_id_count', 0) >= 2:
account_unaffected_earnings = self.search([('company_id', '=', res['company_id'][0]),
('user_type_id', '=', data_unaffected_earnings.id)])
raise ValidationError(_('You cannot have more than one account with "Current Year Earnings" as type. (accounts: %s)') % [a.code for a in account_unaffected_earnings])
raise ValidationError(_('You cannot have more than one account with "Current Year Earnings" as type. (accounts: %s)', [a.code for a in account_unaffected_earnings]))
name = fields.Char(string="Account Name", required=True, index=True)
currency_id = fields.Many2one('res.currency', string='Account Currency',
@@ -147,7 +147,11 @@ class AccountAccount(models.Model):
if res:
account = self.env['account.account'].browse(res[0])
journal = self.env['account.journal'].browse(res[1])
raise ValidationError(_("The foreign currency set on the journal '%s' and the account '%s' must be the same.") % (journal.display_name, account.display_name))
raise ValidationError(_(
"The foreign currency set on the journal '%(journal)s' and the account '%(account)s' must be the same.",
journal=journal.display_name,
account=account.display_name
))
@api.constrains('company_id')
def _check_company_consistency(self):
@@ -445,7 +449,7 @@ class AccountAccount(models.Model):
if partner_prop_acc:
account_name = partner_prop_acc.get_by_record().display_name
raise UserError(
_('You cannot remove/deactivate the account %s which is set on a customer or vendor.') % account_name
_('You cannot remove/deactivate the account %s which is set on a customer or vendor.', account_name)
)
return super(AccountAccount, self).unlink()
+23 -18
View File
@@ -75,7 +75,7 @@ class AccountBankStmtCashWizard(models.Model):
def name_get(self):
result = []
for cashbox in self:
result.append((cashbox.id, _("%s")%(cashbox.total)))
result.append((cashbox.id, str(cashbox.total)))
return result
@api.model_create_multi
@@ -294,29 +294,34 @@ class AccountBankStatement(models.Model):
for stmt in self:
if not stmt.currency_id.is_zero(stmt.difference):
if stmt.journal_type == 'cash':
if stmt.difference < 0.0:
account = stmt.journal_id.loss_account_id
name = _('Loss')
else:
# statement.difference > 0.0
account = stmt.journal_id.profit_account_id
name = _('Profit')
if not account:
raise UserError(_('Please go on the %s journal and define a %s Account. This account will be used to record cash difference.') % (stmt.journal_id.name, name))
st_line_vals = {
'statement_id': stmt.id,
'journal_id': stmt.journal_id.id,
'amount': stmt.difference,
'payment_ref': _("Cash difference observed during the counting (%s)") % name,
'date': stmt.date,
}
self.env['account.bank.statement.line'].with_context(counterpart_account_id=account.id).create(st_line_vals)
if stmt.difference < 0.0:
if not stmt.journal_id.loss_account_id:
raise UserError(_('Please go on the %s journal and define a Loss Account. This account will be used to record cash difference.', stmt.journal_id.name))
st_line_vals['payment_ref'] = _("Cash difference observed during the counting (Loss)")
self.env['account.bank.statement.line'].with_context(counterpart_account_id=stmt.journal_id.loss_account_id).create(st_line_vals)
else:
# statement.difference > 0.0
if not stmt.journal_id.profit_account_id:
raise UserError(_('Please go on the %s journal and define a Profit Account. This account will be used to record cash difference.', stmt.journal_id.name))
st_line_vals['payment_ref'] = _("Cash difference observed during the counting (Profit)")
self.env['account.bank.statement.line'].with_context(counterpart_account_id=stmt.journal_id.profit_account_id).create(st_line_vals)
else:
balance_end_real = formatLang(self.env, stmt.balance_end_real, currency_obj=stmt.currency_id)
balance_end = formatLang(self.env, stmt.balance_end, currency_obj=stmt.currency_id)
raise UserError(_('The ending balance is incorrect !\nThe expected balance (%s) is different from the computed one. (%s)')
% (balance_end_real, balance_end))
raise UserError(_(
'The ending balance is incorrect !\nThe expected balance (%(real_balance)s) is different from the computed one (%(computed_balance)s).',
real_balance=balance_end_real,
computed_balance=balance_end
))
return True
def unlink(self):
@@ -392,13 +397,13 @@ class AccountBankStatement(models.Model):
for statement in self:
# Chatter.
statement.message_post(body=_('Statement %s confirmed.') % statement.name)
statement.message_post(body=_('Statement %s confirmed.', statement.name))
# Bank statement report.
if statement.journal_id.type == 'bank':
content, content_type = self.env.ref('account.action_report_account_statement')._render(statement.id)
self.env['ir.attachment'].create({
'name': statement.name and _("Bank Statement %s.pdf") % statement.name or _("Bank Statement.pdf"),
'name': statement.name and _("Bank Statement %s.pdf", statement.name) or _("Bank Statement.pdf"),
'type': 'binary',
'datas': base64.encodebytes(content),
'res_model': statement._name,
@@ -873,7 +878,7 @@ class AccountBankStatementLine(models.Model):
if st_line.currency_id.is_zero(st_line.amount):
raise ValidationError(_("The amount of a statement line can't be equal to zero."))
if st_line.foreign_currency_id == st_line.currency_id:
raise ValidationError(_("The foreign currency must be different than the journal one: %s") % st_line.currency_id.name)
raise ValidationError(_("The foreign currency must be different than the journal one: %s", st_line.currency_id.name))
if st_line.foreign_currency_id and st_line.foreign_currency_id.is_zero(st_line.amount_currency):
raise ValidationError(_("The amount in foreign currency must be set if the amount is not equal to zero."))
if not st_line.foreign_currency_id and st_line.amount_currency:
+8 -4
View File
@@ -213,11 +213,11 @@ class AccountJournal(models.Model):
for journal in self:
if journal.type == 'bank' and journal.bank_account_id:
if journal.bank_account_id.company_id and journal.bank_account_id.company_id != journal.company_id:
raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % journal.company_id.name)
raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).', journal.company_id.name))
# A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier.
# Or they are part of a bank journal and their partner_id must be the company's partner_id.
if journal.bank_account_id.partner_id != journal.company_id.partner_id:
raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % journal.company_id.name)
raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).', journal.company_id.name))
@api.constrains('company_id')
def _check_company_consistency(self):
@@ -270,7 +270,11 @@ class AccountJournal(models.Model):
''', [tuple(accounts.ids)])
res = self._cr.fetchone()
if res:
raise ValidationError(_("The account %s can't be shared between multiple journals: %s") % (res[0], ', '.join(res[1])))
raise ValidationError(_(
"The account %(account_name)s can't be shared between multiple journals: %(journals)s",
account_name=res[0],
journals=', '.join(res[1])
))
@api.constrains('type', 'default_credit_account_id', 'default_debit_account_id')
def _check_type_default_credit_account_id_type(self):
@@ -365,7 +369,7 @@ class AccountJournal(models.Model):
journal_entry = self.env['account.move'].search([('journal_id', '=', self.id), ('state', '=', 'posted'), ('secure_sequence_number', '!=', 0)], limit=1)
if len(journal_entry) > 0:
field_string = self._fields['restrict_mode_hash_table'].get_description(self.env)['string']
raise UserError(_("You cannot modify the field %s of a journal that already has accounting entries.") % field_string)
raise UserError(_("You cannot modify the field %s of a journal that already has accounting entries.", field_string))
result = super(AccountJournal, self).write(vals)
for journal in self:
+16 -11
View File
@@ -65,9 +65,10 @@ class AccountMove(models.Model):
if not journal:
company = self.env['res.company'].browse(company_id)
error_msg = _("No journal could be found in company %s for any of those types: %s") % (
company.display_name,
', '.join(journal_types),
error_msg = _(
"No journal could be found in company %(company_name)s for any of those types: %(journal_types)s",
company_name=company.display_name,
journal_types=', '.join(journal_types),
)
raise UserError(error_msg)
@@ -91,7 +92,11 @@ class AccountMove(models.Model):
journal = self.env['account.journal'].browse(self._context['default_journal_id'])
if move_type != 'entry' and journal.type not in journal_types:
raise UserError(_("Cannot create an invoice of type %s with a journal having %s as type.") % (move_type, journal.type))
raise UserError(_(
"Cannot create an invoice of type %(move_type)s with a journal having %(journal_type)s as type.",
move_type=move_type,
journal_type=journal.type,
))
else:
journal = self._search_default_journal(journal_types)
@@ -377,7 +382,7 @@ class AccountMove(models.Model):
if p.invoice_warn != 'block' and p.parent_id and p.parent_id.invoice_warn == 'block':
p = p.parent_id
warning = {
'title': _("Warning for %s") % p.name,
'title': _("Warning for %s", p.name),
'message': p.invoice_warn_msg
}
if p.invoice_warn == 'block':
@@ -758,7 +763,7 @@ class AccountMove(models.Model):
return
rounding_line_vals.update({
'name': _('%s (rounding)') % biggest_tax_line.name,
'name': _('%s (rounding)', biggest_tax_line.name),
'account_id': biggest_tax_line.account_id.id,
'tax_repartition_line_id': biggest_tax_line.tax_repartition_line_id.id,
'tax_exigible': biggest_tax_line.tax_exigible,
@@ -1582,9 +1587,9 @@ class AccountMove(models.Model):
lock_date = move.company_id._get_user_fiscal_lock_date()
if move.date <= lock_date:
if self.user_has_groups('account.group_account_manager'):
message = _("You cannot add/modify entries prior to and inclusive of the lock date %s.") % format_date(self.env, lock_date)
message = _("You cannot add/modify entries prior to and inclusive of the lock date %s.", format_date(self.env, lock_date))
else:
message = _("You cannot add/modify entries prior to and inclusive of the lock date %s. Check the company settings or ask someone with the 'Adviser' role") % format_date(self.env, lock_date)
message = _("You cannot add/modify entries prior to and inclusive of the lock date %s. Check the company settings or ask someone with the 'Adviser' role", format_date(self.env, lock_date))
raise UserError(message)
return True
@@ -2284,7 +2289,7 @@ class AccountMove(models.Model):
raise UserError(_('You need to add a line before posting.'))
if move.auto_post and move.date > fields.Date.today():
date_msg = move.date.strftime(get_lang(self.env).date_format)
raise UserError(_("This move is configured to be auto-posted on %s") % date_msg)
raise UserError(_("This move is configured to be auto-posted on %s", date_msg))
if not move.partner_id:
if move.is_sale_document():
@@ -3466,9 +3471,9 @@ class AccountMoveLine(models.Model):
control_type_failed = journal.type_control_ids and account.user_type_id not in journal.type_control_ids
control_account_failed = journal.account_control_ids and account not in journal.account_control_ids
if control_journal_failed:
raise UserError(_('You cannot use this account (%s) in this journal, check the field \'Allowed Journals\' on the related account.') % account.display_name)
raise UserError(_('You cannot use this account (%s) in this journal, check the field \'Allowed Journals\' on the related account.', account.display_name))
if control_type_failed or control_account_failed:
raise UserError(_('You cannot use this account (%s) in this journal, check the section \'Control-Access\' under tab \'Advanced Settings\' on the related journal.') % account.display_name)
raise UserError(_('You cannot use this account (%s) in this journal, check the section \'Control-Access\' under tab \'Advanced Settings\' on the related journal.', account.display_name))
@api.constrains('account_id', 'tax_ids', 'tax_line_id', 'reconciled')
def _check_off_balance(self):
@@ -67,7 +67,7 @@ class AccountPartialReconcile(models.Model):
def _check_required_computed_currencies(self):
bad_partials = self.filtered(lambda partial: not partial.debit_currency_id or not partial.credit_currency_id)
if bad_partials:
raise ValidationError(_("Missing foreign currencies on partials having ids: %s") % bad_partials.ids)
raise ValidationError(_("Missing foreign currencies on partials having ids: %s", bad_partials.ids))
# -------------------------------------------------------------------------
# COMPUTE METHODS
+2 -2
View File
@@ -205,9 +205,9 @@ class AccountPayment(models.Model):
if self.is_internal_transfer:
if self.payment_type == 'inbound':
liquidity_line_name = _('Transfer to %s') % self.journal_id.name
liquidity_line_name = _('Transfer to %s', self.journal_id.name)
else: # payment.payment_type == 'outbound':
liquidity_line_name = _('Transfer from %s') % self.journal_id.name
liquidity_line_name = _('Transfer from %s', self.journal_id.name)
else:
liquidity_line_name = self.payment_reference
+1 -1
View File
@@ -184,7 +184,7 @@ class AccountTax(models.Model):
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
default = dict(default or {}, name=_("%s (Copy)") % self.name)
default = dict(default or {}, name=_("%s (Copy)", self.name))
return super(AccountTax, self).copy(default=default)
def name_get(self):
+1 -1
View File
@@ -1040,7 +1040,7 @@ class AccountTaxRepartitionLineTemplate(models.Model):
all_tax_rep_lines = self.mapped('plus_report_line_ids') + self.mapped('minus_report_line_ids')
lines_without_tag = all_tax_rep_lines.filtered(lambda x: not x.tag_name)
if lines_without_tag:
raise ValidationError(_("The following tax report lines are used in some tax repartition template though they don't generate any tag: %s . This probably means you forgot to set a tag_name on these lines.") % str(lines_without_tag.mapped('name')))
raise ValidationError(_("The following tax report lines are used in some tax repartition template though they don't generate any tag: %s . This probably means you forgot to set a tag_name on these lines.", str(lines_without_tag.mapped('name'))))
def get_repartition_line_create_vals(self, company):
rslt = [(5, 0, 0)]
+1 -1
View File
@@ -537,7 +537,7 @@ class ResCompany(models.Model):
hash_corrupted = False
for move in moves:
if move.inalterable_hash != move._compute_hash(previous_hash=previous_hash):
rslt.update({'msg_cover': _('Corrupted data on journal entry with id %s.') % move.id})
rslt.update({'msg_cover': _('Corrupted data on journal entry with id %s.', move.id)})
results_by_journal['results'].append(rslt)
hash_corrupted = True
break
+1 -1
View File
@@ -36,7 +36,7 @@ class ResPartnerBank(models.Model):
return self._get_qr_code_url(candidate_method, amount, currency, debtor_partner, free_communication, structured_communication)
elif not silent_errors:
error_header = _("The following error prevented '%s' QR-code to be generated though it was detected as eligible: ") % candidate_name
error_header = _("The following error prevented '%s' QR-code to be generated though it was detected as eligible: ", candidate_name)
raise UserError( error_header + error_message)
return None
+1 -1
View File
@@ -96,7 +96,7 @@ class SequenceMixin(models.AbstractModel):
"""
self.ensure_one()
if self._sequence_field not in self._fields or not self._fields[self._sequence_field].store:
raise ValidationError(_('%s is not a stored field') % self._sequence_field)
raise ValidationError(_('%s is not a stored field', self._sequence_field))
where_string, param = self._get_last_sequence_domain(relaxed)
if self.id or self.id.origin:
where_string += " AND id != %(id)s "
@@ -202,7 +202,7 @@ class AccrualAccountingWizard(models.TransientModel):
record.preview_data = json.dumps({
'groups_vals': preview_vals,
'options': {
'discarded_number': (_("%d moves") % preview_discarded) if preview_discarded else False,
'discarded_number': _("%d moves", preview_discarded) if preview_discarded else False,
'columns': preview_columns,
},
})
@@ -57,7 +57,9 @@ class AccountMoveReversal(models.TransientModel):
def _prepare_default_reversal(self, move):
reverse_date = self.date if self.date_mode == 'custom' else move.date
return {
'ref': _('Reversal of: %s, %s') % (move.name, self.reason) if self.reason else _('Reversal of: %s') % (move.name),
'ref': _('Reversal of: %(move_name)s, %(reason)s', move_name=move.name, reason=self.reason)
if self.reason
else _('Reversal of: %s', move.name),
'date': reverse_date,
'invoice_date': move.is_invoice(include_receipts=True) and (self.date or move.date) or False,
'journal_id': self.journal_id and self.journal_id.id or move.journal_id.id,
@@ -81,7 +81,7 @@ class AccountTransferWizard(models.TransientModel):
# Generate counterpart lines' vals
for (counterpart_partner, counterpart_currency), counterpart_vals in counterpart_balances.items():
source_accounts = self.move_line_ids.mapped('account_id')
counterpart_label = len(source_accounts) == 1 and _("Transfer from %s") % source_accounts.display_name or _("Transfer counterpart")
counterpart_label = len(source_accounts) == 1 and _("Transfer from %s", source_accounts.display_name) or _("Transfer counterpart")
if not self.company_id.currency_id.is_zero(counterpart_vals['balance']) or (counterpart_currency and not counterpart_currency.is_zero(counterpart_vals['amount_currency'])):
line_vals.append({
@@ -112,7 +112,7 @@ class AccountTransferWizard(models.TransientModel):
return {
'journal_id': self.journal_id.id,
'date': self.date,
'ref': self.destination_account_id.display_name and _("Transfer entry to %s") % self.destination_account_id.display_name or '',
'ref': self.destination_account_id.display_name and _("Transfer entry to %s", self.destination_account_id.display_name) or '',
'line_ids': [(0, 0, line) for line in line_vals],
}
+2 -2
View File
@@ -143,11 +143,11 @@ class ResPartner(models.Model):
partner = self.search([('signup_token', '=', token)], limit=1)
if not partner:
if raise_exception:
raise exceptions.UserError(_("Signup token '%s' is not valid") % token)
raise exceptions.UserError(_("Signup token '%s' is not valid", token))
return False
if check_validity and not partner.signup_valid:
if raise_exception:
raise exceptions.UserError(_("Signup token '%s' is no longer valid") % token)
raise exceptions.UserError(_("Signup token '%s' is no longer valid", token))
return False
return partner
+2 -2
View File
@@ -123,7 +123,7 @@ class ResUsers(models.Model):
invite_partner = user.create_uid.partner_id
if invite_partner:
# notify invite user that new user is connected
title = _("%s connected") % user.name
title = _("%s connected", user.name)
message = _("This is his first connection. Wish him welcome")
self.env['bus.bus'].sendone(
(self._cr.dbname, 'res.partner', invite_partner.id),
@@ -196,7 +196,7 @@ class ResUsers(models.Model):
for user in self:
if not user.email:
raise UserError(_("Cannot send email: user %s has no email address.") % user.name)
raise UserError(_("Cannot send email: user %s has no email address.", user.name))
# TDE FIXME: make this template technical (qweb)
with self.env.cr.savepoint():
force_send = not(self.env.context.get('import_file', False))
@@ -35,7 +35,7 @@ class Partner(models.Model):
field_name = re_match.group()[2:-2]
field_pos = re_match.start()
if field_name not in street_fields:
raise UserError(_("Unrecognized field %s in street format.") % field_name)
raise UserError(_("Unrecognized field %s in street format.", field_name))
if not previous_field:
# first iteration: add heading chars in street_format
if partner[field_name]:
@@ -104,7 +104,7 @@ class Partner(models.Model):
# value not found: keep looking for the same field
pass
if field_name not in street_fields:
raise UserError(_("Unrecognized field %s in street format.") % field_name)
raise UserError(_("Unrecognized field %s in street format.", field_name))
previous_pos = re_match.end()
# last field value is what remains in street_raw minus trailing chars in street_format
@@ -91,7 +91,7 @@ class BaseGengoTranslations(models.TransientModel):
return (True, gengo)
except Exception as e:
_logger.exception('Gengo connection failed')
return (False, _("Gengo connection failed with this message:\n``%s``") % e)
return (False, _("Gengo connection failed with this message:\n``%s``", e))
def act_update(self):
'''
+3 -3
View File
@@ -297,7 +297,7 @@ class Import(models.TransientModel):
_("Invalid cell value at row %(row)s, column %(col)s: %(cell_value)s") % {
'row': rowx,
'col': colx,
'cell_value': xlrd.error_text_from_code.get(cell.value, _("unknown error code %s") % cell.value)
'cell_value': xlrd.error_text_from_code.get(cell.value, _("unknown error code %s", cell.value))
}
)
else:
@@ -856,13 +856,13 @@ class Import(models.TransientModel):
response.raise_for_status()
if response.headers.get('Content-Length') and int(response.headers['Content-Length']) > maxsize:
raise ValueError(_("File size exceeds configured maximum (%s bytes)") % maxsize)
raise ValueError(_("File size exceeds configured maximum (%s bytes)", maxsize))
content = bytearray()
for chunk in response.iter_content(DEFAULT_IMAGE_CHUNK_SIZE):
content += chunk
if len(content) > maxsize:
raise ValueError(_("File size exceeds configured maximum (%s bytes)") % maxsize)
raise ValueError(_("File size exceeds configured maximum (%s bytes)", maxsize))
image = Image.open(io.BytesIO(content))
w, h = image.size
@@ -30,7 +30,7 @@ class ImportModule(Controller):
@webservice
def login_upload(self, login, password, db=None, force='', mod_file=None, **kw):
if db and db != request.db:
raise Exception(_("Could not select database '%s'") % db)
raise Exception(_("Could not select database '%s'", db))
uid = request.session.authenticate(request.db, login, password)
self.check_user(uid)
force = True if force == '1' else False
@@ -121,7 +121,7 @@ class IrModule(models.Model):
with zipfile.ZipFile(module_file, "r") as z:
for zf in z.filelist:
if zf.file_size > MAX_FILE_SIZE:
raise UserError(_("File '%s' exceed maximum allowed file size") % zf.filename)
raise UserError(_("File '%s' exceed maximum allowed file size", zf.filename))
with tempfile.TemporaryDirectory() as module_dir:
import odoo.modules.module as module
+2 -2
View File
@@ -32,9 +32,9 @@ class IrModelFields(models.Model):
if 'serialization_field_id' in vals or 'name' in vals:
for field in self:
if 'serialization_field_id' in vals and field.serialization_field_id.id != vals['serialization_field_id']:
raise UserError(_('Changing the storing system for field "%s" is not allowed.') % field.name)
raise UserError(_('Changing the storing system for field "%s" is not allowed.', field.name))
if field.serialization_field_id and (field.name != vals['name']):
raise UserError(_('Renaming sparse field "%s" is not allowed') % field.name)
raise UserError(_('Renaming sparse field "%s" is not allowed', field.name))
return super(IrModelFields, self).write(vals)
+12 -2
View File
@@ -162,8 +162,18 @@ class ResPartner(models.Model):
else:
company = self.env.company
if company.vat_check_vies:
return '\n' + _('The VAT number [%s] for partner [%s] either failed the VIES VAT validation check or did not respect the expected format %s.') % (self.vat, self.name, vat_no)
return '\n' + _('The VAT number [%s] for partner [%s] does not seem to be valid. \nNote: the expected format is %s') % (self.vat, self.name, vat_no)
return '\n' + _(
'The VAT number [%(vat)s] for partner [%(name)s] either failed the VIES VAT validation check or did not respect the expected format %(format)s.',
vat=self.vat,
name=self.name,
format=vat_no
)
return '\n' + _(
'The VAT number [%(vat)s] for partner [%(name)s] does not seem to be valid. \nNote: the expected format is %(format)s',
vat=self.vat,
name=self.name,
format=vat_no
)
__check_vat_ch_re1 = re.compile(r'(MWST|TVA|IVA)[0-9]{6}$')
__check_vat_ch_re2 = re.compile(r'E([0-9]{9}|-[0-9]{3}\.[0-9]{3}\.[0-9]{3})(MWST|TVA|IVA)$')
+24 -14
View File
@@ -135,25 +135,27 @@ class Meeting(models.Model):
time_str = to_text(date.strftime(format_time))
if zallday:
display_time = _("AllDay , %s") % (date_str)
display_time = _("AllDay , %(day)s", day=date_str)
elif zduration < 24:
duration = date + timedelta(minutes=round(zduration*60))
duration_time = to_text(duration.strftime(format_time))
display_time = _(u"%s at (%s To %s) (%s)") % (
date_str,
time_str,
duration_time,
timezone,
display_time = _(
u"%(day)s at (%(start)s To %(end)s) (%(timezone)s)",
day=date_str,
start=time_str,
end=duration_time,
timezone=timezone,
)
else:
dd_date = to_text(date_deadline.strftime(format_date))
dd_time = to_text(date_deadline.strftime(format_time))
display_time = _(u"%s at %s To\n %s at %s (%s)") % (
date_str,
time_str,
dd_date,
dd_time,
timezone,
display_time = _(
u"%(date_start)s at %(time_start)s To\n %(date_end)s at %(time_end)s (%(timezone)s)",
date_start=date_str,
time_start=time_str,
date_end=dd_date,
time_end=dd_time,
timezone=timezone,
)
return display_time
@@ -356,12 +358,20 @@ class Meeting(models.Model):
if meeting.start and meeting.stop and meeting.stop < meeting.start:
raise ValidationError(
_('The ending date and time cannot be earlier than the starting date and time.') + '\n' +
_("Meeting '%s' starts '%s' and ends '%s'") % (meeting.name, meeting.start, meeting.stop)
_("Meeting '%(name)s' starts '%(start_datetime)s' and ends '%(end_datetime)s'",
name=meeting.name,
start_datetime=meeting.start,
end_datetime=meeting.stop
)
)
if meeting.start_date and meeting.stop_date and meeting.stop_date < meeting.start_date:
raise ValidationError(
_('The ending date cannot be earlier than the starting date.') + '\n' +
_("Meeting '%s' starts '%s' and ends '%s'") % (meeting.name, meeting.start_date, meeting.stop_date)
_("Meeting '%(name)s' starts '%(start_datetime)s' and ends '%(end_datetime)s'",
name=meeting.name,
start_datetime=meeting.start,
end_datetime=meeting.stop
)
)
####################################################
@@ -124,12 +124,12 @@ class RecurrenceRule(models.Model):
def _compute_name(self):
for recurrence in self:
period = dict(RRULE_TYPE_SELECTION)[recurrence.rrule_type]
every = _("Every %s %s, ") % (recurrence.interval, period)
every = _("Every %(count)s %(period)s, ", count=recurrence.interval, period=period)
if recurrence.end_type == 'count':
end = _("for %s events") % recurrence.count
end = _("for %s events", recurrence.count)
elif recurrence.end_type == 'end_date':
end = _("until %s") % recurrence.until
end = _("until %s", recurrence.until)
else:
end = ''
@@ -140,9 +140,9 @@ class RecurrenceRule(models.Model):
elif recurrence.rrule_type == 'monthly':
if recurrence.month_by == 'day':
weekday_label = dict(BYDAY_SELECTION)[recurrence.byday]
on = _("on the %(position)s %(weekday)s, ") % {'position': recurrence.byday, 'weekday': weekday_label}
on = _("on the %(position)s %(weekday)s, ", position=recurrence.byday, weekday=weekday_label)
else:
on = _("day %s, ") % recurrence.day
on = _("day %s, ", recurrence.day)
else:
on = ''
recurrence.name = every + on + end
+1 -1
View File
@@ -22,7 +22,7 @@ class CalendarEvent(models.Model):
for event in self:
event._message_sms_with_template(
template_xmlid='calendar_sms.sms_template_data_calendar_reminder',
template_fallback=_("Event reminder: %s, %s.") % (event.name, event.display_time),
template_fallback=_("Event reminder: %(name)s, %(time)s.", name=event.name, time=event.display_time),
partner_ids=self._sms_get_default_partners().ids,
put_in_queue=False
)
+5 -1
View File
@@ -894,7 +894,11 @@ class Lead(models.Model):
for message in opportunity.message_ids:
message.write({
'res_id': self.id,
'subject': _("From %s : %s") % (opportunity.name, message.subject)
'subject': _(
"From %(source_name)s : %(source_subject)s",
source_name=opportunity.name,
source_subject=message.subject
)
})
return True
+1 -1
View File
@@ -101,7 +101,7 @@ class SaleOrder(models.Model):
}
if carrier.invoice_policy == 'real':
values['price_unit'] = 0
values['name'] += _(' (Estimated Cost: %s )') % self._format_currency_amount(price_unit)
values['name'] += _(' (Estimated Cost: %s )', self._format_currency_amount(price_unit))
else:
values['price_unit'] = price_unit
if carrier.free_over and self.currency_id.is_zero(price_unit) :
+7 -1
View File
@@ -172,7 +172,13 @@ class StockPicking(models.Model):
if res['tracking_number']:
self.carrier_tracking_ref = res['tracking_number']
order_currency = self.sale_id.currency_id or self.company_id.currency_id
msg = _("Shipment sent to carrier %s for shipping with tracking number %s<br/>Cost: %.2f %s") % (self.carrier_id.name, self.carrier_tracking_ref, self.carrier_price, order_currency.name)
msg = _(
"Shipment sent to carrier %(carrier_name)s for shipping with tracking number %(ref)s<br/>Cost: %(price).2f %(currency)s",
carrier_name=self.carrier_id.name,
ref=self.carrier_tracking_ref,
price=self.carrier_price,
currency=order_currency.name
)
self.message_post(body=msg)
self._add_delivery_cost_to_so()
+1 -1
View File
@@ -51,7 +51,7 @@ class EventTicket(models.Model):
def default_get(self, fields):
res = super(EventTicket, self).default_get(fields)
if 'name' in fields and (not res.get('name') or res['name'] == _('Registration')) and self.env.context.get('default_event_name'):
res['name'] = _('Registration for %s') % self.env.context['default_event_name']
res['name'] = _('Registration for %s', self.env.context['default_event_name'])
return res
# description
+1 -1
View File
@@ -126,7 +126,7 @@ odoo_mailgate: "|/path/to/odoo-mailgate.py --host=localhost -u %(uid)d -p PASSWO
server.write({'state': 'done'})
except Exception as err:
_logger.info("Failed to connect to %s server %s.", server.server_type, server.name, exc_info=True)
raise UserError(_("Connection test failed: %s") % tools.ustr(err))
raise UserError(_("Connection test failed: %s", tools.ustr(err)))
finally:
try:
if connection:
+8 -4
View File
@@ -596,7 +596,7 @@ class Challenge(models.Model):
def accept_challenge(self):
user = self.env.user
sudoed = self.sudo()
sudoed.message_post(body=_("%s has joined the challenge") % user.name)
sudoed.message_post(body=_("%s has joined the challenge", user.name))
sudoed.write({'invited_user_ids': [(3, user.id)], 'user_ids': [(4, user.id)]})
return sudoed._generate_goals_from_challenge()
@@ -604,7 +604,7 @@ class Challenge(models.Model):
"""The user discard the suggested challenge"""
user = self.env.user
sudoed = self.sudo()
sudoed.message_post(body=_("%s has refused the challenge") % user.name)
sudoed.message_post(body=_("%s has refused the challenge", user.name))
return sudoed.write({'invited_user_ids': (3, user.id)})
def _check_challenge_reward(self, force=False):
@@ -652,11 +652,15 @@ class Challenge(models.Model):
if challenge_ended:
# open chatter message
message_body = _("The challenge %s is finished.") % challenge.name
message_body = _("The challenge %s is finished.", challenge.name)
if rewarded_users:
user_names = rewarded_users.name_get()
message_body += _("<br/>Reward (badge %s) for every succeeding user was sent to %s.") % (challenge.reward_id.name, ", ".join(name for (user_id, name) in user_names))
message_body += _(
"<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)
)
else:
message_body += _("<br/>Nobody has succeeded to reach every goal, no badge is rewarded for this challenge.")
+11 -5
View File
@@ -111,11 +111,17 @@ class GoalDefinition(models.Model):
Model = self.env[definition.model_id.model]
field = Model._fields.get(definition.field_id.name)
if not (field and field.store):
raise exceptions.UserError(
_("The model configuration for the definition %s seems incorrect, please check it.\n\n%s not stored") % (definition.name, definition.field_id.name))
raise exceptions.UserError(_(
"The model configuration for the definition %(name)s seems incorrect, please check it.\n\n%(field_name)s not stored",
name=definition.name,
field_name=definition.field_id.name
))
except KeyError as e:
raise exceptions.UserError(
_("The model configuration for the definition %s seems incorrect, please check it.\n\n%s not found") % (definition.name, e))
raise exceptions.UserError(_(
"The model configuration for the definition %(name)s seems incorrect, please check it.\n\n%(error)s not found",
name=definition.name,
error=e
))
@api.model
def create(self, vals):
@@ -430,7 +436,7 @@ class Goal(models.Model):
if self.computation_mode == 'manually':
# open a wizard window to update the value manually
action = {
'name': _("Update %s") % self.definition_id.name,
'name': _("Update %s", self.definition_id.name),
'id': self.id,
'type': 'ir.actions.act_window',
'views': [[False, 'form']],
+15 -3
View File
@@ -131,15 +131,27 @@ class Meeting(models.Model):
if minutes % (60*24) == 0:
interval = 'days'
duration = minutes / 60 / 24
name = _("%s - %s Days") % (alarm_type_label, duration)
name = _(
"%(reminder_type)s - %(duration)s Days",
reminder_type=alarm_type_label,
duration=duration,
)
elif minutes % 60 == 0:
interval = 'hours'
duration = minutes / 60
name = _("%s - %s Hours") % (alarm_type_label, duration)
name = _(
"%(reminder_type)s - %(duration)s Hours",
reminder_type=alarm_type_label,
duration=duration,
)
else:
interval = 'minutes'
duration = minutes
name = _("%s - %s Minutes") % (alarm_type_label, duration)
name = _(
"%(reminder_type)s - %(duration)s Minutes",
reminder_type=alarm_type_label,
duration=duration,
)
commands += [(0, 0, {'duration': duration, 'interval': interval, 'name': name, 'alarm_type': alarm_type})]
return commands
+1 -1
View File
@@ -74,7 +74,7 @@ class User(models.Model):
with self.pool.cursor() as cr:
self.env.user.with_env(self.env(cr=cr)).write({'google_calendar_rtoken': False})
error_key = error.response.json().get("error", "nc")
error_msg = _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]") % error_key
error_msg = _("Something went wrong during your token generation. Maybe your Authorization Code is invalid or already expired [%s]", error_key)
raise UserError(error_msg)
def _sync_google_calendar(self, calendar_service: GoogleCalendarService):
+6 -6
View File
@@ -34,24 +34,24 @@ class HrPlanActivityType(models.Model):
def get_responsible_id(self, employee):
if self.responsible == 'coach':
if not employee.coach_id:
raise UserError(_('Coach of employee %s is not set.') % employee.name)
raise UserError(_('Coach of employee %s is not set.', employee.name))
responsible = employee.coach_id.user_id
if not responsible:
raise UserError(_('User of coach of employee %s is not set.') % employee.name)
raise UserError(_('User of coach of employee %s is not set.', employee.name))
elif self.responsible == 'manager':
if not employee.parent_id:
raise UserError(_('Manager of employee %s is not set.') % employee.name)
raise UserError(_('Manager of employee %s is not set.', employee.name))
responsible = employee.parent_id.user_id
if not responsible:
raise UserError(_('User of manager of employee %s is not set.') % employee.name)
raise UserError(_('User of manager of employee %s is not set.', employee.name))
elif self.responsible == 'employee':
responsible = employee.user_id
if not responsible:
raise UserError(_('User linked to employee %s is required.') % employee.name)
raise UserError(_('User linked to employee %s is required.', employee.name))
elif self.responsible == 'other':
responsible = self.responsible_id
if not responsible:
raise UserError(_('No specific user given on activity %s.') % self.activity_type_id.name)
raise UserError(_('No specific user given on activity %s.', self.activity_type_id.name))
return responsible
+1 -1
View File
@@ -144,7 +144,7 @@ class Contract(models.Model):
for contract in contracts:
contract.activity_schedule(
'mail.mail_activity_data_todo', contract.date_end,
_("The contract of %s is about to expire.") % contract.employee_id.name,
_("The contract of %s is about to expire.", contract.employee_id.name),
user_id=contract.hr_responsible_id.id or self.env.uid)
contracts.write({'kanban_state': 'blocked'})
@@ -113,7 +113,14 @@ class HrExpenseSheetRegisterPaymentWizard(models.TransientModel):
payment.action_post()
# Log the payment in the chatter
body = (_("A payment of %s %s with the reference <a href='/mail/view?%s'>%s</a> related to your expense %s has been made.") % (payment.amount, payment.currency_id.symbol, url_encode({'model': 'account.payment', 'res_id': payment.id}), payment.name, expense_sheet.name))
body = _(
"A payment of %(amount)s %(currency)s with the reference <a href='/mail/view?%(url)s'>%(payment_name)s</a> related to your expense %(expense_name)s has been made.",
amount=payment.amount,
currency=payment.currency_id.symbol,
url=url_encode({'model': 'account.payment', 'res_id': payment.id}),
payment_name=payment.name,
expense_name=expense_sheet.name
)
expense_sheet.message_post(body=body)
# Reconcile the payment and the expense, i.e. lookup on the payable account move lines
+6 -1
View File
@@ -52,7 +52,12 @@ class HrFleet(Controller):
date_start = car_line_doc.date_start
date_end = car_line_doc.date_end or '...'
text_to_print = _("%s (driven from: %s to %s)") % (car_name, date_start, date_end)
text_to_print = _(
"%(car_name)s (driven from: %(date_start)s to %(date_end)s)",
car_name=car_name,
date_start=date_start,
date_end=date_end
)
can.drawCentredString(width / 2, height - normal_font_size, text_to_print)
can.save()
header_pdf = PdfFileReader(header, overwriteWarnings=False)
+34 -21
View File
@@ -621,11 +621,11 @@ class HolidaysRequest(models.Model):
if leave.leave_type_request_unit == 'hour':
res.append((
leave.id,
_("%s on %s: %.2f hours on %s") % (
target,
leave.holiday_status_id.name,
leave.number_of_hours_display,
fields.Date.to_string(leave.date_from),
_("%(person)s on %(leave_type)s: %(duration).2f hours on %(date)s",
person=target,
leave_type=leave.holiday_status_id.name,
duration=leave.number_of_hours_display,
date=fields.Date.to_string(leave.date_from),
)
))
else:
@@ -634,11 +634,11 @@ class HolidaysRequest(models.Model):
display_date += ' ⇨ %s' % fields.Date.to_string(leave.date_to)
res.append((
leave.id,
_("%s on %s: %.2f days (%s)") % (
target,
leave.holiday_status_id.name,
leave.number_of_days,
display_date,
_("%(person)s on %(leave_type)s: %(duration).2f days (%(start)s)",
person=target,
leave_type=leave.holiday_status_id.name,
duration=leave.number_of_days,
start=display_date,
)
))
return res
@@ -657,19 +657,26 @@ class HolidaysRequest(models.Model):
dto = leave.date_to
if leave.holiday_status_id.validity_start and leave.holiday_status_id.validity_stop:
if dfrom and dto and (dfrom.date() < vstart or dto.date() > vstop):
raise ValidationError(
_('%s are only valid between %s and %s') % (
leave.holiday_status_id.display_name, leave.holiday_status_id.validity_start, leave.holiday_status_id.validity_stop))
raise ValidationError(_(
'%(leave_type)s are only valid between %(start)s and %(end)s',
leave_type=leave.holiday_status_id.display_name,
start=leave.holiday_status_id.validity_start,
end=leave.holiday_status_id.validity_stop
))
elif leave.holiday_status_id.validity_start:
if dfrom and (dfrom.date() < vstart):
raise ValidationError(
_('%s are only valid starting from %s') % (
leave.holiday_status_id.display_name, leave.holiday_status_id.validity_start))
raise ValidationError(_(
'%(leave_type)s are only valid starting from %(date)s',
leave_type=leave.holiday_status_id.display_name,
date=leave.holiday_status_id.validity_start
))
elif leave.holiday_status_id.validity_stop:
if dto and (dto.date() > vstop):
raise ValidationError(
_('%s are only valid until %s') % (
leave.holiday_status_id.display_name, leave.holiday_status_id.validity_stop))
raise ValidationError(_(
'%(leave_type)s are only valid until %(date)s',
leave_type=leave.holiday_status_id.display_name,
date=leave.holiday_status_id.validity_stop
))
def _check_double_validation_rules(self, employees, state):
if self.user_has_groups('hr_holidays.group_hr_holidays_manager'):
@@ -1032,7 +1039,7 @@ class HolidaysRequest(models.Model):
for holiday in self:
if holiday.employee_id.user_id:
holiday.message_post(
body=_('Your %s planned on %s has been refused') % (holiday.holiday_status_id.display_name, holiday.date_from),
body=_('Your %(leave_type)s planned on %(date)s has been refused', leave_type=holiday.holiday_status_id.display_name, date=holiday.date_from),
partner_ids=holiday.employee_id.user_id.partner_id.ids)
self._remove_resource_leave()
@@ -1101,7 +1108,13 @@ class HolidaysRequest(models.Model):
for holiday in self:
start = UTC.localize(holiday.date_from).astimezone(timezone(holiday.employee_id.tz or 'UTC'))
end = UTC.localize(holiday.date_to).astimezone(timezone(holiday.employee_id.tz or 'UTC'))
note = _('New %s Request created by %s from %s to %s') % (holiday.holiday_status_id.name, holiday.create_uid.name, start, end)
note = _(
'New %(leave_type)s Request created by %(user)s from %(start)s to %(end)s',
leave_type=holiday.holiday_status_id.name,
user=holiday.create_uid.name,
start=start,
end=end
)
if holiday.state == 'draft':
to_clean |= holiday
elif holiday.state == 'confirm':
@@ -389,11 +389,12 @@ class HolidaysAllocation(models.Model):
res.append(
(allocation.id,
_("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))
_("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
))
)
return res
@@ -410,7 +411,11 @@ class HolidaysAllocation(models.Model):
today = fields.Date.today()
if vstop < today:
raise ValidationError(_('You can allocate %s only before %s.') % (allocation.holiday_status_id.display_name, allocation.holiday_status_id.validity_stop))
raise ValidationError(_(
'You can allocate %(allocation_type)s only before %(date)s.',
allocation_type=allocation.holiday_status_id.display_name,
date=allocation.holiday_status_id.validity_stop
))
@api.model
def create(self, values):
@@ -613,7 +618,12 @@ class HolidaysAllocation(models.Model):
def activity_update(self):
to_clean, to_do = self.env['hr.leave.allocation'], self.env['hr.leave.allocation']
for allocation in self:
note = _('New Allocation Request created by %s: %s Days of %s') % (allocation.create_uid.name, allocation.number_of_days, allocation.holiday_status_id.name)
note = _(
'New Allocation Request created by %(user)s: %(count)s Days of %(allocation_type)s',
user=allocation.create_uid.name,
count=allocation.number_of_days,
allocation_type=allocation.holiday_status_id.name
)
if allocation.state == 'draft':
to_clean |= allocation
elif allocation.state == 'confirm':
@@ -466,7 +466,7 @@ class Applicant(models.Model):
if applicant.job_id:
applicant.job_id.write({'no_of_hired_employee': applicant.job_id.no_of_hired_employee + 1})
applicant.job_id.message_post(
body=_('New Employee %s Hired') % applicant.partner_name if applicant.partner_name else applicant.name,
body=_('New Employee %s Hired', applicant.partner_name if applicant.partner_name else applicant.name),
subtype_xmlid="hr_recruitment.mt_job_applicant_hired")
applicant.message_post_with_view(
'hr_recruitment.applicant_hired_template',
+2 -2
View File
@@ -33,13 +33,13 @@ class EmployeeSkill(models.Model):
def _check_skill_type(self):
for record in self:
if record.skill_id not in record.skill_type_id.skill_ids:
raise ValidationError(_("The skill %s and skill type %s doesn't match") % (record.skill_id.name, record.skill_type_id.name))
raise ValidationError(_("The skill %(name)s and skill type %(type)s doesn't match", name=record.skill_id.name, type=record.skill_type_id.name))
@api.constrains('skill_type_id', 'skill_level_id')
def _check_skill_level(self):
for record in self:
if record.skill_level_id not in record.skill_type_id.skill_level_ids:
raise ValidationError(_("The skill level %s is not valid for skill type: %s ") % (record.skill_level_id.name, record.skill_type_id.name))
raise ValidationError(_("The skill level %(level)s is not valid for skill type: %(type)s", level=record.skill_level_id.name, type=record.skill_type_id.name))
class SkillLevel(models.Model):
+6 -1
View File
@@ -186,7 +186,12 @@ class Task(models.Model):
for task in self:
if 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 = _("(%s%s:%s remaining)") % ('-' if task.remaining_hours < 0 else '', hours, mins)
hours_left = _(
"(%(sign)s%(hours)s:%(minutes)s remaining)",
sign='-' if task.remaining_hours < 0 else '',
hours=hours,
minutes=mins,
)
name_mapping[task.id] = name_mapping.get(task.id, '') + " ‒ " + hours_left
return list(name_mapping.items())
return super().name_get()
@@ -142,7 +142,7 @@ class SerialDriver(Driver):
self._take_measure()
time.sleep(self._protocol.newMeasureDelay)
except Exception:
msg = _('Error while reading %s') % self.device_name
msg = _('Error while reading %s', self.device_name)
_logger.exception(msg)
self._status = {'status': self.STATUS_ERROR, 'message_title': msg, 'message_body': traceback.format_exc()}
self._push_status()
+1 -1
View File
@@ -68,7 +68,7 @@ def jsonrpc(url, method='call', params=None, timeout=15):
return response.get('result')
except (ValueError, requests.exceptions.ConnectionError, requests.exceptions.MissingSchema, requests.exceptions.Timeout, requests.exceptions.HTTPError) as e:
raise exceptions.AccessError(
_('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s') % url
_('The url that this service requested returned an error. Please contact the author of the app. The url it tried to contact was %s', url)
)
#----------------------------------------------------------
+1 -1
View File
@@ -207,7 +207,7 @@ class MailChannel(models.Model):
mail_body = template._render(render_context, engine='ir.qweb', minimal_qcontext=True)
mail_body = self.env['mail.render.mixin']._replace_local_links(mail_body)
mail = self.env['mail.mail'].sudo().create({
'subject': _('Conversation with %s') % self.livechat_operator_id.name,
'subject': _('Conversation with %s', self.livechat_operator_id.name),
'email_from': company.catchall_formatted or company.email_formatted,
'author_id': self.env.user.partner_id.id,
'email_to': email,
+5 -7
View File
@@ -98,7 +98,7 @@ class AccountMove(models.Model):
for line in inv.mapped('invoice_line_ids').filtered(lambda x: x.display_type not in ('line_section', 'line_note')):
vat_taxes = line.tax_ids.filtered(lambda x: x.tax_group_id.l10n_ar_vat_afip_code)
if len(vat_taxes) != 1:
raise UserError(_('There must be one and only one VAT tax per line. Check line "%s"') % line.name)
raise UserError(_('There must be one and only one VAT tax per line. Check line "%s"', line.name))
elif purchase_aliquots == 'zero' and vat_taxes.tax_group_id.l10n_ar_vat_afip_code != '0':
raise UserError(_('On invoice id "%s" you must use VAT Not Applicable on every line.') % inv.id)
elif purchase_aliquots == 'not_zero' and vat_taxes.tax_group_id.l10n_ar_vat_afip_code == '0':
@@ -129,22 +129,20 @@ class AccountMove(models.Model):
res_code = rec.partner_id.l10n_ar_afip_responsibility_type_id.code
domain = [('company_id', '=', rec.company_id.id), ('l10n_latam_use_documents', '=', True), ('type', '=', 'sale')]
journal = self.env['account.journal']
partner_type = journal_type = False
msg = False
if res_code in ['9', '10'] and rec.journal_id.l10n_ar_afip_pos_system not in expo_journals:
# if partner is foregin and journal is not of expo, we try to change to expo journal
journal = journal.search(domain + [('l10n_ar_afip_pos_system', 'in', expo_journals)], limit=1)
partner_type, journal_type = (_('foreign partner'), _('exportation'))
msg = _('You are trying to create an invoice for foreign partner but you don\'t have an exportation journal')
elif res_code not in ['9', '10'] and rec.journal_id.l10n_ar_afip_pos_system in expo_journals:
# if partner is NOT foregin and journal is for expo, we try to change to local journal
journal = journal.search(domain + [('l10n_ar_afip_pos_system', 'not in', expo_journals)], limit=1)
partner_type, journal_type = (_('domestic partner'), _('domestic market'))
msg = _('You are trying to create an invoice for domestic partner but you don\'t have an domestic market journal')
if journal:
rec.journal_id = journal.id
elif partner_type and journal_type:
elif msg:
# Throw an error to user in order to proper configure the journal for the type of operation
action = self.env.ref('account.action_account_journal_form')
msg = _('You are trying to create an invoice for %s but you dont have an %s journal') % (
partner_type, journal_type)
raise RedirectWarning(msg, action.id, _('Go to Journals'))
def post(self):
+3 -3
View File
@@ -103,10 +103,10 @@ class ResPartner(models.Model):
try:
module.validate(rec.vat)
except module.InvalidChecksum:
raise ValidationError(_('The validation digit is not valid for "%s"') % rec.l10n_latam_identification_type_id.name)
raise ValidationError(_('The validation digit is not valid for "%s"', rec.l10n_latam_identification_type_id.name))
except module.InvalidLength:
raise ValidationError(_('Invalid length for "%s"') % rec.l10n_latam_identification_type_id.name)
raise ValidationError(_('Invalid length for "%s"', rec.l10n_latam_identification_type_id.name))
except module.InvalidFormat:
raise ValidationError(_('Only numbers allowed for "%s"') % rec.l10n_latam_identification_type_id.name)
raise ValidationError(_('Only numbers allowed for "%s"', rec.l10n_latam_identification_type_id.name))
except Exception as error:
raise ValidationError(repr(error))
+1 -1
View File
@@ -88,7 +88,7 @@ class AccountFrFec(models.TransientModel):
is_dom_tom = company.country_id.code in dom_tom_group.country_ids.mapped('code')
if not is_dom_tom and not company.vat:
raise Warning(
_("Missing VAT number for company %s") % company.name)
_("Missing VAT number for company %s", company.name))
if not is_dom_tom and company.vat[0:2] != 'FR':
raise Warning(
_("FEC is for French companies only !"))
+1 -1
View File
@@ -28,7 +28,7 @@ class pos_session(models.Model):
date_today = datetime.utcnow()
session_start = Datetime.from_string(self.start_at)
if not date_today - timedelta(hours=24) <= session_start:
raise UserError(_("This session has been opened another day. To comply with the French law, you should close sessions on a daily basis. Please close session %s and open a new one.") % self.name)
raise UserError(_("This session has been opened another day. To comply with the French law, you should close sessions on a daily basis. Please close session %s and open a new one.", self.name))
return True
def open_frontend_cb(self):
@@ -64,14 +64,14 @@ class ResCompany(models.Model):
('l10n_fr_secure_sequence_number', '!=', 0)], order="l10n_fr_secure_sequence_number ASC")
if not orders:
msg_alert = (_('There isn\'t any order flagged for data inalterability yet for the company %s. This mechanism only runs for point of sale orders generated after the installation of the module France - Certification CGI 286 I-3 bis. - POS') % self.env.company.name)
msg_alert = (_('There isn\'t any order flagged for data inalterability yet for the company %s. This mechanism only runs for point of sale orders generated after the installation of the module France - Certification CGI 286 I-3 bis. - POS', self.env.company.name))
hash_verified = False
previous_hash = u''
start_order_info = []
for order in orders:
if order.l10n_fr_hash != order._compute_hash(previous_hash=previous_hash):
msg_alert = (_('Corrupted data on point of sale order with id %s.') % order.id)
msg_alert = (_('Corrupted data on point of sale order with id %s.', order.id))
hash_verified = False
break
previous_hash = order.l10n_fr_hash
@@ -102,7 +102,7 @@ class AccountMove(models.Model):
"""Reset E-Faktur, so it can be use for other invoice."""
for move in self:
if move.l10n_id_attachment_id:
raise UserError(_('You have already generated the tax report for this document: %s') % move.name)
raise UserError(_('You have already generated the tax report for this document: %s', move.name))
self.env['l10n_id_efaktur.efaktur.range'].push_number(move.company_id.id, move.l10n_id_tax_number[3:])
move.message_post(
body='e-Faktur Reset: %s ' % (move.l10n_id_tax_number),
@@ -83,13 +83,13 @@ class AccountEdiFormat(models.Model):
else:
company = self.env.company
if elements:
_logger.info(_('Company not found with codice fiscale: %s. The company\'s user is set by default.') % elements[0].text)
_logger.info(_('Company not found with codice fiscale: %s. The company\'s user is set by default.', elements[0].text))
else:
_logger.info(_('Company not found. The company\'s user is set by default.'))
if not self.env.is_superuser():
if self.env.company != company:
raise UserError(_("You can only import invoice concern your current company: %s") % self.env.company.display_name)
raise UserError(_("You can only import invoice concern your current company: %s", self.env.company.display_name))
# Refund type.
# TD01 == invoice
+1 -1
View File
@@ -168,7 +168,7 @@ class AccountMove(models.Model):
}
data = b"<?xml version='1.0' encoding='UTF-8'?>" + invoice._export_as_xml()
description = _('Italian invoice: %s') % invoice.move_type
description = _('Italian invoice: %s', invoice.move_type)
invoice.edi_document_ids = self.env['ir.attachment'].create({
'name': report_name,
'res_id': invoice.id,
@@ -156,7 +156,7 @@ class AccountMove(models.Model):
invoice_type = rec.move_type
if internal_type in ['debit_note', 'invoice'] and invoice_type in ['out_refund', 'in_refund'] and \
rec.l10n_latam_document_type_id.code != '99':
raise ValidationError(_('You can not use a %s document type with a refund invoice') % internal_type)
raise ValidationError(_('You can not use a %s document type with a refund invoice', internal_type))
elif internal_type == 'credit_note' and invoice_type in ['out_invoice', 'in_invoice']:
raise ValidationError(_('You can not use a %s document type with a invoice') % (internal_type))
+1 -1
View File
@@ -37,7 +37,7 @@ class MailController(http.Controller):
def _check_token_and_record_or_redirect(cls, model, res_id, token):
comparison = cls._check_token(token)
if not comparison:
_logger.warning(_('Invalid token in route %s') % request.httprequest.url)
_logger.warning(_('Invalid token in route %s', request.httprequest.url))
return comparison, None, cls._redirect_to_messaging()
try:
record = request.env[model].browse(res_id).exists()
+3 -1
View File
@@ -433,7 +433,9 @@ class MailActivity(models.Model):
record.message_notify(
partner_ids=activity.user_id.partner_id.ids,
body=body,
subject=_('%s: %s assigned to you') % (activity.res_name, activity.summary or activity.activity_type_id.name),
subject=_('%(activity_name)s: %(summary)s assigned to you',
activity_name=activity.res_name,
summary=activity.summary or activity.activity_type_id.name),
record_name=activity.res_name,
model_description=model_description,
email_layout_xmlid='mail.mail_notification_light',
+1 -1
View File
@@ -28,7 +28,7 @@ class MailBlackList(models.Model):
for value in values:
email = tools.email_normalize(value.get('email'))
if not email:
raise UserError(_('Invalid email address %r') % value['email'])
raise UserError(_('Invalid email address %r', value['email']))
if email in all_emails:
continue
all_emails.append(email)
+3 -3
View File
@@ -427,7 +427,7 @@ class Channel(models.Model):
'email_from': company.catchall_formatted or company.email_formatted,
'author_id': self.env.user.partner_id.id,
'body_html': view._render({'channel': self, 'partner': partner}, engine='ir.qweb', minimal_qcontext=True),
'subject': _("Guidelines of channel %s") % self.name,
'subject': _("Guidelines of channel %s", self.name),
'recipient_ids': [(4, partner.id)]
}
mail = self.env['mail.mail'].sudo().create(create_values)
@@ -976,7 +976,7 @@ class Channel(models.Model):
def _execute_command_help(self, **kwargs):
partner = self.env.user.partner_id
if self.channel_type == 'channel':
msg = _("You are in channel <b>#%s</b>.") % self.name
msg = _("You are in channel <b>#%s</b>.", self.name)
if self.public == 'private':
msg += _(" This channel is private. People must be invited to join it.")
else:
@@ -1016,6 +1016,6 @@ class Channel(models.Model):
msg = _("You are alone in this channel.")
else:
dots = "..." if len(members) != len(self.channel_partner_ids) - 1 else ""
msg = _("Users in this channel: %s %s and you.") % (", ".join(members), dots)
msg = _("Users in this channel: %(members)s %(dots)s and you.", members=", ".join(members), dots=dots)
self._send_transient_message(partner, msg)
+1 -1
View File
@@ -316,7 +316,7 @@ class MailRenderMixin(models.AbstractModel):
render_result = template.render(variables)
except Exception as e:
_logger.info("Failed to render template : %s" % e, exc_info=True)
raise UserError(_("Failed to render template : %s") % e)
raise UserError(_("Failed to render template : %s", e))
if render_result == u"False":
render_result = u""
results[record.id] = render_result
+3 -3
View File
@@ -74,7 +74,7 @@ class MailTemplate(models.Model):
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
default = dict(default or {},
name=_("%s (copy)") % self.name)
name=_("%s (copy)", self.name))
return super(MailTemplate, self).copy(default=default)
def unlink_action(self):
@@ -88,7 +88,7 @@ class MailTemplate(models.Model):
view = self.env.ref('mail.email_compose_message_wizard_form')
for template in self:
button_name = _('Send Mail (%s)') % template.name
button_name = _('Send Mail (%s)', template.name)
action = ActWindow.create({
'name': button_name,
'type': 'ir.actions.act_window',
@@ -200,7 +200,7 @@ class MailTemplate(models.Model):
else:
res = report._render([res_id])
if not res:
raise UserError(_('Unsupported report type %s found.') % report.report_type)
raise UserError(_('Unsupported report type %s found.', report.report_type))
result, format = res
# TODO in trunk, change return format to binary to match message_post expected format
+19 -9
View File
@@ -544,7 +544,7 @@ class MailThread(models.AbstractModel):
"""
self.ensure_one()
doc_name = self.env['ir.model']._get(self._name).name
return _('%s created') % doc_name
return _('%s created', doc_name)
def _track_subtype(self, init_values):
""" Give the subtypes triggered by the changes on the record according
@@ -671,7 +671,7 @@ class MailThread(models.AbstractModel):
def _routing_warn(self, error_message, message_id, route, raise_exception=True):
""" Tools method used in _routing_check_route: whether to log a warning or raise an error """
short_message = _("Mailbox unavailable - %s") % error_message
short_message = _("Mailbox unavailable - %s", error_message)
full_message = ('Routing mail with Message-Id %s: route %s: %s' %
(message_id, route, error_message))
_logger.info(full_message)
@@ -791,22 +791,27 @@ class MailThread(models.AbstractModel):
self._routing_warn(_('target model unspecified'), message_id, route, raise_exception)
return ()
elif model not in self.env:
self._routing_warn(_('unknown target model %s') % model, message_id, route, raise_exception)
self._routing_warn(_('unknown target model %s', model), message_id, route, raise_exception)
return ()
record_set = self.env[model].browse(thread_id) if thread_id else self.env[model]
# Existing Document: check if exists and model accepts the mailgateway; if not, fallback on create if allowed
if thread_id:
if not record_set.exists():
self._routing_warn(_('reply to missing document (%s,%s), fall back on document creation') % (model, thread_id), message_id, route, False)
self._routing_warn(
_('reply to missing document (%(model)s,%(thread)s), fall back on document creation', model=model, thread=thread_id),
message_id,
route,
False
)
thread_id = None
elif not hasattr(record_set, 'message_update'):
self._routing_warn(_('reply to model %s that does not accept document update, fall back on document creation') % model, message_id, route, False)
self._routing_warn(_('reply to model %s that does not accept document update, fall back on document creation', model), message_id, route, False)
thread_id = None
# New Document: check model accepts the mailgateway
if not thread_id and model and not hasattr(record_set, 'message_new'):
self._routing_warn(_('model %s does not accept document creation') % model, message_id, route, raise_exception)
self._routing_warn(_('model %s does not accept document creation', model), message_id, route, raise_exception)
return ()
# Update message author. We do it now because we need it for aliases (contact settings)
@@ -834,7 +839,12 @@ class MailThread(models.AbstractModel):
else:
error_code = self.env['mail.alias.mixin']._alias_check_contact_on_record(obj, message, message_dict, alias)
if error_code is not True:
self._routing_warn(_('alias %s: %s') % (alias.alias_name, error_code or _('unknown error')), message_id, route, False)
self._routing_warn(
_('alias %(name)s: %(error)s', name=alias.alias_name, error=error_code or _('unknown error')),
message_id,
route,
False
)
body = alias._get_alias_bounced_body(message_dict)
self._routing_create_bounce_email(email_from, body, message, references=message_id)
return False
@@ -2595,7 +2605,7 @@ class MailThread(models.AbstractModel):
access_link = self._notify_get_action_link('view')
if model_name:
view_title = _('View %s') % model_name
view_title = _('View %s', model_name)
else:
view_title = _('View')
@@ -2859,7 +2869,7 @@ class MailThread(models.AbstractModel):
assignation_msg = view._render(values, engine='ir.qweb', minimal_qcontext=True)
assignation_msg = self.env['mail.render.mixin']._replace_local_links(assignation_msg)
record.message_notify(
subject=_('You have been assigned to %s') % record.display_name,
subject=_('You have been assigned to %s', record.display_name),
body=assignation_msg,
partner_ids=partner_ids,
record_name=record.display_name,
+2 -2
View File
@@ -93,9 +93,9 @@ class MailBlackListMixin(models.AbstractModel):
def _assert_primary_email(self):
if not hasattr(self, "_primary_email") or not isinstance(self._primary_email, str):
raise UserError(_('Invalid primary email field on model %s') % self._name)
raise UserError(_('Invalid primary email field on model %s', self._name))
if self._primary_email not in self._fields or self._fields[self._primary_email].type != 'char':
raise UserError(_('Invalid primary email field on model %s') % self._name)
raise UserError(_('Invalid primary email field on model %s', self._name))
def _message_receive_bounce(self, email, partner):
""" Override of mail.thread generic method. Purpose is to increment the
+1 -1
View File
@@ -64,7 +64,7 @@ class Invite(models.TransientModel):
# send an email if option checked and if a message exists (do not send void emails)
if wizard.send_mail and wizard.message and not wizard.message == '<br>': # when deleting the message, cleditor keeps a <br>
message = self.env['mail.message'].create({
'subject': _('Invitation to follow %s: %s') % (model_name, document.display_name),
'subject': _('Invitation to follow %(document_model)s: %(document_name)s', document_model=model_name, document_name=document.display_name),
'body': wizard.message,
'record_name': document.display_name,
'email_from': email_from,
+1 -1
View File
@@ -223,7 +223,7 @@ class MaintenanceEquipment(models.Model):
def _create_new_request(self, date):
self.ensure_one()
self.env['maintenance.request'].create({
'name': _('Preventive Maintenance - %s') % self.name,
'name': _('Preventive Maintenance - %s', self.name),
'request_date': date,
'schedule_date': date,
'category_id': self.category_id.id,
+2 -2
View File
@@ -259,7 +259,7 @@ class MassMailing(models.Model):
def copy(self, default=None):
self.ensure_one()
default = dict(default or {},
name=_('%s (copy)') % self.name,
name=_('%s (copy)', self.name),
contact_list_ids=self.contact_list_ids.ids)
return super(MassMailing, self).copy(default=default)
@@ -469,7 +469,7 @@ class MassMailing(models.Model):
elif 'email' in target._fields:
mail_field = 'email'
else:
raise UserError(_("Unsupported mass mailing model %s") % self.mailing_model_id.name)
raise UserError(_("Unsupported mass mailing model %s", self.mailing_model_id.name))
if self.unique_ab_testing:
query +="""
@@ -171,7 +171,7 @@ class Mailing(models.Model):
if 'phone' in target._fields:
phone_fields.append('phone')
if not phone_fields:
raise UserError(_("Unsupported %s for mass SMS") % self.mailing_model_id.name)
raise UserError(_("Unsupported %s for mass SMS", self.mailing_model_id.name))
query = """
SELECT %(select_query)s
@@ -23,7 +23,7 @@ class MassSMSTest(models.TransientModel):
sanitized_numbers = [info['sanitized'] for info in sanitize_res.values() if info['sanitized']]
invalid_numbers = [number for number, info in sanitize_res.items() if info['code']]
if invalid_numbers:
raise exceptions.UserError(_('Following numbers are not correctly encoded: %s, example : "+32 495 85 85 77, +33 545 55 55 55"') % repr(invalid_numbers))
raise exceptions.UserError(_('Following numbers are not correctly encoded: %s, example : "+32 495 85 85 77, +33 545 55 55 55"', repr(invalid_numbers)))
self.env['sms.api']._send_sms_batch([{
'res_id': 0,
'number': number,
@@ -45,7 +45,7 @@ class SMSComposer(models.TransientModel):
trace_values['ignored'] = fields.Datetime.now()
else:
if self.mass_sms_allow_unsubscribe:
sms_values['body'] = '%s\n%s' % (sms_values['body'] or '', _('STOP SMS : %s') % self._get_unsubscribe_url(record.id, trace_code, sms_values['number']))
sms_values['body'] = '%s\n%s' % (sms_values['body'] or '', _('STOP SMS : %s', self._get_unsubscribe_url(record.id, trace_code, sms_values['number'])))
return trace_values
def _get_blacklist_record_ids(self, records, recipients_info):
+7 -5
View File
@@ -90,16 +90,18 @@ class MrpBom(models.Model):
for bom in self:
for bom_line in bom.bom_line_ids:
if bom.product_id and bom_line.product_id == bom.product_id:
raise ValidationError(_("BoM line product %s should not be the same as BoM product.") % bom.display_name)
raise ValidationError(_("BoM line product %s should not be the same as BoM product.", bom.display_name))
if bom.product_id and bom_line.bom_product_template_attribute_value_ids:
raise ValidationError(_("BoM cannot concern product %s and have a line with attributes (%s) at the same time.")
% (bom.product_id.display_name, ", ".join([ptav.display_name for ptav in bom_line.bom_product_template_attribute_value_ids])))
for ptav in bom_line.bom_product_template_attribute_value_ids:
if ptav.product_tmpl_id != bom.product_tmpl_id:
raise ValidationError(
_("The attribute value %s set on product %s does not match the BoM product %s.") %
(ptav.display_name, ptav.product_tmpl_id.display_name, bom_line.parent_product_tmpl_id.display_name)
)
raise ValidationError(_(
"The attribute value %(attribute)s set on product %(product)s does not match the BoM product %(bom_product)s.",
attribute=ptav.display_name,
product=ptav.product_tmpl_id.display_name,
bom_product=bom_line.parent_product_tmpl_id.display_name
))
@api.onchange('product_uom_id')
def onchange_product_uom_id(self):
+10 -6
View File
@@ -718,7 +718,7 @@ class MrpProduction(models.Model):
not_cancel = self.filtered(lambda m: m.state != 'cancel')
if not_cancel:
productions_name = ', '.join([prod.display_name for prod in not_cancel])
raise UserError(_('%s cannot be deleted. Try to cancel them before.') % productions_name)
raise UserError(_('%s cannot be deleted. Try to cancel them before.', productions_name))
workorders_to_delete = self.workorder_ids.filtered(lambda wo: wo.state != 'done')
if workorders_to_delete:
@@ -794,7 +794,7 @@ class MrpProduction(models.Model):
moves = []
for production in self:
if production.product_id in production.bom_id.byproduct_ids.mapped('product_id'):
raise UserError(_("You cannot have %s as the finished product and in the Byproducts") % self.product_id.name)
raise UserError(_("You cannot have %s as the finished product and in the Byproducts", self.product_id.name))
moves = [production._get_move_finished_values(production.product_id.id, production.product_qty, production.product_uom_id.id)]
for byproduct in production.bom_id.byproduct_ids:
product_uom_factor = production.product_uom_id._compute_quantity(production.product_qty, production.bom_id.product_uom_id)
@@ -1554,7 +1554,7 @@ class MrpProduction(models.Model):
def button_unbuild(self):
self.ensure_one()
return {
'name': _('Unbuild: %s') % self.product_id.display_name,
'name': _('Unbuild: %s', self.product_id.display_name),
'view_mode': 'form',
'res_model': 'mrp.unbuild',
'view_id': self.env.ref('mrp.mrp_unbuild_form_view_simplified').id,
@@ -1585,7 +1585,7 @@ class MrpProduction(models.Model):
('state', '=', 'done')
])
if sml:
raise UserError(_('This serial number for product %s has already been produced') % self.product_id.name)
raise UserError(_('This serial number for product %s has already been produced', self.product_id.name))
for move in self.move_finished_ids:
if move.has_tracking != 'serial' or move.product_id == self.product_id:
@@ -1596,7 +1596,9 @@ class MrpProduction(models.Model):
('qty_done', '=', 1),
('state', '=', 'done')
]
message = _('The serial number %s used for byproduct %s has already been produced') % (move_line.lot_id.name, move_line.product_id.name)
message = _('The serial number %(number)s used for byproduct %(product_name)s has already been produced',
number=move_line.lot_id.name,
product_name=move_line.product_id.name)
co_prod_move_lines = self.move_finished_ids.move_line_ids.filtered(lambda ml: ml.product_id != self.product_id)
domain_unbuild = domain + [
('production_id', '=', False),
@@ -1628,7 +1630,9 @@ class MrpProduction(models.Model):
('qty_done', '=', 1),
('state', '=', 'done')
]
message = _('The serial number %s used for component %s has already been consumed') % (move_line.lot_id.name, move_line.product_id.name)
message = _('The serial number %(number)s used for component %(component)s has already been consumed',
number=move_line.lot_id.name,
component=move_line.product_id.name)
co_prod_move_lines = self.move_raw_ids.move_line_ids
domain_unbuild = domain + [
('production_id', '=', False),
+9 -9
View File
@@ -175,9 +175,9 @@ class MrpWorkorder(models.Model):
if wo.state == 'pending' and prev_start and not (prev_start > wo.date_planned_start):
infos.append({
'color': 'text-primary',
'msg': _("Waiting the previous work order, planned from %s to %s") % (
format_datetime(self.env, prev_start, dt_format=False),
format_datetime(self.env, prev_finished, dt_format=False))
'msg': _("Waiting the previous work order, planned from %(start)s to %(end)s",
start=format_datetime(self.env, prev_start, dt_format=False),
end=format_datetime(self.env, prev_finished, dt_format=False))
})
if wo.date_planned_finished < fields.Datetime.now():
infos.append({
@@ -187,14 +187,14 @@ class MrpWorkorder(models.Model):
if prev_start and prev_start > wo.date_planned_start:
infos.append({
'color': 'text-danger',
'msg': _("Scheduled before the previous work order, planned from %s to %s") % (
format_datetime(self.env, prev_start, dt_format=False),
format_datetime(self.env, prev_finished, dt_format=False))
'msg': _("Scheduled before the previous work order, planned from %(start)s to %(end)s",
start=format_datetime(self.env, prev_start, dt_format=False),
end=format_datetime(self.env, prev_finished, dt_format=False))
})
if conflicted_dict.get(wo.id):
infos.append({
'color': 'text-danger',
'msg': _("Planned at the same time than other workorder(s) at %s" % wo.workcenter_id.display_name)
'msg': _("Planned at the same time than other workorder(s) at %s", wo.workcenter_id.display_name)
})
color_icon = infos and infos[-1]['color'] or False
wo.show_json_popover = bool(color_icon)
@@ -751,7 +751,7 @@ class MrpWorkorder(models.Model):
qty_done += line.product_uom_id._compute_quantity(line.qty_done, move.product_uom)
rounding = move.product_uom_id.rounding
if float_compare(qty_done, move.product_uom_qty, precision_rounding=rounding) != 0:
raise UserError(_('You should consume the quantity of %s defined in the BoM. If you want to consume more or less components, change the consumption setting on the BoM.') % move.product_id.name)
raise UserError(_('You should consume the quantity of %s defined in the BoM. If you want to consume more or less components, change the consumption setting on the BoM.', move.product_id.name))
def _check_sn_uniqueness(self):
""" Alert the user if the serial number as already been produced """
@@ -763,4 +763,4 @@ class MrpWorkorder(models.Model):
('state', '=', 'done')
])
if sml:
raise UserError(_('This serial number for product %s has already been produced') % self.product_id.name)
raise UserError(_('This serial number for product %s has already been produced', self.product_id.name))
+5 -1
View File
@@ -48,7 +48,11 @@ class ChangeProductionQty(models.TransientModel):
produced = sum(production.move_finished_ids.filtered(lambda m: m.product_id == production.product_id).mapped('quantity_done'))
if wizard.product_qty < produced:
format_qty = '%.{precision}f'.format(precision=precision)
raise UserError(_("You have already processed %s. Please input a quantity higher than %s ") % (format_qty % produced, format_qty % produced))
raise UserError(_(
"You have already processed %(quantity)s. Please input a quantity higher than %(minimum)s ",
quantity=format_qty % produced,
minimum=format_qty % produced
))
old_production_qty = production.product_qty
new_production_qty = wizard.product_qty
done_moves = production.move_finished_ids.filtered(lambda x: x.state == 'done' and x.product_id == production.product_id)
+1 -1
View File
@@ -159,7 +159,7 @@ class TxSips(models.Model):
payment_tx = self.search([('reference', '=', reference)])
if not payment_tx or len(payment_tx) > 1:
error_msg = _('Sips: received data for reference %s') % reference
error_msg = _('Sips: received data for reference %s', reference)
if not payment_tx:
error_msg += _('; no order found')
else:
+3 -3
View File
@@ -82,7 +82,7 @@ class PaymentAcquirerStripe(models.Model):
except HTTPError:
_logger.error(resp.text)
stripe_error = resp.json().get('error', {}).get('message', '')
error_msg = " " + (_("Stripe gave us the following info about the problem: '%s'") % stripe_error)
error_msg = " " + (_("Stripe gave us the following info about the problem: '%s'", stripe_error))
raise ValidationError(error_msg)
return resp.json()
@@ -249,11 +249,11 @@ class PaymentTransactionStripe(models.Model):
tx = self.search([('reference', '=', reference)])
if not tx:
error_msg = (_('Stripe: no order found for reference %s') % reference)
error_msg = _('Stripe: no order found for reference %s', reference)
_logger.error(error_msg)
raise ValidationError(error_msg)
elif len(tx) > 1:
error_msg = (_('Stripe: %s orders found for reference %s') % (len(tx), reference))
error_msg = _('Stripe: %(count)s orders found for reference %(reference)s', count=len(tx), reference=reference)
_logger.error(error_msg)
raise ValidationError(error_msg)
return tx[0]
@@ -106,9 +106,9 @@ class PhoneMixin(models.AbstractModel):
def _assert_phone_field(self):
if not hasattr(self, "_phone_get_number_fields"):
raise UserError(_('Invalid primary phone field on model %s') % self._name)
raise UserError(_('Invalid primary phone field on model %s', self._name))
if not any(fname in self and self._fields[fname].type == 'char' for fname in self._phone_get_number_fields()):
raise UserError(_('Invalid primary phone field on model %s') % self._name)
raise UserError(_('Invalid primary phone field on model %s', self._name))
def _phone_get_number_fields(self):
""" This method returns the fields to use to find the number to use to
@@ -17,12 +17,12 @@ try:
try:
phone_nbr = phonenumbers.parse(number, region=country_code, keep_raw_input=True)
except phonenumbers.phonenumberutil.NumberParseException as e:
raise UserError(_('Unable to parse %s.: %s') % (number, str(e)))
raise UserError(_('Unable to parse %(phone)s: %(error)s', phone=number, error=str(e)))
if not phonenumbers.is_possible_number(phone_nbr):
raise UserError(_('Impossible number %s: probably invalid number of digits.') % number)
raise UserError(_('Impossible number %s: probably invalid number of digits.', number))
if not phonenumbers.is_valid_number(phone_nbr):
raise UserError(_('Invalid number %s: probably incorrect prefix.') % number)
raise UserError(_('Invalid number %s: probably incorrect prefix.', number))
return phone_nbr
+2 -2
View File
@@ -459,7 +459,7 @@ class PosConfig(models.Model):
def create(self, values):
IrSequence = self.env['ir.sequence'].sudo()
val = {
'name': _('POS Order %s') % values['name'],
'name': _('POS Order %s', values['name']),
'padding': 4,
'prefix': "%s/" % values['name'],
'code': "pos.order",
@@ -468,7 +468,7 @@ class PosConfig(models.Model):
# force sequence_id field to new pos.order sequence
values['sequence_id'] = IrSequence.create(val).id
val.update(name=_('POS order line %s') % values['name'], code='pos.order.line')
val.update(name=_('POS order line %s', values['name']), code='pos.order.line')
values['sequence_line_id'] = IrSequence.create(val).id
pos_config = super(PosConfig, self).create(values)
pos_config.sudo()._check_modules_to_install()
+3 -3
View File
@@ -363,7 +363,7 @@ class PosOrder(models.Model):
total = float_round(self.amount_total, precision_rounding=self.config_id.rounding_method.rounding, rounding_method=self.config_id.rounding_method.rounding_method)
if not float_is_zero(total - self.amount_paid, precision_rounding=self.currency_id.rounding):
raise UserError(_("Order %s is not fully paid.") % self.name)
raise UserError(_("Order %s is not fully paid.", self.name))
self.write({'state': 'paid'})
@@ -479,7 +479,7 @@ class PosOrder(models.Model):
# order. It can be the same session, or if it has been closed the new one that has been opened.
current_session = order.session_id.config_id.current_session_id
if not current_session:
raise UserError(_('To return product(s), you need to open a session in the POS %s') % order.session_id.config_id.display_name)
raise UserError(_('To return product(s), you need to open a session in the POS %s', order.session_id.config_id.display_name))
refund_order = order.copy({
'name': order.name + _(' REFUND'),
'session_id': current_session.id,
@@ -533,7 +533,7 @@ class PosOrder(models.Model):
'mimetype': 'image/jpeg',
})
mail_values = {
'subject': _('Receipt %s') % name,
'subject': _('Receipt %s', name),
'body_html': message,
'author_id': self.env.user.partner_id.id,
'email_from': self.env.company.email or self.env.user.email_formatted,
+1 -1
View File
@@ -33,7 +33,7 @@ class PosPayment(models.Model):
res = []
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))))
res.append((payment.id, '%s %s' % (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
+1 -1
View File
@@ -111,7 +111,7 @@ class PortalChatter(http.Controller):
try:
CustomerPortal._document_check_access(self, 'ir.attachment', attachment_id, access_token)
except (AccessError, MissingError):
raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.") % attachment_id)
raise UserError(_("The attachment %s does not exist or you do not have the rights to access it.", attachment_id))
@http.route(['/mail/chatter_post'], type='http', methods=['POST'], auth='public', website=True)
def portal_chatter_post(self, res_model, res_id, message, redirect=None, attachment_ids='', attachment_tokens='', **kw):
+4 -4
View File
@@ -273,10 +273,10 @@ class CustomerPortal(Controller):
raise UserError(_("The attachment does not exist or you do not have the rights to access it."))
if attachment_sudo.res_model != 'mail.compose.message' or attachment_sudo.res_id != 0:
raise UserError(_("The attachment %s cannot be removed because it is not in a pending state.") % attachment_sudo.name)
raise UserError(_("The attachment %s cannot be removed because it is not in a pending state.", attachment_sudo.name))
if attachment_sudo.env['mail.message'].search([('attachment_ids', 'in', attachment_sudo.ids)]):
raise UserError(_("The attachment %s cannot be removed because it is linked to a message.") % attachment_sudo.name)
raise UserError(_("The attachment %s cannot be removed because it is linked to a message.", attachment_sudo.name))
return attachment_sudo.unlink()
@@ -364,12 +364,12 @@ class CustomerPortal(Controller):
def _show_report(self, model, report_type, report_ref, download=False):
if report_type not in ('html', 'pdf', 'text'):
raise UserError(_("Invalid report type: %s") % report_type)
raise UserError(_("Invalid report type: %s", report_type))
report_sudo = request.env.ref(report_ref).sudo()
if not isinstance(report_sudo, type(request.env['ir.actions.report'])):
raise UserError(_("%s is not the reference of a report") % report_ref)
raise UserError(_("%s is not the reference of a report", report_ref))
method_name = '_render_qweb_%s' % (report_type)
report = getattr(report_sudo, method_name)([model.id], data={'report_type': report_type})[0]
+5 -1
View File
@@ -28,7 +28,11 @@ class MailThread(models.AbstractModel):
self.ensure_one()
# check token field exists
if self._mail_post_token_field not in self._fields:
raise NotImplementedError(_("Model %s does not support token signature, as it does not have %s field.") % (self._name, self._mail_post_token_field))
raise NotImplementedError(_(
"Model %(model_name)s does not support token signature, as it does not have %(field_name)s field.",
model_name=self._name,
field_name=self._mail_post_token_field
))
# sign token
secret = self.env["ir.config_parameter"].sudo().get_param("database.secret")
token = (self.env.cr.dbname, self[self._mail_post_token_field], pid)
+1 -1
View File
@@ -17,7 +17,7 @@ class PosConfig(models.Model):
def _check_adyen_ask_customer_for_tip(self):
for config in self:
if config.adyen_ask_customer_for_tip and (not config.tip_product_id or not config.iface_tipproduct):
raise ValidationError(_("Please configure a tip product for POS %s to support tipping with Adyen.") % config.name)
raise ValidationError(_("Please configure a tip product for POS %s to support tipping with Adyen.", config.name))
@api.onchange('adyen_ask_customer_for_tip')
def _onchange_adyen_ask_customer_for_tip(self):
@@ -19,7 +19,7 @@ class MercuryTransaction(models.Model):
def _get_pos_session(self):
pos_session = self.env['pos.session'].search([('state', '=', 'opened'), ('user_id', '=', self.env.uid)], limit=1)
if not pos_session:
raise UserError(_("No opened point of sale session for user %s found.") % self.env.user.name)
raise UserError(_("No opened point of sale session for user %s found.", self.env.user.name))
pos_session.login()
+2 -2
View File
@@ -519,9 +519,9 @@ class PricelistItem(models.Model):
),
)
elif item.compute_price == 'percentage':
item.price = _("%s %% discount") % (item.percent_price)
item.price = _("%s %% discount", item.percent_price)
else:
item.price = _("%s %% discount and %s surcharge") % (item.price_discount, item.price_surcharge)
item.price = _("%(percentage)s %% discount and %(price)s surcharge", percentage=item.price_discount, price=item.price_surcharge)
@api.onchange('compute_price')
def _onchange_compute_price(self):
+1 -1
View File
@@ -436,7 +436,7 @@ class ProductTemplate(models.Model):
if default is None:
default = {}
if 'name' not in default:
default['name'] = _("%s (copy)") % self.name
default['name'] = _("%s (copy)", self.name)
return super(ProductTemplate, self).copy(default=default)
def name_get(self):
+2 -2
View File
@@ -639,7 +639,7 @@ class Task(models.Model):
portal_users = task.allowed_user_ids.filtered('share')
if portal_users:
user_names = ', '.join(portal_users[:10].mapped('name'))
raise ValidationError(_("The project visibility setting doesn't allow portal users to see the project's tasks. (%s)") % user_names)
raise ValidationError(_("The project visibility setting doesn't allow portal users to see the project's tasks. (%s)", user_names))
def _compute_attachment_ids(self):
for task in self:
@@ -752,7 +752,7 @@ class Task(models.Model):
if default is None:
default = {}
if not default.get('name'):
default['name'] = _("%s (copy)") % self.name
default['name'] = _("%s (copy)", self.name)
return super(Task, self).copy(default)
@api.constrains('parent_id')
+15 -5
View File
@@ -138,7 +138,12 @@ class PurchaseOrder(models.Model):
companies = order.order_line.product_id.company_id
if companies and companies != order.company_id:
bad_products = order.order_line.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id)
raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name')))))
raise ValidationError(_(
"Your quotation contains products from company %(product_company)s whereas your quotation belongs to company %(quote_company)s. \n Please change the company of your quotation or remove the products from other companies (%(bad_products)s).",
product_company=', '.join(companies.mapped('display_name')),
quote_company=order.company_id.display_name,
bad_products=', '.join(bad_products.mapped('display_name')),
))
def _compute_access_url(self):
super(PurchaseOrder, self)._compute_access_url()
@@ -284,7 +289,7 @@ class PurchaseOrder(models.Model):
# Block if partner only has warning but parent company is blocked
if partner.purchase_warn != 'block' and partner.parent_id and partner.parent_id.purchase_warn == 'block':
partner = partner.parent_id
title = _("Warning for %s") % partner.name
title = _("Warning for %s", partner.name)
message = partner.purchase_warn_msg
warning = {
'title': title,
@@ -721,9 +726,14 @@ class PurchaseOrder(models.Model):
def _compose_note(self, updated_dates):
"""Helper method for creating log note when user update scheduled date
on portal website."""
note = _('<p> %s modified receipt dates for the following products:</p>') % self.partner_id.name
note = _('<p> %s modified receipt dates for the following products:</p>', self.partner_id.name)
for line, date in updated_dates:
note += _('<p> &nbsp; - %s from %s to %s </p>') % (line.product_id.display_name, line.date_planned, date)
note += _(
'<p> &nbsp; - %(product_name)s from %(date_start)s to %(date_end)s </p>',
product_name=line.product_id.display_name,
date_start=line.date_planned,
date_end=date
)
return note
@@ -980,7 +990,7 @@ class PurchaseOrderLine(models.Model):
product_info = self.product_id
if product_info.purchase_line_warn != 'no-message':
title = _("Warning for %s") % product_info.name
title = _("Warning for %s", product_info.name)
message = product_info.purchase_line_warn_msg
warning['title'] = title
warning['message'] = message
@@ -89,7 +89,7 @@ class PurchaseRequisition(models.Model):
('company_id', '=', self.company_id.id),
])
if any(requisitions):
title = _("Warning for %s") % self.vendor_id.name
title = _("Warning for %s", self.vendor_id.name)
message = _("There is already an open blanket order for this supplier. We suggest you to use to complete this open blanket order instead of creating a new one.")
warning = {
'title': title,
@@ -115,7 +115,7 @@ class PurchaseRequisition(models.Model):
def action_in_progress(self):
self.ensure_one()
if not all(obj.line_ids for obj in self):
raise UserError(_("You cannot confirm agreement '%s' because there is no product line.") % self.name)
raise UserError(_("You cannot confirm agreement '%s' because there is no product line.", self.name))
if self.type_id.quantity_copy == 'none' and self.vendor_id:
for requisition_line in self.line_ids:
if requisition_line.price_unit <= 0.0:
+3 -3
View File
@@ -218,7 +218,7 @@ class PurchaseOrder(models.Model):
'partner_id': self.partner_id.id
})
if not self.partner_id.property_stock_supplier.id:
raise UserError(_("You must set a Vendor Location for this partner %s") % self.partner_id.name)
raise UserError(_("You must set a Vendor Location for this partner %s", self.partner_id.name))
return {
'picking_type_id': self.picking_type_id.id,
'partner_id': self.partner_id.id,
@@ -258,9 +258,9 @@ class PurchaseOrder(models.Model):
validated_picking = self.picking_ids.filtered(lambda p: p.state == 'done')
if validated_picking:
note += _("<p>Those dates couldn’t be modified accordingly on the receipt %s which had already been validated.</p>") % validated_picking.name
note += _("<p>Those dates couldn’t be modified accordingly on the receipt %s which had already been validated.</p>", validated_picking.name)
else:
note += _("<p>Those dates have been updated accordingly on the receipt %s.</p>") % self.picking_ids[0].name
note += _("<p>Those dates have been updated accordingly on the receipt %s.</p>", self.picking_ids[0].name)
for line, date in updated_dates:
date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S')
line._update_date_planned(date)
+2 -2
View File
@@ -360,7 +360,7 @@ class Repair(models.Model):
account = operation.product_id.product_tmpl_id._get_product_accounts()['income']
if not account:
raise UserError(_('No account defined for product "%s".') % operation.product_id.name)
raise UserError(_('No account defined for product "%s".', operation.product_id.name))
invoice_line_vals = {
'name': name,
@@ -402,7 +402,7 @@ class Repair(models.Model):
account = fee.product_id.product_tmpl_id._get_product_accounts()['income']
if not account:
raise UserError(_('No account defined for product "%s".') % fee.product_id.name)
raise UserError(_('No account defined for product "%s".', fee.product_id.name))
invoice_line_vals = {
'name': name,
+1 -1
View File
@@ -160,7 +160,7 @@ class ResourceCalendar(models.Model):
def default_get(self, fields):
res = super(ResourceCalendar, self).default_get(fields)
if not res.get('name') and res.get('company_id'):
res['name'] = _('Working Hours of %s') % self.env['res.company'].browse(res['company_id']).name
res['name'] = _('Working Hours of %s', self.env['res.company'].browse(res['company_id']).name)
if 'attendance_ids' in fields and not res.get('attendance_ids'):
res['attendance_ids'] = [
(0, 0, {'name': _('Monday Morning'), 'dayofweek': '0', 'hour_from': 8, 'hour_to': 12, 'day_period': 'morning'}),
+1 -1
View File
@@ -160,7 +160,7 @@ class CustomerPortal(CustomerPortal):
session_obj_date = request.session.get('view_quote_%s' % order_sudo.id)
if session_obj_date != now and request.env.user.share and access_token:
request.session['view_quote_%s' % order_sudo.id] = now
body = _('Quotation viewed by customer %s') % order_sudo.partner_id.name
body = _('Quotation viewed by customer %s', order_sudo.partner_id.name)
_message_post_helper(
"sale.order",
order_sudo.id,
+1 -1
View File
@@ -96,7 +96,7 @@ class AccountMove(models.Model):
for sale_line in line.sale_line_ids:
todo.add((sale_line.order_id, invoice.name))
for (order, name) in todo:
order.message_post(body=_("Invoice %s paid") % name)
order.message_post(body=_("Invoice %s paid", name))
return res
def _get_invoice_delivery_partner_id(self):
+1 -1
View File
@@ -83,7 +83,7 @@ class PaymentTransaction(models.Model):
order.amount_total, self.amount,
)
order.message_post(
subject=_("Amount Mismatch (%s)") % self.acquirer_id.provider,
subject=_("Amount Mismatch (%s)", self.acquirer_id.provider),
body=_("The order was not confirmed despite response from the acquirer (%s): order total is %r but acquirer replied with %r.") % (
self.acquirer_id.provider,
order.amount_total,
+8 -3
View File
@@ -263,7 +263,12 @@ class SaleOrder(models.Model):
companies = order.order_line.product_id.company_id
if companies and companies != order.company_id:
bad_products = order.order_line.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id)
raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name')))))
raise ValidationError(_(
"Your quotation contains products from company %(product_company)s whereas your quotation belongs to company %(quote_company)s. \n Please change the company of your quotation or remove the products from other companies (%(bad_products)s).",
product_company=', '.join(companies.mapped('display_name')),
quote_company=order.company_id.display_name,
bad_products=', '.join(bad_products.mapped('display_name')),
))
@api.depends('pricelist_id', 'date_order', 'company_id')
def _compute_currency_rate(self):
@@ -449,7 +454,7 @@ class SaleOrder(models.Model):
lines_to_update.append((1, line.id, {'price_unit': price_unit}))
self.update({'order_line': lines_to_update})
self.show_update_pricelist = False
self.message_post(body=_("Product prices have been recomputed according to pricelist <b>%s<b> ") % self.pricelist_id.display_name)
self.message_post(body=_("Product prices have been recomputed according to pricelist <b>%s<b> ", self.pricelist_id.display_name))
@api.model
def create(self, vals):
@@ -1595,7 +1600,7 @@ class SaleOrderLine(models.Model):
result = {}
warning = {}
if product.sale_line_warn != 'no-message':
title = _("Warning for %s") % product.name
title = _("Warning for %s", product.name)
message = product.sale_line_warn_msg
warning['title'] = title
warning['message'] = message
+5 -1
View File
@@ -25,7 +25,11 @@ class Coupon(models.Model):
message = {'error': _('This coupon is expired (%s).') % (self.code)}
# Minimum requirement should not be checked if the coupon got generated by a promotion program (the requirement should have only be checked to generate the coupon)
elif self.program_id.program_type == 'coupon_program' and not self.program_id._filter_on_mimimum_amount(order):
message = {'error': _('A minimum of %s %s should be purchased to get the reward') % (self.program_id.rule_minimum_amount, self.program_id.currency_id.name)}
message = {'error': _(
'A minimum of %(amount)s %(currency)s should be purchased to get the reward',
amount=self.program_id.rule_minimum_amount,
currency=self.program_id.currency_id.name
)}
elif not self.program_id.active:
message = {'error': _('The coupon program for %s is in draft or closed state') % (self.code)}
elif self.partner_id and self.partner_id != order.partner_id:
+5 -1
View File
@@ -34,7 +34,11 @@ class CouponProgram(models.Model):
if self.maximum_use_number != 0 and self.order_count >= self.maximum_use_number:
message = {'error': _('Promo code %s has been expired.') % (coupon_code)}
elif not self._filter_on_mimimum_amount(order):
message = {'error': _('A minimum of %s %s should be purchased to get the reward') % (self.rule_minimum_amount, self.currency_id.name)}
message = {'error': _(
'A minimum of %(amount)s %(currency)s should be purchased to get the reward',
amount=self.rule_minimum_amount,
currency=self.currency_id.name
)}
elif self.promo_code and self.promo_code == order.promo_code:
message = {'error': _('The promo code is already applied on this order')}
elif not self.promo_code and self in order.no_code_promo_program_ids:

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