diff --git a/addons/hr/models/hr_plan.py b/addons/hr/models/hr_plan.py
index c1d897e9d38..dd45a280a6f 100644
--- a/addons/hr/models/hr_plan.py
+++ b/addons/hr/models/hr_plan.py
@@ -13,7 +13,8 @@ class HrPlanActivityType(models.Model):
activity_type_id = fields.Many2one(
'mail.activity.type', 'Activity Type',
default=lambda self: self.env.ref('mail.mail_activity_data_todo'),
- domain=lambda self: ['|', ('res_model_id', '=', False), ('res_model_id', '=', self.env['ir.model']._get('hr.employee').id)]
+ domain=lambda self: ['|', ('res_model_id', '=', False), ('res_model_id', '=', self.env['ir.model']._get('hr.employee').id)],
+ ondelete='restrict'
)
summary = fields.Char('Summary')
responsible = fields.Selection([
diff --git a/addons/hr/wizard/hr_plan_wizard.py b/addons/hr/wizard/hr_plan_wizard.py
index 7dc74bbb035..c0f2d663e4c 100644
--- a/addons/hr/wizard/hr_plan_wizard.py
+++ b/addons/hr/wizard/hr_plan_wizard.py
@@ -24,14 +24,12 @@ class HrPlanWizard(models.TransientModel):
responsible = activity_type.get_responsible_id(self.employee_id)
if self.env['hr.employee'].with_user(responsible).check_access_rights('read', raise_exception=False):
- self.env['mail.activity'].create({
- 'res_id': self.employee_id.id,
- 'res_model_id': self.env['ir.model']._get('hr.employee').id,
- 'summary': activity_type.summary,
- 'note': activity_type.note,
- 'activity_type_id': activity_type.activity_type_id.id,
- 'user_id': responsible.id,
- })
+ self.employee_id.activity_schedule(
+ activity_type_id=activity_type.activity_type_id.id,
+ summary=activity_type.summary,
+ note=activity_type.note,
+ user_id=responsible.id
+ )
return {
'type': 'ir.actions.act_window',
diff --git a/addons/l10n_it_edi/models/ir_mail_server.py b/addons/l10n_it_edi/models/ir_mail_server.py
index 2674cfba5bf..8df9763f147 100644
--- a/addons/l10n_it_edi/models/ir_mail_server.py
+++ b/addons/l10n_it_edi/models/ir_mail_server.py
@@ -244,11 +244,10 @@ class FetchmailServer(models.Model):
related_invoice.message_post(
body=(_("Errors in the E-Invoice :
%s") % (error))
)
- activity_vals = {
- 'activity_type_id': self.env.ref('mail.mail_activity_data_todo').id,
- 'invoice_user_id': related_invoice.invoice_user_id.id if related_invoice.invoice_user_id else self.env.user.id
- }
- related_invoice.activity_schedule(summary='Rejection notice', **activity_vals)
+ related_invoice.activity_schedule(
+ 'mail.mail_activity_data_todo',
+ summary='Rejection notice',
+ user_id=related_invoice.invoice_user_id.id if related_invoice.invoice_user_id else self.env.user.id)
elif receipt_type == 'MC':
# Failed delivery notice
@@ -304,11 +303,10 @@ class FetchmailServer(models.Model):
body=(_("Outcome notice: %s
%s") % (related_invoice.l10n_it_send_state, info))
)
if related_invoice.l10n_it_send_state == 'delivered_refused':
- activity_vals = {
- 'activity_type_id': self.env.ref('mail.mail_activity_data_todo').id,
- 'invoice_user_id': related_invoice.invoice_user_id.id if related_invoice.invoice_user_id else self.env.user.id
- }
- related_invoice.activity_schedule(summary='Outcome notice: Refused', **activity_vals)
+ related_invoice.activity_schedule(
+ 'mail.mail_activity_todo',
+ user_id=related_invoice.invoice_user_id.id if related_invoice.invoice_user_id else self.env.user.id,
+ summary='Outcome notice: Refused')
# elif receipt_type == 'MT':
# Metadata file
diff --git a/addons/mail/models/ir_actions.py b/addons/mail/models/ir_actions.py
index ef9495f52fd..22a39a29164 100644
--- a/addons/mail/models/ir_actions.py
+++ b/addons/mail/models/ir_actions.py
@@ -29,7 +29,8 @@ class ServerActions(models.Model):
# Next Activity
activity_type_id = fields.Many2one(
'mail.activity.type', string='Activity',
- domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', model_id)]")
+ domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', model_id)]",
+ ondelete='restrict')
activity_summary = fields.Char('Summary')
activity_note = fields.Html('Note')
activity_date_deadline_range = fields.Integer(string='Due Date In')
diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py
index 8fc502ee6de..55e2db647bd 100644
--- a/addons/mail/models/mail_activity.py
+++ b/addons/mail/models/mail_activity.py
@@ -59,7 +59,7 @@ class MailActivityType(models.Model):
help='Specify a model if the activity should be specific to a model'
' and not available when managing activities for other models.')
default_next_type_id = fields.Many2one('mail.activity.type', 'Default Next Activity',
- domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', res_model_id)]")
+ domain="['|', ('res_model_id', '=', False), ('res_model_id', '=', res_model_id)]", ondelete='restrict')
force_next = fields.Boolean("Trigger Next Activity", default=False)
next_type_ids = fields.Many2many(
'mail.activity.type', 'mail_activity_rel', 'activity_id', 'recommended_id',
@@ -91,11 +91,6 @@ class MailActivityType(models.Model):
for activity_type in self:
activity_type.initial_res_model_id = activity_type.res_model_id
- def unlink(self):
- if any(self.get_external_id().values()) and not self._context.get(MODULE_UNINSTALL_FLAG):
- raise exceptions.ValidationError("You can not delete activity type that are used as master data.")
- return super(MailActivityType, self).unlink()
-
class MailActivity(models.Model):
""" An actual activity to perform. Activities are linked to
@@ -575,6 +570,16 @@ class MailActivityMixin(models.AbstractModel):
_name = 'mail.activity.mixin'
_description = 'Activity Mixin'
+ def _default_activity_type(self):
+ """Define a default fallback activity type when requested xml id wasn't found.
+
+ Can be overriden to specify the default activity type of a model.
+ It is only called in in activity_schedule() for now.
+ """
+ return self.env.ref('mail.mail_activity_data_todo', raise_if_not_found=False) \
+ or self.env['mail.activity.type'].search([('res_model', '=', self._name)], limit=1) \
+ or self.env['mail.activity.type'].search([('res_model_id', '=', False)], limit=1)
+
activity_ids = fields.One2many(
'mail.activity', 'res_id', 'Activities',
auto_join=True,
@@ -732,15 +737,16 @@ class MailActivityMixin(models.AbstractModel):
if isinstance(date_deadline, datetime):
_logger.warning("Scheduled deadline should be a date (got %s)", date_deadline)
if act_type_xmlid:
- activity_type = self.sudo().env.ref(act_type_xmlid)
+ activity_type = self.env.ref(act_type_xmlid, raise_if_not_found=False) or self._default_activity_type()
else:
- activity_type = self.env['mail.activity.type'].sudo().browse(act_values['activity_type_id'])
+ activity_type_id = act_values.get('activity_type_id', False)
+ activity_type = activity_type_id and self.env['mail.activity.type'].sudo().browse(activity_type_id)
model_id = self.env['ir.model']._get(self._name).id
activities = self.env['mail.activity']
for record in self:
create_vals = {
- 'activity_type_id': activity_type.id,
+ 'activity_type_id': activity_type and activity_type.id,
'summary': summary or activity_type.summary,
'automated': True,
'note': note or activity_type.default_description,
@@ -792,7 +798,10 @@ class MailActivityMixin(models.AbstractModel):
return False
Data = self.env['ir.model.data'].sudo()
- activity_types_ids = [Data.xmlid_to_res_id(xmlid) for xmlid in act_type_xmlids]
+ activity_types_ids = [Data.xmlid_to_res_id(xmlid, raise_if_not_found=False) for xmlid in act_type_xmlids]
+ activity_types_ids = [act_type_id for act_type_id in activity_types_ids if act_type_id]
+ if not any(activity_types_ids):
+ return False
domain = [
'&', '&', '&',
('res_model', '=', self._name),
@@ -819,7 +828,10 @@ class MailActivityMixin(models.AbstractModel):
return False
Data = self.env['ir.model.data'].sudo()
- activity_types_ids = [Data.xmlid_to_res_id(xmlid) for xmlid in act_type_xmlids]
+ activity_types_ids = [Data.xmlid_to_res_id(xmlid, raise_if_not_found=False) for xmlid in act_type_xmlids]
+ activity_types_ids = [act_type_id for act_type_id in activity_types_ids if act_type_id]
+ if not any(activity_types_ids):
+ return False
domain = [
'&', '&', '&',
('res_model', '=', self._name),
@@ -841,7 +853,10 @@ class MailActivityMixin(models.AbstractModel):
return False
Data = self.env['ir.model.data'].sudo()
- activity_types_ids = [Data.xmlid_to_res_id(xmlid) for xmlid in act_type_xmlids]
+ activity_types_ids = [Data.xmlid_to_res_id(xmlid, raise_if_not_found=False) for xmlid in act_type_xmlids]
+ activity_types_ids = [act_type_id for act_type_id in activity_types_ids if act_type_id]
+ if not any(activity_types_ids):
+ return False
domain = [
'&', '&', '&',
('res_model', '=', self._name),
diff --git a/addons/note/controllers/note.py b/addons/note/controllers/note.py
index bdcf2e85059..6cafea730cf 100644
--- a/addons/note/controllers/note.py
+++ b/addons/note/controllers/note.py
@@ -12,16 +12,9 @@ class NoteController(http.Controller):
""" Route to create note and their activity directly from the systray """
note = request.env['note.note'].create({'memo': note})
if date_deadline:
- activity_values = {
- 'note': note.memo,
- 'date_deadline': date_deadline,
- 'res_model_id': request.env.ref("note.model_note_note").id,
- 'res_id': note.id,
- 'note_id': note.id,
- }
- if not activity_type_id:
- activity_type_id = request.env['mail.activity.type'].sudo().search([('category', '=', 'reminder')], limit=1).id
- if activity_type_id:
- activity_values['activity_type_id'] = activity_type_id
- request.env['mail.activity'].create(activity_values)
+ note.activity_schedule(
+ activity_type_id=activity_type_id or request.env['mail.activity.type'].sudo().search([('category', '=', 'reminder')], limit=1).id,
+ note=note.memo,
+ date_deadline=date_deadline
+ )
return note.id
diff --git a/addons/purchase_stock/models/purchase.py b/addons/purchase_stock/models/purchase.py
index d697538db9f..7616fa86269 100644
--- a/addons/purchase_stock/models/purchase.py
+++ b/addons/purchase_stock/models/purchase.py
@@ -306,13 +306,9 @@ class PurchaseOrderLine(models.Model):
if float_compare(line.product_qty, line.qty_invoiced, line.product_uom.rounding) == -1:
# If the quantity is now below the invoiced quantity, create an activity on the vendor bill
# inviting the user to create a refund.
- activity = self.env['mail.activity'].sudo().create({
- 'activity_type_id': self.env.ref('mail.mail_activity_data_warning').id,
- 'note': _('The quantities on your purchase order indicate less than billed. You should ask for a refund. '),
- 'res_id': line.invoice_lines[0].invoice_id.id,
- 'res_model_id': self.env.ref('account.model_account_move').id,
- })
- activity._onchange_activity_type_id()
+ line.invoice_lines[0].move_id.activity_schedule(
+ 'mail.mail_activity_data_warning',
+ note=_('The quantities on your purchase order indicate less than billed. You should ask for a refund.'))
# If the user increased quantity of existing line or created a new line
pickings = line.order_id.picking_ids.filtered(lambda x: x.state not in ('done', 'cancel') and x.location_dest_id.usage in ('internal', 'transit'))
diff --git a/addons/stock/models/stock_rule.py b/addons/stock/models/stock_rule.py
index b8add883f27..94b6b9ea646 100644
--- a/addons/stock/models/stock_rule.py
+++ b/addons/stock/models/stock_rule.py
@@ -298,18 +298,11 @@ class StockRule(models.Model):
existing_activity = self.env['mail.activity'].search([('res_id', '=', product_id.product_tmpl_id.id), ('res_model_id', '=', self.env.ref('product.model_product_template').id),
('note', '=', note)])
if not existing_activity:
- # If the user deleted warning activity type.
- try:
- activity_type_id = self.env.ref('mail.mail_activity_data_warning').id
- except:
- activity_type_id = False
- self.env['mail.activity'].create({
- 'activity_type_id': activity_type_id,
- 'note': note,
- 'user_id': product_id.responsible_id.id or SUPERUSER_ID,
- 'res_id': product_id.product_tmpl_id.id,
- 'res_model_id': self.env.ref('product.model_product_template').id,
- })
+ product_id.product_tmpl_id.activity_schedule(
+ 'mail.mail_activity_data_warning',
+ note=note,
+ user_id=product_id.responsible_id.id or SUPERUSER_ID,
+ )
class ProcurementGroup(models.Model):