From db19463f255cbf56d9e6577ee7ab3ea9aa050e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 8 Dec 2021 10:11:11 +0000 Subject: [PATCH 1/8] [REF] event(_*): clean tests common files Purpose is to have a common event class for users and useful stuff (customers, products, ...) but lessen usage of common test data through sub modules. Indeed having a "global event type" test data updated in various addons is actually complicated to maintain. Sub add-ons are updated to use mainly the ``EventCase`` test class holding users and side data. Data specific to those modules (event type with some specific configuration notably) is created and used in tests in the given module only, and not through generic event_type_complex and event_0 test data anymore. With this commit tests are more localized to their add-on and modifying data in a given add-on has less chances to have unwanted side effect in other event submodules unit tests. Task-2703285 (Event performance improvements) Task-2703289 (Event testing and coverage) Part-of: odoo/odoo#81068 --- addons/event/tests/common.py | 110 +++++++-------- addons/event/tests/test_event_flow.py | 4 +- addons/event/tests/test_event_internals.py | 125 ++++++++++-------- .../event/tests/test_event_mail_schedule.py | 4 +- addons/event_booth/tests/common.py | 14 +- addons/event_booth_sale/tests/common.py | 3 +- addons/event_crm/tests/common.py | 30 ++++- addons/event_sale/tests/common.py | 30 ++++- .../event_sale/tests/test_event_internals.py | 11 +- addons/event_sms/tests/test_sms_schedule.py | 44 +++--- .../tests/test_event_security.py | 58 +++++--- addons/website_event/tests/common.py | 37 +++--- .../website_event/tests/test_event_menus.py | 4 +- .../website_event/tests/test_event_visitor.py | 4 +- .../website_event/tests/test_website_event.py | 4 +- .../website_event_exhibitor/tests/common.py | 2 + .../tests/test_sponsor_internals.py | 5 - .../tests/test_website_event_meet.py | 19 ++- .../website_event_questions/tests/common.py | 20 ++- .../tests/test_event_internals.py | 4 +- .../tests/test_event_menus.py | 4 +- 21 files changed, 314 insertions(+), 222 deletions(-) diff --git a/addons/event/tests/common.py b/addons/event/tests/common.py index c3c32a9880a..4713aa09716 100644 --- a/addons/event/tests/common.py +++ b/addons/event/tests/common.py @@ -1,52 +1,79 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime, timedelta - from odoo import fields from odoo.addons.mail.tests.common import mail_new_test_user from odoo.tests import common -class TestEventCommon(common.TransactionCase): +class EventCase(common.TransactionCase): @classmethod def setUpClass(cls): - super(TestEventCommon, cls).setUpClass() + super(EventCase, cls).setUpClass() + + cls.admin_user = cls.env.ref('base.user_admin') + cls.admin_user.write({ + 'country_id': cls.env.ref('base.be').id, + 'login': 'admin', + 'notification_type': 'inbox', + }) + cls.company_admin = cls.admin_user.company_id + # set country in order to format Belgian numbers + cls.company_admin.write({ + 'country_id': cls.env.ref('base.be').id, + }) # Test users to use through the various tests cls.user_portal = mail_new_test_user( - cls.env, login='portal_test', - name='Patrick Portal', email='patrick.portal@test.example.com', - notification_type='email', company_id=cls.env.ref("base.main_company").id, - groups='base.group_portal') + cls.env, + company_id=cls.company_admin.id, + email='patrick.portal@test.example.com', + groups='base.group_portal', + login='portal_test', + name='Patrick Portal', + notification_type='email', + tz='Europe/Brussels', + ) cls.user_employee = mail_new_test_user( - cls.env, login='user_employee', - name='Eglantine Employee', email='eglantine.employee@test.example.com', - tz='Europe/Brussels', notification_type='inbox', - company_id=cls.env.ref("base.main_company").id, + cls.env, + company_id=cls.company_admin.id, + email='eglantine.employee@test.example.com', groups='base.group_user', + login='user_employee', + name='Eglantine Employee', + notification_type='inbox', + tz='Europe/Brussels', ) cls.user_eventregistrationdesk = mail_new_test_user( - cls.env, login='user_eventregistrationdesk', - name='Ursule EventRegistration', email='ursule.eventregistration@test.example.com', - tz='Europe/Brussels', notification_type='inbox', - company_id=cls.env.ref("base.main_company").id, + cls.env, + company_id=cls.company_admin.id, + email='ursule.eventregistration@test.example.com', + login='user_eventregistrationdesk', groups='base.group_user,event.group_event_registration_desk', + name='Ursule EventRegistration', + notification_type='inbox', + tz='Europe/Brussels', ) cls.user_eventuser = mail_new_test_user( - cls.env, login='user_eventuser', - name='Ursule EventUser', email='ursule.eventuser@test.example.com', - tz='Europe/Brussels', notification_type='inbox', - company_id=cls.env.ref("base.main_company").id, + cls.env, + company_id=cls.company_admin.id, + email='ursule.eventuser@test.example.com', groups='base.group_user,event.group_event_user', + login='user_eventuser', + name='Ursule EventUser', + notification_type='inbox', + tz='Europe/Brussels', ) cls.user_eventmanager = mail_new_test_user( - cls.env, login='user_eventmanager', - name='Martine EventManager', email='martine.eventmanager@test.example.com', - tz='Europe/Brussels', notification_type='inbox', - company_id=cls.env.ref("base.main_company").id, + cls.env, + company_id=cls.company_admin.id, + email='martine.eventmanager@test.example.com', groups='base.group_user,event.group_event_manager', + login='user_eventmanager', + name='Martine EventManager', + notification_type='inbox', + tz='Europe/Brussels', ) cls.event_customer = cls.env['res.partner'].create({ @@ -64,41 +91,6 @@ class TestEventCommon(common.TransactionCase): 'mobile': '0456654321', }) - cls.event_type_complex = cls.env['event.type'].create({ - 'name': 'Update Type', - 'auto_confirm': True, - 'has_seats_limitation': True, - 'seats_max': 30, - 'default_timezone': 'Europe/Paris', - 'event_type_ticket_ids': [(0, 0, { - 'name': 'First Ticket', - }), (0, 0, { - 'name': 'Second Ticket', - }) - ], - 'event_type_mail_ids': [ - (0, 0, { # right at subscription - 'interval_unit': 'now', - 'interval_type': 'after_sub', - 'template_ref': 'mail.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event.event_subscription')}), - (0, 0, { # 1 days before event - 'interval_nbr': 1, - 'interval_unit': 'days', - 'interval_type': 'before_event', - 'template_ref': 'mail.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event.event_reminder')}), - ], - }) - cls.event_0 = cls.env['event.event'].create({ - 'name': 'TestEvent', - 'auto_confirm': True, - 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), - 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), - 'date_tz': 'Europe/Brussels', - }) - - # set country in order to format Belgian numbers - cls.event_0.company_id.write({'country_id': cls.env.ref('base.be').id}) - @classmethod def _create_registrations(cls, event, reg_count): # create some registrations diff --git a/addons/event/tests/test_event_flow.py b/addons/event/tests/test_event_flow.py index 93667aba78e..dd021b25e73 100644 --- a/addons/event/tests/test_event_flow.py +++ b/addons/event/tests/test_event_flow.py @@ -5,12 +5,12 @@ import datetime from dateutil.relativedelta import relativedelta -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase from odoo.exceptions import ValidationError from odoo.tools import mute_logger -class TestEventFlow(TestEventCommon): +class TestEventFlow(EventCase): @mute_logger('odoo.addons.base.models.ir_model', 'odoo.models') def test_event_auto_confirm(self): diff --git a/addons/event/tests/test_event_internals.py b/addons/event/tests/test_event_internals.py index 9fb11beff6d..e02a42aedf5 100644 --- a/addons/event/tests/test_event_internals.py +++ b/addons/event/tests/test_event_internals.py @@ -1,63 +1,95 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import date, datetime, timedelta -from unittest.mock import patch +from datetime import datetime, timedelta +from freezegun import freeze_time from odoo import Command -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase from odoo import exceptions -from odoo.fields import Datetime as FieldsDatetime, Date as FieldsDate +from odoo.fields import Datetime as FieldsDatetime from odoo.tests.common import users, Form from odoo.tools import mute_logger -class TestEventData(TestEventCommon): +class TestEventInternalsCommon(EventCase): @classmethod def setUpClass(cls): - super(TestEventData, cls).setUpClass() - cls.patcher = patch('odoo.addons.event.models.event_event.fields.Datetime', wraps=FieldsDatetime) - cls.mock_datetime = cls.patcher.start() - cls.mock_datetime.now.return_value = datetime(2020, 1, 31, 10, 0, 0) - cls.addClassCleanup(cls.patcher.stop) + super(TestEventInternalsCommon, cls).setUpClass() - cls.event_0.write({ - 'date_begin': datetime(2020, 2, 1, 8, 30, 0), - 'date_end': datetime(2020, 2, 4, 18, 45, 0), + cls.event_type_complex = cls.env['event.type'].create({ + 'name': 'Update Type', + 'auto_confirm': True, + 'has_seats_limitation': True, + 'seats_max': 30, + 'default_timezone': 'Europe/Paris', + 'event_type_ticket_ids': [ + (0, 0, {'name': 'First Ticket',}), + (0, 0, {'name': 'Second Ticket',}), + ], + 'event_type_mail_ids': [ + (0, 0, { # right at subscription + 'interval_unit': 'now', + 'interval_type': 'after_sub', + 'template_ref': 'mail.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event.event_subscription')}), + (0, 0, { # 1 days before event + 'interval_nbr': 1, + 'interval_unit': 'days', + 'interval_type': 'before_event', + 'template_ref': 'mail.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event.event_reminder')}), + ], }) + # Mock dates to have reproducible computed fields based on time + cls.reference_now = datetime(2020, 1, 31, 10, 0, 0) + cls.reference_beg = datetime(2020, 2, 1, 8, 30, 0) + cls.reference_end = datetime(2020, 2, 4, 18, 45, 0) + + cls.event_0 = cls.env['event.event'].create({ + 'auto_confirm': True, + 'date_begin': cls.reference_beg, + 'date_end': cls.reference_end, + 'date_tz': 'Europe/Brussels', + 'name': 'TestEvent', + }) + + +class TestEventData(TestEventInternalsCommon): + @users('user_eventmanager') def test_event_date_computation(self): event = self.event_0.with_user(self.env.user) - event.write({ - 'registration_ids': [(0, 0, {'partner_id': self.event_customer.id, 'name': 'test_reg'})], - 'date_begin': datetime(2020, 1, 31, 15, 0, 0), - 'date_end': datetime(2020, 4, 5, 18, 0, 0), - }) - registration = event.registration_ids[0] - self.assertEqual(registration.get_date_range_str(), u'today') + with freeze_time(self.reference_now): + event.write({ + 'registration_ids': [(0, 0, {'partner_id': self.event_customer.id, 'name': 'test_reg'})], + 'date_begin': datetime(2020, 1, 31, 15, 0, 0), + 'date_end': datetime(2020, 4, 5, 18, 0, 0), + }) + registration = event.registration_ids[0] + self.assertEqual(registration.get_date_range_str(), u'today') - event.date_begin = datetime(2020, 2, 1, 15, 0, 0) - self.assertEqual(registration.get_date_range_str(), u'tomorrow') + event.date_begin = datetime(2020, 2, 1, 15, 0, 0) + self.assertEqual(registration.get_date_range_str(), u'tomorrow') - event.date_begin = datetime(2020, 2, 2, 6, 0, 0) - self.assertEqual(registration.get_date_range_str(), u'in 2 days') + event.date_begin = datetime(2020, 2, 2, 6, 0, 0) + self.assertEqual(registration.get_date_range_str(), u'in 2 days') - event.date_begin = datetime(2020, 2, 20, 17, 0, 0) - self.assertEqual(registration.get_date_range_str(), u'next month') + event.date_begin = datetime(2020, 2, 20, 17, 0, 0) + self.assertEqual(registration.get_date_range_str(), u'next month') - event.date_begin = datetime(2020, 3, 1, 10, 0, 0) - self.assertEqual(registration.get_date_range_str(), u'on Mar 1, 2020, 11:00:00 AM') + event.date_begin = datetime(2020, 3, 1, 10, 0, 0) + self.assertEqual(registration.get_date_range_str(), u'on Mar 1, 2020, 11:00:00 AM') - # Is actually 8:30 to 20:00 in Mexico - event.write({ - 'date_begin': datetime(2020, 1, 31, 14, 30, 0), - 'date_end': datetime(2020, 2, 1, 2, 0, 0), - 'date_tz': 'Mexico/General' - }) - self.assertTrue(event.is_one_day) + # Is actually 8:30 to 20:00 in Mexico + event.write({ + 'date_begin': datetime(2020, 1, 31, 14, 30, 0), + 'date_end': datetime(2020, 2, 1, 2, 0, 0), + 'date_tz': 'Mexico/General' + }) + self.assertTrue(event.is_one_day) + @freeze_time('2020-1-31 10:00:00') @users('user_eventmanager') def test_event_date_timezone(self): event = self.event_0.with_user(self.env.user) @@ -349,6 +381,7 @@ class TestEventData(TestEventCommon): templates = self.env['mail.template'].with_context(filter_template_on_event=True).name_search('test template') self.assertEqual(len(templates), 1, 'Should return only mail templates related to the event registration model') + @freeze_time('2020-1-31 10:00:00') @users('user_eventmanager') def test_event_registrable(self): """Test if `_compute_event_registrations_open` works properly.""" @@ -401,6 +434,7 @@ class TestEventData(TestEventCommon): self.assertTrue(ticket.is_expired) self.assertFalse(event.event_registrations_open) + @freeze_time('2020-1-31 10:00:00') @users('user_eventmanager') def test_event_ongoing(self): event_1 = self.env['event.event'].create({ @@ -475,7 +509,7 @@ class TestEventData(TestEventCommon): self.assertEqual(event.seats_expected, 7) -class TestEventRegistrationData(TestEventCommon): +class TestEventRegistrationData(TestEventInternalsCommon): @users('user_eventmanager') def test_registration_partner_sync(self): @@ -569,22 +603,9 @@ class TestEventRegistrationData(TestEventCommon): self.assertEqual(new_reg.phone, contact.phone) -class TestEventTicketData(TestEventCommon): - - def setUp(self): - super(TestEventTicketData, self).setUp() - self.ticket_date_patcher = patch('odoo.addons.event.models.event_ticket.fields.Date', wraps=FieldsDate) - self.ticket_date_patcher_mock = self.ticket_date_patcher.start() - self.ticket_date_patcher_mock.context_today.return_value = date(2020, 1, 31) - self.ticket_datetime_patcher = patch('odoo.addons.event.models.event_ticket.fields.Datetime', wraps=FieldsDatetime) - self.ticket_datetime_patcher_mock = self.ticket_datetime_patcher.start() - self.ticket_datetime_patcher_mock.now.return_value = datetime(2020, 1, 31, 10, 0, 0) - - def tearDown(self): - super(TestEventTicketData, self).tearDown() - self.ticket_date_patcher.stop() - self.ticket_datetime_patcher.stop() +class TestEventTicketData(TestEventInternalsCommon): + @freeze_time('2020-1-31 10:00:00') @users('user_eventmanager') def test_event_ticket_fields(self): """ Test event ticket fields synchronization """ @@ -657,7 +678,7 @@ class TestEventTicketData(TestEventCommon): self.assertTrue(second_ticket.is_expired) -class TestEventTypeData(TestEventCommon): +class TestEventTypeData(TestEventInternalsCommon): @users('user_eventmanager') def test_event_type_fields(self): diff --git a/addons/event/tests/test_event_mail_schedule.py b/addons/event/tests/test_event_mail_schedule.py index 85f639648d2..1089c8358a5 100644 --- a/addons/event/tests/test_event_mail_schedule.py +++ b/addons/event/tests/test_event_mail_schedule.py @@ -5,12 +5,12 @@ from datetime import datetime from dateutil.relativedelta import relativedelta from freezegun import freeze_time -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase from odoo.addons.mail.tests.common import MockEmail from odoo.tools import formataddr, mute_logger -class TestMailSchedule(TestEventCommon, MockEmail): +class TestMailSchedule(EventCase, MockEmail): @mute_logger('odoo.addons.base.models.ir_model', 'odoo.models') def test_event_mail_schedule(self): diff --git a/addons/event_booth/tests/common.py b/addons/event_booth/tests/common.py index b378449ad6a..7b8fb50f907 100644 --- a/addons/event_booth/tests/common.py +++ b/addons/event_booth/tests/common.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase -class TestEventBoothCommon(TestEventCommon): +class TestEventBoothCommon(EventCase): @classmethod def setUpClass(cls): @@ -18,13 +18,3 @@ class TestEventBoothCommon(TestEventCommon): 'name': 'Premium', 'description': '

Premium

', }) - - cls.event_type_complex.write({ - 'event_type_booth_ids': [ - (5, 0), - (0, 0, - {'name': 'Standard 1', 'booth_category_id': cls.event_booth_category_1.id}), - (0, 0, - {'name': 'Premium 1', 'booth_category_id': cls.event_booth_category_2.id}), - ], - }) diff --git a/addons/event_booth_sale/tests/common.py b/addons/event_booth_sale/tests/common.py index b2c98e5b4a0..f72e6bf399b 100644 --- a/addons/event_booth_sale/tests/common.py +++ b/addons/event_booth_sale/tests/common.py @@ -2,10 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.event_booth.tests.common import TestEventBoothCommon -from odoo.addons.event_sale.tests.common import TestEventSaleCommon -class TestEventBoothSaleCommon(TestEventBoothCommon, TestEventSaleCommon): +class TestEventBoothSaleCommon(TestEventBoothCommon): @classmethod def setUpClass(cls): diff --git a/addons/event_crm/tests/common.py b/addons/event_crm/tests/common.py index c27b82d21c0..6d53c0fb41f 100644 --- a/addons/event_crm/tests/common.py +++ b/addons/event_crm/tests/common.py @@ -1,15 +1,18 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from datetime import datetime, timedelta + +from odoo import fields from odoo.addons.crm.tests.common import TestCrmCommon -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase -class TestEventCrmCommon(TestCrmCommon, TestEventCommon): +class EventCrmCase(TestCrmCommon, EventCase): @classmethod def setUpClass(cls): - super(TestEventCrmCommon, cls).setUpClass() + super(EventCrmCase, cls).setUpClass() # avoid clash with existing rules cls.env['event.lead.rule'].search([]).write({'active': False}) @@ -20,7 +23,6 @@ class TestEventCrmCommon(TestCrmCommon, TestEventCommon): 'name': 'Rule Attendee', 'lead_creation_basis': 'attendee', 'lead_creation_trigger': 'create', - 'event_id': cls.event_0.id, 'event_registration_filter': [['email', 'ilike', '@test.example.com']], 'lead_type': 'lead', 'lead_user_id': cls.user_sales_salesman.id, @@ -31,7 +33,6 @@ class TestEventCrmCommon(TestCrmCommon, TestEventCommon): 'name': 'Rule Order', 'lead_creation_basis': 'order', 'lead_creation_trigger': 'create', - 'event_id': cls.event_0.id, 'event_registration_filter': [['email', 'ilike', '@test.example.com']], 'lead_type': 'opportunity', 'lead_user_id': cls.user_sales_leads.id, @@ -96,7 +97,6 @@ class TestEventCrmCommon(TestCrmCommon, TestEventCommon): self.assertEqual(lead.partner_id, partner) self.assertEqual(lead.name, '%s - %s' % (event.name, expected_reg_name)) self.assertNotIn('False', lead.name) # avoid a "Dear False" like construct ^^ (this assert is serious and intended) - self.assertEqual(lead.contact_name, expected_contact_name) self.assertEqual(lead.partner_name, expected_partner_name) self.assertEqual(lead.email_from, partner.email if partner else registrations._find_first_notnull('email')) @@ -120,3 +120,21 @@ class TestEventCrmCommon(TestCrmCommon, TestEventCommon): self.assertEqual(lead.user_id, rule.lead_user_id) self.assertEqual(lead.team_id, rule.lead_sales_team_id) self.assertEqual(lead.tag_ids, rule.lead_tag_ids) + + +class TestEventCrmCommon(EventCrmCase): + + @classmethod + def setUpClass(cls): + super(TestEventCrmCommon, cls).setUpClass() + + cls.event_0 = cls.env['event.event'].create({ + 'name': 'TestEvent', + 'auto_confirm': True, + 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), + 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), + 'date_tz': 'Europe/Brussels', + }) + + cls.test_rule_attendee.event_id = cls.event_0.id + cls.test_rule_order.event_id = cls.event_0.id diff --git a/addons/event_sale/tests/common.py b/addons/event_sale/tests/common.py index cf75273e000..d40bbc853da 100644 --- a/addons/event_sale/tests/common.py +++ b/addons/event_sale/tests/common.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.event.tests.common import TestEventCommon +from datetime import datetime, timedelta + +from odoo import fields +from odoo.addons.event.tests.common import EventCase from odoo.addons.sales_team.tests.common import TestSalesCommon -class TestEventSaleCommon(TestEventCommon, TestSalesCommon): +class TestEventSaleCommon(EventCase, TestSalesCommon): @classmethod def setUpClass(cls): @@ -18,3 +21,26 @@ class TestEventSaleCommon(TestEventCommon, TestSalesCommon): 'standard_price': 30.0, 'detailed_type': 'event', }) + + cls.event_type_tickets = cls.env['event.type'].create({ + 'name': 'Update Type', + 'auto_confirm': True, + 'has_seats_limitation': True, + 'seats_max': 30, + 'default_timezone': 'Europe/Paris', + 'event_type_ticket_ids': [ + (0, 0, {'name': 'First Ticket', + 'product_id': cls.event_product.id, + 'seats_max': 5, + }) + ], + 'event_type_mail_ids': [], + }) + + cls.event_0 = cls.env['event.event'].create({ + 'name': 'TestEvent', + 'auto_confirm': True, + 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), + 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), + 'date_tz': 'Europe/Brussels', + }) diff --git a/addons/event_sale/tests/test_event_internals.py b/addons/event_sale/tests/test_event_internals.py index 6eb4833426e..b133a477f7e 100644 --- a/addons/event_sale/tests/test_event_internals.py +++ b/addons/event_sale/tests/test_event_internals.py @@ -15,7 +15,8 @@ class TestEventData(TestEventSaleCommon): def test_event_configuration_from_type(self): """ In addition to event test, also test tickets configuration coming from event_sale capabilities. """ - event_type = self.event_type_complex.with_user(self.env.user) + event_type = self.event_type_tickets.with_user(self.env.user) + self.assertEqual(event_type.event_type_ticket_ids.description, self.event_product.description_sale) event = self.env['event.event'].create({ 'name': 'Event Update Type', @@ -23,14 +24,6 @@ class TestEventData(TestEventSaleCommon): 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), }) - event_type.write({ - 'event_type_ticket_ids': [(5, 0), (0, 0, { - 'name': 'First Ticket', - 'product_id': self.event_product.id, - 'seats_max': 5, - })] - }) - self.assertEqual(event_type.event_type_ticket_ids.description, self.event_product.description_sale) # synchronize event event.write({'event_type_id': event_type.id}) diff --git a/addons/event_sms/tests/test_sms_schedule.py b/addons/event_sms/tests/test_sms_schedule.py index 25caf1b1855..8045c1ac65e 100644 --- a/addons/event_sms/tests/test_sms_schedule.py +++ b/addons/event_sms/tests/test_sms_schedule.py @@ -1,14 +1,16 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from dateutil.relativedelta import relativedelta +from datetime import datetime, timedelta -from odoo.addons.event.tests.common import TestEventCommon +from odoo import fields +from odoo.addons.event.tests.common import EventCase from odoo.addons.phone_validation.tools import phone_validation from odoo.addons.sms.tests.common import SMSCase +from odoo.tests import users -class TestSMSSchedule(TestEventCommon, SMSCase): +class TestSMSSchedule(EventCase, SMSCase): @classmethod def setUpClass(cls): @@ -27,7 +29,11 @@ class TestSMSSchedule(TestEventCommon, SMSCase): 'lang': '{{ object.partner_id.lang }}' }) - cls.event_0.write({ + cls.test_event = cls.env['event.event'].create({ + 'auto_confirm': True, + 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), + 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), + 'date_tz': 'Europe/Brussels', 'event_mail_ids': [ (5, 0), (0, 0, { # right at subscription @@ -41,51 +47,55 @@ class TestSMSSchedule(TestEventCommon, SMSCase): 'interval_type': 'before_event', 'notification_type': 'sms', 'template_ref': 'sms.template,%i' % cls.sms_template_rem.id}), - ] + ], + 'name': 'TestEvent', }) + @users('user_eventmanager') def test_sms_schedule(self): + test_event = self.env['event.event'].browse(self.test_event.ids) + with self.mockSMSGateway(): - self._create_registrations(self.event_0, 3) + self._create_registrations(test_event, 3) # check subscription scheduler - sub_scheduler = self.env['event.mail'].search([('event_id', '=', self.event_0.id), ('interval_type', '=', 'after_sub')]) + sub_scheduler = self.env['event.mail'].search([('event_id', '=', test_event.id), ('interval_type', '=', 'after_sub')]) self.assertEqual(len(sub_scheduler), 1) - self.assertEqual(sub_scheduler.scheduled_date, self.event_0.create_date, 'event: incorrect scheduled date for checking controller') + self.assertEqual(sub_scheduler.scheduled_date, test_event.create_date, 'event: incorrect scheduled date for checking controller') # verify that subscription scheduler was auto-executed after each registration self.assertEqual(len(sub_scheduler.mail_registration_ids), 3) self.assertTrue(all(m.mail_sent is True for m in sub_scheduler.mail_registration_ids)) - self.assertEqual(sub_scheduler.mapped('mail_registration_ids.registration_id'), self.event_0.registration_ids) + self.assertEqual(sub_scheduler.mapped('mail_registration_ids.registration_id'), test_event.registration_ids) sanitized_numbers = [] - for registration in self.event_0.registration_ids: + for registration in test_event.registration_ids: reg_sanitized_number = phone_validation.phone_format(registration.phone, 'BE', '32', force_format='E164') sanitized_numbers.append(reg_sanitized_number) self.assertSMSOutgoing( self.env['res.partner'], reg_sanitized_number, - content='%s registration confirmation.' % self.event_0.organizer_id.name) + content='%s registration confirmation.' % test_event.organizer_id.name) self.assertTrue(sub_scheduler.mail_done) self.assertEqual(sub_scheduler.mail_count_done, 3) # clear notification queue to avoid conflicts when checking next notifications - self.env['mail.notification'].search([('sms_number', 'in', sanitized_numbers)]).unlink() - self.env['sms.sms'].search([('number', 'in', sanitized_numbers)]).unlink() + self.env['mail.notification'].sudo().search([('sms_number', 'in', sanitized_numbers)]).unlink() + self.env['sms.sms'].sudo().search([('number', 'in', sanitized_numbers)]).unlink() # check before event scheduler - before_scheduler = self.env['event.mail'].search([('event_id', '=', self.event_0.id), ('interval_type', '=', 'before_event')]) + before_scheduler = self.env['event.mail'].search([('event_id', '=', test_event.id), ('interval_type', '=', 'before_event')]) self.assertEqual(len(before_scheduler), 1, 'event: wrong scheduler creation') - self.assertEqual(before_scheduler.scheduled_date, self.event_0.date_begin + relativedelta(days=-3)) + self.assertEqual(before_scheduler.scheduled_date, test_event.date_begin + timedelta(days=-3)) # execute event reminder scheduler explicitly with self.mockSMSGateway(): before_scheduler.execute() # verify that subscription scheduler was auto-executed after each registration - for registration in self.event_0.registration_ids: + for registration in test_event.registration_ids: reg_sanitized_number = phone_validation.phone_format(registration.phone, 'BE', '32', force_format='E164') self.assertSMSOutgoing( self.env['res.partner'], reg_sanitized_number, - content='%s reminder' % self.event_0.organizer_id.name) + content='%s reminder' % test_event.organizer_id.name) self.assertTrue(before_scheduler.mail_done) self.assertEqual(before_scheduler.mail_count_done, 3) diff --git a/addons/test_event_full/tests/test_event_security.py b/addons/test_event_full/tests/test_event_security.py index a5ba250691d..ec7f0ac3448 100644 --- a/addons/test_event_full/tests/test_event_security.py +++ b/addons/test_event_full/tests/test_event_security.py @@ -1,30 +1,46 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime -from dateutil.relativedelta import relativedelta +from datetime import datetime, timedelta -from odoo.addons.event.tests.common import TestEventCommon +from odoo import fields +from odoo.addons.event.tests.common import EventCase from odoo.exceptions import AccessError from odoo.tests.common import users from odoo.tools import mute_logger -class TestEventSecurity(TestEventCommon): +class TestEventSecurity(EventCase): + + @classmethod + def setUpClass(cls): + super(TestEventSecurity, cls).setUpClass() + + cls.test_event = cls.env['event.event'].create({ + 'auto_confirm': True, + 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), + 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), + 'date_tz': 'Europe/Brussels', + 'name': 'TestEvent', + }) + cls.test_event_type = cls.env['event.type'].create({ + 'auto_confirm': True, + 'name': 'Update Type', + }) @users('user_employee') @mute_logger('odoo.models.unlink', 'odoo.addons.base.models.ir_model') def test_event_access_employee(self): # Event: read ok - event = self.event_0.with_user(self.env.user) + event = self.test_event.with_user(self.env.user) event.read(['name']) # Event: read only with self.assertRaises(AccessError): self.env['event.event'].create({ 'name': 'TestEvent', - 'date_begin': datetime.now() + relativedelta(days=-1), - 'date_end': datetime.now() + relativedelta(days=1), + 'date_begin': datetime.now() + timedelta(days=-1), + 'date_end': datetime.now() + timedelta(days=1), 'seats_limited': True, 'seats_max': 10, }) @@ -35,9 +51,9 @@ class TestEventSecurity(TestEventCommon): # Event Type with self.assertRaises(AccessError): - self.event_type_complex.with_user(self.env.user).read(['name']) + self.test_event_type.with_user(self.env.user).read(['name']) with self.assertRaises(AccessError): - self.event_type_complex.with_user(self.env.user).write({'name': 'Test Write'}) + self.test_event_type.with_user(self.env.user).write({'name': 'Test Write'}) # Event Stage with self.assertRaises(AccessError): @@ -53,7 +69,7 @@ class TestEventSecurity(TestEventCommon): @mute_logger('odoo.models.unlink', 'odoo.addons.base.models.ir_model') def test_event_access_event_registration(self): # Event: read ok - event = self.event_0.with_user(self.env.user) + event = self.test_event.with_user(self.env.user) event.read(['name', 'user_id', 'kanban_state_label']) # Event: read only @@ -64,9 +80,9 @@ class TestEventSecurity(TestEventCommon): # Event Registration registration = self.env['event.registration'].create({ - 'event_id': self.event_0.id, + 'event_id': self.test_event.id, }) - self.assertEqual(registration.event_id.name, self.event_0.name, 'Registration users should be able to read') + self.assertEqual(registration.event_id.name, self.test_event.name, 'Registration users should be able to read') registration.name = 'Test write' with self.assertRaises(AccessError): registration.unlink() @@ -75,13 +91,13 @@ class TestEventSecurity(TestEventCommon): @mute_logger('odoo.models.unlink', 'odoo.addons.base.models.ir_model') def test_event_access_event_user(self): # Event - event = self.event_0.with_user(self.env.user) + event = self.test_event.with_user(self.env.user) event.read(['name', 'user_id', 'kanban_state_label']) event.write({'name': 'New name'}) self.env['event.event'].create({ 'name': 'Event', - 'date_begin': datetime.now() + relativedelta(days=-1), - 'date_end': datetime.now() + relativedelta(days=1), + 'date_begin': datetime.now() + timedelta(days=-1), + 'date_end': datetime.now() + timedelta(days=1), }) # Event: cannot unlink @@ -112,8 +128,8 @@ class TestEventSecurity(TestEventCommon): # Event event = self.env['event.event'].create({ 'name': 'ManagerEvent', - 'date_begin': datetime.now() + relativedelta(days=-1), - 'date_end': datetime.now() + relativedelta(days=1), + 'date_begin': datetime.now() + timedelta(days=-1), + 'date_end': datetime.now() + timedelta(days=1), }) event.write({'name': 'New Event Name'}) @@ -180,13 +196,13 @@ class TestEventSecurity(TestEventCommon): event_company_1, event_company_2 = self.env['event.event'].create([ { 'name': 'Event Company 1', - 'date_begin': datetime.now() + relativedelta(days=-1), - 'date_end': datetime.now() + relativedelta(days=1), + 'date_begin': datetime.now() + timedelta(days=-1), + 'date_end': datetime.now() + timedelta(days=1), 'company_id': company_1.id, }, { 'name': 'Event Company 2', - 'date_begin': datetime.now() + relativedelta(days=-1), - 'date_end': datetime.now() + relativedelta(days=1), + 'date_begin': datetime.now() + timedelta(days=-1), + 'date_end': datetime.now() + timedelta(days=1), 'company_id': company_2.id, } ]) diff --git a/addons/website_event/tests/common.py b/addons/website_event/tests/common.py index 7fe660d403f..31f7decc06a 100644 --- a/addons/website_event/tests/common.py +++ b/addons/website_event/tests/common.py @@ -4,7 +4,7 @@ from datetime import datetime, timedelta, time from unittest.mock import patch -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase from odoo.addons.mail.tests.common import mail_new_test_user from odoo.fields import Datetime as FieldsDatetime, Date as FieldsDate from odoo.tests.common import TransactionCase @@ -57,21 +57,30 @@ class EventDtPatcher(TransactionCase): cls.addClassCleanup(cls.wevent_main_date.stop) -class TestWebsiteEventCommon(TestEventCommon): +class OnlineEventCase(EventCase): @classmethod def setUpClass(cls): - super(TestWebsiteEventCommon, cls).setUpClass() + super(OnlineEventCase, cls).setUpClass() cls.company_main = cls.env.user.company_id cls.user_event_web_manager = mail_new_test_user( - cls.env, login='user_event_web_manager', - name='Martin Sales Manager', email='crm_manager@test.example.com', - company_id=cls.company_main.id, - notification_type='inbox', + cls.env, + company_id=cls.company_admin.id, + email='crm_manager@test.example.com', groups='event.group_event_manager,website.group_website_designer', + login='user_event_web_manager', + name='Martin Sales Manager', + notification_type='inbox', ) + cls.event_customer.write({ + 'website_description': '

I am your best customer, %s

' % cls.event_customer.name, + }) + cls.event_customer2.write({ + 'website_description': '

I am your best customer, %s

' % cls.event_customer2.name, + }) + def _get_menus(self): return set(['Introduction', 'Location', 'Register', 'Community']) @@ -97,21 +106,17 @@ class TestWebsiteEventCommon(TestEventCommon): self.assertFalse(bool(view)) -class TestEventOnlineCommon(TestEventCommon, EventDtPatcher): +class TestEventOnlineCommon(OnlineEventCase, EventDtPatcher): @classmethod def setUpClass(cls): super(TestEventOnlineCommon, cls).setUpClass() # event if 8-18 in Europe/Brussels (DST) (first day: begins at 9, last day: ends at 15) - cls.event_0.write({ + cls.event_0 = cls.env['event.event'].create({ + 'name': 'TestEvent', + 'auto_confirm': True, 'date_begin': datetime.combine(cls.reference_now, time(7, 0)) - timedelta(days=1), 'date_end': datetime.combine(cls.reference_now, time(13, 0)) + timedelta(days=1), - }) - - cls.event_customer.write({ - 'website_description': '

I am your best customer, %s

' % cls.event_customer.name, - }) - cls.event_customer2.write({ - 'website_description': '

I am your best customer, %s

' % cls.event_customer2.name, + 'date_tz': 'Europe/Brussels', }) diff --git a/addons/website_event/tests/test_event_menus.py b/addons/website_event/tests/test_event_menus.py index aa65e159119..5ecdcb16236 100644 --- a/addons/website_event/tests/test_event_menus.py +++ b/addons/website_event/tests/test_event_menus.py @@ -4,11 +4,11 @@ from datetime import datetime, timedelta from odoo import fields -from odoo.addons.website_event.tests.common import TestWebsiteEventCommon +from odoo.addons.website_event.tests.common import OnlineEventCase from odoo.tests.common import users -class TestEventMenus(TestWebsiteEventCommon): +class TestEventMenus(OnlineEventCase): @users('user_eventmanager') def test_menu_management(self): diff --git a/addons/website_event/tests/test_event_visitor.py b/addons/website_event/tests/test_event_visitor.py index b9ef29c6547..7ba97eee480 100644 --- a/addons/website_event/tests/test_event_visitor.py +++ b/addons/website_event/tests/test_event_visitor.py @@ -4,10 +4,10 @@ from datetime import datetime, timedelta from odoo import fields -from odoo.addons.website_event.tests.common import TestWebsiteEventCommon +from odoo.addons.website_event.tests.common import TestEventOnlineCommon -class TestEventVisitor(TestWebsiteEventCommon): +class TestEventVisitor(TestEventOnlineCommon): def test_visitor_events(self): event_1 = self.env['event.event'].create({ diff --git a/addons/website_event/tests/test_website_event.py b/addons/website_event/tests/test_website_event.py index 36ce39b74c8..3bdd6ed447f 100644 --- a/addons/website_event/tests/test_website_event.py +++ b/addons/website_event/tests/test_website_event.py @@ -6,7 +6,7 @@ from datetime import datetime, timedelta from odoo.addons.base.tests.common import HttpCaseWithUserDemo from odoo.addons.mail.tests.common import mail_new_test_user from odoo.addons.website.tests.test_base_url import TestUrlCommon -from odoo.addons.website_event.tests.common import TestWebsiteEventCommon +from odoo.addons.website_event.tests.common import OnlineEventCase from odoo.tests import tagged from odoo.tools import mute_logger @@ -27,7 +27,7 @@ class TestURLs(TestUrlCommon): @tagged('post_install', '-at_install') -class TestWebsiteAccess(HttpCaseWithUserDemo, TestWebsiteEventCommon): +class TestWebsiteAccess(HttpCaseWithUserDemo, OnlineEventCase): def setUp(self): super(TestWebsiteAccess, self).setUp() diff --git a/addons/website_event_exhibitor/tests/common.py b/addons/website_event_exhibitor/tests/common.py index 9e957fc2d32..57768661eed 100644 --- a/addons/website_event_exhibitor/tests/common.py +++ b/addons/website_event_exhibitor/tests/common.py @@ -26,4 +26,6 @@ class TestEventExhibitorCommon(TestEventOnlineCommon): 'partner_id': cls.sponsor_0_partner.id, 'event_id': cls.event_0.id, 'sponsor_type_id': cls.sponsor_type_0.id, + 'hour_from': 8.0, + 'hour_to': 18.0, }) diff --git a/addons/website_event_exhibitor/tests/test_sponsor_internals.py b/addons/website_event_exhibitor/tests/test_sponsor_internals.py index 8a84840042f..4d952f7ff2e 100644 --- a/addons/website_event_exhibitor/tests/test_sponsor_internals.py +++ b/addons/website_event_exhibitor/tests/test_sponsor_internals.py @@ -15,11 +15,6 @@ class TestSponsorData(TestEventExhibitorCommon): def setUpClass(cls): super(TestSponsorData, cls).setUpClass() - cls.sponsor_0.write({ - 'hour_from': 8.0, - 'hour_to': 18.0, - }) - cls.wevent_exhib_dt = patch( 'odoo.addons.website_event_exhibitor.models.event_sponsor.fields.Datetime', wraps=FieldsDatetime diff --git a/addons/website_event_meet/tests/test_website_event_meet.py b/addons/website_event_meet/tests/test_website_event_meet.py index 8d1b8a95b0f..3e91f364481 100644 --- a/addons/website_event_meet/tests/test_website_event_meet.py +++ b/addons/website_event_meet/tests/test_website_event_meet.py @@ -1,11 +1,26 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.event.tests.common import TestEventCommon +from datetime import datetime, timedelta + +from odoo import fields +from odoo.addons.event.tests.common import EventCase from odoo.tests import Form -class TestWebsiteEventMeet(TestEventCommon): +class TestWebsiteEventMeet(EventCase): + + @classmethod + def setUpClass(cls): + super(TestWebsiteEventMeet, cls).setUpClass() + cls.event_0 = cls.env['event.event'].create({ + 'name': 'TestEvent', + 'auto_confirm': True, + 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), + 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), + 'date_tz': 'Europe/Brussels', + }) + def test_meeting_room_create(self): """Test that the field of the mixin are automatically filled.""" new_meeting_room_form = Form(self.env["event.meeting.room"]) diff --git a/addons/website_event_questions/tests/common.py b/addons/website_event_questions/tests/common.py index 1a621875dc2..62c30acbd70 100644 --- a/addons/website_event_questions/tests/common.py +++ b/addons/website_event_questions/tests/common.py @@ -1,19 +1,29 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.event.tests.common import TestEventCommon +from odoo.addons.event.tests.common import EventCase -class TestEventQuestionCommon(TestEventCommon): +class TestEventQuestionCommon(EventCase): @classmethod def setUpClass(cls): super(TestEventQuestionCommon, cls).setUpClass() + cls.event_type_questions = cls.env['event.type'].create({ + 'name': 'Update Type', + 'auto_confirm': True, + 'has_seats_limitation': True, + 'seats_max': 30, + 'default_timezone': 'Europe/Paris', + 'event_type_ticket_ids': [], + 'event_type_mail_ids': [], + }) + cls.event_question_1 = cls.env['event.question'].create({ 'title': 'Question1', 'question_type': 'simple_choice', - 'event_type_id': cls.event_type_complex.id, + 'event_type_id': cls.event_type_questions.id, 'once_per_order': False, 'answer_ids': [ (0, 0, {'name': 'Q1-Answer1'}), @@ -23,7 +33,7 @@ class TestEventQuestionCommon(TestEventCommon): cls.event_question_2 = cls.env['event.question'].create({ 'title': 'Question2', 'question_type': 'simple_choice', - 'event_type_id': cls.event_type_complex.id, + 'event_type_id': cls.event_type_questions.id, 'once_per_order': True, 'answer_ids': [ (0, 0, {'name': 'Q2-Answer1'}), @@ -33,6 +43,6 @@ class TestEventQuestionCommon(TestEventCommon): cls.event_question_3 = cls.env['event.question'].create({ 'title': 'Question3', 'question_type': 'text_box', - 'event_type_id': cls.event_type_complex.id, + 'event_type_id': cls.event_type_questions.id, 'once_per_order': True, }) diff --git a/addons/website_event_questions/tests/test_event_internals.py b/addons/website_event_questions/tests/test_event_internals.py index 28c9099734a..f1b8ce7d322 100644 --- a/addons/website_event_questions/tests/test_event_internals.py +++ b/addons/website_event_questions/tests/test_event_internals.py @@ -14,7 +14,7 @@ class TestEventData(TestEventQuestionCommon): @users('user_eventmanager') def test_event_type_configuration_from_type(self): - event_type = self.event_type_complex.with_user(self.env.user) + event_type = self.event_type_questions.with_user(self.env.user) event = self.env['event.event'].create({ 'name': 'Event Update Type', @@ -40,7 +40,7 @@ class TestEventData(TestEventQuestionCommon): def test_process_attendees_form(self): event = self.env['event.event'].create({ 'name': 'Event Update Type', - 'event_type_id': self.event_type_complex.with_user(self.env.user).id, + 'event_type_id': self.event_type_questions.with_user(self.env.user).id, 'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)), 'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)), }) diff --git a/addons/website_event_track/tests/test_event_menus.py b/addons/website_event_track/tests/test_event_menus.py index ab0093563b2..3d07e3baf89 100644 --- a/addons/website_event_track/tests/test_event_menus.py +++ b/addons/website_event_track/tests/test_event_menus.py @@ -4,11 +4,11 @@ from datetime import datetime, timedelta from odoo import fields -from odoo.addons.website_event.tests.common import TestWebsiteEventCommon +from odoo.addons.website_event.tests.common import OnlineEventCase from odoo.tests.common import users -class TestEventWebsiteTrack(TestWebsiteEventCommon): +class TestEventWebsiteTrack(OnlineEventCase): def _get_menus(self): return super(TestEventWebsiteTrack, self)._get_menus() | set(['Talks', 'Agenda', 'Talk Proposals']) From 237911775c7b230695c229b924cd96cb8cda3b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 8 Dec 2021 08:36:01 +0000 Subject: [PATCH 2/8] [REF] website_event_*: remove manual datetime patch Use freezegun as it is more easy to use and allow to remove a lot of extra boilerplate. Indeed manually patching datetime is a PITA as a lot of imports have to be patched. A custom patching has to be done for create_date, as it is done using a value stored on the cursor (cr._now), based on SQL now. As it has nothing to do with standard python library it cannot be patched using freezegun. Task-2703285 (Event performance improvements) Task-2703289 (Event testing and coverage) Part-of: odoo/odoo#81068 --- .../event_sale/tests/test_event_internals.py | 17 +--- addons/test_event_full/tests/common.py | 5 +- addons/website_event/tests/common.py | 53 +---------- .../tests/test_sponsor_internals.py | 92 ++++++++----------- 4 files changed, 46 insertions(+), 121 deletions(-) diff --git a/addons/event_sale/tests/test_event_internals.py b/addons/event_sale/tests/test_event_internals.py index b133a477f7e..260a4ddf131 100644 --- a/addons/event_sale/tests/test_event_internals.py +++ b/addons/event_sale/tests/test_event_internals.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import date, datetime, timedelta -from unittest.mock import patch +from freezegun import freeze_time from odoo.addons.event_sale.tests.common import TestEventSaleCommon from odoo.fields import Datetime as FieldsDatetime, Date as FieldsDate @@ -66,20 +66,7 @@ class TestEventData(TestEventSaleCommon): class TestEventTicketData(TestEventSaleCommon): - def setUp(self): - super(TestEventTicketData, self).setUp() - self.ticket_date_patcher = patch('odoo.addons.event.models.event_ticket.fields.Date', wraps=FieldsDate) - self.ticket_date_patcher_mock = self.ticket_date_patcher.start() - self.ticket_date_patcher_mock.context_today.return_value = date(2020, 1, 31) - self.ticket_datetime_patcher = patch('odoo.addons.event.models.event_event.fields.Datetime', wraps=FieldsDatetime) - self.mock_datetime = self.ticket_datetime_patcher.start() - self.mock_datetime.now.return_value = datetime(2020, 1, 31, 10, 0, 0) - - def tearDown(self): - super(TestEventTicketData, self).tearDown() - self.ticket_date_patcher.stop() - self.ticket_datetime_patcher.stop() - + @freeze_time('2020-01-31 10:00:00') @users('user_eventmanager') def test_event_ticket_fields(self): """ Test event ticket fields synchronization """ diff --git a/addons/test_event_full/tests/common.py b/addons/test_event_full/tests/common.py index 0f5b152364b..9b4f4ede0c2 100644 --- a/addons/test_event_full/tests/common.py +++ b/addons/test_event_full/tests/common.py @@ -7,10 +7,9 @@ from odoo.addons.base.tests.common import HttpCaseWithUserDemo, HttpCaseWithUser from odoo.addons.event_crm.tests.common import TestEventCrmCommon from odoo.addons.sales_team.tests.common import TestSalesCommon from odoo.addons.website.tests.test_website_visitor import MockVisitor -from odoo.addons.website_event.tests.common import EventDtPatcher -class TestEventFullCommon(TestEventCrmCommon, TestSalesCommon, EventDtPatcher, MockVisitor): +class TestEventFullCommon(TestEventCrmCommon, TestSalesCommon, MockVisitor): @classmethod def setUpClass(cls): @@ -127,7 +126,7 @@ class TestEventFullCommon(TestEventCrmCommon, TestSalesCommon, EventDtPatcher, M self.assertIn(answer.value_text_box, lead.description) # better: check multi line -class TestWEventCommon(HttpCaseWithUserDemo, HttpCaseWithUserPortal, EventDtPatcher, MockVisitor): +class TestWEventCommon(HttpCaseWithUserDemo, HttpCaseWithUserPortal, MockVisitor): def setUp(self): super(TestWEventCommon, self).setUp() diff --git a/addons/website_event/tests/common.py b/addons/website_event/tests/common.py index 31f7decc06a..cc081c84ed4 100644 --- a/addons/website_event/tests/common.py +++ b/addons/website_event/tests/common.py @@ -10,53 +10,6 @@ from odoo.fields import Datetime as FieldsDatetime, Date as FieldsDate from odoo.tests.common import TransactionCase -class EventDtPatcher(TransactionCase): - - @classmethod - def setUpClass(cls): - super(EventDtPatcher, cls).setUpClass() - - # Mock dates to have reproducible computed fields based on time - cls.reference_now = datetime(2020, 7, 6, 10, 0, 0) - cls.reference_today = datetime(2020, 7, 6) - - cls.event_dt = patch( - 'odoo.addons.event.models.event_event.fields.Datetime', - wraps=FieldsDatetime - ) - cls.wevent_dt = patch( - 'odoo.addons.website_event.models.event_event.fields.Datetime', - wraps=FieldsDatetime - ) - cls.wevent_main_dt = patch( - 'odoo.addons.website_event.controllers.main.fields.Datetime', - wraps=FieldsDatetime - ) - cls.event_date = patch( - 'odoo.addons.event.models.event_event.fields.Date', - wraps=FieldsDate - ) - cls.wevent_main_date = patch( - 'odoo.addons.website_event.controllers.main.fields.Date', - wraps=FieldsDate - ) - cls.mock_event_dt = cls.event_dt.start() - cls.mock_wevent_dt = cls.wevent_dt.start() - cls.mock_wevent_main_dt = cls.wevent_main_dt.start() - cls.mock_event_date = cls.event_date.start() - cls.mock_wevent_main_date = cls.wevent_main_date.start() - cls.mock_event_dt.now.return_value = cls.reference_now - cls.mock_wevent_dt.now.return_value = cls.reference_now - cls.mock_wevent_main_dt.now.return_value = cls.reference_now - cls.mock_event_date.today.return_value = cls.reference_today - cls.mock_wevent_main_date.today.return_value = cls.reference_today - cls.addClassCleanup(cls.event_dt.stop) - cls.addClassCleanup(cls.wevent_dt.stop) - cls.addClassCleanup(cls.wevent_main_dt.stop) - cls.addClassCleanup(cls.event_date.stop) - cls.addClassCleanup(cls.wevent_main_date.stop) - - class OnlineEventCase(EventCase): @classmethod @@ -106,12 +59,16 @@ class OnlineEventCase(EventCase): self.assertFalse(bool(view)) -class TestEventOnlineCommon(OnlineEventCase, EventDtPatcher): +class TestEventOnlineCommon(OnlineEventCase): @classmethod def setUpClass(cls): super(TestEventOnlineCommon, cls).setUpClass() + # Mock dates to have reproducible computed fields based on time + cls.reference_now = datetime(2020, 7, 6, 10, 0, 0) + cls.reference_today = datetime(2020, 7, 6) + # event if 8-18 in Europe/Brussels (DST) (first day: begins at 9, last day: ends at 15) cls.event_0 = cls.env['event.event'].create({ 'name': 'TestEvent', diff --git a/addons/website_event_exhibitor/tests/test_sponsor_internals.py b/addons/website_event_exhibitor/tests/test_sponsor_internals.py index 4d952f7ff2e..64ac1595b58 100644 --- a/addons/website_event_exhibitor/tests/test_sponsor_internals.py +++ b/addons/website_event_exhibitor/tests/test_sponsor_internals.py @@ -2,81 +2,63 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from datetime import datetime -from unittest.mock import patch +from freezegun import freeze_time from odoo.addons.website_event_exhibitor.tests.common import TestEventExhibitorCommon -from odoo.fields import Datetime as FieldsDatetime from odoo.tests.common import users class TestSponsorData(TestEventExhibitorCommon): - @classmethod - def setUpClass(cls): - super(TestSponsorData, cls).setUpClass() - - cls.wevent_exhib_dt = patch( - 'odoo.addons.website_event_exhibitor.models.event_sponsor.fields.Datetime', - wraps=FieldsDatetime - ) - cls.mock_wevent_exhib_dt = cls.wevent_exhib_dt.start() - cls.mock_wevent_exhib_dt.now.return_value = cls.reference_now - cls.addClassCleanup(cls.wevent_exhib_dt.stop) - @users('user_eventmanager') def test_event_date_computation(self): """ Test date computation. Pay attention that mocks returns UTC values, meaning we have to take into account Europe/Brussels offset """ - event = self.env['event.event'].browse(self.event_0.id) - sponsor = self.env['event.sponsor'].browse(self.sponsor_0.id) - event.invalidate_cache(fnames=['is_ongoing']) - self.assertTrue(sponsor.is_in_opening_hours) - self.assertTrue(event.is_ongoing) + with freeze_time(self.reference_now): + event = self.env['event.event'].browse(self.event_0.id) + sponsor = self.env['event.sponsor'].browse(self.sponsor_0.id) + event.invalidate_cache(fnames=['is_ongoing']) + self.assertTrue(sponsor.is_in_opening_hours) + self.assertTrue(event.is_ongoing) # After hour_from (9 > 8) - self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 7, 0, 0) - self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 7, 0, 0) - event.invalidate_cache(fnames=['is_ongoing']) - sponsor.invalidate_cache(fnames=['is_in_opening_hours']) - self.assertTrue(sponsor.is_in_opening_hours) - self.assertTrue(event.is_ongoing) + with freeze_time(datetime(2020, 7, 6, 7, 0, 0)): + event.invalidate_cache(fnames=['is_ongoing']) + sponsor.invalidate_cache(fnames=['is_in_opening_hours']) + self.assertTrue(sponsor.is_in_opening_hours) + self.assertTrue(event.is_ongoing) # At hour_from (8 = 8) - self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 6, 0, 0) - self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 6, 0, 0) - event.invalidate_cache(fnames=['is_ongoing']) - sponsor.invalidate_cache(fnames=['is_in_opening_hours']) - self.assertTrue(sponsor.is_in_opening_hours) - self.assertTrue(event.is_ongoing) + with freeze_time(datetime(2020, 7, 6, 6, 0, 0)): + event.invalidate_cache(fnames=['is_ongoing']) + sponsor.invalidate_cache(fnames=['is_in_opening_hours']) + self.assertTrue(sponsor.is_in_opening_hours) + self.assertTrue(event.is_ongoing) # Started but not opened (7h59 < 8) - self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 5, 59, 59) - self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 5, 59, 59) - event.invalidate_cache(fnames=['is_ongoing']) - sponsor.invalidate_cache(fnames=['is_in_opening_hours']) - self.assertFalse(sponsor.is_in_opening_hours) - self.assertTrue(event.is_ongoing) + with freeze_time(datetime(2020, 7, 6, 5, 59, 59)): + event.invalidate_cache(fnames=['is_ongoing']) + sponsor.invalidate_cache(fnames=['is_in_opening_hours']) + self.assertFalse(sponsor.is_in_opening_hours) + self.assertTrue(event.is_ongoing) # Evening event is not in opening hours (20 > 18) - self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 18, 0, 0) - self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 18, 0, 0) - event.invalidate_cache(fnames=['is_ongoing']) - sponsor.invalidate_cache(fnames=['is_in_opening_hours']) - self.assertFalse(sponsor.is_in_opening_hours) - self.assertTrue(event.is_ongoing) + with freeze_time(datetime(2020, 7, 6, 18, 0, 0)): + event.invalidate_cache(fnames=['is_ongoing']) + sponsor.invalidate_cache(fnames=['is_in_opening_hours']) + self.assertFalse(sponsor.is_in_opening_hours) + self.assertTrue(event.is_ongoing) # First day begins later - self.mock_wevent_dt.now.return_value = datetime(2020, 7, 5, 6, 30, 0) - self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 5, 6, 30, 0) - event.invalidate_cache(fnames=['is_ongoing']) - sponsor.invalidate_cache(fnames=['is_in_opening_hours']) - self.assertFalse(sponsor.is_in_opening_hours) - self.assertFalse(event.is_ongoing) + with freeze_time(datetime(2020, 7, 5, 6, 30, 0)): + event.invalidate_cache(fnames=['is_ongoing']) + sponsor.invalidate_cache(fnames=['is_in_opening_hours']) + self.assertFalse(sponsor.is_in_opening_hours) + self.assertFalse(event.is_ongoing) # End day finished sooner - self.mock_wevent_dt.now.return_value = datetime(2020, 7, 7, 13, 0, 1) - self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 7, 13, 0, 1) - event.invalidate_cache(fnames=['is_ongoing']) - sponsor.invalidate_cache(fnames=['is_in_opening_hours']) - self.assertFalse(sponsor.is_in_opening_hours) - self.assertFalse(event.is_ongoing) + with freeze_time(datetime(2020, 7, 7, 13, 0, 1)): + event.invalidate_cache(fnames=['is_ongoing']) + sponsor.invalidate_cache(fnames=['is_in_opening_hours']) + self.assertFalse(sponsor.is_in_opening_hours) + self.assertFalse(event.is_ongoing) From ad5c08ca090e2cd0ae579b72a8ab22583fcbc378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 7 Dec 2021 15:55:32 +0000 Subject: [PATCH 3/8] [REF] test_event_full: cleanup tests Purpose of this commit is to make test_event_full globally independent from other event sub modules testing data. We now define a complete event type with all sub options clearly activated in a single setup. That way tests in test_event_full are easier to read, understand and modify. A custom report replacing badge report is added as the base one is quite complex. It is easier to test the result with simpler templates. Task-2703285 (Event performance improvements) Task-2703289 (Event testing and coverage) Part-of: odoo/odoo#81068 --- addons/test_event_full/__manifest__.py | 5 +- .../data/ir_actions_report_data.xml | 13 + addons/test_event_full/tests/common.py | 327 ++++++++++++++---- .../test_event_full/tests/test_event_crm.py | 38 +- .../tests/test_event_security.py | 27 +- .../tests/test_wevent_register.py | 16 +- .../event_registration_templates_reports.xml | 14 + 7 files changed, 323 insertions(+), 117 deletions(-) create mode 100644 addons/test_event_full/data/ir_actions_report_data.xml create mode 100644 addons/test_event_full/views/event_registration_templates_reports.xml diff --git a/addons/test_event_full/__manifest__.py b/addons/test_event_full/__manifest__.py index a474fbd6cdf..1b7bd2c6741 100644 --- a/addons/test_event_full/__manifest__.py +++ b/addons/test_event_full/__manifest__.py @@ -25,7 +25,10 @@ automatic lead generation, full Online support, ... 'website_event_track_live', 'website_event_track_quiz', ], - 'installable': True, + 'data': [ + 'data/ir_actions_report_data.xml', + 'views/event_registration_templates_reports.xml', + ], 'assets': { 'web.assets_tests': [ 'test_event_full/static/**/*', diff --git a/addons/test_event_full/data/ir_actions_report_data.xml b/addons/test_event_full/data/ir_actions_report_data.xml new file mode 100644 index 00000000000..2b1608935a7 --- /dev/null +++ b/addons/test_event_full/data/ir_actions_report_data.xml @@ -0,0 +1,13 @@ + + + + Test Report + event.registration + qweb-pdf + test_event_full.event_registration_template_report + test_event_full.event_registration_template_report + 'Badge - %s - %s' % ((object.event_id.name or 'Event').replace('/',''), object.name.replace('/','')) + + report + + diff --git a/addons/test_event_full/tests/common.py b/addons/test_event_full/tests/common.py index 9b4f4ede0c2..d3c962cffc4 100644 --- a/addons/test_event_full/tests/common.py +++ b/addons/test_event_full/tests/common.py @@ -4,109 +4,287 @@ from datetime import datetime, timedelta, time from odoo.addons.base.tests.common import HttpCaseWithUserDemo, HttpCaseWithUserPortal -from odoo.addons.event_crm.tests.common import TestEventCrmCommon +from odoo.addons.event_crm.tests.common import EventCrmCase +from odoo.addons.mail.tests.common import mail_new_test_user from odoo.addons.sales_team.tests.common import TestSalesCommon from odoo.addons.website.tests.test_website_visitor import MockVisitor -class TestEventFullCommon(TestEventCrmCommon, TestSalesCommon, MockVisitor): +class TestEventFullCommon(EventCrmCase, TestSalesCommon, MockVisitor): @classmethod def setUpClass(cls): super(TestEventFullCommon, cls).setUpClass() + cls._init_mail_gateway() - # ------------------------------------------------------------ - # TICKET INFORMATIONS + # Context data: dates # ------------------------------------------------------------ - cls.event_product = cls.env['product.product'].create({ - 'name': 'Test Registration Product', - 'description_sale': 'Mighty Description', - 'list_price': 10, - 'standard_price': 30.0, - 'detailed_type': 'event', + # Mock dates to have reproducible computed fields based on time + cls.reference_now = datetime(2021, 12, 1, 10, 0, 0) + cls.reference_today = datetime(2021, 12, 1) + + # Users and contacts + # ------------------------------------------------------------ + + cls.admin_user = cls.env.ref('base.user_admin') + cls.admin_user.write({ + 'country_id': cls.env.ref('base.be').id, + 'login': 'admin', + 'notification_type': 'inbox', }) - - cls.website = cls.env['website'].search([ - ('company_id', '=', cls.env.user.company_id.id) - ], limit=1) - - cls.event_0.write({ - # event if 8-18 in Europe/Brussels (DST) (first day: begins at 9, last day: ends at 15) - 'date_begin': datetime.combine(cls.reference_now, time(7, 0)) - timedelta(days=1), - 'date_end': datetime.combine(cls.reference_now, time(13, 0)) + timedelta(days=1), - # ticket informations - 'event_ticket_ids': [ - (5, 0), - (0, 0, { - 'name': 'First Ticket', - 'product_id': cls.event_product.id, - 'seats_max': 30, - }), (0, 0, { - 'name': 'Second Ticket', - 'product_id': cls.event_product.id, - }) - ], + cls.company_admin = cls.admin_user.company_id + # set country in order to format Belgian numbers + cls.company_admin.write({ + 'country_id': cls.env.ref('base.be').id, }) + cls.event_user = mail_new_test_user( + cls.env, + company_id=cls.company_admin.id, + company_ids=[(4, cls.company_admin.id)], + country_id=cls.env.ref('base.be').id, + groups='base.group_user,base.group_partner_manager,event.group_event_user', + email='e.e@example.com', + login='event_user', + name='Ernest Employee', + notification_type='inbox', + signature='--\nErnest', + ) + cls.customer = cls.env['res.partner'].create({ + 'country_id': cls.env.ref('base.be').id, + 'email': 'customer.test@example.com', + 'name': 'Test Customer', + 'mobile': '0456123456', + 'phone': '0456123456', + }) # make a SO for a customer, selling some tickets cls.customer_so = cls.env['sale.order'].with_user(cls.user_sales_salesman).create({ 'partner_id': cls.event_customer.id, }) - # ------------------------------------------------------------ - # QUESTIONS + # Side records for event main records # ------------------------------------------------------------ - cls.event_question_1 = cls.env['event.question'].create({ - 'title': 'Question1', - 'question_type': 'simple_choice', - 'event_id': cls.event_0.id, - 'once_per_order': False, - 'answer_ids': [ - (0, 0, {'name': 'Q1-Answer1'}), - (0, 0, {'name': 'Q1-Answer2'}) + cls.ticket_product = cls.env['product.product'].create({ + 'description_sale': 'Ticket Product Description', + 'detailed_type': 'event', + 'list_price': 10, + 'name': 'Test Registration Product', + 'standard_price': 30.0, + }) + cls.booth_product = cls.env['product.product'].create({ + 'description_sale': 'Booth Product Description', + 'detailed_type': 'event_booth', + 'list_price': 20, + 'name': 'Test Booth Product', + 'standard_price': 60.0, + }) + + cls.tag_categories = cls.env['event.tag.category'].create([ + {'is_published': True, 'name': 'Published Category'}, + {'is_published': False, 'name': 'Unpublished Category'}, + ]) + cls.tags = cls.env['event.tag'].create([ + {'category_id': cls.tag_categories[0].id, 'name': 'PubTag1'}, + {'category_id': cls.tag_categories[0].id, 'color': 0, 'name': 'PubTag2'}, + {'category_id': cls.tag_categories[1].id, 'name': 'UnpubTag1'}, + ]) + + cls.event_booth_categories = cls.env['event.booth.category'].create([ + {'description': '

Standard

', + 'name': 'Standard', + 'product_id': cls.booth_product.id, + }, + {'description': '

Premium

', + 'name': 'Premium', + 'product_id': cls.booth_product.id, + 'price': 90, + } + ]) + + cls.sponsor_types = cls.env['event.sponsor.type'].create([ + {'name': 'GigaTop', + 'sequence': 1, + } + ]) + cls.sponsor_partners = cls.env['res.partner'].create([ + {'country_id': cls.env.ref('base.be').id, + 'email': 'event.sponsor@example.com', + 'name': 'EventSponsor', + 'phone': '04856112233', + } + ]) + + # Event type + # ------------------------------------------------------------ + test_registration_report = cls.env.ref('test_event_full.event_registration_report_test') + subscription_template = cls.env.ref('event.event_subscription') + subscription_template.write({'report_template': test_registration_report.id}) + cls.test_event_type = cls.env['event.type'].create({ + 'auto_confirm': True, + 'default_timezone': 'Europe/Paris', + 'event_type_booth_ids': [ + (0, 0, {'booth_category_id': cls.event_booth_categories[0].id, + 'name': 'Standard Booth', + } + ), + (0, 0, {'booth_category_id': cls.event_booth_categories[0].id, + 'name': 'Standard Booth 2', + } + ), + (0, 0, {'booth_category_id': cls.event_booth_categories[1].id, + 'name': 'Premium Booth', + } + ), + (0, 0, {'booth_category_id': cls.event_booth_categories[1].id, + 'name': 'Premium Booth 2', + } + ), ], - }) - cls.event_question_2 = cls.env['event.question'].create({ - 'title': 'Question2', - 'question_type': 'simple_choice', - 'event_id': cls.event_0.id, - 'once_per_order': True, - 'answer_ids': [ - (0, 0, {'name': 'Q2-Answer1'}), - (0, 0, {'name': 'Q2-Answer2'}) + 'event_type_mail_ids': [ + (0, 0, {'interval_unit': 'now', # right at subscription + 'interval_type': 'after_sub', + 'notification_type': 'mail', + 'template_ref': 'mail.template,%i' % subscription_template.id, + } + ), + (0, 0, {'interval_nbr': 1, # 1 days before event + 'interval_unit': 'days', + 'interval_type': 'before_event', + 'notification_type': 'mail', + 'template_ref': 'mail.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event.event_reminder'), + } + ), + (0, 0, {'interval_nbr': 1, # 1 days after event + 'interval_unit': 'days', + 'interval_type': 'after_event', + 'notification_type': 'sms', + 'template_ref': 'sms.template,%i' % cls.env['ir.model.data']._xmlid_to_res_id('event_sms.sms_template_data_event_reminder'), + } + ), ], - }) - cls.event_question_3 = cls.env['event.question'].create({ - 'title': 'Question3', - 'question_type': 'text_box', - 'event_id': cls.event_0.id, - 'once_per_order': True, + 'event_type_ticket_ids': [ + (0, 0, {'description': 'Ticket1 Description', + 'name': 'Ticket1', + 'product_id': cls.ticket_product.id, + 'seats_max': 10, + } + ), + (0, 0, {'description': 'Ticket2 Description', + 'name': 'Ticket2', + 'product_id': cls.ticket_product.id, + 'price': 45, + } + ) + ], + 'has_seats_limitation': True, + 'name': 'Test Type', + 'note': '

Template note

', + 'question_ids': [ + (0, 0, {'answer_ids': + [(0, 0, {'name': 'Q1-Answer1'}), + (0, 0, {'name': 'Q1-Answer2'}), + ], + 'question_type': 'simple_choice', + 'once_per_order': False, + 'title': 'Question1', + } + ), + (0, 0, {'answer_ids': + [(0, 0, {'name': 'Q2-Answer1'}), + (0, 0, {'name': 'Q2-Answer2'}), + ], + 'question_type': 'simple_choice', + 'once_per_order': False, + 'title': 'Question2', + } + ), + (0, 0, {'question_type': 'text_box', + 'once_per_order': True, + 'title': 'Question3', + } + ), + ], + 'seats_max': 30, + 'tag_ids': [(4, tag.id) for tag in cls.tags], + 'ticket_instructions': '

Ticket Instructions

', + 'website_menu': True, }) - # ------------------------------------------------------------ - # DATA MARSHMALLING + # Stages + cls.stage_def = cls.env['event.stage'].create({ + 'name': 'First Stage', + 'sequence': 0, + }) + + # Event data # ------------------------------------------------------------ - cls.website_customer_data = [{ - 'name': 'My Customer %02d' % x, - 'partner_id': cls.env.ref('base.public_partner').id, - 'email': 'email.%02d@test.example.com' % x, - 'phone': '04560000%02d' % x, - 'registration_answer_ids': [ + cls.event_base_vals = { + 'name': 'Test Event', + 'date_begin': cls.reference_now + timedelta(days=1), + 'date_end': cls.reference_now + timedelta(days=5), + 'is_published': True, + } + + cls.test_event = cls.env['event.event'].create({ + 'name': 'Test Event', + 'auto_confirm': True, + 'date_begin': datetime.now() + timedelta(days=1), + 'date_end': datetime.now() + timedelta(days=5), + 'date_tz': 'Europe/Brussels', + 'event_type_id': cls.test_event_type.id, + 'is_published': True, + }) + # update post-synchronize data + ticket_1 = cls.test_event.event_ticket_ids.filtered(lambda t: t.name == 'Ticket1') + ticket_2 = cls.test_event.event_ticket_ids.filtered(lambda t: t.name == 'Ticket2') + ticket_1.start_sale_datetime = cls.reference_now + timedelta(hours=1) + ticket_2.start_sale_datetime = cls.reference_now + timedelta(hours=2) + + # Website data + # ------------------------------------------------------------ + + cls.website = cls.env['website'].search([ + ('company_id', '=', cls.company_admin.id) + ], limit=1) + + cls.customer_data = [ + {'email': 'customer.email.%02d@test.example.com' % x, + 'name': 'My Customer %02d' % x, + 'mobile': '04569999%02d' % x, + 'partner_id': False, + 'phone': '04560000%02d' % x, + } for x in range(0, 10) + ] + cls.website_customer_data = [ + {'email': 'website.email.%02d@test.example.com' % x, + 'name': 'My Customer %02d' % x, + 'mobile': '04569999%02d' % x, + 'partner_id': cls.env.ref('base.public_partner').id, + 'phone': '04560000%02d' % x, + 'registration_answer_ids': [ (0, 0, { - 'question_id': cls.event_question_1.id, - 'value_answer_id': cls.event_question_1.answer_ids[(x % 2)].id, + 'question_id': cls.test_event.question_ids[0].id, + 'value_answer_id': cls.test_event.question_ids[0].answer_ids[(x % 2)].id, }), (0, 0, { - 'question_id': cls.event_question_2.id, - 'value_answer_id': cls.event_question_2.answer_ids[(x % 2)].id, + 'question_id': cls.test_event.question_ids[1].id, + 'value_answer_id': cls.test_event.question_ids[1].answer_ids[(x % 2)].id, }), (0, 0, { - 'question_id': cls.event_question_3.id, + 'question_id': cls.test_event.question_ids[2].id, 'value_text_box': 'CustomerAnswer%s' % x, }) - ], - } for x in range(0, 4)] + ], + } for x in range(0, 10) + ] + cls.partners = cls.env['res.partner'].create([ + {'email': 'partner.email.%02d@test.example.com' % x, + 'name': 'PartnerCustomer', + 'mobile': '04569999%02d' % x, + 'phone': '04560000%02d' % x, + } for x in range(0, 10) + ]) def assertLeadConvertion(self, rule, registrations, partner=None, **expected): super(TestEventFullCommon, self).assertLeadConvertion(rule, registrations, partner=partner, **expected) @@ -131,6 +309,13 @@ class TestWEventCommon(HttpCaseWithUserDemo, HttpCaseWithUserPortal, MockVisitor def setUp(self): super(TestWEventCommon, self).setUp() + # Context data: dates + # ------------------------------------------------------------ + + # Mock dates to have reproducible computed fields based on time + self.reference_now = datetime(2021, 12, 1, 10, 0, 0) + self.reference_today = datetime(2021, 12, 1) + self.event_product = self.env['product.product'].create({ 'name': 'Test Event Registration', 'default_code': 'EVENT_REG', diff --git a/addons/test_event_full/tests/test_event_crm.py b/addons/test_event_full/tests/test_event_crm.py index 5da23531480..9c1d6f11375 100644 --- a/addons/test_event_full/tests/test_event_crm.py +++ b/addons/test_event_full/tests/test_event_crm.py @@ -12,8 +12,10 @@ class TestEventCrm(TestEventFullCommon): super(TestEventCrm, cls).setUpClass() cls.TICKET1_COUNT, cls.TICKET2_COUNT = 3, 1 - ticket1 = cls.event_0.event_ticket_ids[0] - ticket2 = cls.event_0.event_ticket_ids[1] + ticket1 = cls.test_event.event_ticket_ids[0] + ticket2 = cls.test_event.event_ticket_ids[1] + + (cls.test_rule_attendee + cls.test_rule_order).write({'event_id': cls.test_event.id}) # PREPARE SO DATA # ------------------------------------------------------------ @@ -22,12 +24,12 @@ class TestEventCrm(TestEventFullCommon): cls.customer_so.write({ 'order_line': [ (0, 0, { - 'event_id': cls.event_0.id, + 'event_id': cls.test_event.id, 'event_ticket_id': ticket1.id, 'product_id': ticket1.product_id.id, 'product_uom_qty': cls.TICKET1_COUNT, }), (0, 0, { - 'event_id': cls.event_0.id, + 'event_id': cls.test_event.id, 'event_ticket_id': ticket2.id, 'product_id': ticket2.product_id.id, 'product_uom_qty': cls.TICKET2_COUNT, @@ -52,7 +54,7 @@ class TestEventCrm(TestEventFullCommon): t1_registrations = self.env['event.registration'].create(t1_reg_vals) # check effect: registrations, leads - self.assertEqual(self.event_0.registration_ids, t1_registrations) + self.assertEqual(self.test_event.registration_ids, t1_registrations) self.assertEqual(len(self.test_rule_order.lead_ids), 1) self.assertEqual(self.test_rule_order_done.lead_ids, self.env['crm.lead']) # check lead converted based on registrations @@ -62,17 +64,17 @@ class TestEventCrm(TestEventFullCommon): # and added to the lead as part of the same group customer_so.action_confirm() self.assertEqual(customer_so.state, 'sale') - self.assertEqual(len(self.event_0.registration_ids), self.TICKET1_COUNT + self.TICKET2_COUNT) + self.assertEqual(len(self.test_event.registration_ids), self.TICKET1_COUNT + self.TICKET2_COUNT) self.assertEqual(len(self.test_rule_order.lead_ids), 1) # no new lead created self.assertEqual(self.test_rule_order_done.lead_ids, self.env['crm.lead']) # this one still not triggered # check existing lead has been updated with new registrations - self.assertLeadConvertion(self.test_rule_order, self.event_0.registration_ids, partner=customer_so.partner_id) + self.assertLeadConvertion(self.test_rule_order, self.test_event.registration_ids, partner=customer_so.partner_id) # Confirm registrations -> trigger the "DONE" rule, one new lead linked to all # event registrations created in this test as all belong to the same SO - self.event_0.registration_ids.write({'state': 'done'}) - self.assertLeadConvertion(self.test_rule_order_done, self.event_0.registration_ids, partner=customer_so.partner_id) + self.test_event.registration_ids.write({'state': 'done'}) + self.assertLeadConvertion(self.test_rule_order_done, self.test_event.registration_ids, partner=customer_so.partner_id) @users('user_sales_salesman') def test_event_crm_sale_mixed_group(self): @@ -83,9 +85,9 @@ class TestEventCrm(TestEventFullCommon): 'partner_id': public_partner.id, 'order_line': [ (0, 0, { - 'event_id': self.event_0.id, - 'event_ticket_id': self.event_0.event_ticket_ids[0].id, - 'product_id': self.event_0.event_ticket_ids[0].product_id.id, + 'event_id': self.test_event.id, + 'event_ticket_id': self.test_event.event_ticket_ids[0].id, + 'product_id': self.test_event.event_ticket_ids[0].product_id.id, 'product_uom_qty': 2, }) ] @@ -109,9 +111,9 @@ class TestEventCrm(TestEventFullCommon): ] self.env['event.registration'].create(mixed_reg_vals) - public_regs = self.event_0.registration_ids.filtered(lambda reg: reg.sale_order_id == public_so) + public_regs = self.test_event.registration_ids.filtered(lambda reg: reg.sale_order_id == public_so) self.assertEqual(len(public_regs), 2) - customer_regs = self.event_0.registration_ids.filtered(lambda reg: reg.sale_order_id == customer_so) + customer_regs = self.test_event.registration_ids.filtered(lambda reg: reg.sale_order_id == customer_so) self.assertEqual(len(customer_regs), 2) self.assertLeadConvertion(self.test_rule_order, public_regs, partner=None) self.assertLeadConvertion(self.test_rule_order, customer_regs, partner=customer_so.partner_id) @@ -122,7 +124,9 @@ class TestEventCrm(TestEventFullCommon): This somehow simulates a simplified website_event_sale flow. """ public_partner = self.env.ref('base.public_partner') customer_so = self.env['sale.order'].browse(self.customer_so.id) - customer_so.write({'partner_id': public_partner.id}) + customer_so.write({ + 'partner_id': public_partner.id, + }) # adding some tickets to SO t1_reg_vals = [ @@ -132,7 +136,7 @@ class TestEventCrm(TestEventFullCommon): for customer_data in self.website_customer_data[:self.TICKET1_COUNT] ] t1_registrations = self.env['event.registration'].create(t1_reg_vals) - self.assertEqual(self.event_0.registration_ids, t1_registrations) + self.assertEqual(self.test_event.registration_ids, t1_registrations) # check lead converted based on registrations self.assertLeadConvertion(self.test_rule_order, t1_registrations, partner=None) @@ -141,7 +145,7 @@ class TestEventCrm(TestEventFullCommon): # BUT as public user -> no email -> not taken into account by rule customer_so.action_confirm() self.assertEqual(customer_so.state, 'sale') - self.assertEqual(len(self.event_0.registration_ids), self.TICKET1_COUNT + self.TICKET2_COUNT) + self.assertEqual(len(self.test_event.registration_ids), self.TICKET1_COUNT + self.TICKET2_COUNT) self.assertLeadConvertion(self.test_rule_order, t1_registrations, partner=None) # SO has a customer set -> main contact of lead is updated accordingly diff --git a/addons/test_event_full/tests/test_event_security.py b/addons/test_event_full/tests/test_event_security.py index ec7f0ac3448..e6adc5817a8 100644 --- a/addons/test_event_full/tests/test_event_security.py +++ b/addons/test_event_full/tests/test_event_security.py @@ -3,30 +3,15 @@ from datetime import datetime, timedelta -from odoo import fields -from odoo.addons.event.tests.common import EventCase +from odoo.addons.test_event_full.tests.common import TestEventFullCommon from odoo.exceptions import AccessError +from odoo.tests import tagged from odoo.tests.common import users from odoo.tools import mute_logger -class TestEventSecurity(EventCase): - - @classmethod - def setUpClass(cls): - super(TestEventSecurity, cls).setUpClass() - - cls.test_event = cls.env['event.event'].create({ - 'auto_confirm': True, - 'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)), - 'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)), - 'date_tz': 'Europe/Brussels', - 'name': 'TestEvent', - }) - cls.test_event_type = cls.env['event.type'].create({ - 'auto_confirm': True, - 'name': 'Update Type', - }) +@tagged('security') +class TestEventSecurity(TestEventFullCommon): @users('user_employee') @mute_logger('odoo.models.unlink', 'odoo.addons.base.models.ir_model') @@ -80,9 +65,9 @@ class TestEventSecurity(EventCase): # Event Registration registration = self.env['event.registration'].create({ - 'event_id': self.test_event.id, + 'event_id': event.id, }) - self.assertEqual(registration.event_id.name, self.test_event.name, 'Registration users should be able to read') + self.assertEqual(registration.event_id.name, event.name, 'Registration users should be able to read') registration.name = 'Test write' with self.assertRaises(AccessError): registration.unlink() diff --git a/addons/test_event_full/tests/test_wevent_register.py b/addons/test_event_full/tests/test_wevent_register.py index b1f34d102cd..6b64c6896c1 100644 --- a/addons/test_event_full/tests/test_wevent_register.py +++ b/addons/test_event_full/tests/test_wevent_register.py @@ -1,21 +1,23 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from freezegun import freeze_time + from odoo import tests from odoo.addons.test_event_full.tests.common import TestWEventCommon -from odoo.tests.common import HOST @tests.common.tagged('post_install', '-at_install') class TestWEventRegister(TestWEventCommon): def test_register(self): - self.browser_js( - '/event', - 'odoo.__DEBUG__.services["web_tour.tour"].run("wevent_register")', - 'odoo.__DEBUG__.services["web_tour.tour"].tours.wevent_register.ready', - login=None - ) + with freeze_time(self.reference_now): + self.browser_js( + '/event', + 'odoo.__DEBUG__.services["web_tour.tour"].run("wevent_register")', + 'odoo.__DEBUG__.services["web_tour.tour"].tours.wevent_register.ready', + login=None + ) new_registrations = self.event.registration_ids visitor = new_registrations.visitor_id diff --git a/addons/test_event_full/views/event_registration_templates_reports.xml b/addons/test_event_full/views/event_registration_templates_reports.xml new file mode 100644 index 00000000000..0fede0937b8 --- /dev/null +++ b/addons/test_event_full/views/event_registration_templates_reports.xml @@ -0,0 +1,14 @@ + + + + From ea563282802adf1b0fa4d879a3940a7e5f1606cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 8 Dec 2021 12:36:47 +0000 Subject: [PATCH 4/8] [IMP] test_event_full: add tests for template and seats synchronization Purpose of this commit is to add tests about template (``event.type`` model) synchronization when creating an event. Some tests already exist in event sub addons but this one has all community features activate. It eases checking the final result. Tests about seats computation and registration creation prevention due to limits are also added as this behavior may be re-implemented soon. Task-2703285 (Event performance improvements) Task-2703289 (Event testing and coverage) Part-of: odoo/odoo#81068 --- addons/test_event_full/__manifest__.py | 2 + addons/test_event_full/tests/__init__.py | 3 +- .../test_event_full/tests/test_event_event.py | 158 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 addons/test_event_full/tests/test_event_event.py diff --git a/addons/test_event_full/__manifest__.py b/addons/test_event_full/__manifest__.py index 1b7bd2c6741..05f7fe5241d 100644 --- a/addons/test_event_full/__manifest__.py +++ b/addons/test_event_full/__manifest__.py @@ -14,7 +14,9 @@ automatic lead generation, full Online support, ... 'event', 'event_booth', 'event_crm', + 'event_crm_sale', 'event_sale', + 'event_sms', 'website_event_booth_sale_exhibitor', 'website_event_crm_questions', 'website_event_exhibitor', diff --git a/addons/test_event_full/tests/__init__.py b/addons/test_event_full/tests/__init__.py index f08227d67fe..9292333c6d9 100644 --- a/addons/test_event_full/tests/__init__.py +++ b/addons/test_event_full/tests/__init__.py @@ -3,5 +3,6 @@ from . import common from . import test_event_crm -from . import test_wevent_register +from . import test_event_event from . import test_event_security +from . import test_wevent_register diff --git a/addons/test_event_full/tests/test_event_event.py b/addons/test_event_full/tests/test_event_event.py new file mode 100644 index 00000000000..7a96c7eee93 --- /dev/null +++ b/addons/test_event_full/tests/test_event_event.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from datetime import datetime, timedelta +from freezegun import freeze_time + +from odoo import Command, exceptions +from odoo.addons.test_event_full.tests.common import TestEventFullCommon +from odoo.tests.common import users + + +class TestEventEvent(TestEventFullCommon): + + @users('event_user') + def test_event_create_wtype(self): + """ Test a single event creation with a type defining all sub records. """ + event_type = self.env['event.type'].browse(self.test_event_type.ids) + + event_values = dict( + self.event_base_vals, + event_type_id=event_type.id, + ) + event = self.env['event.event'].create([event_values]) + event.write({ + 'event_ticket_ids': [ + Command.update( + event.event_ticket_ids[0].id, + {'start_sale_datetime': self.reference_now + timedelta(hours=1)}, + ), + Command.update( + event.event_ticket_ids[1].id, + {'start_sale_datetime': self.reference_now + timedelta(hours=2)}, + ) + ], + }) + + # check result + self.assertEqual(event.address_id, self.env.user.company_id.partner_id) + self.assertTrue(event.auto_confirm) + self.assertEqual(event.country_id, self.env.user.company_id.country_id) + self.assertEqual(event.date_tz, 'Europe/Paris') + self.assertEqual(event.event_booth_count, 4) + self.assertEqual(len(event.event_mail_ids), 3) + self.assertEqual(len(event.event_ticket_ids), 2) + self.assertTrue(event.introduction_menu) + self.assertTrue(event.location_menu) + self.assertTrue(event.menu_register_cta) + self.assertEqual(event.message_partner_ids, self.env.user.partner_id + self.env.user.company_id.partner_id) + self.assertEqual(event.note, '

Template note

') + self.assertTrue(event.register_menu) + self.assertEqual(len(event.question_ids), 3) + self.assertTrue(event.seats_limited) + self.assertEqual(event.seats_max, 30) + self.assertEqual(event.stage_id, self.stage_def) + self.assertEqual(event.tag_ids, self.tags) + self.assertTrue(event.website_menu) + + # check time dependent computation: before event + with freeze_time(self.reference_now): + self.assertFalse(event.is_finished) + self.assertFalse(event.is_ongoing) + self.assertFalse(event.event_registrations_started) + + # check time dependent computation: registrations started + with freeze_time(self.reference_now + timedelta(hours=1)): + event.invalidate_cache(fnames=['is_finished', 'is_ongoing', 'event_registrations_started']) + self.assertFalse(event.is_finished) + self.assertFalse(event.is_ongoing) + self.assertTrue(event.event_registrations_started) + + # check time dependent computation: during event + with freeze_time(self.reference_now + timedelta(days=1, hours=1)): + event.invalidate_cache(fnames=['is_finished', 'is_ongoing', 'event_registrations_started']) + self.assertFalse(event.is_finished) + self.assertTrue(event.is_ongoing) + self.assertTrue(event.event_registrations_started) + + @freeze_time('2021-12-01 11:00:00') + @users('event_user') + def test_event_seats_and_schedulers(self): + now = datetime.now() # used to force create_date, as sql is not wrapped by freeze gun + self.env.cr._now = now + + test_event = self.env['event.event'].browse(self.test_event.ids) + ticket_1 = test_event.event_ticket_ids.filtered(lambda ticket: ticket.name == 'Ticket1') + ticket_2 = test_event.event_ticket_ids.filtered(lambda ticket: ticket.name == 'Ticket2') + + # check initial data + self.assertTrue(test_event.event_registrations_started) + self.assertEqual(test_event.seats_available, 30) + self.assertEqual(ticket_1.seats_available, 10) + self.assertTrue(ticket_1.sale_available) + self.assertEqual(ticket_2.seats_available, 0) + self.assertFalse(ticket_2.sale_available) + + # make 9 registrations (let 1 on ticket) + with self.mock_mail_gateway(): + self.env['event.registration'].create([ + {'create_date': now, + 'email': 'test.customer.%02d@test.example.com' % x, + 'phone': '04560011%02d' % x, + 'event_id': test_event.id, + 'event_ticket_id': ticket_1.id, + 'name': 'Customer %d' % x, + } + for x in range(0, 9) + ]) + # generated emails from scheduler + self.assertEqual(len(self._new_mails), 9) + # event and ticket seats update + self.assertEqual(len(test_event.registration_ids), 9) + self.assertEqual(test_event.seats_available, 21) + self.assertEqual(ticket_1.seats_available, 1) + self.assertEqual(ticket_2.seats_available, 0) + + # prevent registration due to ticket limit + with self.assertRaises(exceptions.ValidationError): + self.env['event.registration'].create([ + {'create_date': now, + 'email': 'additional.customer.%02d@test.example.com' % x, + 'phone': '04560011%02d' % x, + 'event_id': test_event.id, + 'event_ticket_id': ticket_1.id, + 'name': 'Additional Customer %d' % x, + } + for x in range(0, 2) + ]) + + # make 20 registrations (on free ticket) + with self.mock_mail_gateway(): + self.env['event.registration'].create([ + {'create_date': now, + 'email': 'other.customer.%02d@test.example.com' % x, + 'phone': '04560011%02d' % x, + 'event_id': test_event.id, + 'event_ticket_id': ticket_2.id, + 'name': 'Other Customer %d' % x, + } + for x in range(0, 20) + ]) + # event and ticket seats update + self.assertEqual(len(test_event.registration_ids), 29) + self.assertEqual(test_event.seats_available, 1) + self.assertEqual(ticket_1.seats_available, 1) + self.assertEqual(ticket_2.seats_available, 0) + + # prevent registration due to event limit + with self.assertRaises(exceptions.ValidationError): + self.env['event.registration'].create([ + {'create_date': now, + 'email': 'additional.customer.%02d@test.example.com' % x, + 'phone': '04560011%02d' % x, + 'event_id': test_event.id, + 'event_ticket_id': ticket_2.id, + 'name': 'Additional Customer %d' % x, + } + for x in range(0, 2) + ]) From d55165931af8768182fafefa30b639e1fd1364f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 15 Dec 2021 11:13:31 +0000 Subject: [PATCH 5/8] [FIX] website_event: pre-compute website_menu With this commit we ensure website_menu field is computed before calling create. Indeed otherwise it is computed after the create if value is not given and stays to False. This is due to the compute that does not distinguish a False value from user from a False value added as default. This breaks the event type -> event synchronization when no form view is used (either through UI or in code). With this commit, it is computed before resuming the creation and field is correctly synchronized with the template value unless the user gives a value at create time. Task-2341656 (Event submenus shenanigans) Part-of: odoo/odoo#81068 --- addons/website_event/models/event_event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website_event/models/event_event.py b/addons/website_event/models/event_event.py index 22ab9a88b91..41570117f58 100644 --- a/addons/website_event/models/event_event.py +++ b/addons/website_event/models/event_event.py @@ -44,7 +44,7 @@ class Event(models.Model): website_published = fields.Boolean(tracking=True) website_menu = fields.Boolean( string='Website Menu', - compute='_compute_website_menu', readonly=False, store=True, + compute='_compute_website_menu', precompute=True, readonly=False, store=True, help="Allows to display and manage event-specific menus on website.") menu_id = fields.Many2one('website.menu', 'Event Menu', copy=False) menu_register_cta = fields.Boolean( From 79c2979c9001c3b27ac70475b4a014c277d5b789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 16 Dec 2021 11:15:07 +0000 Subject: [PATCH 6/8] [IMP] website_event(_questions): add anchors to ease registration testing Add some classes and name on some DOM elements easing tests writing. Otherwise xpath are hard to write, especially in tours where it can quickly become a PITA to write and update. Task-2703285 (Event performance improvements) Task-2703289 (Event testing and coverage) Part-of: odoo/odoo#81068 --- .../website_event/views/event_templates_page_registration.xml | 4 +++- addons/website_event_questions/views/event_templates.xml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/addons/website_event/views/event_templates_page_registration.xml b/addons/website_event/views/event_templates_page_registration.xml index bb82f43fa57..41908d7c1d1 100644 --- a/addons/website_event/views/event_templates_page_registration.xml +++ b/addons/website_event/views/event_templates_page_registration.xml @@ -167,7 +167,9 @@
-
+
diff --git a/addons/website_event_questions/views/event_templates.xml b/addons/website_event_questions/views/event_templates.xml index 02c21b99b34..21b3428b8b8 100644 --- a/addons/website_event_questions/views/event_templates.xml +++ b/addons/website_event_questions/views/event_templates.xml @@ -5,7 +5,7 @@ -
+
@@ -18,7 +18,7 @@