diff --git a/addons/account/report/account_invoice_report_view.xml b/addons/account/report/account_invoice_report_view.xml index c2788f27c49..11ea2253821 100644 --- a/addons/account/report/account_invoice_report_view.xml +++ b/addons/account/report/account_invoice_report_view.xml @@ -117,7 +117,10 @@ - + + diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml index c17c07d0c58..e0cece23871 100644 --- a/addons/crm/views/crm_lead_views.xml +++ b/addons/crm/views/crm_lead_views.xml @@ -998,7 +998,10 @@ - + + diff --git a/addons/mass_mailing/models/mailing.py b/addons/mass_mailing/models/mailing.py index 0956945843a..12460592403 100644 --- a/addons/mass_mailing/models/mailing.py +++ b/addons/mass_mailing/models/mailing.py @@ -11,6 +11,7 @@ import threading import werkzeug.urls from ast import literal_eval from dateutil.relativedelta import relativedelta +from markupsafe import Markup from werkzeug.urls import url_join from odoo import api, fields, models, tools, _ @@ -544,12 +545,19 @@ class MassMailing(models.Model): def action_view_clicked(self): model_name = self.env['ir.model']._get('link.tracker').display_name + recipient = self.env['ir.model']._get(self.mailing_model_real).display_name + helper_header = _("No %s clicked your mailing yet!", recipient) + helper_message = _("Link Trackers will measure how many times each link is clicked as well as " + "the proportion of %s who clicked at least once in your mailing.", recipient) return { 'name': model_name, 'type': 'ir.actions.act_window', 'view_mode': 'tree', 'res_model': 'link.tracker', 'domain': [('mass_mailing_id.id', '=', self.id)], + 'help': Markup('

%s

%s

') % ( + helper_header, helper_message, + ), 'context': dict(self._context, create=False) } @@ -566,28 +574,45 @@ class MassMailing(models.Model): return self._action_view_documents_filtered('delivered') def _action_view_documents_filtered(self, view_filter): - if view_filter in ('reply', 'bounce'): + model_name = self.env['ir.model']._get(self.mailing_model_real).display_name + helper_header = None + helper_message = None + if view_filter == 'reply': found_traces = self.mailing_trace_ids.filtered(lambda trace: trace.trace_status == view_filter) + helper_header = _("No %s replied to your mailing yet!", model_name) + helper_message = _("To track how many replies this mailing gets, make sure " + "its reply-to address belongs to this database.") + elif view_filter == 'bounce': + found_traces = self.mailing_trace_ids.filtered(lambda trace: trace.trace_status == view_filter) + helper_header = _("No %s address bounced yet!", model_name) + helper_message = _("Bounce happens when a mailing cannot be delivered (fake address, " + "server issues, ...). Check each record to see what went wrong.") elif view_filter == 'open': found_traces = self.mailing_trace_ids.filtered(lambda trace: trace.trace_status in ('open', 'reply')) - elif view_filter == 'click': - found_traces = self.mailing_trace_ids.filtered(lambda trace: trace.links_click_datetime) + helper_header = _("No %s opened your mailing yet!", model_name) + helper_message = _("Come back once your mailing has been sent to track who opened your mailing.") elif view_filter == 'delivered': found_traces = self.mailing_trace_ids.filtered(lambda trace: trace.trace_status in ('sent', 'open', 'reply')) + helper_header = _("No %s received your mailing yet!", model_name) + helper_message = _("Wait until your mailing has been sent to check how many recipients you managed to reach.") elif view_filter == 'sent': found_traces = self.mailing_trace_ids.filtered(lambda trace: trace.sent_datetime) else: found_traces = self.env['mailing.trace'] res_ids = found_traces.mapped('res_id') - model_name = self.env['ir.model']._get(self.mailing_model_real).display_name - return { + action = { 'name': model_name, 'type': 'ir.actions.act_window', 'view_mode': 'tree', 'res_model': self.mailing_model_real, 'domain': [('id', 'in', res_ids)], - 'context': dict(self._context, create=False) + 'context': dict(self._context, create=False), } + if helper_header and helper_message: + action['help'] = Markup('

%s

%s

') % ( + helper_header, helper_message, + ), + return action def update_opt_out(self, email, list_ids, value): if len(list_ids) > 0: diff --git a/addons/mass_mailing_crm/models/mailing_mailing.py b/addons/mass_mailing_crm/models/mailing_mailing.py index b804327242a..a2796d529f4 100644 --- a/addons/mass_mailing_crm/models/mailing_mailing.py +++ b/addons/mass_mailing_crm/models/mailing_mailing.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from markupsafe import Markup from odoo import fields, models, _, tools @@ -9,27 +10,40 @@ class MassMailing(models.Model): _inherit = 'mailing.mailing' use_leads = fields.Boolean('Use Leads', compute='_compute_use_leads') - crm_lead_count = fields.Integer('Leads/Opportunities Count', groups='sales_team.group_sale_salesman', compute='_compute_crm_lead_count') + crm_lead_count = fields.Integer('Leads/Opportunities Count', compute='_compute_crm_lead_count') def _compute_use_leads(self): self.use_leads = self.env.user.has_group('crm.group_use_lead') def _compute_crm_lead_count(self): - lead_data = self.env['crm.lead'].with_context(active_test=False).read_group( + lead_data = self.env['crm.lead'].with_context(active_test=False).sudo().read_group( [('source_id', 'in', self.source_id.ids)], - ['source_id'], ['source_id'] + ['source_id'], ['source_id'], ) mapped_data = {datum['source_id'][0]: datum['source_id_count'] for datum in lead_data} for mass_mailing in self: mass_mailing.crm_lead_count = mapped_data.get(mass_mailing.source_id.id, 0) def action_redirect_to_leads_and_opportunities(self): - view = 'crm.crm_lead_all_leads' if self.use_leads else 'crm.crm_lead_opportunities' - action = self.env.ref(view).sudo().read()[0] - action['view_mode'] = 'tree,kanban,graph,pivot,form,calendar' - action['domain'] = [('source_id', 'in', self.source_id.ids)] - action['context'] = {'active_test': False, 'create': False} - return action + text = _("Leads") if self.use_leads else _("Opportunities") + helper_header = _("No %s yet!", text) + helper_message = _("Note that Odoo cannot track replies if they are sent towards email addresses to this database.") + return { + 'context': { + 'active_test': False, + 'create': False, + 'search_default_group_by_create_date_day': True, + 'crm_lead_view_hide_month': True, + }, + 'domain': [('source_id', 'in', self.source_id.ids)], + 'help': Markup('

%s

%s

') % ( + helper_header, helper_message, + ), + 'name': _("Leads Analysis"), + 'res_model': 'crm.lead', + 'type': 'ir.actions.act_window', + 'view_mode': 'graph,pivot,tree,form', + } def _prepare_statistics_email_values(self): self.ensure_one() diff --git a/addons/mass_mailing_crm/views/mailing_mailing_views.xml b/addons/mass_mailing_crm/views/mailing_mailing_views.xml index dc75114a7cb..c57c6837559 100644 --- a/addons/mass_mailing_crm/views/mailing_mailing_views.xml +++ b/addons/mass_mailing_crm/views/mailing_mailing_views.xml @@ -10,7 +10,6 @@ type="object" icon="fa-star" class="oe_stat_button" - groups="sales_team.group_sale_salesman" attrs="{'invisible': [('state', '=', 'draft')]}">
@@ -22,4 +21,4 @@ - \ No newline at end of file + diff --git a/addons/mass_mailing_sale/models/mailing_mailing.py b/addons/mass_mailing_sale/models/mailing_mailing.py index ad4f2f1fc8d..40e6091a98a 100644 --- a/addons/mass_mailing_sale/models/mailing_mailing.py +++ b/addons/mass_mailing_sale/models/mailing_mailing.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - +from markupsafe import Markup from odoo import api, fields, models, _, tools from odoo.osv import expression @@ -10,64 +10,77 @@ class MassMailing(models.Model): _name = 'mailing.mailing' _inherit = 'mailing.mailing' - sale_quotation_count = fields.Integer('Quotation Count', groups='sales_team.group_sale_salesman', compute='_compute_sale_quotation_count') - sale_invoiced_amount = fields.Integer('Invoiced Amount', groups='sales_team.group_sale_salesman', compute='_compute_sale_invoiced_amount') + sale_quotation_count = fields.Integer('Quotation Count', compute='_compute_sale_quotation_count') + sale_invoiced_amount = fields.Integer('Invoiced Amount', compute='_compute_sale_invoiced_amount') @api.depends('mailing_domain') def _compute_sale_quotation_count(self): - has_so_access = self.env['sale.order'].check_access_rights('read', raise_exception=False) - if not has_so_access: - self.sale_quotation_count = 0 - return + quotation_data = self.env['sale.order'].sudo().read_group( + [('source_id', 'in', self.source_id.ids)], + ['source_id'], ['source_id'], + ) + mapped_data = {datum['source_id'][0]: datum['source_id_count'] for datum in quotation_data} for mass_mailing in self: - mass_mailing.sale_quotation_count = self.env['sale.order'].search_count(mass_mailing._get_sale_utm_domain()) + mass_mailing.sale_quotation_count = mapped_data.get(mass_mailing.source_id.id, 0) @api.depends('mailing_domain') def _compute_sale_invoiced_amount(self): - if not self.user_has_groups('sales_team.group_sale_salesman') or not self.user_has_groups('account.group_account_invoice'): - self.sale_invoiced_amount = 0 - return + domain = expression.AND([ + [('source_id', 'in', self.source_id.ids)], + [('state', 'not in', ['draft', 'cancel'])] + ]) + moves_data = self.env['account.move'].sudo().read_group( + domain, ['source_id', 'amount_untaxed_signed'], ['source_id'], + ) + mapped_data = {datum['source_id'][0]: datum['amount_untaxed_signed'] for datum in moves_data} for mass_mailing in self: - domain = expression.AND([ - mass_mailing._get_sale_utm_domain(), - [('state', 'not in', ['draft', 'cancel'])] - ]) - moves = self.env['account.move'].search_read(domain, ['amount_untaxed_signed']) - mass_mailing.sale_invoiced_amount = sum(i['amount_untaxed_signed'] for i in moves) + mass_mailing.sale_invoiced_amount = mapped_data.get(mass_mailing.source_id.id, 0) def action_redirect_to_quotations(self): - action = self.env["ir.actions.actions"]._for_xml_id("sale.action_quotations_with_onboarding") - action['domain'] = self._get_sale_utm_domain() - action['context'] = {'create': False} - return action + helper_header = _("No Quotations yet!") + helper_message = _("Quotations will appear here once your customers add " + "products to their Carts or when your sales reps assign this mailing.") + return { + 'context': { + 'create': False, + 'search_default_group_by_date_day': True, + 'sale_report_view_hide_date': True, + }, + 'domain': [('source_id', '=', self.source_id.id)], + 'help': Markup('

%s

%s

') % ( + helper_header, helper_message, + ), + 'name': _("Sales Analysis"), + 'res_model': 'sale.report', + 'type': 'ir.actions.act_window', + 'view_mode': 'graph,pivot,tree,form', + } def action_redirect_to_invoiced(self): - action = self.env["ir.actions.actions"]._for_xml_id("account.action_move_out_invoice_type") - moves = self.env['account.move'].search(self._get_sale_utm_domain()) - action['context'] = { - 'create': False, - 'edit': False, - 'view_no_maturity': True + domain = expression.AND([ + [('source_id', '=', self.source_id.id)], + [('state', 'not in', ['draft', 'cancel'])] + ]) + moves = self.env['account.move'].search(domain) + helper_header = _("No Revenues yet!") + helper_message = _("Revenues will appear here once orders are turned into invoices.") + return { + 'context': { + 'create': False, + 'edit': False, + 'view_no_maturity': True, + 'search_default_group_by_invoice_date_week': True, + 'invoice_report_view_hide_invoice_date': True, + }, + 'domain': [('move_id', 'in', moves.ids)], + 'help': Markup('

%s

%s

') % ( + helper_header, helper_message, + ), + 'name': _("Invoices Analysis"), + 'res_model': 'account.invoice.report', + 'type': 'ir.actions.act_window', + 'view_mode': 'graph,pivot,tree,form', } - action['domain'] = [ - ('id', 'in', moves.ids), - ('move_type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt')), - ('state', 'not in', ['draft', 'cancel']) - ] - action['context'] = {'create': False} - return action - - def _get_sale_utm_domain(self): - res = [] - if self.campaign_id: - res.append(('campaign_id', '=', self.campaign_id.id)) - if self.source_id: - res.append(('source_id', '=', self.source_id.id)) - if self.medium_id: - res.append(('medium_id', '=', self.medium_id.id)) - if not res: - res.append((0, '=', 1)) - return res def _prepare_statistics_email_values(self): self.ensure_one() diff --git a/addons/mass_mailing_sale/views/mailing_mailing_views.xml b/addons/mass_mailing_sale/views/mailing_mailing_views.xml index 76308b22c39..219c5a24fd4 100644 --- a/addons/mass_mailing_sale/views/mailing_mailing_views.xml +++ b/addons/mass_mailing_sale/views/mailing_mailing_views.xml @@ -10,7 +10,6 @@ type="object" icon="fa-pencil-square-o" class="oe_stat_button" - groups="sales_team.group_sale_salesman" attrs="{'invisible': [('state', '=', 'draft')]}"> @@ -18,11 +17,10 @@ type="object" icon="fa-dollar" class="oe_stat_button" - groups="sales_team.group_sale_salesman" attrs="{'invisible': [('state', '=', 'draft')]}" > - \ No newline at end of file + diff --git a/addons/sale/report/sale_report_views.xml b/addons/sale/report/sale_report_views.xml index 6121877d918..33bfcdfe7b4 100644 --- a/addons/sale/report/sale_report_views.xml +++ b/addons/sale/report/sale_report_views.xml @@ -76,7 +76,10 @@ - + +