[MERGE] various: support batch creation in marketing apps
SPECIFICATIONS
By default, ORM supports creation of records in batch (one SQL INSERT by
record but batching other operations). When a create override on a given
model is specified as api.model or api.model_create_single this ability
is disabled and records are created one by one. This leads to performance
losses.
In this merge we update create to support batch creation. This allows to
gain performances linked to batch code improvements. Note that some of the
changes done in this merge will not have much impact because some records
are always created one by one. Converting them
* encourages new overrides to support multi record creation;
* provides the basis for a potential future API change to enforce batch
creation support;
LINKS
Task ID-2330149
COM PR odoo/odoo#61246
ENT PR odoo/enterprise#14561
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -67,15 +67,16 @@ class ResPartnerBank(models.Model):
|
||||
raise UserError(_("Cannot compute the BBAN because the account number is not an IBAN."))
|
||||
return get_bban_from_iban(self.acc_number)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('acc_number'):
|
||||
try:
|
||||
validate_iban(vals['acc_number'])
|
||||
vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number']))
|
||||
except ValidationError:
|
||||
pass
|
||||
return super(ResPartnerBank, self).create(vals)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('acc_number'):
|
||||
try:
|
||||
validate_iban(vals['acc_number'])
|
||||
vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number']))
|
||||
except ValidationError:
|
||||
pass
|
||||
return super(ResPartnerBank, self).create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
if vals.get('acc_number'):
|
||||
|
||||
@@ -9,8 +9,8 @@ class Board(models.AbstractModel):
|
||||
_description = "Board"
|
||||
_auto = False
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
return self
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -82,11 +82,11 @@ class CRMRevealRule(models.Model):
|
||||
(self._cr.dbname, 'res.partner', self.env.user.partner_id.id),
|
||||
{'type': 'simple_notification', 'title': _('Missing Library'), 'message': message, 'sticky': True, 'warning': True})
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
self.clear_caches() # Clear the cache in order to recompute _get_active_rules
|
||||
self._assert_geoip()
|
||||
return super(CRMRevealRule, self).create(vals)
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
fields_set = {
|
||||
|
||||
@@ -72,12 +72,13 @@ class Digest(models.Model):
|
||||
def _onchange_periodicity(self):
|
||||
self.next_run_date = self._get_next_run_date()
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
digest = super(Digest, self).create(vals)
|
||||
if not digest.next_run_date:
|
||||
digest.next_run_date = digest._get_next_run_date()
|
||||
return digest
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
digests = super().create(vals_list)
|
||||
for digest in digests:
|
||||
if not digest.next_run_date:
|
||||
digest.next_run_date = digest._get_next_run_date()
|
||||
return digests
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# ACTIONS
|
||||
|
||||
@@ -481,16 +481,18 @@ class EventEvent(models.Model):
|
||||
def _read_group_stage_ids(self, stages, domain, order):
|
||||
return self.env['event.stage'].search([])
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# Temporary fix for ``seats_limited`` and ``date_tz`` required fields (see ``_compute_from_event_type``
|
||||
vals.update(self._sync_required_computed(vals))
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
# Temporary fix for ``seats_limited`` and ``date_tz`` required fields (see ``_compute_from_event_type``
|
||||
vals.update(self._sync_required_computed(vals))
|
||||
|
||||
res = super(EventEvent, self).create(vals)
|
||||
if res.organizer_id:
|
||||
res.message_subscribe([res.organizer_id.id])
|
||||
res.flush()
|
||||
return res
|
||||
events = super(EventEvent, self).create(vals_list)
|
||||
for res in events:
|
||||
if res.organizer_id:
|
||||
res.message_subscribe([res.organizer_id.id])
|
||||
events.flush()
|
||||
return events
|
||||
|
||||
def write(self, vals):
|
||||
res = super(EventEvent, self).write(vals)
|
||||
|
||||
@@ -80,9 +80,9 @@ Example configuration for the postfix mta running locally:
|
||||
odoo_mailgate: "|/path/to/odoo-mailgate.py --host=localhost -u %(uid)d -p PASSWORD -d %(dbname)s"
|
||||
""" % conf
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
res = super(FetchmailServer, self).create(values)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
res = super(FetchmailServer, self).create(vals_list)
|
||||
self._update_cron()
|
||||
return res
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ class BadgeUser(models.Model):
|
||||
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
self.env['gamification.badge'].browse(vals['badge_id']).check_granting()
|
||||
return super(BadgeUser, self).create(vals)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
self.env['gamification.badge'].browse(vals['badge_id']).check_granting()
|
||||
return super().create(vals_list)
|
||||
|
||||
|
||||
class GamificationBadge(models.Model):
|
||||
|
||||
@@ -154,18 +154,18 @@ class Challenge(models.Model):
|
||||
|
||||
return template.id if template else False
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
"""Overwrite the create method to add the user of groups"""
|
||||
for vals in vals_list:
|
||||
if vals.get('user_domain'):
|
||||
users = self._get_challenger_users(ustr(vals.get('user_domain')))
|
||||
|
||||
if vals.get('user_domain'):
|
||||
users = self._get_challenger_users(ustr(vals.get('user_domain')))
|
||||
if not vals.get('user_ids'):
|
||||
vals['user_ids'] = []
|
||||
vals['user_ids'].extend((4, user.id) for user in users)
|
||||
|
||||
if not vals.get('user_ids'):
|
||||
vals['user_ids'] = []
|
||||
vals['user_ids'].extend((4, user.id) for user in users)
|
||||
|
||||
return super(Challenge, self).create(vals)
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
if vals.get('user_domain'):
|
||||
|
||||
@@ -122,14 +122,16 @@ class GoalDefinition(models.Model):
|
||||
error=e
|
||||
))
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
definition = super(GoalDefinition, self).create(vals)
|
||||
if definition.computation_mode in ('count', 'sum'):
|
||||
definition._check_domain_validity()
|
||||
if vals.get('field_id'):
|
||||
definition._check_model_validity()
|
||||
return definition
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
definitions = super(GoalDefinition, self).create(vals_list)
|
||||
definitions.filtered_domain([
|
||||
('computation_mode', 'in', ['count', 'sum']),
|
||||
])._check_domain_validity()
|
||||
definitions.filtered_domain([
|
||||
('field_id', '=', 'True'),
|
||||
])._check_model_validity()
|
||||
return definitions
|
||||
|
||||
def write(self, vals):
|
||||
res = super(GoalDefinition, self).write(vals)
|
||||
@@ -386,9 +388,9 @@ class Goal(models.Model):
|
||||
next goal update."""
|
||||
return self.write({'state': 'inprogress'})
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
return super(Goal, self.with_context(no_remind_goal=True)).create(vals)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
return super(Goal, self.with_context(no_remind_goal=True)).create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
"""Overwrite the write method to update the last_update field to today
|
||||
|
||||
@@ -34,11 +34,12 @@ class MailMessageSubtype(models.Model):
|
||||
})
|
||||
return department_subtype
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
result = super(MailMessageSubtype, self).create(vals)
|
||||
if result.res_model in ['hr.leave', 'hr.leave.allocation']:
|
||||
result._update_department_subtype()
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
result = super(MailMessageSubtype, self).create(vals_list)
|
||||
result.filtered(
|
||||
lambda st: st.res_model in ['hr.leave', 'hr.leave.allocation']
|
||||
)._update_department_subtype()
|
||||
return result
|
||||
|
||||
def write(self, vals):
|
||||
|
||||
@@ -23,14 +23,15 @@ class ResCompany(models.Model):
|
||||
return False
|
||||
return self.country_id and self.country_id.code in self._get_unalterable_country()
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
company = super(ResCompany, self).create(vals)
|
||||
#when creating a new french company, create the securisation sequence as well
|
||||
if company._is_accounting_unalterable():
|
||||
sequence_fields = ['l10n_fr_closing_sequence_id']
|
||||
company._create_secure_sequence(sequence_fields)
|
||||
return company
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
companies = super().create(vals_list)
|
||||
for company in companies:
|
||||
#when creating a new french company, create the securisation sequence as well
|
||||
if company._is_accounting_unalterable():
|
||||
sequence_fields = ['l10n_fr_closing_sequence_id']
|
||||
company._create_secure_sequence(sequence_fields)
|
||||
return companies
|
||||
|
||||
def write(self, vals):
|
||||
res = super(ResCompany, self).write(vals)
|
||||
|
||||
@@ -26,14 +26,15 @@ class ResCompany(models.Model):
|
||||
|
||||
l10n_fr_pos_cert_sequence_id = fields.Many2one('ir.sequence')
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
company = super(ResCompany, self).create(vals)
|
||||
#when creating a new french company, create the securisation sequence as well
|
||||
if company._is_accounting_unalterable():
|
||||
sequence_fields = ['l10n_fr_pos_cert_sequence_id']
|
||||
company._create_secure_sequence(sequence_fields)
|
||||
return company
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
companies = super().create(vals_list)
|
||||
for company in companies:
|
||||
#when creating a new french company, create the securisation sequence as well
|
||||
if company._is_accounting_unalterable():
|
||||
sequence_fields = ['l10n_fr_pos_cert_sequence_id']
|
||||
company._create_secure_sequence(sequence_fields)
|
||||
return companies
|
||||
|
||||
def write(self, vals):
|
||||
res = super(ResCompany, self).write(vals)
|
||||
|
||||
@@ -11,11 +11,11 @@ class IrConfigParameter(models.Model):
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('key') in ['mail.bounce.alias', 'mail.catchall.alias']:
|
||||
vals['value'] = self.env['mail.alias']._clean_and_check_unique(vals.get('value'))
|
||||
vals['value'] = self.env['mail.alias']._clean_and_check_unique([vals.get('value')])[0]
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
for parameter in self:
|
||||
if 'value' in vals and parameter.key in ['mail.bounce.alias', 'mail.catchall.alias'] and vals['value'] != parameter.value:
|
||||
vals['value'] = self.env['mail.alias']._clean_and_check_unique(vals.get('value'))
|
||||
vals['value'] = self.env['mail.alias']._clean_and_check_unique([vals.get('value')])[0]
|
||||
return super().write(vals)
|
||||
|
||||
@@ -346,34 +346,35 @@ class MailActivity(models.Model):
|
||||
# ORM overrides
|
||||
# ------------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
activity = super(MailActivity, self).create(values)
|
||||
need_sudo = False
|
||||
try: # in multicompany, reading the partner might break
|
||||
partner_id = activity.user_id.partner_id.id
|
||||
except exceptions.AccessError:
|
||||
need_sudo = True
|
||||
partner_id = activity.user_id.sudo().partner_id.id
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
activities = super(MailActivity, self).create(vals_list)
|
||||
for activity in activities:
|
||||
need_sudo = False
|
||||
try: # in multicompany, reading the partner might break
|
||||
partner_id = activity.user_id.partner_id.id
|
||||
except exceptions.AccessError:
|
||||
need_sudo = True
|
||||
partner_id = activity.user_id.sudo().partner_id.id
|
||||
|
||||
# send a notification to assigned user; in case of manually done activity also check
|
||||
# target has rights on document otherwise we prevent its creation. Automated activities
|
||||
# are checked since they are integrated into business flows that should not crash.
|
||||
if activity.user_id != self.env.user:
|
||||
if not activity.automated:
|
||||
activity._check_access_assignation()
|
||||
if not self.env.context.get('mail_activity_quick_update', False):
|
||||
if need_sudo:
|
||||
activity.sudo().action_notify()
|
||||
else:
|
||||
activity.action_notify()
|
||||
# send a notification to assigned user; in case of manually done activity also check
|
||||
# target has rights on document otherwise we prevent its creation. Automated activities
|
||||
# are checked since they are integrated into business flows that should not crash.
|
||||
if activity.user_id != self.env.user:
|
||||
if not activity.automated:
|
||||
activity._check_access_assignation()
|
||||
if not self.env.context.get('mail_activity_quick_update', False):
|
||||
if need_sudo:
|
||||
activity.sudo().action_notify()
|
||||
else:
|
||||
activity.action_notify()
|
||||
|
||||
self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[partner_id])
|
||||
if activity.date_deadline <= fields.Date.today():
|
||||
self.env['bus.bus'].sendone(
|
||||
(self._cr.dbname, 'res.partner', activity.user_id.partner_id.id),
|
||||
{'type': 'activity_updated', 'activity_created': True})
|
||||
return activity
|
||||
self.env[activity.res_model].browse(activity.res_id).message_subscribe(partner_ids=[partner_id])
|
||||
if activity.date_deadline <= fields.Date.today():
|
||||
self.env['bus.bus'].sendone(
|
||||
(self._cr.dbname, 'res.partner', activity.user_id.partner_id.id),
|
||||
{'type': 'activity_updated', 'activity_created': True})
|
||||
return activities
|
||||
|
||||
def write(self, values):
|
||||
if values.get('user_id'):
|
||||
|
||||
@@ -107,22 +107,34 @@ class Alias(models.Model):
|
||||
except Exception:
|
||||
raise ValidationError(_('Invalid expression, it must be a literal python dictionary definition e.g. "{\'field\': \'value\'}"'))
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
""" Creates an email.alias record according to the values provided in ``vals``,
|
||||
with 2 alterations: the ``alias_name`` value may be cleaned by replacing
|
||||
certain unsafe characters, and the ``alias_model_id`` value will set to the
|
||||
model ID of the ``model_name`` context value, if provided. Also, it raises
|
||||
UserError if given alias name is already assigned.
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
""" Creates email.alias records according to the values provided in
|
||||
``vals`` with 1 alteration:
|
||||
|
||||
* ``alias_name`` value may be cleaned by replacing certain unsafe
|
||||
characters;
|
||||
|
||||
:raise UserError: if given alias_name is already assigned or there are
|
||||
duplicates in given vals_list;
|
||||
"""
|
||||
if vals.get('alias_name'):
|
||||
vals['alias_name'] = self._clean_and_check_unique(vals.get('alias_name'))
|
||||
return super(Alias, self).create(vals)
|
||||
alias_names = [vals['alias_name'] for vals in vals_list if vals.get('alias_name')]
|
||||
if alias_names:
|
||||
sanitized_names = self._clean_and_check_unique(alias_names)
|
||||
for vals in vals_list:
|
||||
if vals.get('alias_name'):
|
||||
vals['alias_name'] = sanitized_names[alias_names.index(vals['alias_name'])]
|
||||
return super(Alias, self).create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
""""Raises UserError if given alias name is already assigned"""
|
||||
if vals.get('alias_name') and self.ids:
|
||||
vals['alias_name'] = self._clean_and_check_unique(vals.get('alias_name'))
|
||||
if len(self) > 1:
|
||||
raise UserError(_(
|
||||
'Email alias %(alias_name)s cannot be used on %(count)d records at the same time. Please update records one by one.',
|
||||
alias_name=vals['alias_name'], count=len(self)
|
||||
))
|
||||
vals['alias_name'] = self._clean_and_check_unique([vals.get('alias_name')])[0]
|
||||
return super(Alias, self).write(vals)
|
||||
|
||||
def name_get(self):
|
||||
@@ -140,22 +152,25 @@ class Alias(models.Model):
|
||||
res.append((record['id'], _("Inactive Alias")))
|
||||
return res
|
||||
|
||||
def _clean_and_check_unique(self, name):
|
||||
def _clean_and_check_unique(self, names):
|
||||
"""When an alias name appears to already be an email, we keep the local
|
||||
part only. A sanitizing / cleaning is also performed on the name. If
|
||||
name already exists an UserError is raised. """
|
||||
sanitized_name = remove_accents(name).lower().split('@')[0]
|
||||
sanitized_name = re.sub(r'[^\w+.]+', '-', sanitized_name)
|
||||
sanitized_name = sanitized_name.encode('ascii', errors='replace').decode()
|
||||
sanitized_names = []
|
||||
for name in names:
|
||||
sanitized_name = remove_accents(name).lower().split('@')[0]
|
||||
sanitized_name = re.sub(r'[^\w+.]+', '-', sanitized_name)
|
||||
sanitized_name = sanitized_name.encode('ascii', errors='replace').decode()
|
||||
sanitized_names.append(sanitized_name)
|
||||
|
||||
catchall_alias = self.env['ir.config_parameter'].sudo().get_param('mail.catchall.alias')
|
||||
bounce_alias = self.env['ir.config_parameter'].sudo().get_param('mail.bounce.alias')
|
||||
domain = [('alias_name', '=', sanitized_name)]
|
||||
domain = [('alias_name', 'in', sanitized_names)]
|
||||
if self:
|
||||
domain += [('id', 'not in', self.ids)]
|
||||
if sanitized_name in [catchall_alias, bounce_alias] or self.search_count(domain):
|
||||
if any(sanitized_name in [catchall_alias, bounce_alias] for sanitized_name in sanitized_names) or self.search_count(domain):
|
||||
raise UserError(_('The e-mail alias is already used. Please enter another one.'))
|
||||
return sanitized_name
|
||||
return sanitized_names
|
||||
|
||||
def open_document(self):
|
||||
if not self.alias_model_id or not self.alias_force_thread_id:
|
||||
|
||||
@@ -27,14 +27,29 @@ class AliasMixin(models.AbstractModel):
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
""" Create a record with each ``vals`` or ``vals_list`` and create a corresponding alias. """
|
||||
valid_vals_list = []
|
||||
# prepare all alias values
|
||||
alias_vals_list, record_vals_list = [], []
|
||||
for vals in vals_list:
|
||||
new_alias = not vals.get('alias_id')
|
||||
if new_alias:
|
||||
alias_vals, record_vals = self._alias_filter_fields(vals)
|
||||
alias_vals.update(self._alias_get_creation_values())
|
||||
alias = self.env['mail.alias'].sudo().create(alias_vals)
|
||||
record_vals['alias_id'] = alias.id
|
||||
alias_vals_list.append(alias_vals)
|
||||
record_vals_list.append(record_vals)
|
||||
|
||||
# create all aliases
|
||||
alias_ids = []
|
||||
if alias_vals_list:
|
||||
alias_ids = iter(self.env['mail.alias'].sudo().create(alias_vals_list).ids)
|
||||
|
||||
# update alias values in create vals directly
|
||||
valid_vals_list = []
|
||||
record_vals_iter = iter(record_vals_list)
|
||||
for vals in vals_list:
|
||||
new_alias = not vals.get('alias_id')
|
||||
if new_alias:
|
||||
record_vals = next(record_vals_iter)
|
||||
record_vals['alias_id'] = next(alias_ids)
|
||||
valid_vals_list.append(record_vals)
|
||||
else:
|
||||
valid_vals_list.append(vals)
|
||||
|
||||
@@ -204,26 +204,27 @@ class Channel(models.Model):
|
||||
else:
|
||||
self.moderator_ids |= self.env.user
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# ensure image at quick create
|
||||
if not vals.get('image_128'):
|
||||
defaults = self.default_get(['image_128'])
|
||||
vals['image_128'] = defaults['image_128']
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
defaults = self.default_get(['image_128'])
|
||||
for vals in vals_list:
|
||||
# ensure image at quick create
|
||||
if not vals.get('image_128'):
|
||||
vals['image_128'] = defaults['image_128']
|
||||
|
||||
# Create channel and alias
|
||||
channel = super(Channel, self.with_context(
|
||||
channels = super(Channel, self.with_context(
|
||||
mail_create_nolog=True, mail_create_nosubscribe=True)
|
||||
).create(vals)
|
||||
).create(vals_list)
|
||||
|
||||
if vals.get('group_ids'):
|
||||
channel._subscribe_users()
|
||||
channels._subscribe_users()
|
||||
|
||||
# make channel listen itself: posting on a channel notifies the channel
|
||||
if not self._context.get('mail_channel_noautofollow'):
|
||||
channel.message_subscribe(channel_ids=[channel.id])
|
||||
for channel in channels:
|
||||
channel.message_subscribe(channel_ids=[channel.id])
|
||||
|
||||
return channel
|
||||
return channels
|
||||
|
||||
def unlink(self):
|
||||
# Delete mail.channel
|
||||
@@ -266,13 +267,15 @@ class Channel(models.Model):
|
||||
def _subscribe_users(self):
|
||||
to_create = []
|
||||
for mail_channel in self:
|
||||
partners_to_add = mail_channel.group_ids.users.partner_id - mail_channel.channel_partner_ids
|
||||
to_create += [{
|
||||
'channel_id': mail_channel.id,
|
||||
'partner_id': partner.id,
|
||||
} for partner in partners_to_add]
|
||||
if mail_channel.group_ids:
|
||||
partners_to_add = mail_channel.group_ids.users.partner_id - mail_channel.channel_partner_ids
|
||||
to_create += [{
|
||||
'channel_id': mail_channel.id,
|
||||
'partner_id': partner.id,
|
||||
} for partner in partners_to_add]
|
||||
|
||||
self.env['mail.channel.partner'].create(to_create)
|
||||
if to_create:
|
||||
self.env['mail.channel.partner'].create(to_create)
|
||||
|
||||
def action_follow(self):
|
||||
self.ensure_one()
|
||||
|
||||
@@ -41,10 +41,10 @@ class MailMessageSubtype(models.Model):
|
||||
sequence = fields.Integer('Sequence', default=1, help="Used to order subtypes.")
|
||||
hidden = fields.Boolean('Hidden', help="Hide the subtype in the follower options")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
self.clear_caches()
|
||||
return super(MailMessageSubtype, self).create(vals)
|
||||
return super(MailMessageSubtype, self).create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
self.clear_caches()
|
||||
|
||||
@@ -293,13 +293,15 @@ class MassMailing(models.Model):
|
||||
# ORM
|
||||
# ------------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
if values.get('subject') and not values.get('name'):
|
||||
values['name'] = "%s %s" % (values['subject'], datetime.strftime(fields.datetime.now(), tools.DEFAULT_SERVER_DATETIME_FORMAT))
|
||||
if values.get('body_html'):
|
||||
values['body_html'] = self._convert_inline_images_to_urls(values['body_html'])
|
||||
return super(MassMailing, self).create(values)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
now = fields.Datetime.now()
|
||||
for values in vals_list:
|
||||
if values.get('subject') and not values.get('name'):
|
||||
values['name'] = "%s %s" % (values['subject'], now)
|
||||
if values.get('body_html'):
|
||||
values['body_html'] = self._convert_inline_images_to_urls(values['body_html'])
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, values):
|
||||
if values.get('body_html'):
|
||||
|
||||
@@ -27,15 +27,17 @@ class MassMailingContactListRel(models.Model):
|
||||
'A contact cannot be subscribed multiple times to the same list!')
|
||||
]
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if 'opt_out' in vals:
|
||||
vals['unsubscription_date'] = vals['opt_out'] and fields.Datetime.now()
|
||||
return super(MassMailingContactListRel, self).create(vals)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
now = fields.Datetime.now()
|
||||
for vals in vals_list:
|
||||
if 'opt_out' in vals:
|
||||
vals['unsubscription_date'] = now if vals['opt_out'] else False
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
if 'opt_out' in vals:
|
||||
vals['unsubscription_date'] = vals['opt_out'] and fields.Datetime.now()
|
||||
vals['unsubscription_date'] = fields.Datetime.now() if vals['opt_out'] else False
|
||||
return super(MassMailingContactListRel, self).write(vals)
|
||||
|
||||
|
||||
|
||||
@@ -325,11 +325,11 @@ class PaymentAcquirer(models.Model):
|
||||
journals += journal
|
||||
return journals
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
record = super(PaymentAcquirer, self).create(vals)
|
||||
record._check_required_if_provider()
|
||||
return record
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
records = super(PaymentAcquirer, self).create(vals_list)
|
||||
records._check_required_if_provider()
|
||||
return records
|
||||
|
||||
def write(self, vals):
|
||||
result = super(PaymentAcquirer, self).write(vals)
|
||||
|
||||
@@ -7,24 +7,28 @@ from odoo import api, models, _
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
new_company = super(ResCompany, self).create(vals)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
companies = super(ResCompany, self).create(vals_list)
|
||||
ProductPricelist = self.env['product.pricelist']
|
||||
pricelist = ProductPricelist.search([('currency_id', '=', new_company.currency_id.id), ('company_id', '=', False)], limit=1)
|
||||
if not pricelist:
|
||||
params = {'currency': new_company.currency_id.name}
|
||||
pricelist = ProductPricelist.create({
|
||||
'name': _("Default %(currency)s pricelist") % params,
|
||||
'currency_id': new_company.currency_id.id,
|
||||
})
|
||||
self.env['ir.property']._set_default(
|
||||
'property_product_pricelist',
|
||||
'res.partner',
|
||||
pricelist,
|
||||
new_company,
|
||||
)
|
||||
return new_company
|
||||
for new_company in companies:
|
||||
pricelist = ProductPricelist.search([
|
||||
('currency_id', '=', new_company.currency_id.id),
|
||||
('company_id', '=', False)
|
||||
], limit=1)
|
||||
if not pricelist:
|
||||
params = {'currency': new_company.currency_id.name}
|
||||
pricelist = ProductPricelist.create({
|
||||
'name': _("Default %(currency)s pricelist") % params,
|
||||
'currency_id': new_company.currency_id.id,
|
||||
})
|
||||
self.env['ir.property']._set_default(
|
||||
'property_product_pricelist',
|
||||
'res.partner',
|
||||
pricelist,
|
||||
new_company,
|
||||
)
|
||||
return companies
|
||||
|
||||
def write(self, values):
|
||||
# When we modify the currency of the company, we reflect the change on the list0 pricelist, if
|
||||
|
||||
@@ -125,11 +125,12 @@ class Rating(models.Model):
|
||||
else:
|
||||
rating.rating_text = 'no_rating'
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
if values.get('res_model_id') and values.get('res_id'):
|
||||
values.update(self._find_parent_data(values))
|
||||
return super(Rating, self).create(values)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for values in vals_list:
|
||||
if values.get('res_model_id') and values.get('res_id'):
|
||||
values.update(self._find_parent_data(values))
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, values):
|
||||
if values.get('res_model_id') and values.get('res_id'):
|
||||
|
||||
@@ -85,12 +85,11 @@ class CrmTeam(models.Model):
|
||||
# CRUD
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
team = super(CrmTeam, self.with_context(mail_create_nosubscribe=True)).create(values)
|
||||
if values.get('member_ids'):
|
||||
team._add_members_to_favorites()
|
||||
return team
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
teams = super(CrmTeam, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
|
||||
teams.filtered(lambda t: t.member_ids)._add_members_to_favorites()
|
||||
return teams
|
||||
|
||||
def write(self, values):
|
||||
res = super(CrmTeam, self).write(values)
|
||||
|
||||
@@ -77,35 +77,40 @@ class SnailmailLetter(models.Model):
|
||||
for res in self:
|
||||
res.reference = "%s,%s" % (res.model, res.res_id)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
msg_id = self.env[vals['model']].browse(vals['res_id']).message_post(
|
||||
body=_("Letter sent by post with Snailmail"),
|
||||
message_type='snailmail'
|
||||
)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
msg_id = self.env[vals['model']].browse(vals['res_id']).message_post(
|
||||
body=_("Letter sent by post with Snailmail"),
|
||||
message_type='snailmail',
|
||||
)
|
||||
|
||||
partner_id = self.env['res.partner'].browse(vals['partner_id'])
|
||||
vals.update({
|
||||
'message_id': msg_id.id,
|
||||
'street': partner_id.street,
|
||||
'street2': partner_id.street2,
|
||||
'zip': partner_id.zip,
|
||||
'city': partner_id.city,
|
||||
'state_id': partner_id.state_id.id,
|
||||
'country_id': partner_id.country_id.id,
|
||||
})
|
||||
letter = super(SnailmailLetter, self).create(vals)
|
||||
partner_id = self.env['res.partner'].browse(vals['partner_id'])
|
||||
vals.update({
|
||||
'message_id': msg_id.id,
|
||||
'street': partner_id.street,
|
||||
'street2': partner_id.street2,
|
||||
'zip': partner_id.zip,
|
||||
'city': partner_id.city,
|
||||
'state_id': partner_id.state_id.id,
|
||||
'country_id': partner_id.country_id.id,
|
||||
})
|
||||
letters = super().create(vals_list)
|
||||
|
||||
self.env['mail.notification'].sudo().create({
|
||||
'mail_message_id': msg_id.id,
|
||||
'res_partner_id': partner_id.id,
|
||||
'notification_type': 'snail',
|
||||
'letter_id': letter.id,
|
||||
'is_read': True, # discard Inbox notification
|
||||
'notification_status': 'ready',
|
||||
})
|
||||
notification_vals = []
|
||||
for letter in letters:
|
||||
notification_vals.append({
|
||||
'mail_message_id': letter.message_id.id,
|
||||
'res_partner_id': letter.partner_id.id,
|
||||
'notification_type': 'snail',
|
||||
'letter_id': letter.id,
|
||||
'is_read': True, # discard Inbox notification
|
||||
'notification_status': 'ready',
|
||||
})
|
||||
|
||||
return letter
|
||||
self.env['mail.notification'].sudo().create(notification_vals)
|
||||
|
||||
return letters
|
||||
|
||||
def _fetch_attachment(self):
|
||||
"""
|
||||
|
||||
@@ -149,15 +149,16 @@ class SurveyInvite(models.TransientModel):
|
||||
invite.subject = invite.template_id.subject
|
||||
invite.body = invite.template_id.body_html
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
if values.get('template_id') and not (values.get('body') or values.get('subject')):
|
||||
template = self.env['mail.template'].browse(values['template_id'])
|
||||
if not values.get('subject'):
|
||||
values['subject'] = template.subject
|
||||
if not values.get('body'):
|
||||
values['body'] = template.body_html
|
||||
return super(SurveyInvite, self).create(values)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for values in vals_list:
|
||||
if values.get('template_id') and not (values.get('body') or values.get('subject')):
|
||||
template = self.env['mail.template'].browse(values['template_id'])
|
||||
if not values.get('subject'):
|
||||
values['subject'] = template.subject
|
||||
if not values.get('body'):
|
||||
values['body'] = template.body_html
|
||||
return super().create(vals_list)
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Wizard validation and send
|
||||
|
||||
@@ -755,13 +755,13 @@ class Base(models.AbstractModel):
|
||||
class ResCompany(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
res = super().create(values)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
companies = super().create(vals_list)
|
||||
style_fields = {'external_report_layout_id', 'font', 'primary_color', 'secondary_color'}
|
||||
if not style_fields.isdisjoint(values):
|
||||
if any(not style_fields.isdisjoint(values) for values in vals_list):
|
||||
self._update_asset_style()
|
||||
return res
|
||||
return companies
|
||||
|
||||
def write(self, values):
|
||||
res = super().write(values)
|
||||
|
||||
@@ -158,11 +158,11 @@ class Event(models.Model):
|
||||
# CRUD
|
||||
# ------------------------------------------------------------
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
res = super(Event, self).create(vals)
|
||||
res._update_website_menus()
|
||||
return res
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
events = super().create(vals_list)
|
||||
events._update_website_menus()
|
||||
return events
|
||||
|
||||
def write(self, vals):
|
||||
menus_state_by_field = self._split_menus_state_by_field()
|
||||
|
||||
@@ -180,11 +180,14 @@ class Forum(models.Model):
|
||||
def _set_default_faq(self):
|
||||
self.faq = self.env['ir.ui.view']._render_template('website_forum.faq_accordion', {"forum": self}).decode('utf-8')
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
res = super(Forum, self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)).create(values)
|
||||
res._set_default_faq() # will trigger a write and call update_website_count
|
||||
return res
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
forums = super(
|
||||
Forum,
|
||||
self.with_context(mail_create_nolog=True, mail_create_nosubscribe=True)
|
||||
).create(vals_list)
|
||||
forums._set_default_faq() # will trigger a write and call update_website_count
|
||||
return forums
|
||||
|
||||
def write(self, vals):
|
||||
if 'privacy' in vals:
|
||||
|
||||
@@ -33,12 +33,11 @@ class Channel(models.Model):
|
||||
for channel in self:
|
||||
channel.product_sale_revenues = rg_data.get(channel.product_id.id, 0)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
channel = super(Channel, self).create(vals)
|
||||
if channel.enroll == 'payment':
|
||||
channel._synchronize_product_publish()
|
||||
return channel
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
channels = super(Channel, self).create(vals_list)
|
||||
channels.filtered(lambda channel: channel.enroll == 'payment')._synchronize_product_publish()
|
||||
return channels
|
||||
|
||||
def write(self, vals):
|
||||
res = super(Channel, self).write(vals)
|
||||
@@ -47,6 +46,8 @@ class Channel(models.Model):
|
||||
return res
|
||||
|
||||
def _synchronize_product_publish(self):
|
||||
if not self:
|
||||
return
|
||||
self.filtered(lambda channel: channel.is_published and not channel.product_id.is_published).sudo().product_id.write({'is_published': True})
|
||||
self.filtered(lambda channel: not channel.is_published and channel.product_id.is_published).sudo().product_id.write({'is_published': False})
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@ from odoo import api, models
|
||||
class Users(models.Model):
|
||||
_inherit = 'res.users'
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
""" Trigger automatic subscription based on user groups """
|
||||
user = super(Users, self).create(values)
|
||||
self.env['slide.channel'].sudo().search([('enroll_group_ids', 'in', user.groups_id.ids)])._action_add_members(user.partner_id)
|
||||
return user
|
||||
users = super(Users, self).create(vals_list)
|
||||
for user in users:
|
||||
self.env['slide.channel'].sudo().search([
|
||||
('enroll_group_ids', 'in', user.groups_id.ids)
|
||||
])._action_add_members(user.partner_id)
|
||||
return users
|
||||
|
||||
def write(self, vals):
|
||||
""" Trigger automatic subscription based on updated user groups """
|
||||
|
||||
@@ -35,8 +35,9 @@ class SlidePartnerRelation(models.Model):
|
||||
completed = fields.Boolean('Completed')
|
||||
quiz_attempts_count = fields.Integer('Quiz attempts count', default=0)
|
||||
|
||||
def create(self, values):
|
||||
res = super(SlidePartnerRelation, self).create(values)
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
res = super().create(vals_list)
|
||||
completed = res.filtered('completed')
|
||||
if completed:
|
||||
completed._set_completed_callback()
|
||||
|
||||
@@ -25,12 +25,11 @@ class Channel(models.Model):
|
||||
|
||||
return action
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
channel = super(Channel, self.with_context(mail_create_nosubscribe=True)).create(vals)
|
||||
if channel.forum_id:
|
||||
channel.forum_id.privacy = False
|
||||
return channel
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
channels = super(Channel, self.with_context(mail_create_nosubscribe=True)).create(vals_list)
|
||||
channels.forum_id.privacy = False
|
||||
return channels
|
||||
|
||||
def write(self, vals):
|
||||
old_forum = self.forum_id
|
||||
|
||||
Reference in New Issue
Block a user