diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index f65487073fe..af28f991608 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1493,11 +1493,11 @@ class AccountInvoice(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'state' in init_values and self.state == 'paid' and self.type in ('out_invoice', 'out_refund'):
- return 'account.mt_invoice_paid'
+ return self.env.ref('account.mt_invoice_paid')
elif 'state' in init_values and self.state == 'open' and self.type in ('out_invoice', 'out_refund'):
- return 'account.mt_invoice_validated'
+ return self.env.ref('account.mt_invoice_validated')
elif 'state' in init_values and self.state == 'draft' and self.type in ('out_invoice', 'out_refund'):
- return 'account.mt_invoice_created'
+ return self.env.ref('account.mt_invoice_created')
return super(AccountInvoice, self)._track_subtype(init_values)
def _amount_by_group(self):
diff --git a/addons/account_voucher/models/account_voucher.py b/addons/account_voucher/models/account_voucher.py
index c979480bf35..2c5d9d9f30c 100644
--- a/addons/account_voucher/models/account_voucher.py
+++ b/addons/account_voucher/models/account_voucher.py
@@ -390,7 +390,7 @@ class AccountVoucher(models.Model):
@api.multi
def _track_subtype(self, init_values):
if 'state' in init_values:
- return 'account_voucher.mt_voucher_state_change'
+ return self.env.ref('account_voucher.mt_voucher_state_change')
return super(AccountVoucher, self)._track_subtype(init_values)
diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py
index 076ee98be60..f6dc16a9366 100644
--- a/addons/crm/models/crm_lead.py
+++ b/addons/crm/models/crm_lead.py
@@ -1095,13 +1095,13 @@ class Lead(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'stage_id' in init_values and self.probability == 100 and self.stage_id and self.stage_id.on_change:
- return 'crm.mt_lead_won'
+ return self.env.ref('crm.mt_lead_won')
elif 'active' in init_values and self.probability == 0 and not self.active:
- return 'crm.mt_lead_lost'
+ return self.env.ref('crm.mt_lead_lost')
elif 'stage_id' in init_values and self.stage_id and self.stage_id.sequence <= 1:
- return 'crm.mt_lead_create'
+ return self.env.ref('crm.mt_lead_create')
elif 'stage_id' in init_values:
- return 'crm.mt_lead_stage'
+ return self.env.ref('crm.mt_lead_stage')
return super(Lead, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/fleet/models/fleet_vehicle.py b/addons/fleet/models/fleet_vehicle.py
index 7a00aea283f..1d03bc030f0 100644
--- a/addons/fleet/models/fleet_vehicle.py
+++ b/addons/fleet/models/fleet_vehicle.py
@@ -268,7 +268,7 @@ class FleetVehicle(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'driver_id' in init_values:
- return 'fleet.mt_fleet_driver_updated'
+ return self.env.ref('fleet.mt_fleet_driver_updated')
return super(FleetVehicle, self)._track_subtype(init_values)
def open_assignation_logs(self):
diff --git a/addons/hr_contract/models/hr_contract.py b/addons/hr_contract/models/hr_contract.py
index bb30f94856e..a98bb326846 100644
--- a/addons/hr_contract/models/hr_contract.py
+++ b/addons/hr_contract/models/hr_contract.py
@@ -128,7 +128,7 @@ class Contract(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'state' in init_values and self.state == 'pending':
- return 'hr_contract.mt_contract_pending'
+ return self.env.ref('hr_contract.mt_contract_pending')
elif 'state' in init_values and self.state == 'close':
- return 'hr_contract.mt_contract_close'
+ return self.env.ref('hr_contract.mt_contract_close')
return super(Contract, self)._track_subtype(init_values)
diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py
index 5e511352c64..67c7c5ebb7a 100644
--- a/addons/hr_expense/models/hr_expense.py
+++ b/addons/hr_expense/models/hr_expense.py
@@ -595,11 +595,11 @@ class HrExpenseSheet(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'state' in init_values and self.state == 'approve':
- return 'hr_expense.mt_expense_approved'
+ return self.env.ref('hr_expense.mt_expense_approved')
elif 'state' in init_values and self.state == 'cancel':
- return 'hr_expense.mt_expense_refused'
+ return self.env.ref('hr_expense.mt_expense_refused')
elif 'state' in init_values and self.state == 'done':
- return 'hr_expense.mt_expense_paid'
+ return self.env.ref('hr_expense.mt_expense_paid')
return super(HrExpenseSheet, self)._track_subtype(init_values)
def _message_auto_subscribe_followers(self, updated_values, subtype_ids):
diff --git a/addons/hr_holidays/__manifest__.py b/addons/hr_holidays/__manifest__.py
index a0e95455d20..9c765ea2596 100644
--- a/addons/hr_holidays/__manifest__.py
+++ b/addons/hr_holidays/__manifest__.py
@@ -26,8 +26,8 @@ A synchronization with an internal agenda (Meetings of the CRM module) is also p
'depends': ['hr', 'calendar', 'resource'],
'data': [
'data/report_paperformat.xml',
- 'data/hr_holidays_data.xml',
'data/mail_data.xml',
+ 'data/hr_holidays_data.xml',
'data/ir_cron_data.xml',
'security/hr_holidays_security.xml',
diff --git a/addons/hr_holidays/data/hr_holidays_data.xml b/addons/hr_holidays/data/hr_holidays_data.xml
index 57b2fdb57c5..44c4d53e151 100644
--- a/addons/hr_holidays/data/hr_holidays_data.xml
+++ b/addons/hr_holidays/data/hr_holidays_data.xml
@@ -8,6 +8,15 @@
black
+
+
+
+
+
+
+ Home Workings
+ lightgreen
+
@@ -16,6 +25,7 @@
no
red
+
@@ -26,6 +36,7 @@
lavender
+
@@ -36,6 +47,7 @@
brown
+
diff --git a/addons/hr_holidays/data/mail_data.xml b/addons/hr_holidays/data/mail_data.xml
index 2dc75bcb8c8..9b0a62f06c4 100644
--- a/addons/hr_holidays/data/mail_data.xml
+++ b/addons/hr_holidays/data/mail_data.xml
@@ -26,63 +26,32 @@
-
- Approved
+
+ Leave
hr.leave
- Request approved
+ Leave Request
-
- Refused
+
+ Home Working
hr.leave
-
- Request refused
+ Home Working
+
+
+ Sick Leave
+ hr.leave
+ Sick Leave
+
+
+ Unpaid Leave
+ hr.leave
+ Unpaid Leave
-
- Approved
+
+ Allocation
hr.leave.allocation
- Request approved
-
-
- Refused
- hr.leave.allocation
-
- Request refused
-
-
-
-
- Leaves Approved
- hr.department
-
-
- department_id
-
-
-
- Leaves Refused
- hr.department
-
-
- department_id
-
-
-
- Allocation Approved
- hr.department
-
-
- department_id
-
-
-
- Allocation Refused
- hr.department
-
-
- department_id
-
+ Allocation Request
\ No newline at end of file
diff --git a/addons/hr_holidays/models/__init__.py b/addons/hr_holidays/models/__init__.py
index 621aeccd08b..d391276412b 100644
--- a/addons/hr_holidays/models/__init__.py
+++ b/addons/hr_holidays/models/__init__.py
@@ -6,3 +6,4 @@ from . import hr
from . import hr_leave
from . import hr_leave_allocation
from . import hr_leave_type
+from . import mail_message_subtype
\ No newline at end of file
diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py
index b826f110b08..1ba9b220535 100644
--- a/addons/hr_holidays/models/hr_leave.py
+++ b/addons/hr_holidays/models/hr_leave.py
@@ -760,9 +760,8 @@ class HolidaysRequest(models.Model):
@api.multi
def _track_subtype(self, init_values):
if 'state' in init_values and self.state == 'validate':
- return 'hr_holidays.mt_leave_approved'
- elif 'state' in init_values and self.state == 'refuse':
- return 'hr_holidays.mt_leave_refused'
+ leave_notif_subtype = self.holiday_status_id.leave_notif_subtype_id
+ return leave_notif_subtype or self.env.ref('hr_holidays.mt_leave')
return super(HolidaysRequest, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py
index 0c2037a50ef..b244558c151 100644
--- a/addons/hr_holidays/models/hr_leave_allocation.py
+++ b/addons/hr_holidays/models/hr_leave_allocation.py
@@ -544,9 +544,8 @@ class HolidaysAllocation(models.Model):
@api.multi
def _track_subtype(self, init_values):
if 'state' in init_values and self.state == 'validate':
- return 'hr_holidays.mt_leave_allocation_approved'
- elif 'state' in init_values and self.state == 'refuse':
- return 'hr_holidays.mt_leave_allocation_refused'
+ allocation_notif_subtype_id = self.holiday_status_id.allocation_notif_subtype_id
+ return allocation_notif_subtype_id or self.env.ref('hr_holidays.mt_leave_allocation')
return super(HolidaysAllocation, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/hr_holidays/models/hr_leave_type.py b/addons/hr_holidays/models/hr_leave_type.py
index 828df4a5586..37087540776 100644
--- a/addons/hr_holidays/models/hr_leave_type.py
+++ b/addons/hr_holidays/models/hr_leave_type.py
@@ -83,6 +83,8 @@ class HolidaysType(models.Model):
('day', 'Day'), ('hour', 'Hours')],
default='day', string='Take Leaves in', required=True)
unpaid = fields.Boolean('Is Unpaid', default=False)
+ leave_notif_subtype_id = fields.Many2one('mail.message.subtype', string='Leave Notification Subtype')
+ allocation_notif_subtype_id = fields.Many2one('mail.message.subtype', string='Allocation Notification Subtype')
@api.multi
@api.constrains('validity_start', 'validity_stop')
diff --git a/addons/hr_holidays/models/mail_message_subtype.py b/addons/hr_holidays/models/mail_message_subtype.py
new file mode 100644
index 00000000000..78d0c394ad5
--- /dev/null
+++ b/addons/hr_holidays/models/mail_message_subtype.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+
+from odoo import api, models
+
+_logger = logging.getLogger(__name__)
+
+
+class MailMessageSubtype(models.Model):
+ _inherit = 'mail.message.subtype'
+
+ def _get_department_subtype(self):
+ return self.search([
+ ('res_model', '=', 'hr.department'),
+ ('parent_id', '=', self.id)])
+
+ def _update_department_subtype(self):
+ for subtype in self:
+ department_subtype = subtype._get_department_subtype()
+ if department_subtype:
+ department_subtype.write({
+ 'name': subtype.name,
+ 'default': subtype.default,
+ })
+ else:
+ department_subtype = self.create({
+ 'name': subtype.name,
+ 'res_model': 'hr.department',
+ 'default': subtype.default or False,
+ 'parent_id': subtype.id,
+ 'relation_field': 'department_id',
+ })
+ 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()
+ return result
+
+ @api.multi
+ def write(self, vals):
+ result = super(MailMessageSubtype, self).write(vals)
+ self.filtered(
+ lambda subtype: subtype.res_model in ['hr.leave', 'hr.leave.allocation']
+ )._update_department_subtype()
+ return result
diff --git a/addons/hr_holidays/views/hr_leave_type_views.xml b/addons/hr_holidays/views/hr_leave_type_views.xml
index c3bdc445ec0..5c9116cd90d 100644
--- a/addons/hr_holidays/views/hr_leave_type_views.xml
+++ b/addons/hr_holidays/views/hr_leave_type_views.xml
@@ -56,6 +56,16 @@
+
+
+
+
+
+
diff --git a/addons/hr_maintenance/models/equipment.py b/addons/hr_maintenance/models/equipment.py
index d66f29fdfc6..f2537086174 100644
--- a/addons/hr_maintenance/models/equipment.py
+++ b/addons/hr_maintenance/models/equipment.py
@@ -65,7 +65,7 @@ class MaintenanceEquipment(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if ('employee_id' in init_values and self.employee_id) or ('department_id' in init_values and self.department_id):
- return 'maintenance.mt_mat_assign'
+ return self.env.ref('maintenance.mt_mat_assign')
return super(MaintenanceEquipment, self)._track_subtype(init_values)
diff --git a/addons/hr_recruitment/models/hr_job.py b/addons/hr_recruitment/models/hr_job.py
index 7f1510c19c3..1a73bab1f84 100644
--- a/addons/hr_recruitment/models/hr_job.py
+++ b/addons/hr_recruitment/models/hr_job.py
@@ -69,7 +69,7 @@ class Job(models.Model):
@api.multi
def _track_subtype(self, init_values):
if 'state' in init_values and self.state == 'open':
- return 'hr_recruitment.mt_job_new'
+ return self.env.ref('hr_recruitment.mt_job_new')
return super(Job, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py
index f1b9aae9c0c..d52e0bb3a45 100644
--- a/addons/hr_recruitment/models/hr_recruitment.py
+++ b/addons/hr_recruitment/models/hr_recruitment.py
@@ -346,11 +346,11 @@ class Applicant(models.Model):
def _track_subtype(self, init_values):
record = self[0]
if 'emp_id' in init_values and record.emp_id and record.emp_id.active:
- return 'hr_recruitment.mt_applicant_hired'
+ return self.env.ref('hr_recruitment.mt_applicant_hired')
elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence <= 1:
- return 'hr_recruitment.mt_applicant_new'
+ return self.env.ref('hr_recruitment.mt_applicant_new')
elif 'stage_id' in init_values and record.stage_id and record.stage_id.sequence > 1:
- return 'hr_recruitment.mt_applicant_stage_changed'
+ return self.env.ref('hr_recruitment.mt_applicant_stage_changed')
return super(Applicant, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py
index 47174571dcb..99328583a44 100644
--- a/addons/mail/models/mail_thread.py
+++ b/addons/mail/models/mail_thread.py
@@ -562,7 +562,7 @@ class MailThread(models.AbstractModel):
:param init_values: the original values of the record; only modified fields
are present in the dict
:type init_values: dict
- :returns: a subtype xml_id or False if no subtype is trigerred
+ :returns: a subtype browse record or False if no subtype is trigerred
"""
return False
@@ -635,17 +635,15 @@ class MailThread(models.AbstractModel):
continue
# find subtypes and post messages or log if no subtype found
- subtype_xmlid = False
+ subtype = False
# By passing this key, that allows to let the subtype empty and so don't sent email because partners_to_notify from mail_message._notify will be empty
if not self._context.get('mail_track_log_only'):
- subtype_xmlid = record._track_subtype(dict((col_name, initial_values[record.id][col_name]) for col_name in changes))
-
- if subtype_xmlid:
- subtype_rec = self.env.ref(subtype_xmlid) # TDE FIXME check for raise if not found
- if not (subtype_rec and subtype_rec.exists()):
- _logger.debug('subtype %s not found' % subtype_xmlid)
+ subtype = record._track_subtype(dict((col_name, initial_values[record.id][col_name]) for col_name in changes))
+ if subtype:
+ if not subtype.exists():
+ _logger.debug('subtype "%s" not found' % subtype.name)
continue
- record.message_post(subtype=subtype_xmlid, tracking_value_ids=tracking_value_ids)
+ record.message_post(subtype_id=subtype.id, tracking_value_ids=tracking_value_ids)
elif tracking_value_ids:
record._message_log(tracking_value_ids=tracking_value_ids)
diff --git a/addons/maintenance/models/maintenance.py b/addons/maintenance/models/maintenance.py
index 719c912e038..4ea20b6e948 100644
--- a/addons/maintenance/models/maintenance.py
+++ b/addons/maintenance/models/maintenance.py
@@ -98,7 +98,7 @@ class MaintenanceEquipment(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'owner_user_id' in init_values and self.owner_user_id:
- return 'maintenance.mt_mat_assign'
+ return self.env.ref('maintenance.mt_mat_assign')
return super(MaintenanceEquipment, self)._track_subtype(init_values)
@api.multi
@@ -267,9 +267,9 @@ class MaintenanceRequest(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'stage_id' in init_values and self.stage_id.sequence <= 1:
- return 'maintenance.mt_req_created'
+ return self.env.ref('maintenance.mt_req_created')
elif 'stage_id' in init_values and self.stage_id.sequence > 1:
- return 'maintenance.mt_req_status'
+ return self.env.ref('maintenance.mt_req_status')
return super(MaintenanceRequest, self)._track_subtype(init_values)
def _get_default_team_id(self):
diff --git a/addons/project/models/project.py b/addons/project/models/project.py
index dc1044defce..658444f2023 100644
--- a/addons/project/models/project.py
+++ b/addons/project/models/project.py
@@ -775,13 +775,13 @@ class Task(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'kanban_state_label' in init_values and self.kanban_state == 'blocked':
- return 'project.mt_task_blocked'
+ return self.env.ref('project.mt_task_blocked')
elif 'kanban_state_label' in init_values and self.kanban_state == 'done':
- return 'project.mt_task_ready'
+ return self.env.ref('project.mt_task_ready')
elif 'stage_id' in init_values and self.stage_id and self.stage_id.sequence <= 1: # start stage -> new
- return 'project.mt_task_new'
+ return self.env.ref('project.mt_task_new')
elif 'stage_id' in init_values:
- return 'project.mt_task_stage'
+ return self.env.ref('project.mt_task_stage')
return super(Task, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py
index 9b13a39b6e3..829c1e86684 100644
--- a/addons/purchase/models/purchase.py
+++ b/addons/purchase/models/purchase.py
@@ -179,11 +179,11 @@ class PurchaseOrder(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'state' in init_values and self.state == 'purchase':
- return 'purchase.mt_rfq_approved'
+ return self.env.ref('purchase.mt_rfq_approved')
elif 'state' in init_values and self.state == 'to approve':
- return 'purchase.mt_rfq_confirmed'
+ return self.env.ref('purchase.mt_rfq_confirmed')
elif 'state' in init_values and self.state == 'done':
- return 'purchase.mt_rfq_done'
+ return self.env.ref('purchase.mt_rfq_done')
return super(PurchaseOrder, self)._track_subtype(init_values)
@api.onchange('partner_id', 'company_id')
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 6246fa32ca4..560abb200a2 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -272,9 +272,9 @@ class SaleOrder(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'state' in init_values and self.state == 'sale':
- return 'sale.mt_order_confirmed'
+ return self.env.ref('sale.mt_order_confirmed')
elif 'state' in init_values and self.state == 'sent':
- return 'sale.mt_order_sent'
+ return self.env.ref('sale.mt_order_sent')
return super(SaleOrder, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/stock_landed_costs/models/stock_landed_cost.py b/addons/stock_landed_costs/models/stock_landed_cost.py
index 07aa7be9a51..4e3c022a4b1 100644
--- a/addons/stock_landed_costs/models/stock_landed_cost.py
+++ b/addons/stock_landed_costs/models/stock_landed_cost.py
@@ -73,7 +73,7 @@ class LandedCost(models.Model):
@api.multi
def _track_subtype(self, init_values):
if 'state' in init_values and self.state == 'done':
- return 'stock_landed_costs.mt_stock_landed_cost_open'
+ return self.env.ref('stock_landed_costs.mt_stock_landed_cost_open')
return super(LandedCost, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/stock_picking_batch/models/stock_picking_batch.py b/addons/stock_picking_batch/models/stock_picking_batch.py
index 18a3e9cb4b2..18592687d6b 100644
--- a/addons/stock_picking_batch/models/stock_picking_batch.py
+++ b/addons/stock_picking_batch/models/stock_picking_batch.py
@@ -106,7 +106,7 @@ class StockPickingBatch(models.Model):
def _track_subtype(self, init_values):
if 'state' in init_values:
- return 'stock_picking_batch.mt_batch_state'
+ return self.env.ref('stock_picking_batch.mt_batch_state')
return super(StockPickingBatch, self)._track_subtype(init_values)
diff --git a/addons/test_mail/models/test_mail_models.py b/addons/test_mail/models/test_mail_models.py
index 8ada6ed86c8..5ba9ff195e8 100644
--- a/addons/test_mail/models/test_mail_models.py
+++ b/addons/test_mail/models/test_mail_models.py
@@ -78,7 +78,7 @@ class MailTestFull(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'umbrella_id' in init_values and self.umbrella_id:
- return 'test_mail.st_mail_test_full_umbrella_upd'
+ return self.env.ref('test_mail.st_mail_test_full_umbrella_upd')
return super(MailTestFull, self)._track_subtype(init_values)
diff --git a/addons/website_event/models/event.py b/addons/website_event/models/event.py
index 50e60db63c1..c9f9554b149 100644
--- a/addons/website_event/models/event.py
+++ b/addons/website_event/models/event.py
@@ -118,9 +118,9 @@ class Event(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'is_published' in init_values and self.is_published:
- return 'website_event.mt_event_published'
+ return self.env.ref('website_event.mt_event_published')
elif 'is_published' in init_values and not self.is_published:
- return 'website_event.mt_event_unpublished'
+ return self.env.ref('website_event.mt_event_unpublished')
return super(Event, self)._track_subtype(init_values)
@api.multi
diff --git a/addons/website_event_track/models/event_track.py b/addons/website_event_track/models/event_track.py
index 2f35e86bb0e..1c4758d50af 100644
--- a/addons/website_event_track/models/event_track.py
+++ b/addons/website_event_track/models/event_track.py
@@ -151,9 +151,9 @@ class Track(models.Model):
def _track_subtype(self, init_values):
self.ensure_one()
if 'kanban_state' in init_values and self.kanban_state == 'blocked':
- return 'website_event_track.mt_track_blocked'
+ return self.env.ref('website_event_track.mt_track_blocked')
elif 'kanban_state' in init_values and self.kanban_state == 'done':
- return 'website_event_track.mt_track_ready'
+ return self.env.ref('website_event_track.mt_track_ready')
return super(Track, self)._track_subtype(init_values)
@api.multi
diff --git a/doc/reference/mixins.rst b/doc/reference/mixins.rst
index d8c976ddaaa..af06849b435 100644
--- a/doc/reference/mixins.rst
+++ b/doc/reference/mixins.rst
@@ -331,7 +331,7 @@ can override the ``_track_subtype()`` function:
# in cache
self.ensure_one()
if 'state' in init_values and self.state == 'confirmed':
- return 'my_module.mt_state_change' # Full external id
+ return self.env.ref('my_module.mt_state_change')
return super(BusinessTrip, self)._track_subtype(init_values)