From f95356a7a21e12a071f8d5cbf3f399e50a5bd06f Mon Sep 17 00:00:00 2001 From: roen-odoo <roen@odoo.com> Date: Fri, 15 Oct 2021 12:07:41 +0000 Subject: [PATCH] [FIX] sale,sale_project : Avoid sending multiple email on upsell Expected behaviour: When you create a sale order with a project associated. When the sale order change state from non upsell to upsell sales person should receive one email. Current behaviour: The sales person receive an email for every entry in the timesheet after the sale order goes from non upsell to upsell. Step to reproduce: Create a sale order setup to create a project and task and the invoicing policy is ordered quantities. Add a timesheet entry which takes it past the ordered quantity. Create the invoice for the order. The state of the line and order goes to upsell, and the upsell email is sent to the salesperson. Add another line in the timesheet and the email is sent again to the salesperson closes odoo/odoo#78457 Signed-off-by: Laurent Stukkens (ltu) <ltu@odoo.com> --- addons/sale/models/sale.py | 10 +++- addons/sale_timesheet/tests/__init__.py | 1 + addons/sale_timesheet/tests/common.py | 17 ++++++ .../sale_timesheet/tests/test_sale_service.py | 2 +- .../tests/test_sale_timesheet.py | 60 +++++++++++++++++++ 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index fdbb1e80a181..4436ccd00a54 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -511,13 +511,19 @@ class SaleOrder(models.Model): return result def _compute_field_value(self, field): + send_mail = True + for record in self: + if field.name == 'invoice_status' and record._origin.invoice_status == 'upselling': + send_mail = False + super()._compute_field_value(field) - if field.name != 'invoice_status' or self.env.context.get('mail_activity_automation_skip'): + if field.name != 'invoice_status' or self.env.context.get('mail_activity_automation_skip') or not send_mail: return - + filtered_self = self.filtered(lambda so: so.user_id and so.invoice_status == 'upselling') if not filtered_self: return + filtered_self.activity_unlink(['sale.mail_act_sale_upsell']) for order in filtered_self: diff --git a/addons/sale_timesheet/tests/__init__.py b/addons/sale_timesheet/tests/__init__.py index db81f9e58641..e38fc12667a6 100644 --- a/addons/sale_timesheet/tests/__init__.py +++ b/addons/sale_timesheet/tests/__init__.py @@ -10,3 +10,4 @@ from . import test_reinvoice from . import test_reporting from . import test_project_overview from . import test_project_billing_multicompany + diff --git a/addons/sale_timesheet/tests/common.py b/addons/sale_timesheet/tests/common.py index d17db84ad9ba..993e9dc2b539 100644 --- a/addons/sale_timesheet/tests/common.py +++ b/addons/sale_timesheet/tests/common.py @@ -319,3 +319,20 @@ class TestCommonSaleTimesheet(TestSaleCommon): 'taxes_id': False, 'property_account_income_id': cls.account_sale.id, }) + + cls.service_prepaid = cls.env['product.product'].create({ + 'name': "Service delivered, create task in new project", + 'standard_price': 10, + 'list_price': 20, + 'type': 'service', + 'invoice_policy': 'delivery', + 'uom_id': uom_hour.id, + 'uom_po_id': uom_hour.id, + 'default_code': 'SERV-DELI3', + 'service_type': 'manual', + 'service_tracking': 'task_in_project', + 'project_id': False, # will create a project + 'taxes_id': False, + 'property_account_income_id': cls.account_sale.id, + 'service_policy': 'ordered_timesheet' + }) diff --git a/addons/sale_timesheet/tests/test_sale_service.py b/addons/sale_timesheet/tests/test_sale_service.py index ca4875593c1e..a62d869651fa 100644 --- a/addons/sale_timesheet/tests/test_sale_service.py +++ b/addons/sale_timesheet/tests/test_sale_service.py @@ -596,4 +596,4 @@ class TestSaleService(TestCommonSaleTimesheet): # copy the task task_copy = task.copy() - self.assertEqual(task_copy.sale_line_id, task.sale_line_id, "Duplicating task should keep its Sale line") + self.assertEqual(task_copy.sale_line_id, task.sale_line_id, "Duplicating task should keep its Sale line") \ No newline at end of file diff --git a/addons/sale_timesheet/tests/test_sale_timesheet.py b/addons/sale_timesheet/tests/test_sale_timesheet.py index cc8ea6102d28..636ca4cbaf09 100644 --- a/addons/sale_timesheet/tests/test_sale_timesheet.py +++ b/addons/sale_timesheet/tests/test_sale_timesheet.py @@ -671,3 +671,63 @@ class TestSaleTimesheet(TestCommonSaleTimesheet): self.assertEqual(self.partner_b, task_so1_timesheet2.partner_id, "The Task's second Timesheet entry should have its partner changed, as it was not invoiced and the Task's partner/customer changed.") self.assertEqual(so1_product_global_project_so_line, task_so1_timesheet1.so_line, "The Task's first Timesheet entry should not have changed as it was already invoiced (its so_line should still be equal to the first Sales Order line).") self.assertEqual(so2_product_global_project_so_line, task_so1_timesheet2.so_line, "The Task's second Timesheet entry should have it's so_line changed, as the Sales Order Item of the Task changed, and this entry was not invoiced.") + + def test_timesheet_upsell(self): + """ Test timesheet upselling and email """ + + self.sale_order_with_user = self.env['sale.order'].with_context(mail_notrack=True, mail_create_nolog=True).create({ + 'partner_id': self.partner_a.id, + 'partner_invoice_id': self.partner_a.id, + 'partner_shipping_id': self.partner_a.id, + 'user_id' : self.user_employee_company_B.id + }) + # create SO and confirm it + uom_days = self.env.ref('uom.product_uom_day') + sale_order_line = self.env['sale.order.line'].create({ + 'order_id': self.sale_order_with_user.id, + 'name': self.service_prepaid.name, + 'product_id': self.service_prepaid.id, + 'product_uom_qty': 1, + 'product_uom': uom_days.id, + 'price_unit': self.service_prepaid.list_price, + }) + self.sale_order_with_user.action_confirm() + task = self.env['project.task'].search([('sale_line_id', '=', sale_order_line.id)]) + + # let's log some timesheets + self.env['account.analytic.line'].create({ + 'name': 'Test Line', + 'project_id': task.project_id.id, + 'task_id': task.id, + 'unit_amount': 8, + 'employee_id': self.employee_manager.id, + }) + + self.sale_order_with_user._create_invoices() + id_max = self.env['mail.message'].search([], order='id desc', limit=1) + if id_max: + id_max = id_max[0].id + else: + id_max = 0 + self.env['account.analytic.line'].create({ + 'name': 'Test Line', + 'project_id': task.project_id.id, + 'task_id': task.id, + 'unit_amount': 5, + 'employee_id': self.employee_user.id, + }) + + self.assertEqual(self.sale_order_with_user.invoice_status, 'upselling', 'Sale Timesheet: "invoice on delivery" timesheets should not modify the invoice_status of the so') + message_sent = self.env['mail.message'].search([('id', '>', id_max), ('subject', 'like', 'Upsell')]) + self.assertEqual(len(message_sent),1,'Sale Timesheet: An email should always be sent to the saleperson when the state of the sale order change to upselling') + + self.env['account.analytic.line'].create({ + 'name': 'Test Line', + 'project_id': task.project_id.id, + 'task_id': task.id, + 'unit_amount': 5, + 'employee_id': self.employee_user.id, + }) + + message_sent = self.env['mail.message'].search([('id', '>', id_max), ('subject', 'like', 'Upsell')]) + self.assertEqual(len(message_sent),1,'Sale Timesheet: An email should only be sent to the saleperson when the state of the sale order change to upselling') \ No newline at end of file -- GitLab