[IMP] *: use named placeholders in translated message
When more than one parameter is present in a message, it helps the translation to use named placeholder. This way, the order can be changed. It also helps the comprehension of the message.
This commit is contained in:
@@ -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):
|
||||
|
||||
@@ -317,8 +317,11 @@ class AccountBankStatement(models.Model):
|
||||
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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)$')
|
||||
|
||||
@@ -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,7 +124,7 @@ 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)
|
||||
@@ -140,7 +140,7 @@ 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)
|
||||
else:
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -656,7 +656,11 @@ class Challenge(models.Model):
|
||||
|
||||
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.")
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -798,7 +798,12 @@ class MailThread(models.AbstractModel):
|
||||
# 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)
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -96,10 +96,12 @@ class MrpBom(models.Model):
|
||||
% (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):
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -253,7 +253,7 @@ class PaymentTransactionStripe(models.Model):
|
||||
_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]
|
||||
|
||||
@@ -17,7 +17,7 @@ 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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -521,7 +521,7 @@ class PricelistItem(models.Model):
|
||||
elif item.compute_price == 'percentage':
|
||||
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):
|
||||
|
||||
@@ -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()
|
||||
@@ -723,7 +728,12 @@ class PurchaseOrder(models.Model):
|
||||
on portal website."""
|
||||
note = _('<p> %s modified receipt dates for the following products:</p>', self.partner_id.name)
|
||||
for line, date in updated_dates:
|
||||
note += _('<p> - %s from %s to %s </p>') % (line.product_id.display_name, line.date_planned, date)
|
||||
note += _(
|
||||
'<p> - %(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
|
||||
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -35,7 +35,12 @@ class SaleOrder(models.Model):
|
||||
companies = order.sale_order_option_ids.product_id.company_id
|
||||
if companies and companies != order.company_id:
|
||||
bad_products = order.sale_order_option_ids.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.returns('self', lambda value: value.id)
|
||||
def copy(self, default=None):
|
||||
|
||||
@@ -37,7 +37,11 @@ class SaleOrderTemplate(models.Model):
|
||||
if len(companies) > 1:
|
||||
raise ValidationError(_("Your template cannot contain products from multiple companies."))
|
||||
elif companies and companies != template.company_id:
|
||||
raise ValidationError((_("Your template contains products from company %s whereas your template belongs to company %s. \n Please change the company of your template or remove the products from other companies.") % (companies.mapped('display_name'), template.company_id.display_name)))
|
||||
raise ValidationError(_(
|
||||
"Your template contains products from company %(product_company)s whereas your template belongs to company %(template_company)s. \n Please change the company of your template or remove the products from other companies.",
|
||||
product_company=', '.join(companies.mapped('display_name')),
|
||||
template_company=template.company_id.display_name,
|
||||
))
|
||||
|
||||
@api.onchange('sale_order_template_line_ids', 'sale_order_template_option_ids')
|
||||
def _onchange_template_line_ids(self):
|
||||
|
||||
@@ -584,7 +584,13 @@ class SaleOrderLine(models.Model):
|
||||
return {
|
||||
'warning': {
|
||||
'title': _('Warning'),
|
||||
'message': _("This product is packaged by %.2f %s. You should sell %.2f %s.") % (pack.qty, default_uom.name, newqty, self.product_uom.name),
|
||||
'message': _(
|
||||
"This product is packaged by %(pack_size).2f %(pack_name)s. You should sell %(quantity).2f %(unit)s.",
|
||||
pack_size=pack.qty,
|
||||
pack_name=default_uom.name,
|
||||
quantity=newqty,
|
||||
unit=self.product_uom.name
|
||||
),
|
||||
},
|
||||
}
|
||||
return {}
|
||||
|
||||
@@ -686,7 +686,7 @@ class Warehouse(models.Model):
|
||||
|
||||
def _get_inter_warehouse_route_values(self, supplier_warehouse):
|
||||
return {
|
||||
'name': _('%s: Supply Product from %s') % (self.name, supplier_warehouse.name),
|
||||
'name': _('%(warehouse)s: Supply Product from %(supplier)s', warehouse=self.name, supplier=supplier_warehouse.name),
|
||||
'warehouse_selectable': True,
|
||||
'product_selectable': True,
|
||||
'product_categ_selectable': True,
|
||||
|
||||
@@ -253,13 +253,25 @@ class ProductProduct(models.Model):
|
||||
'stock_valuation_layer_ids': [(6, None, [stock_valuation_layer.id])],
|
||||
'move_type': 'entry',
|
||||
'line_ids': [(0, 0, {
|
||||
'name': _('%s changed cost from %s to %s - %s') % (self.env.user.name, product.standard_price, new_price, product.display_name),
|
||||
'name': _(
|
||||
'%(user)s changed cost from %(previous)s to %(new_price)s - %(product)s',
|
||||
user=self.env.user.name,
|
||||
previous=product.standard_price,
|
||||
new_price=new_price,
|
||||
product=product.display_name
|
||||
),
|
||||
'account_id': debit_account_id,
|
||||
'debit': abs(value),
|
||||
'credit': 0,
|
||||
'product_id': product.id,
|
||||
}), (0, 0, {
|
||||
'name': _('%s changed cost from %s to %s - %s') % (self.env.user.name, product.standard_price, new_price, product.display_name),
|
||||
'name': _(
|
||||
'%(user)s changed cost from %(previous)s to %(new_price)s - %(product)s',
|
||||
user=self.env.user.name,
|
||||
previous=product.standard_price,
|
||||
new_price=new_price,
|
||||
product=product.display_name
|
||||
),
|
||||
'account_id': credit_account_id,
|
||||
'debit': 0,
|
||||
'credit': abs(value),
|
||||
|
||||
@@ -131,15 +131,23 @@ class StockValuationLayerRevaluation(models.TransientModel):
|
||||
'date': self.date or fields.Date.today(),
|
||||
'move_type': 'entry',
|
||||
'line_ids': [(0, 0, {
|
||||
'name': _('%s changed stock valuation from %s to %s of %s') % (
|
||||
self.env.user.name, self.current_value_svl, self.current_value_svl + self.added_value, product_id.display_name),
|
||||
'name': _('%(user)s changed stock valuation from %(previous)s to %(new_value)s - %(product)s',
|
||||
user=self.env.user.name,
|
||||
previous=self.current_value_svl,
|
||||
new_value=self.current_value_svl + self.added_value,
|
||||
product=product_id.display_name,
|
||||
),
|
||||
'account_id': debit_account_id,
|
||||
'debit': abs(self.added_value),
|
||||
'credit': 0,
|
||||
'product_id': product_id.id,
|
||||
}), (0, 0, {
|
||||
'name': _('%s changed stock valuation from %s to %s of %s') % (
|
||||
self.env.user.name, self.current_value_svl, self.current_value_svl + self.added_value, product_id.display_name),
|
||||
'name': _('%(user)s changed stock valuation from %(previous)s to %(new_value)s - %(product)s',
|
||||
user=self.env.user.name,
|
||||
previous=self.current_value_svl,
|
||||
new_value=self.current_value_svl + self.added_value,
|
||||
product=product_id.display_name,
|
||||
),
|
||||
'account_id': credit_account_id,
|
||||
'debit': 0,
|
||||
'credit': abs(self.added_value),
|
||||
|
||||
@@ -20,7 +20,11 @@ class WebsiteSaleStock(WebsiteSale):
|
||||
cart_qty = sum(order.order_line.filtered(lambda p: p.product_id.id == line.product_id.id).mapped('product_uom_qty'))
|
||||
avl_qty = line.product_id.with_context(warehouse=order.warehouse_id.id).virtual_available
|
||||
if cart_qty > avl_qty:
|
||||
values.append(_('You ask for %s products but only %s is available') % (cart_qty, avl_qty if avl_qty > 0 else 0))
|
||||
values.append(_(
|
||||
'You ask for %(quantity)s products but only %(available_qty)s is available',
|
||||
quantity=cart_qty,
|
||||
available_qty=avl_qty if avl_qty > 0 else 0
|
||||
))
|
||||
if values:
|
||||
raise ValidationError('. '.join(values) + '.')
|
||||
return super(WebsiteSaleStock, self).payment_transaction(**kwargs)
|
||||
|
||||
Reference in New Issue
Block a user