[IMP] mail: Return a browse record in _track_subtype instead of xmlid

Purpose
=======

- A manager could want to follow only home working of its own department
- A HR officer could want to follow only sick leaves of all dpts.

We have to improve what people follow and how they follow it in the leaves module

Specifications
==============

Subtype on department
---------------------

In department form view, right now, people can follow approvals

Instead we should have some generic and specific subtypes depending on the leave type

For instance, a HR Officer wants to follow only sick leaves and a manager only home working

Following mechanism
-------------------

Remove first / second approval subtype differences
if a leave type is not linked to a specific subtype, consider only classic
people follow it (employee and assigned HR people / manager)

Link leave type to subtypes, with some by default (i.e. home working, ...), not mandatory

When creating a leave type, link it to the department to be able to
activate the subtype for only one department.

closes odoo/odoo#27620
This commit is contained in:
Robot Odoo
2018-10-19 11:44:24 +02:00
committed by GitHub
29 changed files with 145 additions and 105 deletions
+3 -3
View File
@@ -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):
@@ -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)
+4 -4
View File
@@ -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
+1 -1
View File
@@ -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):
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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):
+1 -1
View File
@@ -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',
@@ -8,6 +8,15 @@
<field name="color_name">black</field>
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
<field name="leave_notif_subtype_id" eval="ref('mt_leave')"/>
<field name="allocation_notif_subtype_id" eval="ref('mt_leave_allocation')"/>
</record>
<!-- Home working -->
<record id="holiday_status_hw" model="hr.leave.type">
<field name="name">Home Workings</field>
<field name="color_name">lightgreen</field>
<field name="leave_notif_subtype_id" eval="ref('mt_leave_home_working')"/>
</record>
<!-- Sick leave -->
@@ -16,6 +25,7 @@
<field name="allocation_type">no</field>
<field name="color_name">red</field>
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
<field name="leave_notif_subtype_id" eval="ref('mt_leave_sick')"/>
</record>
<!-- Compensatory Days -->
@@ -26,6 +36,7 @@
<field name="color_name">lavender</field>
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
<field name="validity_stop" eval="time.strftime('%Y-12-31')"/>
<field name="leave_notif_subtype_id" eval="ref('mt_leave')"/>
</record>
<!--Unpaid Leave -->
@@ -36,6 +47,7 @@
<field name="color_name">brown</field>
<field name="unpaid" eval="True"/>
<field name="validity_start" eval="time.strftime('%Y-01-01')"/>
<field name="leave_notif_subtype_id" eval="ref('mt_leave_unpaid')"/>
</record>
</data>
</odoo>
+19 -50
View File
@@ -26,63 +26,32 @@
</record>
<!-- Holidays-related subtypes for messaging / Chatter -->
<record id="mt_leave_approved" model="mail.message.subtype">
<field name="name">Approved</field>
<record id="mt_leave" model="mail.message.subtype">
<field name="name">Leave</field>
<field name="res_model">hr.leave</field>
<field name="description">Request approved</field>
<field name="description">Leave Request</field>
</record>
<record id="mt_leave_refused" model="mail.message.subtype">
<field name="name">Refused</field>
<record id="mt_leave_home_working" model="mail.message.subtype">
<field name="name">Home Working</field>
<field name="res_model">hr.leave</field>
<field name="default" eval="False"/>
<field name="description">Request refused</field>
<field name="description">Home Working</field>
</record>
<record id="mt_leave_sick" model="mail.message.subtype">
<field name="name">Sick Leave</field>
<field name="res_model">hr.leave</field>
<field name="description">Sick Leave</field>
</record>
<record id="mt_leave_unpaid" model="mail.message.subtype">
<field name="name">Unpaid Leave</field>
<field name="res_model">hr.leave</field>
<field name="description">Unpaid Leave</field>
</record>
<!-- Allocation-related subtypes for messaging / Chatter -->
<record id="mt_leave_allocation_approved" model="mail.message.subtype">
<field name="name">Approved</field>
<record id="mt_leave_allocation" model="mail.message.subtype">
<field name="name">Allocation</field>
<field name="res_model">hr.leave.allocation</field>
<field name="description">Request approved</field>
</record>
<record id="mt_leave_allocation_refused" model="mail.message.subtype">
<field name="name">Refused</field>
<field name="res_model">hr.leave.allocation</field>
<field name="default" eval="False"/>
<field name="description">Request refused</field>
</record>
<!-- Department related subtypes for messaging / Chatter -->
<record id="mt_department_leave_approved" model="mail.message.subtype">
<field name="name">Leaves Approved</field>
<field name="res_model">hr.department</field>
<field name="default" eval="False"/>
<field name="parent_id" eval="ref('mt_leave_approved')"/>
<field name="relation_field">department_id</field>
<field name="sequence" eval="8"/>
</record>
<record id="mt_department_leave_refused" model="mail.message.subtype">
<field name="name">Leaves Refused</field>
<field name="res_model">hr.department</field>
<field name="default" eval="False"/>
<field name="parent_id" eval="ref('mt_leave_refused')"/>
<field name="relation_field">department_id</field>
<field name="sequence" eval="9"/>
</record>
<record id="mt_department_leave_allocation_approved" model="mail.message.subtype">
<field name="name">Allocation Approved</field>
<field name="res_model">hr.department</field>
<field name="default" eval="False"/>
<field name="parent_id" eval="ref('mt_leave_allocation_approved')"/>
<field name="relation_field">department_id</field>
<field name="sequence" eval="8"/>
</record>
<record id="mt_department_leave_allocation_refused" model="mail.message.subtype">
<field name="name">Allocation Refused</field>
<field name="res_model">hr.department</field>
<field name="default" eval="False"/>
<field name="parent_id" eval="ref('mt_leave_allocation_refused')"/>
<field name="relation_field">department_id</field>
<field name="sequence" eval="9"/>
<field name="description">Allocation Request</field>
</record>
</data>
</odoo>
+1
View File
@@ -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
+2 -3
View File
@@ -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
@@ -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
@@ -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')
@@ -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
@@ -56,6 +56,16 @@
<field name="validity_start"/>
<field name="validity_stop"/>
</group>
<group name="notification" string="Notification" colspan="2">
<group>
<field name="leave_notif_subtype_id"
domain="[('res_model','=','hr.leave')]"
context="{'default_name': name, 'default_res_model': 'hr.leave'}"/>
<field name="allocation_notif_subtype_id"
domain="[('res_model','=','hr.leave.allocation')]"
context="{'default_name': name, 'default_res_model': 'hr.leave.allocation'}"/>
</group>
</group>
<group name="calendar" string="Calendar" groups="base.group_no_one">
<field name="categ_id"/>
<field name="color_name"/>
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
@@ -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
+7 -9
View File
@@ -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)
+3 -3
View File
@@ -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):
+4 -4
View File
@@ -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
+3 -3
View File
@@ -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')
+2 -2
View File
@@ -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
@@ -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
@@ -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)
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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
@@ -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
+1 -1
View File
@@ -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)