Browse Source

[PORT] mail_activity

pull/328/head
Chris White 6 years ago
parent
commit
3a94276621
  1. 2
      mail_activity/__init__.py
  2. 2
      mail_activity/__manifest__.py
  3. 124
      mail_activity/hooks.py
  4. 1
      mail_activity/models/__init__.py
  5. 28
      mail_activity/models/mail_activity.py
  6. 38
      mail_activity/models/mail_activity_mixin.py
  7. 2
      mail_activity/models/mail_activity_type.py
  8. 15
      mail_activity/models/mail_compose_message.py
  9. 2
      mail_activity/models/mail_message.py
  10. 7
      mail_activity/models/res_partner.py
  11. 2
      mail_activity/models/res_users.py
  12. 4
      mail_activity/static/src/less/systray.less
  13. 2
      mail_activity/static/src/xml/systray.xml
  14. 4
      mail_activity/tests/test_mail_activity.py
  15. 0
      mail_activity/views/crm_action_views.xml
  16. 2
      mail_activity/wizards/__init__.py
  17. 12
      mail_activity/wizards/mail_compose_message.py
  18. 0
      mail_activity_calendar/__manifest__.py
  19. 2
      mail_activity_crm/__manifest__.py
  20. 4
      mail_activity_crm/hooks.py
  21. 2
      mail_activity_crm/models/__init__.py
  22. 2
      mail_activity_crm/models/calendar_event.py
  23. 19
      mail_activity_crm/models/crm_activity_report.py
  24. 56
      mail_activity_crm/models/crm_activity_report_odoo_v10.py
  25. 8
      mail_activity_crm/models/crm_lead.py
  26. 2
      mail_activity_crm/models/mail_activity.py
  27. 11
      mail_activity_crm/views/crm_activity_report_view.xml
  28. 4
      mail_activity_crm/views/crm_lead_menu.xml

2
mail_activity/__init__.py

@ -1,4 +1,2 @@
# -*- coding: utf-8 -*-
from . import models
from . import wizards
from .hooks import post_load_hook

2
mail_activity/__openerp__.py → mail_activity/__manifest__.py

@ -19,6 +19,7 @@
"data/mail_message_subtype.xml",
'security/ir.model.access.csv',
'views/mail_activity.xml',
'views/crm_action_views.xml',
'data/mail_activity.xml',
'data/ir_model_data.xml',
'views/templates.xml',
@ -28,5 +29,4 @@
'static/src/xml/systray.xml',
'static/src/xml/web_kanban_activity.xml',
],
"post_load": "post_load_hook",
}

124
mail_activity/hooks.py

@ -1,124 +0,0 @@
# Copyright 2018 Eficent Business and IT Consulting Services S.L.
# Copyright 2018 Odoo, S.A.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from openerp.addons.mail.wizard.mail_compose_message import MailComposer
def post_load_hook():
"""
We need this hook only in v9 in order to be able to capture the subtype.
"""
def new_send_mail(self, auto_commit=False):
if 'subtype_id' not in self._fields:
return self.send_mail_original(auto_commit=auto_commit)
""" Process the wizard content and proceed with sending the related
email(s), rendering any template patterns on the fly
if needed. """
for wizard in self:
# Duplicate attachments linked to the email.template.
# Indeed, basic mail.compose.message wizard duplicates
# attachments in mass
# mailing mode. But in 'single post' mode, attachments of
# an email template
# also have to be duplicated to avoid changing their ownership.
if wizard.attachment_ids and \
wizard.composition_mode != 'mass_mail' and \
wizard.template_id:
new_attachment_ids = []
for attachment in wizard.attachment_ids:
if attachment in wizard.template_id.attachment_ids:
new_attachment_ids.append(attachment.copy(
{'res_model': 'mail.compose.message',
'res_id': wizard.id}).id)
else:
new_attachment_ids.append(attachment.id)
wizard.write({'attachment_ids': [(6, 0,
new_attachment_ids)]})
# Mass Mailing
mass_mode = wizard.composition_mode in ('mass_mail', 'mass_post')
Mail = self.env['mail.mail']
ActiveModel = self.env[
wizard.model if wizard.model else 'mail.thread']
if wizard.template_id:
# template user_signature is added when generating body_html
# mass mailing: use template auto_delete value -> note,
# for emails mass mailing only
Mail = Mail.with_context(mail_notify_user_signature=False)
ActiveModel = ActiveModel.with_context(
mail_notify_user_signature=False,
mail_auto_delete=wizard.template_id.auto_delete)
if not hasattr(ActiveModel, 'message_post'):
ActiveModel = self.env['mail.thread'].with_context(
thread_model=wizard.model)
if wizard.composition_mode == 'mass_post':
# do not send emails directly but use the queue instead
# add context key to avoid subscribing the author
ActiveModel = ActiveModel.with_context(
mail_notify_force_send=False,
mail_create_nosubscribe=True)
# wizard works in batch mode: [res_id] or
# active_ids or active_domain
if mass_mode and wizard.use_active_domain and wizard.model:
res_ids = self.env[wizard.model].search(
eval(wizard.active_domain)).ids
elif mass_mode and wizard.model and self._context.get(
'active_ids'):
res_ids = self._context['active_ids']
else:
res_ids = [wizard.res_id]
batch_size = int(self.env['ir.config_parameter'].sudo().get_param(
'mail.batch_size')) or self._batch_size
sliced_res_ids = [res_ids[i:i + batch_size] for i in
range(0, len(res_ids), batch_size)]
# ---- START OF PATCH
if wizard.composition_mode == 'mass_mail' or wizard.is_log or (
wizard.composition_mode == 'mass_post'
and not wizard.notify): # log a note: subtype is False
subtype_id = False
elif wizard.subtype_id:
subtype_id = wizard.subtype_id
else:
subtype_id = self.sudo().env.ref('mail.mt_comment',
raise_if_not_found=False)
if subtype_id:
external_subtype = subtype_id.get_external_id()
if external_subtype:
subtype = external_subtype[subtype_id.id]
else:
subtype = 'mail.mt_comment'
# ---- END OF PATCH
for res_ids in sliced_res_ids:
batch_mails = Mail
all_mail_values = wizard.get_mail_values(res_ids)
for res_id, mail_values in all_mail_values.iteritems():
if wizard.composition_mode == 'mass_mail':
batch_mails |= Mail.create(mail_values)
else:
# subtype = 'mail.mt_comment' -> Removed
if wizard.is_log or (
wizard.composition_mode == 'mass_post'
and not wizard.notify): # log a note:
# subtype is False
subtype = False
ActiveModel.browse(res_id).message_post(
message_type='comment', subtype=subtype,
**mail_values)
if wizard.composition_mode == 'mass_mail':
batch_mails.send(auto_commit=auto_commit)
return {'type': 'ir.actions.act_window_close'}
if not hasattr(MailComposer, 'send_mail_original'):
MailComposer.send_mail_original = MailComposer.send_mail
MailComposer.send_mail = new_send_mail

1
mail_activity/models/__init__.py

@ -4,4 +4,5 @@ from . import mail_activity_mixin
from . import mail_activity
from . import res_partner
from . import mail_message
from . import mail_compose_message
from . import res_users

28
mail_activity/models/mail_activity.py

@ -3,30 +3,7 @@
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from datetime import date, datetime, timedelta
from openerp import api, fields, models
def message_post_with_view(records, views_or_xmlid, **kwargs):
""" Method ported from mail.thread in v10 """
values = kwargs.pop('values', None) or dict()
try:
from openerp.addons.website.models.website import slug
values['slug'] = slug
except ImportError:
values['slug'] = lambda self: self.id
if isinstance(views_or_xmlid, basestring):
views = records.env.ref(views_or_xmlid, raise_if_not_found=False)
else:
views = views_or_xmlid
if not views:
return
for record in records:
values['object'] = record
rendered_template = views.render(values, engine='ir.qweb')
kwargs['body'] = rendered_template
kwargs['message_type'] = 'notification' # default in v10
kwargs['subtype_id'] = record.env.ref('mail.mt_activities').id,
record.message_post_with_template(False, **kwargs)
from odoo import api, fields, models
class MailActivity(models.Model):
@ -212,8 +189,7 @@ class MailActivity(models.Model):
self.write(dict(feedback=feedback))
for activity in self:
record = self.env[activity.res_model].browse(activity.res_id)
message_post_with_view(
record,
record.message_post_with_view(
'mail.message_activity_done',
values={'activity': activity},
subtype_id=self.env.ref('mail.mt_activities').id,

38
mail_activity/models/mail_activity_mixin.py

@ -3,19 +3,19 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import api, fields
from odoo import api, fields, models
def setup_mail_actitivities(cls):
""" Mixin using AbstractModels are problematic in Odoo v9, since they
prevent the new-style computed fields from working correctly.
This decorator edits the original class in-place, so the Odoo model
is left unchanged. """
cls.activity_ids = fields.One2many(
class MailActivityMixin(models.AbstractModel):
_name = 'mail.activity.mixin'
_description = 'Activity Mixin'
activity_ids = fields.One2many(
'mail.activity', 'res_id', 'Activities',
auto_join=True,
domain=lambda self: [('res_model', '=', self._name)])
cls.activity_state = fields.Selection([
activity_state = fields.Selection([
('overdue', 'Overdue'),
('today', 'Today'),
('planned', 'Planned')], string='State',
@ -23,27 +23,26 @@ def setup_mail_actitivities(cls):
help='Status based on activities\n'
'Overdue: Due date is already passed\n'
'Today: Activity date is today\nPlanned: Future activities.')
cls.activity_user_id = fields.Many2one(
activity_user_id = fields.Many2one(
'res.users', 'Responsible',
related='activity_ids.user_id',
search='_search_activity_user_id')
cls.activity_type_id = fields.Many2one(
activity_type_id = fields.Many2one(
'mail.activity.type', 'Next Activity Type',
related='activity_ids.activity_type_id',
search='_search_activity_type_id')
cls.activity_date_deadline = fields.Date(
activity_date_deadline = fields.Date(
'Next Activity Deadline', related='activity_ids.date_deadline',
readonly=True, store=True) # store to enable ordering + search
cls.activity_summary = fields.Char(
activity_summary = fields.Char(
'Next Activity Summary', related='activity_ids.summary',
search='_search_activity_summary')
cls.nbr_activities = fields.Integer(compute='_compute_nbr_activities')
nbr_activities = fields.Integer(compute='_compute_nbr_activities')
@api.depends('activity_ids')
def _compute_nbr_activities(self):
for record in self:
record.nbr_activities = len(record.activity_ids)
cls._compute_nbr_activities = _compute_nbr_activities
@api.depends('activity_ids.state')
def _compute_activity_state(self):
@ -55,35 +54,26 @@ def setup_mail_actitivities(cls):
record.activity_state = 'today'
elif 'planned' in states:
record.activity_state = 'planned'
cls._compute_activity_state = _compute_activity_state
@api.model
def _search_activity_user_id(self, operator, operand):
return [('activity_ids.user_id', operator, operand)]
cls._search_activity_user_id = _search_activity_user_id
@api.model
def _search_activity_type_id(self, operator, operand):
return [('activity_ids.activity_type_id', operator, operand)]
cls._search_activity_type_id = _search_activity_type_id
@api.model
def _search_activity_summary(self, operator, operand):
return [('activity_ids.summary', operator, operand)]
cls._search_activity_summary = _search_activity_summary
original_unlink = cls.unlink
@api.multi
def unlink(self):
""" Override unlink to delete records activities through
(res_model, res_id). """
record_ids = self.ids
result = original_unlink(self)
result = super(MailActivityMixin, self).unlink()
self.env['mail.activity'].sudo().search(
[('res_model', '=', self._name), ('res_id', 'in', record_ids)]
).unlink()
return result
cls.unlink = unlink
return cls

2
mail_activity/models/mail_activity_type.py

@ -3,7 +3,7 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import fields, models
from odoo import fields, models
class MailActivityType(models.Model):

15
mail_activity/models/mail_compose_message.py

@ -0,0 +1,15 @@
from odoo import api, fields, models
class MailComposeMessage(models.TransientModel):
_inherit = 'mail.compose.message'
@api.multi
def get_mail_values(self, res_ids):
"""Generate the values that will be used by send_mail to create mail_messages
or mail_mails. """
results = super(MailComposeMessage, self).get_mail_values(res_ids)
for res_id in res_ids:
results[res_id]['mail_activity_type_id'] = self.mail_activity_type_id.id
return results

2
mail_activity/models/mail_message.py

@ -3,7 +3,7 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import fields, models
from odoo import fields, models
class MailMessage(models.Model):

7
mail_activity/models/res_partner.py

@ -2,10 +2,9 @@
# Copyright 2016 Odoo SA <https://www.odoo.com>
# Copyright 2018 Therp BV <http://therp.nl>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import models
from .mail_activity_mixin import setup_mail_actitivities
from odoo import models
@setup_mail_actitivities
class ResPartner(models.Model):
_inherit = 'res.partner'
_name = 'res.partner'
_inherit = ['res.partner', 'mail.activity.mixin']

2
mail_activity/models/res_users.py

@ -3,7 +3,7 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import api, fields, models, modules
from odoo import api, fields, models, modules
class ResUsers(models.Model):

4
mail_activity/static/src/less/systray.less

@ -1,7 +1,7 @@
@gray-lighter-darker: #d9d7d7;
@gray-lighter-dark: #E5E5E5;
// Navbar icon and dropdown
.o_mail_navbar_item {
.o_mail_navbar_item_v10 {
> a {
opacity: 1;
> i {
@ -19,7 +19,7 @@
.o-flex-flow(column, nowrap);
}
.o_notification_counter {
.o-position-absolute(@top: 20%, @right: 1px);
.o-position-absolute(@top: 20%, @right: -3px);
background: @odoo-brand-optional;
color: white;
padding: 0em 0.3em;

2
mail_activity/static/src/xml/systray.xml

@ -32,7 +32,7 @@
</t>
<t t-name="mail.chat.ActivityMenu">
<li class="o_mail_navbar_item">
<li class="o_mail_navbar_item o_mail_navbar_item_v10">
<a class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="Activities" href="#">
<i class="fa fa-clock-o"/> <span class="o_notification_counter badge"/>
</a>

4
mail_activity/tests/test_mail_activity.py

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# © 2017 Therp BV <http://therp.nl>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import fields
from openerp.tests.common import TransactionCase
from odoo import fields
from odoo.tests.common import TransactionCase
class TestMailActivity(TransactionCase):

0
mail_activity_crm/views/crm_action_views.xml → mail_activity/views/crm_action_views.xml

2
mail_activity/wizards/__init__.py

@ -1,2 +0,0 @@
# -*- coding: utf-8 -*-
from . import mail_compose_message

12
mail_activity/wizards/mail_compose_message.py

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
from openerp import fields, models
class MailComposer(models.TransientModel):
_inherit = 'mail.compose.message'
# This field is already in v10 onwards.
subtype_id = fields.Many2one(
default=lambda self: self.sudo().env.ref('mail.mt_comment',
raise_if_not_found=False).id)

0
mail_activity_calendar/__openerp__.py → mail_activity_calendar/__manifest__.py

2
mail_activity_crm/__openerp__.py → mail_activity_crm/__manifest__.py

@ -17,9 +17,7 @@
],
"data": [
"views/crm_lead_views.xml",
'views/crm_activity_report_view.xml',
'views/crm_lead_menu.xml',
'views/crm_action_views.xml',
],
'post_init_hook': 'post_init_hook',
}

4
mail_activity_crm/hooks.py

@ -1,7 +1,7 @@
# Copyright 2018 Eficent Business and IT Consulting Services S.L.
# Copyright 2018 Tecnativa, S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from openerp import api, SUPERUSER_ID
from odoo import api, SUPERUSER_ID
def convert_crm_activity_types(env):
@ -72,7 +72,7 @@ def convert_crm_lead_activities(env):
SELECT
cl.id, im.id, 'crm.lead', cl.name, cl.title_action,
mat.id, cl.date_action, cl.create_uid, cl.create_date,
cl.write_uid, cl.write_date, COALESCE(cl.user_id, cl.create_uid)
cl.write_uid, cl.write_date, COALESCE(cl.user_id, cl.create_uid, 1)
FROM
crm_lead AS cl,
mail_activity_type AS mat,

2
mail_activity_crm/models/__init__.py

@ -2,3 +2,5 @@
from . import crm_lead
from . import calendar_event
from . import mail_activity
from . import crm_activity_report_odoo_v10
from . import crm_activity_report

2
mail_activity_crm/models/calendar_event.py

@ -3,7 +3,7 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import api, models
from odoo import api, models
class CalendarEvent(models.Model):

19
mail_activity_crm/models/crm_activity_report.py

@ -0,0 +1,19 @@
from odoo import api, fields, models
class CrmActivityReport(models.Model):
_inherit = 'crm.activity.report'
mail_activity_type_id = fields.Many2one('mail.activity.type', 'Activity Type', readonly=True)
def _select(self):
select = super(CrmActivityReport, self)._select()
return select + """
, m.mail_activity_type_id
"""
def _where(self):
where = super(CrmActivityReport, self)._where()
return where + """
-- AND m.mail_activity_type_id IS NOT NULL
"""

56
mail_activity_crm/models/crm_activity_report_odoo_v10.py

@ -0,0 +1,56 @@
from odoo import tools, api, fields, models
# Copy Odoo's implementation in v12 back to v10 so that we have useful hooks to add what we need to later on.
class CrmActivityReportOdoo(models.Model):
_inherit = 'crm.activity.report'
def _select(self):
return """
SELECT
m.id,
m.subtype_id,
m.author_id,
m.date,
m.subject,
l.id as lead_id,
l.user_id,
l.team_id,
l.country_id,
l.company_id,
l.stage_id,
l.partner_id,
l.type as lead_type,
l.active,
l.probability
"""
def _from(self):
return """
FROM mail_message AS m
"""
def _join(self):
return """
JOIN crm_lead AS l ON m.res_id = l.id
"""
def _where(self):
return """
WHERE
m.model = 'crm.lead'
"""
@api.model_cr
def init(self):
tools.drop_view_if_exists(self._cr, self._table)
self._cr.execute("""
CREATE OR REPLACE VIEW %s AS (
%s
%s
%s
%s
)
""" % (self._table, self._select(), self._from(), self._join(), self._where())
)

8
mail_activity_crm/models/crm_lead.py

@ -3,11 +3,9 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import models
from openerp.addons.mail_activity.models.mail_activity_mixin import \
setup_mail_actitivities
from odoo import models
@setup_mail_actitivities
class CrmLead(models.Model):
_inherit = 'crm.lead'
_name = 'crm.lead'
_inherit = ['crm.lead', 'mail.activity.mixin']

2
mail_activity_crm/models/mail_activity.py

@ -3,7 +3,7 @@
# Copyright 2018 Therp BV <http://therp.nl>
# Copyright 2018 Eficent <http://www.eficent.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from openerp import api, models
from odoo import api, models
class MailActivity(models.Model):

11
mail_activity_crm/views/crm_activity_report_view.xml

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- hide -->
<record id="crm.crm_activity_report_menu" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('base.group_no_one')])]"/>
<field name="name">Activities (obsolete)</field>
</record>
</data>
</openerp>

4
mail_activity_crm/views/crm_lead_menu.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?>
<openerp>
<odoo>
<data>
<!-- hide -->
<record id="crm.crm_lead_menu_activities" model="ir.ui.menu">
@ -8,4 +8,4 @@
</record>
</data>
</openerp>
</odoo>
Loading…
Cancel
Save