mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 22:52:07 +02:00
19.0 vanilla
This commit is contained in:
parent
d1963a3c3a
commit
2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import test_event_flow
|
||||
from . import test_event_internals
|
||||
from . import test_event_mail_schedule
|
||||
from . import test_event_slot
|
||||
from . import test_mailing
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from contextlib import contextmanager
|
||||
from freezegun import freeze_time
|
||||
from unittest.mock import patch
|
||||
|
||||
from odoo import fields
|
||||
from odoo import Command, fields
|
||||
from odoo.addons.mail.tests.common import mail_new_test_user
|
||||
from odoo.tests import common
|
||||
|
||||
|
|
@ -10,7 +11,7 @@ class EventCase(common.TransactionCase):
|
|||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(EventCase, cls).setUpClass()
|
||||
super().setUpClass()
|
||||
|
||||
cls.admin_user = cls.env.ref('base.user_admin')
|
||||
cls.admin_user.write({
|
||||
|
|
@ -22,6 +23,7 @@ class EventCase(common.TransactionCase):
|
|||
# set country in order to format Belgian numbers
|
||||
cls.company_admin.write({
|
||||
'country_id': cls.env.ref('base.be').id,
|
||||
'email': 'noreply@company.com',
|
||||
})
|
||||
|
||||
# Test users to use through the various tests
|
||||
|
|
@ -35,6 +37,16 @@ class EventCase(common.TransactionCase):
|
|||
notification_type='email',
|
||||
tz='Europe/Brussels',
|
||||
)
|
||||
cls.user_public = mail_new_test_user(
|
||||
cls.env,
|
||||
company_id=cls.company_admin.id,
|
||||
email='paulette.public@test.example.com',
|
||||
groups='base.group_public',
|
||||
login='public_test',
|
||||
name='Paulette Public',
|
||||
notification_type='email',
|
||||
tz='Europe/Brussels',
|
||||
)
|
||||
cls.user_employee = mail_new_test_user(
|
||||
cls.env,
|
||||
company_id=cls.company_admin.id,
|
||||
|
|
@ -76,21 +88,62 @@ class EventCase(common.TransactionCase):
|
|||
tz='Europe/Brussels',
|
||||
)
|
||||
|
||||
cls.event_organizer = cls.env['res.partner'].create({
|
||||
'city': 'Bruxelles',
|
||||
'country_id': cls.env.ref('base.be').id,
|
||||
'email': 'organizer@example.com',
|
||||
'name': 'Organizer',
|
||||
'phone': '+32455123456',
|
||||
'street': 'Organizer Street',
|
||||
})
|
||||
cls.event_customer = cls.env['res.partner'].create({
|
||||
'name': 'Constantin Customer',
|
||||
'email': 'constantin@test.example.com',
|
||||
'country_id': cls.env.ref('base.be').id,
|
||||
'phone': '0485112233',
|
||||
'mobile': False,
|
||||
})
|
||||
cls.event_customer2 = cls.env['res.partner'].create({
|
||||
'name': 'Constantin Customer 2',
|
||||
'email': 'constantin2@test.example.com',
|
||||
'country_id': cls.env.ref('base.be').id,
|
||||
'phone': '0456987654',
|
||||
'mobile': '0456654321',
|
||||
})
|
||||
cls.reference_now = fields.Datetime.from_string('2022-09-05 15:11:34')
|
||||
cls.event_type_questions = cls.env['event.type'].create({
|
||||
'name': 'Update Type',
|
||||
'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_ids': [Command.set(cls.event_type_questions.ids)],
|
||||
'once_per_order': False,
|
||||
'answer_ids': [
|
||||
(0, 0, {'name': 'Q1-Answer1'}),
|
||||
(0, 0, {'name': 'Q1-Answer2'})
|
||||
],
|
||||
})
|
||||
cls.event_question_2 = cls.env['event.question'].create({
|
||||
'title': 'Question2',
|
||||
'question_type': 'simple_choice',
|
||||
'event_type_ids': [Command.set(cls.event_type_questions.ids)],
|
||||
'once_per_order': True,
|
||||
'answer_ids': [
|
||||
(0, 0, {'name': 'Q2-Answer1'}),
|
||||
(0, 0, {'name': 'Q2-Answer2'})
|
||||
],
|
||||
})
|
||||
cls.event_question_3 = cls.env['event.question'].create({
|
||||
'title': 'Question3',
|
||||
'question_type': 'text_box',
|
||||
'event_type_ids': [Command.set(cls.event_type_questions.ids)],
|
||||
'once_per_order': True,
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def _create_registrations(cls, event, reg_count):
|
||||
|
|
@ -99,8 +152,90 @@ class EventCase(common.TransactionCase):
|
|||
registrations = cls.env['event.registration'].create([{
|
||||
'create_date': create_date,
|
||||
'event_id': event.id,
|
||||
'name': 'Test Registration %s' % x,
|
||||
'email': '_test_reg_%s@example.com' % x,
|
||||
'phone': '04560000%s%s' % (x, x),
|
||||
} for x in range(0, reg_count)])
|
||||
'name': f'Test Registration {idx}',
|
||||
'email': f'_test_reg_{idx}@example.com',
|
||||
'phone': f'04560000{idx}{idx}',
|
||||
} for idx in range(0, reg_count)])
|
||||
return registrations
|
||||
|
||||
@classmethod
|
||||
def _create_registrations_for_slot_and_ticket(cls, event, slot, ticket, count, **add_values):
|
||||
return cls.env['event.registration'].create([
|
||||
dict(
|
||||
{
|
||||
'email': f'{slot.id if slot else "NoSlot"}.{ticket.id if ticket else "NoTicket"}@test.example.com',
|
||||
'event_id': event.id,
|
||||
'event_slot_id': slot.id if slot else False,
|
||||
'event_ticket_id': ticket.id if ticket else False,
|
||||
'name': f'{slot.id if slot else "NoSlot"}.{ticket.id if ticket else "NoTicket"}',
|
||||
}, **add_values
|
||||
) for idx in range(0, count)
|
||||
])
|
||||
|
||||
@classmethod
|
||||
def _setup_test_reports(cls):
|
||||
cls.test_report_view = cls.env["ir.ui.view"].create({
|
||||
"arch_db": """
|
||||
<t t-call="web.html_container">
|
||||
<t t-foreach="docs" t-as="registration">
|
||||
<t t-call="web.external_layout">
|
||||
<div class="page">
|
||||
<p>This is a sample of an external report.</p>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>""",
|
||||
"key": "event_registration_test_report",
|
||||
"name": "event_registration_test_report",
|
||||
"type": "qweb",
|
||||
})
|
||||
cls.env["ir.model.data"].create({
|
||||
"model": "ir.ui.view",
|
||||
"module": "event",
|
||||
"name": "event_registration_test_report",
|
||||
"res_id": cls.test_report_view.id,
|
||||
})
|
||||
|
||||
cls.test_report_action = cls.env['ir.actions.report'].create({
|
||||
'name': 'Test Report on event.registration',
|
||||
'model': 'event.registration',
|
||||
'print_report_name': "f'TestReport for {object.name}'",
|
||||
'report_type': 'qweb-pdf',
|
||||
'report_name': 'event.event_registration_test_report',
|
||||
})
|
||||
|
||||
cls.template_subscription = cls.env['mail.template'].create({
|
||||
"body_html": """<div>Hello your registration to <t t-out="object.event_id.name"/> is confirmed.</div>""",
|
||||
"email_from": "{{ (object.event_id.organizer_id.email_formatted or object.event_id.user_id.email_formatted or '') }}",
|
||||
"lang": "{{ object.event_id.lang or object.partner_id.lang }}",
|
||||
"model_id": cls.env['ir.model']._get_id("event.registration"),
|
||||
"name": "Event: Registration Confirmation TEST",
|
||||
"subject": "Confirmation for {{ object.event_id.name }}",
|
||||
"report_template_ids": [(4, cls.test_report_action.id)],
|
||||
"use_default_to": True,
|
||||
})
|
||||
cls.template_reminder = cls.env['mail.template'].create({
|
||||
"body_html": """<div>Hello this is a reminder for your registration to <t t-out="object.event_id.name"/>.</div>""",
|
||||
"email_from": "{{ (object.event_id.organizer_id.email_formatted or object.event_id.user_id.email_formatted or '') }}",
|
||||
"lang": "{{ object.event_id.lang or object.partner_id.lang }}",
|
||||
"model_id": cls.env['ir.model']._get_id("event.registration"),
|
||||
"name": "Event: Registration Reminder TEST",
|
||||
"subject": "Reminder for {{ object.event_id.name }}: {{ object.event_date_range }}",
|
||||
"report_template_ids": [(4, cls.test_report_action.id)],
|
||||
"use_default_to": True,
|
||||
})
|
||||
|
||||
def assertSchedulerCronTriggers(self, capture, call_at_list):
|
||||
self.assertEqual(len(capture.records), len(call_at_list))
|
||||
for record, call_at in zip(capture.records, call_at_list):
|
||||
self.assertEqual(record.call_at, call_at.replace(microsecond=0))
|
||||
self.assertEqual(record.cron_id, self.env.ref('event.event_mail_scheduler'))
|
||||
|
||||
@contextmanager
|
||||
def mock_datetime_and_now(self, mock_dt):
|
||||
""" Used when synchronization date (using env.cr.now()) is important
|
||||
in addition to standard datetime mocks. Used mainly to detect sync
|
||||
issues. """
|
||||
with freeze_time(mock_dt), \
|
||||
patch.object(self.env.cr, 'now', lambda: mock_dt):
|
||||
yield
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import datetime
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from freezegun import freeze_time
|
||||
|
||||
from odoo.addons.event.tests.common import EventCase
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tests.common import users
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
class TestEventFlow(EventCase):
|
||||
|
||||
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
|
||||
def test_event_auto_confirm(self):
|
||||
""" Basic event management with auto confirmation """
|
||||
# EventUser creates a new event: ok
|
||||
test_event = self.env['event.event'].with_user(self.user_eventmanager).create({
|
||||
'name': 'TestEvent',
|
||||
'auto_confirm': True,
|
||||
'date_begin': datetime.datetime.now() + relativedelta(days=-1),
|
||||
'date_end': datetime.datetime.now() + relativedelta(days=1),
|
||||
'seats_max': 2,
|
||||
'seats_limited': True,
|
||||
})
|
||||
self.assertTrue(test_event.auto_confirm)
|
||||
|
||||
# EventUser create registrations for this event
|
||||
test_reg1 = self.env['event.registration'].with_user(self.user_eventuser).create({
|
||||
'name': 'TestReg1',
|
||||
'event_id': test_event.id,
|
||||
})
|
||||
scheduler = self.env['event.mail'].sudo().search([
|
||||
('event_id', '=', test_event.id),
|
||||
('interval_type', '=', 'after_sub')
|
||||
])
|
||||
self.assertTrue(scheduler.mail_registration_ids.mail_sent)
|
||||
|
||||
self.assertEqual(test_reg1.state, 'open', 'Event: auto_confirmation of registration failed')
|
||||
self.assertEqual(test_event.seats_reserved, 1, 'Event: wrong number of reserved seats after confirmed registration')
|
||||
test_reg2 = self.env['event.registration'].with_user(self.user_eventuser).create({
|
||||
'name': 'TestReg2',
|
||||
'event_id': test_event.id,
|
||||
})
|
||||
self.assertEqual(test_reg2.state, 'open', 'Event: auto_confirmation of registration failed')
|
||||
self.assertEqual(test_event.seats_reserved, 2, 'Event: wrong number of reserved seats after confirmed registration')
|
||||
|
||||
# EventUser create registrations for this event: too much registrations
|
||||
with self.assertRaises(ValidationError):
|
||||
self.env['event.registration'].with_user(self.user_eventuser).create({
|
||||
'name': 'TestReg3',
|
||||
'event_id': test_event.id,
|
||||
})
|
||||
|
||||
# EventUser validates registrations
|
||||
test_reg1.action_set_done()
|
||||
self.assertEqual(test_reg1.state, 'done', 'Event: wrong state of attended registration')
|
||||
self.assertEqual(test_event.seats_used, 1, 'Event: incorrect number of attendees after closing registration')
|
||||
test_reg2.action_set_done()
|
||||
self.assertEqual(test_reg1.state, 'done', 'Event: wrong state of attended registration')
|
||||
self.assertEqual(test_event.seats_used, 2, 'Event: incorrect number of attendees after closing registration')
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_default_datetime(self):
|
||||
""" Check that the default date_begin and date_end are correctly set """
|
||||
|
||||
# Should apply default datetimes
|
||||
with freeze_time(self.reference_now):
|
||||
default_event = self.env['event.event'].create({
|
||||
'name': 'Test Default Event',
|
||||
})
|
||||
self.assertEqual(default_event.date_begin, datetime.datetime.strptime('2022-09-05 15:30:00', '%Y-%m-%d %H:%M:%S'))
|
||||
self.assertEqual(default_event.date_end, datetime.datetime.strptime('2022-09-06 15:30:00', '%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
specific_datetimes = {
|
||||
'date_begin': self.reference_now + relativedelta(days=1),
|
||||
'date_end': self.reference_now + relativedelta(days=3),
|
||||
}
|
||||
|
||||
# Should not apply default datetimes if values are set manually
|
||||
with freeze_time(self.reference_now):
|
||||
event = self.env['event.event'].create({
|
||||
'name': 'Test Event',
|
||||
**specific_datetimes,
|
||||
})
|
||||
self.assertEqual(event.date_begin, specific_datetimes['date_begin'])
|
||||
self.assertEqual(event.date_end, specific_datetimes['date_end'])
|
||||
|
||||
@mute_logger('odoo.addons.base.models.ir_model', 'odoo.models')
|
||||
def test_event_flow(self):
|
||||
""" Advanced event flow: no auto confirmation, manage minimum / maximum
|
||||
seats, ... """
|
||||
# EventUser creates a new event: ok
|
||||
test_event = self.env['event.event'].with_user(self.user_eventmanager).create({
|
||||
'name': 'TestEvent',
|
||||
'date_begin': datetime.datetime.now() + relativedelta(days=-1),
|
||||
'date_end': datetime.datetime.now() + relativedelta(days=1),
|
||||
'seats_limited': True,
|
||||
'seats_max': 10,
|
||||
})
|
||||
self.assertFalse(test_event.auto_confirm)
|
||||
|
||||
# EventUser create registrations for this event -> no auto confirmation
|
||||
test_reg1 = self.env['event.registration'].with_user(self.user_eventuser).create({
|
||||
'name': 'TestReg1',
|
||||
'event_id': test_event.id,
|
||||
})
|
||||
self.assertEqual(
|
||||
test_reg1.state, 'draft',
|
||||
'Event: new registration should not be confirmed with auto_confirmation parameter being False')
|
||||
|
||||
@mute_logger('odoo.addons.event.models.event_mail')
|
||||
def test_event_missed_mail_template(self):
|
||||
""" Check that error on mail sending is ignored if corresponding mail template was deleted """
|
||||
test_event = self.env['event.event'].with_user(self.user_eventmanager).create({
|
||||
'name': 'TestEvent',
|
||||
'date_begin': datetime.datetime.now() + relativedelta(days=-1),
|
||||
'date_end': datetime.datetime.now() + relativedelta(days=1),
|
||||
'seats_max': 2,
|
||||
'seats_limited': True,
|
||||
})
|
||||
self.assertFalse(test_event.auto_confirm)
|
||||
|
||||
# EventUser create registrations for this event
|
||||
test_reg = self.env['event.registration'].with_user(self.user_eventuser).create({
|
||||
'name': 'TestReg1',
|
||||
'event_id': test_event.id,
|
||||
})
|
||||
|
||||
scheduler = self.env['event.mail'].sudo().search([
|
||||
('event_id', '=', test_event.id),
|
||||
('interval_type', '=', 'after_sub')
|
||||
])
|
||||
|
||||
# Imagine user deletes mail template for whatever reason
|
||||
scheduler.template_ref.unlink()
|
||||
|
||||
# Mails should not be sent
|
||||
test_reg.action_confirm()
|
||||
self.assertFalse(scheduler.mail_registration_ids.mail_sent)
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import date, datetime, timedelta
|
||||
from freezegun import freeze_time
|
||||
|
||||
from odoo import Command
|
||||
from odoo.addons.event.tests.common import EventCase
|
||||
from odoo import exceptions
|
||||
from odoo.fields import Datetime as FieldsDatetime
|
||||
from odoo.tests.common import users, Form, tagged
|
||||
from odoo.tests import Form, users, tagged
|
||||
from odoo.tools import mute_logger
|
||||
|
||||
|
||||
|
|
@ -20,7 +20,6 @@ class TestEventInternalsCommon(EventCase):
|
|||
|
||||
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',
|
||||
|
|
@ -47,7 +46,6 @@ class TestEventInternalsCommon(EventCase):
|
|||
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',
|
||||
|
|
@ -59,73 +57,53 @@ class TestEventInternalsCommon(EventCase):
|
|||
class TestEventData(TestEventInternalsCommon):
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_date_computation(self):
|
||||
event = self.event_0.with_user(self.env.user)
|
||||
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')
|
||||
def test_event_configuration_question_from_type(self):
|
||||
""" Enure configuration & translations are copied from Event Type on Event creation """
|
||||
self.env['res.lang'].sudo()._activate_lang('nl_NL')
|
||||
|
||||
event.date_begin = datetime(2020, 2, 1, 15, 0, 0)
|
||||
self.assertEqual(registration.get_date_range_str(), u'tomorrow')
|
||||
event_type = self.event_type_questions.with_user(self.env.user)
|
||||
event_type_question_nl = self.event_question_1.with_context(lang='nl_NL')
|
||||
event_type_question_nl.title = "Vraag1"
|
||||
event_type_question_nl.answer_ids[0].name = "V1-Antwoord1"
|
||||
|
||||
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, 3, 1, 10, 0, 0)
|
||||
self.assertEqual(registration.get_date_range_str(), u'on Mar 1, 2020')
|
||||
|
||||
# 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': 'America/Mexico_City'
|
||||
})
|
||||
self.assertTrue(event.is_one_day)
|
||||
|
||||
# Checks case when mocked today changes date before event, when event.date_tz considered
|
||||
with freeze_time(datetime(2020, 6, 20, 20, 0, 0)):
|
||||
event.write({
|
||||
'date_begin': datetime(2020, 6, 27, 1, 0, 0),
|
||||
'date_end': datetime(2020, 7, 8, 2, 0, 0),
|
||||
'date_tz': 'America/Los_Angeles'
|
||||
})
|
||||
# event_date_tz = 2020-06-26 18:00
|
||||
# today_tz = 2020-06-20 13:00
|
||||
# event_date_tz.date() - today_tz.date() = 6 days
|
||||
self.assertEqual(registration.get_date_range_str(), 'in 6 days')
|
||||
|
||||
# Checks case when event changes date before mocked today, when event.date_tz considered
|
||||
with freeze_time(datetime(2020, 6, 20, 13, 0, 0)):
|
||||
event.write({
|
||||
'date_begin': datetime(2020, 6, 25, 20, 0, 0),
|
||||
'date_end': datetime(2020, 7, 8, 2, 0, 0),
|
||||
'date_tz': 'Australia/Sydney'
|
||||
})
|
||||
# event_date_tz = 2020-06-26 06:00
|
||||
# today_tz = 2020-06-20 23:00
|
||||
# event_date_tz.date() - today_tz.date() = 6 days
|
||||
self.assertEqual(registration.get_date_range_str(), 'in 6 days')
|
||||
|
||||
@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)
|
||||
# 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': 'America/Mexico_City'
|
||||
event = self.env['event.event'].create({
|
||||
'name': 'Event Update Type',
|
||||
'event_type_id': event_type.id,
|
||||
'date_begin': FieldsDatetime.to_string(datetime.today() + timedelta(days=1)),
|
||||
'date_end': FieldsDatetime.to_string(datetime.today() + timedelta(days=15)),
|
||||
})
|
||||
self.assertTrue(event.is_one_day)
|
||||
self.assertFalse(event.is_ongoing)
|
||||
event.invalidate_recordset(['specific_question_ids', 'general_question_ids'])
|
||||
|
||||
self.assertEqual(
|
||||
sorted(event.question_ids.mapped('question_type')),
|
||||
['email', 'name', 'phone', 'simple_choice', 'simple_choice', 'text_box'])
|
||||
self.assertEqual(event.specific_question_ids.filtered(
|
||||
lambda q: q.question_type in ['simple_choice', 'text_box']).title, 'Question1')
|
||||
self.assertEqual(event.specific_question_ids.filtered(
|
||||
lambda q: q.question_type in ['name', 'email', 'phone', 'company_name'])
|
||||
.mapped('title'), ['Name', 'Email', 'Phone'])
|
||||
self.assertEqual(
|
||||
set(event.specific_question_ids.filtered(
|
||||
lambda q: q.question_type in ['simple_choice', 'text_box']).mapped('answer_ids.name')),
|
||||
{'Q1-Answer1', 'Q1-Answer2'})
|
||||
self.assertEqual(len(event.general_question_ids), 2)
|
||||
self.assertEqual(event.general_question_ids[0].title, 'Question2')
|
||||
self.assertEqual(event.general_question_ids[1].title, 'Question3')
|
||||
self.assertEqual(
|
||||
set(event.general_question_ids[0].mapped('answer_ids.name')),
|
||||
{'Q2-Answer1', 'Q2-Answer2'})
|
||||
# verify translations
|
||||
event_question_nl = event.specific_question_ids.filtered_domain([
|
||||
('title', '=', self.event_question_1.title),
|
||||
]).with_context(lang='nl_NL')
|
||||
self.assertNotEqual(event_question_nl.title, self.event_question_1.title,
|
||||
"Translated title should differ from untranslated title.")
|
||||
self.assertEqual(event_question_nl.title, event_type_question_nl.title,
|
||||
"Translated title should be copied.")
|
||||
self.assertEqual(
|
||||
set(event_question_nl.answer_ids.mapped('name')),
|
||||
set(event_type_question_nl.answer_ids.mapped('name')),
|
||||
"Translated answer names should be copied.")
|
||||
|
||||
@users('user_eventmanager')
|
||||
@mute_logger('odoo.models.unlink')
|
||||
|
|
@ -147,12 +125,10 @@ class TestEventData(TestEventInternalsCommon):
|
|||
})
|
||||
self.assertEqual(event.date_tz, self.env.user.tz)
|
||||
self.assertFalse(event.seats_limited)
|
||||
self.assertFalse(event.auto_confirm)
|
||||
self.assertEqual(event.event_mail_ids, self.env['event.mail'])
|
||||
self.assertEqual(event.event_ticket_ids, self.env['event.event.ticket'])
|
||||
|
||||
registration = self._create_registrations(event, 1)
|
||||
self.assertEqual(registration.state, 'draft') # event is not auto confirm
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# FILL SYNC TEST
|
||||
|
|
@ -170,7 +146,6 @@ class TestEventData(TestEventInternalsCommon):
|
|||
self.assertEqual(event.date_tz, 'Europe/Paris')
|
||||
self.assertTrue(event.seats_limited)
|
||||
self.assertEqual(event.seats_max, event_type.seats_max)
|
||||
self.assertTrue(event.auto_confirm)
|
||||
# check 2many fields being populated
|
||||
self.assertEqual(len(event.event_mail_ids), 1)
|
||||
self.assertEqual(event.event_mail_ids.interval_nbr, 1)
|
||||
|
|
@ -206,16 +181,13 @@ class TestEventData(TestEventInternalsCommon):
|
|||
# setup test records
|
||||
event_type_default = self.env['event.type'].create({
|
||||
'name': 'Type Default',
|
||||
'auto_confirm': True,
|
||||
'event_type_mail_ids': False,
|
||||
})
|
||||
event_type_mails = self.env['event.type'].create({
|
||||
'name': 'Type Mails',
|
||||
'auto_confirm': False,
|
||||
'event_type_mail_ids': [
|
||||
Command.clear(),
|
||||
Command.create({
|
||||
'notification_type': 'mail',
|
||||
'interval_nbr': 77,
|
||||
'interval_unit': 'days',
|
||||
'interval_type': 'after_event',
|
||||
|
|
@ -233,7 +205,6 @@ class TestEventData(TestEventInternalsCommon):
|
|||
'event_mail_ids': [
|
||||
Command.clear(),
|
||||
Command.create({
|
||||
'notification_type': 'mail',
|
||||
'interval_unit': 'now',
|
||||
'interval_type': 'after_sub',
|
||||
'template_ref': 'mail.template,%i' % self.env['ir.model.data']._xmlid_to_res_id('event.event_subscription'),
|
||||
|
|
@ -242,7 +213,7 @@ class TestEventData(TestEventInternalsCommon):
|
|||
})
|
||||
mail = event.event_mail_ids[0]
|
||||
registration = self._create_registrations(event, 1)
|
||||
self.assertEqual(registration.state, 'open') # event auto confirms
|
||||
self.assertEqual(registration.state, 'open')
|
||||
# verify that mail is linked to the registration
|
||||
self.assertEqual(
|
||||
set(mail.mapped('mail_registration_ids.registration_id.id')),
|
||||
|
|
@ -297,6 +268,53 @@ class TestEventData(TestEventInternalsCommon):
|
|||
event.write({'event_type_id': event_type.id})
|
||||
self.assertEqual(event.note, '<p>Event Type Note</p>')
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_configuration_questions_from_type(self):
|
||||
""" Test that the questions of an event are updated as the event type changes. """
|
||||
event_type_1_question, event_type_1_removed_question, event_type_2_question, event_type_common_question = self.env['event.question'].create([{
|
||||
'title': 'Event Type 1 Question'
|
||||
}, {
|
||||
'title': 'Event Type 1 Removed Question'
|
||||
}, {
|
||||
'title': 'Event Type 2 Question'
|
||||
}, {
|
||||
# To check that a question removed from an event can be added again using an event_type.
|
||||
'title': 'Event Type Common Question'
|
||||
}])
|
||||
event_type_1_questions = event_type_1_question + event_type_1_removed_question + event_type_common_question
|
||||
event_type_1, event_type_2 = self.env['event.type'].create([{
|
||||
'name': 'Event Type 1',
|
||||
'question_ids': [Command.set(event_type_1_questions.ids)]
|
||||
}, {
|
||||
'name': 'Event Type 2',
|
||||
'question_ids': [Command.set((event_type_2_question + event_type_common_question).ids)]
|
||||
}])
|
||||
event = self.env['event.event'].create({
|
||||
'name': 'Event',
|
||||
'event_type_id': event_type_1.id,
|
||||
'date_begin': self.reference_beg,
|
||||
'date_end': self.reference_end,
|
||||
})
|
||||
# Check that the questions of the event are updated with those of the event type.
|
||||
self.assertEqual(event.question_ids, event_type_1.question_ids)
|
||||
|
||||
event_type_1.question_ids = [Command.clear()]
|
||||
# Check that the questions of the event are not updated when the questions of the event type are removed.
|
||||
self.assertTrue(event.question_ids, event_type_1_questions)
|
||||
|
||||
self.env['event.registration.answer'].create({
|
||||
'question_id': event_type_1_question.id,
|
||||
'registration_id': self.env['event.registration'].create({'event_id': event.id}).id,
|
||||
'value_text_box': 'Value Registration Answer',
|
||||
})
|
||||
event.write({'event_type_id': event_type_2.id})
|
||||
# Check that the questions of the event are updated with those of the new event type of the event
|
||||
# and that the question with attendee answer is not removed.
|
||||
self.assertEqual(
|
||||
event.question_ids,
|
||||
event_type_1_question + event_type_2_question + event_type_common_question
|
||||
)
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_configuration_tickets_from_type(self):
|
||||
""" Test data computation (related to tickets) of event coming from its event.type template.
|
||||
|
|
@ -308,11 +326,9 @@ class TestEventData(TestEventInternalsCommon):
|
|||
# setup test records
|
||||
event_type_default = self.env['event.type'].create({
|
||||
'name': 'Type Default',
|
||||
'auto_confirm': True
|
||||
})
|
||||
event_type_tickets = self.env['event.type'].create({
|
||||
'name': 'Type Tickets',
|
||||
'auto_confirm': False
|
||||
})
|
||||
event_type_tickets.write({
|
||||
'event_type_ticket_ids': [
|
||||
|
|
@ -364,6 +380,90 @@ class TestEventData(TestEventInternalsCommon):
|
|||
set(['Registration Ticket'])
|
||||
)
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_date_computation(self):
|
||||
event = self.event_0.with_user(self.env.user)
|
||||
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.event_date_range, 'today')
|
||||
|
||||
event.date_begin = datetime(2020, 2, 1, 15, 0, 0)
|
||||
registration.invalidate_recordset(['event_date_range'])
|
||||
self.assertEqual(registration.event_date_range, 'tomorrow')
|
||||
|
||||
event.date_begin = datetime(2020, 2, 2, 6, 0, 0)
|
||||
registration.invalidate_recordset(['event_date_range'])
|
||||
self.assertEqual(registration.event_date_range, 'in 2 days')
|
||||
|
||||
event.date_begin = datetime(2020, 2, 20, 17, 0, 0)
|
||||
registration.invalidate_recordset(['event_date_range'])
|
||||
self.assertEqual(registration.event_date_range, 'next month')
|
||||
|
||||
event.date_begin = datetime(2020, 3, 1, 10, 0, 0)
|
||||
registration.invalidate_recordset(['event_date_range'])
|
||||
self.assertEqual(registration.event_date_range, 'on Mar 1, 2020')
|
||||
|
||||
# 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': 'America/Mexico_City'
|
||||
})
|
||||
self.assertTrue(event.is_one_day)
|
||||
|
||||
# Checks case when mocked today changes date before event, when event.date_tz considered
|
||||
with freeze_time(datetime(2020, 6, 20, 20, 0, 0)):
|
||||
event.write({
|
||||
'date_begin': datetime(2020, 6, 27, 1, 0, 0),
|
||||
'date_end': datetime(2020, 7, 8, 2, 0, 0),
|
||||
'date_tz': 'America/Los_Angeles'
|
||||
})
|
||||
# event_date_tz = 2020-06-26 18:00
|
||||
# today_tz = 2020-06-20 13:00
|
||||
# event_date_tz.date() - today_tz.date() = 6 days
|
||||
registration.invalidate_recordset(['event_date_range'])
|
||||
self.assertEqual(registration.event_date_range, 'in 6 days')
|
||||
|
||||
# Checks case when event changes date before mocked today, when event.date_tz considered
|
||||
with freeze_time(datetime(2020, 6, 20, 13, 0, 0)):
|
||||
event.write({
|
||||
'date_begin': datetime(2020, 6, 25, 20, 0, 0),
|
||||
'date_end': datetime(2020, 7, 8, 2, 0, 0),
|
||||
'date_tz': 'Australia/Sydney'
|
||||
})
|
||||
# event_date_tz = 2020-06-26 06:00
|
||||
# today_tz = 2020-06-20 23:00
|
||||
# event_date_tz.date() - today_tz.date() = 6 days
|
||||
registration.invalidate_recordset(['event_date_range'])
|
||||
self.assertEqual(registration.event_date_range, 'in 6 days')
|
||||
|
||||
@freeze_time('2020-01-31 10:00:00')
|
||||
@users('user_eventmanager')
|
||||
def test_event_date_timezone(self):
|
||||
event = self.event_0.with_user(self.env.user)
|
||||
# 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': 'America/Mexico_City'
|
||||
})
|
||||
self.assertTrue(event.is_one_day)
|
||||
self.assertFalse(event.is_ongoing)
|
||||
|
||||
# Should apply default datetimes
|
||||
with freeze_time(self.reference_now):
|
||||
default_event = self.env['event.event'].create({
|
||||
'name': 'Test Default Event',
|
||||
})
|
||||
self.assertEqual(default_event.date_begin, self.reference_now)
|
||||
self.assertEqual(default_event.date_end, self.reference_now + timedelta(days=1))
|
||||
self.assertEqual(default_event.date_tz, self.user_eventmanager.tz)
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_mail_default_config(self):
|
||||
event = self.env['event.event'].create({
|
||||
|
|
@ -373,7 +473,6 @@ class TestEventData(TestEventInternalsCommon):
|
|||
})
|
||||
self.assertEqual(event.date_tz, self.env.user.tz)
|
||||
self.assertFalse(event.seats_limited)
|
||||
self.assertFalse(event.auto_confirm)
|
||||
|
||||
#Event Communications: when no event type, default configuration
|
||||
self.assertEqual(len(event.event_mail_ids), 3)
|
||||
|
|
@ -405,8 +504,27 @@ class TestEventData(TestEventInternalsCommon):
|
|||
self.env['mail.template'].create({'model_id': self.env['ir.model']._get('res.partner').id, 'name': 'test template'})
|
||||
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')
|
||||
templates = self.env['mail.template'].with_context(filter_template_on_event=True).search([('name', '=', 'test template')])
|
||||
self.assertEqual(len(templates), 1, 'Should also return only mail templates related to the event registration model using search')
|
||||
|
||||
@freeze_time('2020-1-31 10:00:00')
|
||||
@users('user_eventmanager')
|
||||
def test_event_question_defaults(self):
|
||||
""" Test that default questions are linked to the new events and shared by all of them. """
|
||||
event_0, event_1 = self.env['event.event'].create([{
|
||||
'name': 'TestEvent 0',
|
||||
'date_begin': self.reference_beg,
|
||||
'date_end': self.reference_end,
|
||||
}, {
|
||||
'name': 'TestEvent 1',
|
||||
'date_begin': self.reference_beg,
|
||||
'date_end': self.reference_end,
|
||||
}])
|
||||
# Check that event has been linked to the default questions.
|
||||
self.assertCountEqual(event_0.question_ids.mapped('question_type'), ['name', 'email', 'phone'])
|
||||
# Check that default questions are shared by events.
|
||||
self.assertEqual(event_0.question_ids, event_1.question_ids)
|
||||
|
||||
@freeze_time('2020-01-31 10:00:00')
|
||||
@users('user_eventmanager')
|
||||
def test_event_registrable(self):
|
||||
"""Test if `_compute_event_registrations_open` works properly."""
|
||||
|
|
@ -440,7 +558,6 @@ class TestEventData(TestEventInternalsCommon):
|
|||
'name': 'Albert Test',
|
||||
'event_id': event.id,
|
||||
})
|
||||
registration.action_confirm()
|
||||
event.write({
|
||||
'date_end': datetime(2020, 2, 1, 15, 0, 0),
|
||||
'seats_max': 1,
|
||||
|
|
@ -459,7 +576,78 @@ class TestEventData(TestEventInternalsCommon):
|
|||
self.assertTrue(ticket.is_expired)
|
||||
self.assertFalse(event.event_registrations_open)
|
||||
|
||||
@freeze_time('2020-1-31 10:00:00')
|
||||
@freeze_time('2020-01-31 10:00:00')
|
||||
@users('user_eventmanager')
|
||||
def test_event_multi_slots_registrable(self):
|
||||
"""Test if `_compute_event_registrations_open` works properly on multi slots events. """
|
||||
event = self.event_0.with_user(self.env.user)
|
||||
self.assertTrue(event.event_registrations_open)
|
||||
event.write({
|
||||
'date_begin': datetime(2020, 1, 30, 8, 0, 0),
|
||||
'date_end': datetime(2020, 2, 4, 8, 0, 0),
|
||||
'is_multi_slots': True,
|
||||
})
|
||||
self.assertFalse(event.event_ticket_ids)
|
||||
self.assertFalse(event.event_slot_ids)
|
||||
# Should be closed if no slot
|
||||
self.assertFalse(event.event_registrations_open)
|
||||
# Should be open with a slot and no tickets
|
||||
event.write({
|
||||
'event_slot_ids': [
|
||||
(0, 0, {
|
||||
'date': date(2020, 1, 30),
|
||||
'start_hour': 9,
|
||||
'end_hour': 12,
|
||||
}),
|
||||
(0, 0, {
|
||||
'date': date(2020, 1, 31),
|
||||
'start_hour': 14,
|
||||
'end_hour': 16,
|
||||
}),
|
||||
]
|
||||
})
|
||||
self.assertTrue(event.event_registrations_open)
|
||||
# Should be open with a slot, a ticket and slot-ticket availabilities
|
||||
event.write({
|
||||
'event_ticket_ids': [
|
||||
(0, 0, {
|
||||
'name': 'Better',
|
||||
'seats_limited': True,
|
||||
'seats_max': 2,
|
||||
}),
|
||||
]
|
||||
})
|
||||
self.assertTrue(event.event_registrations_open)
|
||||
# Should be closed if all slots are sold out (event seats max)
|
||||
event.write({
|
||||
'seats_limited': True,
|
||||
'seats_max': 1,
|
||||
})
|
||||
slot1 = event.event_slot_ids[0]
|
||||
slot2 = event.event_slot_ids[1]
|
||||
self.assertEqual(slot1.seats_available, 1)
|
||||
self.assertEqual(slot2.seats_available, 1)
|
||||
regs = self.env['event.registration'].create([{
|
||||
'event_id': event.id,
|
||||
'name': 'reg_open',
|
||||
'event_slot_id': slot.id,
|
||||
} for slot in slot1 + slot2])
|
||||
self.assertTrue(slot1.is_sold_out)
|
||||
self.assertTrue(slot2.is_sold_out)
|
||||
self.assertFalse(event.event_registrations_open)
|
||||
regs.unlink()
|
||||
# Should be closed if ticket sold out for each slot (ticket seats max)
|
||||
event.write({'seats_limited': False})
|
||||
self.assertTrue(event.event_registrations_open)
|
||||
regs = self.env['event.registration'].create([{
|
||||
'event_id': event.id,
|
||||
'name': 'reg_open',
|
||||
'event_slot_id': slot.id,
|
||||
'event_ticket_id': event.event_ticket_ids.id,
|
||||
} for slot in slot1 + slot2 for _ in range(2)])
|
||||
self.assertFalse(event.event_registrations_open)
|
||||
|
||||
@freeze_time('2020-01-31 10:00:00')
|
||||
@users('user_eventmanager')
|
||||
def test_event_ongoing(self):
|
||||
event_1 = self.env['event.event'].create({
|
||||
|
|
@ -468,13 +656,13 @@ class TestEventData(TestEventInternalsCommon):
|
|||
'date_end': datetime(2020, 2, 1, 18, 0, 0),
|
||||
})
|
||||
self.assertTrue(event_1.is_ongoing)
|
||||
ongoing_event_ids = self.env['event.event']._search([('is_ongoing', '=', True)])
|
||||
self.assertIn(event_1.id, ongoing_event_ids)
|
||||
ongoing_events = self.env['event.event'].search([('is_ongoing', '=', True)])
|
||||
self.assertIn(event_1, ongoing_events)
|
||||
|
||||
event_1.update({'date_begin': datetime(2020, 2, 1, 9, 0, 0)})
|
||||
self.assertFalse(event_1.is_ongoing)
|
||||
ongoing_event_ids = self.env['event.event']._search([('is_ongoing', '=', True)])
|
||||
self.assertNotIn(event_1.id, ongoing_event_ids)
|
||||
ongoing_events = self.env['event.event'].search([('is_ongoing', '=', True)])
|
||||
self.assertNotIn(event_1, ongoing_events)
|
||||
|
||||
event_2 = self.env['event.event'].create({
|
||||
'name': 'Test Event 2',
|
||||
|
|
@ -482,13 +670,13 @@ class TestEventData(TestEventInternalsCommon):
|
|||
'date_end': datetime(2020, 1, 28, 8, 0, 0),
|
||||
})
|
||||
self.assertFalse(event_2.is_ongoing)
|
||||
finished_or_upcoming_event_ids = self.env['event.event']._search([('is_ongoing', '=', False)])
|
||||
self.assertIn(event_2.id, finished_or_upcoming_event_ids)
|
||||
finished_or_upcoming_events = self.env['event.event'].search([('is_ongoing', '=', False)])
|
||||
self.assertIn(event_2, finished_or_upcoming_events)
|
||||
|
||||
event_2.update({'date_end': datetime(2020, 2, 2, 8, 0, 1)})
|
||||
self.assertTrue(event_2.is_ongoing)
|
||||
finished_or_upcoming_event_ids = self.env['event.event']._search([('is_ongoing', '=', False)])
|
||||
self.assertNotIn(event_2.id, finished_or_upcoming_event_ids)
|
||||
finished_or_upcoming_events = self.env['event.event'].search([('is_ongoing', '=', False)])
|
||||
self.assertNotIn(event_2, finished_or_upcoming_events)
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_event_seats(self):
|
||||
|
|
@ -504,13 +692,11 @@ class TestEventData(TestEventInternalsCommon):
|
|||
# seats: coming from event type configuration
|
||||
self.assertTrue(event.seats_limited)
|
||||
self.assertEqual(event.seats_available, event.event_type_id.seats_max)
|
||||
self.assertEqual(event.seats_unconfirmed, 0)
|
||||
self.assertEqual(event.seats_reserved, 0)
|
||||
self.assertEqual(event.seats_used, 0)
|
||||
self.assertEqual(event.seats_expected, 0)
|
||||
self.assertEqual(event.seats_taken, 0)
|
||||
|
||||
# create registration in order to check the seats computation
|
||||
self.assertTrue(event.auto_confirm)
|
||||
reg_open_multiple = self.env['event.registration'].create([{
|
||||
'event_id': event.id,
|
||||
'name': 'reg_open',
|
||||
|
|
@ -529,10 +715,9 @@ class TestEventData(TestEventInternalsCommon):
|
|||
})
|
||||
reg_done.write({'state': 'done'})
|
||||
self.assertEqual(event.seats_available, event.event_type_id.seats_max - 6)
|
||||
self.assertEqual(event.seats_unconfirmed, 1)
|
||||
self.assertEqual(event.seats_reserved, 5)
|
||||
self.assertEqual(event.seats_used, 1)
|
||||
self.assertEqual(event.seats_expected, 7)
|
||||
self.assertEqual(event.seats_taken, 6)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# SEATS AVAILABILITY AND (UN-)ARCHIVING REGISTRATIONS
|
||||
|
|
@ -542,35 +727,27 @@ class TestEventData(TestEventInternalsCommon):
|
|||
reg_open.action_archive()
|
||||
self.assertEqual(event.seats_reserved, 4)
|
||||
self.assertEqual(event.seats_available, event.event_type_id.seats_max - 5)
|
||||
self.assertEqual(event.seats_expected, 6)
|
||||
self.assertEqual(event.seats_taken, 5)
|
||||
|
||||
reg_draft.action_archive()
|
||||
self.assertEqual(event.seats_unconfirmed, 0)
|
||||
self.assertEqual(event.seats_available, event.event_type_id.seats_max - 5)
|
||||
self.assertEqual(event.seats_expected, 5)
|
||||
self.assertEqual(event.seats_taken, 5)
|
||||
|
||||
# Un-archiving confirmed seats requires available seat(s)
|
||||
reg_open.action_unarchive()
|
||||
self.assertEqual(event.seats_reserved, 5)
|
||||
self.assertEqual(event.seats_available, event.event_type_id.seats_max - 6)
|
||||
self.assertEqual(event.seats_expected, 6)
|
||||
self.assertEqual(event.seats_taken, 6)
|
||||
|
||||
reg_draft.action_unarchive()
|
||||
self.assertEqual(event.seats_unconfirmed, 1)
|
||||
self.assertEqual(event.seats_available, event.event_type_id.seats_max - 6)
|
||||
self.assertEqual(event.seats_expected, 7)
|
||||
self.assertEqual(event.seats_taken, 6)
|
||||
|
||||
reg_open.action_archive()
|
||||
self.assertEqual(event.seats_reserved, 4)
|
||||
|
||||
# It is not possible to set a seats_max value below number of current
|
||||
# confirmed registrations. (4 "reserved" + 1 "used")
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
event.write({'seats_max': 4})
|
||||
event.write({'seats_max': 5})
|
||||
self.assertEqual(event.seats_available, 0)
|
||||
|
||||
# It is not possible to unarchive a confirmed seat if the event is fully booked
|
||||
event.write({'seats_max': 5})
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
reg_open.action_unarchive()
|
||||
|
||||
|
|
@ -584,23 +761,59 @@ class TestEventData(TestEventInternalsCommon):
|
|||
with self.assertRaises(exceptions.ValidationError):
|
||||
reg_draft.write({'state': 'open'})
|
||||
|
||||
# With auto-confirm, it is also impossible to create a draft
|
||||
# registration when the event is full
|
||||
new_draft_to_autoconfirm = {
|
||||
# It is not possible to create an open registration (default value)
|
||||
# when the event is full
|
||||
new_open_registration = {
|
||||
'event_id': event.id,
|
||||
'name': 'New registration with auto confirm'
|
||||
'name': 'reg_open',
|
||||
}
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
self.env['event.registration'].create(new_draft_to_autoconfirm)
|
||||
self.env['event.registration'].create(new_open_registration)
|
||||
|
||||
# If the seats limitation is removed, it becomes possible of course
|
||||
event.write({'seats_limited': 0})
|
||||
self.env['event.registration'].create(new_draft_to_autoconfirm)
|
||||
self.env['event.registration'].create(new_open_registration)
|
||||
reg_draft.write({'state': 'open'})
|
||||
|
||||
|
||||
@tagged('event_registration')
|
||||
class TestEventRegistrationData(TestEventInternalsCommon):
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_registration_attended_log(self):
|
||||
"""Test changes in date_closed field when state is changed."""
|
||||
with self.mock_datetime_and_now('2025-05-03 17:00:00'):
|
||||
event = self.env['event.event'].create({
|
||||
'name': 'Test Event',
|
||||
'date_begin': FieldsDatetime.to_string(datetime.now()),
|
||||
'date_end': FieldsDatetime.to_string(datetime.now() + timedelta(days=2)),
|
||||
})
|
||||
attendee = self.env['event.registration'].create({
|
||||
'name': 'Test Registration',
|
||||
'event_id': event.id,
|
||||
'state': 'done',
|
||||
})
|
||||
self.assertEqual(attendee.date_closed, datetime.now())
|
||||
|
||||
attendee.action_set_done()
|
||||
message = '<p>Attended on 5/3/25</p>'
|
||||
self.assertTrue(message in attendee.message_ids.mapped('body'),
|
||||
'Expected a "Attended on 5/3/25" message in the chatter.')
|
||||
self.assertEqual(attendee.message_ids.mapped('body').count(message), 1,
|
||||
'Logged message when marked as attended.')
|
||||
|
||||
attendee.action_set_done()
|
||||
self.assertEqual(attendee.message_ids.mapped('body').count(message), 2,
|
||||
'Logged message when marked as attended again.')
|
||||
|
||||
with self.mock_datetime_and_now('2025-05-04 17:00:00'):
|
||||
attendee.action_set_done()
|
||||
new_message = '<p>Attended on 5/4/25</p>'
|
||||
self.assertTrue(new_message in attendee.message_ids.mapped('body'),
|
||||
'Expected a "Attended on 5/4/25" message in the chatter.')
|
||||
self.assertEqual(attendee.message_ids.mapped('body').count(new_message), 1,
|
||||
'Logged a new message when marked as attended on a different day.')
|
||||
|
||||
@users('user_eventmanager')
|
||||
def test_registration_partner_sync(self):
|
||||
""" Test registration computed fields about partner """
|
||||
|
|
@ -721,9 +934,7 @@ class TestEventRegistrationPhone(EventCase):
|
|||
customer2 = self.event_customer2.with_env(self.env)
|
||||
event = self.test_event.with_env(self.env)
|
||||
|
||||
self.assertFalse(customer.mobile)
|
||||
self.assertEqual(customer.phone, '0485112233')
|
||||
self.assertEqual(customer2.mobile, '0456654321')
|
||||
self.assertEqual(customer2.phone, '0456987654')
|
||||
|
||||
self.assertEqual(event.company_id.country_id, self.env.ref("base.be"))
|
||||
|
|
@ -734,12 +945,10 @@ class TestEventRegistrationPhone(EventCase):
|
|||
""" Test onchange on phone / mobile, should try to format number """
|
||||
event = self.test_event.with_user(self.env.user)
|
||||
|
||||
lead_form = Form(self.env['event.registration'])
|
||||
lead_form.event_id = event
|
||||
lead_form.mobile = '7200000011'
|
||||
lead_form.phone = '7200000000'
|
||||
self.assertEqual(lead_form.mobile, '+917200000011')
|
||||
self.assertEqual(lead_form.phone, '+917200000000')
|
||||
reg_form = Form(self.env['event.registration'])
|
||||
reg_form.event_id = event
|
||||
reg_form.phone = '7200000000'
|
||||
self.assertEqual(reg_form.phone, '+917200000000')
|
||||
|
||||
@users('user_eventregistrationdesk')
|
||||
def test_registration_phone_format(self):
|
||||
|
|
@ -747,73 +956,61 @@ class TestEventRegistrationPhone(EventCase):
|
|||
(IN numbers) or company (BE numbers). """
|
||||
event = self.test_event.with_user(self.env.user)
|
||||
|
||||
# customer_id, mobile, phone -> based on partner or event country
|
||||
# customer_id, phone -> based on partner or event country
|
||||
sources = [
|
||||
(self.event_customer.id, None, None), # BE local on partner
|
||||
(self.event_customer2.id, None, None), # BE local on partner
|
||||
(self.event_customer2.id, '0456001122', None), # BE local + on partner
|
||||
(False, '0456778899', '+32456778899'), # BE local + BE global
|
||||
(False, '7200000000', False), # IN local
|
||||
(False, False, '7200000011'), # IN local
|
||||
(False, '7200000000', '7200000011'), # IN local
|
||||
(False, '+917200000088', '+917200000099'), # IN global
|
||||
(self.event_customer.id, None), # BE local on partner
|
||||
(self.event_customer2.id, None), # BE local on partner
|
||||
(self.event_customer2.id, '0456001122'), # BE local + on partner
|
||||
(False, '0456778899'), # BE local
|
||||
(False, '7200000000'), # IN local
|
||||
(False, '+917200000088'), # IN global
|
||||
]
|
||||
# mobile, phone
|
||||
# expected phone
|
||||
expected = [
|
||||
(False, '0485112233'), # partner values, no format
|
||||
('0456654321', '0456987654'), # partner values, no format
|
||||
('+32456001122', '0456987654'), # BE on partner / partner value, no format
|
||||
('0456778899', '+32456778899'), # IN on event -> cannot format BE
|
||||
('+917200000000', False), # IN on event
|
||||
(False, '+917200000011'), # IN on event
|
||||
('+917200000000', '+917200000011'), # IN on event
|
||||
('+917200000088', '+917200000099'), # already formatted
|
||||
'0485112233', # partner values, no format (phone only)
|
||||
'0456987654', # partner values, no format (both: phone wins)
|
||||
'+32456001122', # BE on partner
|
||||
'0456778899', # IN on event -> cannot format BE
|
||||
'+917200000000', # IN on event
|
||||
'+917200000088', # already formatted
|
||||
]
|
||||
for (partner_id, mobile, phone), (exp_mobile, exp_phone) in zip(sources, expected):
|
||||
with self.subTest(partner_id=partner_id, mobile=mobile, phone=phone):
|
||||
for (partner_id, phone), exp_phone in zip(sources, expected):
|
||||
with self.subTest(partner_id=partner_id, phone=phone):
|
||||
create_vals = {
|
||||
'event_id': event.id,
|
||||
'partner_id': partner_id,
|
||||
}
|
||||
if mobile is not None:
|
||||
create_vals['mobile'] = mobile
|
||||
if phone is not None:
|
||||
create_vals['phone'] = phone
|
||||
reg = self.env['event.registration'].create(create_vals)
|
||||
self.assertEqual(reg.mobile, exp_mobile)
|
||||
self.assertEqual(reg.phone, exp_phone)
|
||||
|
||||
# no country on event -> based on partner or event company country
|
||||
self.test_event.write({'address_id': False})
|
||||
expected = [
|
||||
(False, '0485112233'), # partner values, no format
|
||||
('0456654321', '0456987654'), # partner values, no format
|
||||
('+32456001122', '0456987654'), # BE on partner / partner value, no format
|
||||
('+32456778899', '+32456778899'), # BE on company
|
||||
('7200000000', False), # BE on company -> cannot format IN
|
||||
(False, '7200000011'), # BE on company -> cannot format IN
|
||||
('7200000000', '7200000011'), # BE on company -> cannot format IN
|
||||
('+917200000088', '+917200000099'), # already formatted
|
||||
'0485112233', # partner values, no format (phone only)
|
||||
'0456987654', # partner values, no format (both: phone wins)
|
||||
'+32456001122', # BE on company
|
||||
'+32456778899', # BE on company
|
||||
'7200000000', # BE on company -> cannot format IN
|
||||
'+917200000088', # already formatted
|
||||
]
|
||||
for (partner_id, mobile, phone), (exp_mobile, exp_phone) in zip(sources, expected):
|
||||
with self.subTest(partner_id=partner_id, mobile=mobile, phone=phone):
|
||||
for (partner_id, phone), exp_phone in zip(sources, expected):
|
||||
with self.subTest(partner_id=partner_id, phone=phone):
|
||||
create_vals = {
|
||||
'event_id': event.id,
|
||||
'partner_id': partner_id,
|
||||
}
|
||||
if mobile is not None:
|
||||
create_vals['mobile'] = mobile
|
||||
if phone is not None:
|
||||
create_vals['phone'] = phone
|
||||
reg = self.env['event.registration'].create(create_vals)
|
||||
self.assertEqual(reg.mobile, exp_mobile)
|
||||
self.assertEqual(reg.phone, exp_phone)
|
||||
|
||||
|
||||
@tagged('event_ticket')
|
||||
class TestEventTicketData(TestEventInternalsCommon):
|
||||
|
||||
@freeze_time('2020-1-31 10:00:00')
|
||||
@freeze_time('2020-01-31 10:00:00')
|
||||
@users('user_eventmanager')
|
||||
def test_event_ticket_fields(self):
|
||||
""" Test event ticket fields synchronization """
|
||||
|
|
@ -831,7 +1028,6 @@ class TestEventTicketData(TestEventInternalsCommon):
|
|||
'end_sale_datetime': datetime(2020, 2, 10, 23, 59, 59),
|
||||
})
|
||||
],
|
||||
'auto_confirm': False # to interact with registrations states
|
||||
})
|
||||
first_ticket = event.event_ticket_ids.filtered(lambda t: t.name == 'First Ticket')
|
||||
second_ticket = event.event_ticket_ids.filtered(lambda t: t.name == 'Second Ticket')
|
||||
|
|
@ -897,23 +1093,23 @@ class TestEventTicketData(TestEventInternalsCommon):
|
|||
'name': f'reg_draft #{idx}',
|
||||
'event_ticket_id': first_ticket.id,
|
||||
} for idx in range(3)])
|
||||
# Draft registrations should not impact seats
|
||||
reg_draft_multiple.state = 'draft'
|
||||
reg_draft = reg_draft_multiple[0]
|
||||
|
||||
reg_open = self.env['event.registration'].create({
|
||||
'event_id': event.id,
|
||||
'name': 'reg_open',
|
||||
'event_ticket_id': first_ticket.id,
|
||||
'state': 'open'
|
||||
})
|
||||
|
||||
reg_done = self.env['event.registration'].create({
|
||||
'event_id': event.id,
|
||||
'name': 'reg_done',
|
||||
'event_ticket_id': first_ticket.id,
|
||||
'state': 'done'
|
||||
})
|
||||
reg_done.action_set_done()
|
||||
|
||||
self.assertEqual(first_ticket.seats_unconfirmed, 3)
|
||||
self.assertEqual(first_ticket.seats_reserved, 1)
|
||||
self.assertEqual(first_ticket.seats_used, 1)
|
||||
self.assertEqual(first_ticket.seats_available, INITIAL_TICKET_SEATS_MAX - 2)
|
||||
|
|
@ -926,9 +1122,6 @@ class TestEventTicketData(TestEventInternalsCommon):
|
|||
self.assertEqual(first_ticket.seats_reserved, 0)
|
||||
self.assertEqual(first_ticket.seats_available, INITIAL_TICKET_SEATS_MAX)
|
||||
|
||||
reg_draft.action_archive()
|
||||
self.assertEqual(first_ticket.seats_unconfirmed, 2)
|
||||
|
||||
# Un-archiving confirmed/done seats requires available seat(s)
|
||||
reg_open.action_unarchive()
|
||||
self.assertEqual(first_ticket.seats_reserved, 1)
|
||||
|
|
@ -938,15 +1131,6 @@ class TestEventTicketData(TestEventInternalsCommon):
|
|||
self.assertEqual(first_ticket.seats_used, 1)
|
||||
self.assertEqual(first_ticket.seats_available, INITIAL_TICKET_SEATS_MAX - 2)
|
||||
|
||||
reg_draft.action_unarchive()
|
||||
self.assertEqual(first_ticket.seats_unconfirmed, 3)
|
||||
self.assertEqual(first_ticket.seats_available, INITIAL_TICKET_SEATS_MAX - 2)
|
||||
|
||||
# It is not possible to set a seats_max value below the current number of confirmed
|
||||
# registrations. (There is still 1 "used" seat too)
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
first_ticket.write({'seats_max': 1})
|
||||
|
||||
reg_open.action_archive()
|
||||
first_ticket.write({'seats_max': 1})
|
||||
|
||||
|
|
@ -956,10 +1140,9 @@ class TestEventTicketData(TestEventInternalsCommon):
|
|||
|
||||
# SEATS AVAILABILITY
|
||||
|
||||
# With auto-confirm, it is impossible to create a draft
|
||||
# registration when the ticket is fully booked (1 used + 1 reserved)
|
||||
# It is impossible to create an open registration when the
|
||||
# ticket is fully booked (1 used + 1 reserved)
|
||||
self.assertEqual(event.seats_available, 0)
|
||||
first_ticket.event_id.auto_confirm = True
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
self.env['event.registration'].create({
|
||||
'event_id': event.id,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
299
odoo-bringout-oca-ocb-event/event/tests/test_event_slot.py
Normal file
299
odoo-bringout-oca-ocb-event/event/tests/test_event_slot.py
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
from datetime import date, datetime, timedelta
|
||||
|
||||
from odoo.addons.event.tests.common import EventCase
|
||||
from odoo import exceptions
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
class TestEventSlotsCommon(EventCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# Mock dates to have reproducible computed fields based on time
|
||||
cls.reference_now = datetime(2025, 4, 15, 10, 0, 0)
|
||||
cls.reference_beg = datetime(2025, 4, 21, 6, 30, 0)
|
||||
cls.reference_end = datetime(2025, 8, 21, 17, 45, 0)
|
||||
|
||||
with cls.mock_datetime_and_now(cls, cls.reference_now):
|
||||
cls.test_event = cls.env['event.event'].create({
|
||||
'date_begin': cls.reference_beg,
|
||||
'date_end': cls.reference_end,
|
||||
'date_tz': 'Europe/Brussels',
|
||||
'event_ticket_ids': [
|
||||
(0, 0, {
|
||||
'name': 'Classic',
|
||||
'seats_limited': False,
|
||||
'seats_max': 0,
|
||||
}), (0, 0, {
|
||||
'name': 'Better',
|
||||
'seats_limited': True,
|
||||
'seats_max': 3,
|
||||
}), (0, 0, {
|
||||
'name': 'VIP',
|
||||
'seats_limited': True,
|
||||
'seats_max': 1,
|
||||
}),
|
||||
],
|
||||
'name': 'Test Event',
|
||||
'seats_limited': True,
|
||||
'seats_max': 5,
|
||||
'event_slot_ids': [
|
||||
(0, 0, {
|
||||
'date': date(2025, 4, 21),
|
||||
'end_hour': 12,
|
||||
'start_hour': 9,
|
||||
}),
|
||||
(0, 0, {
|
||||
'date': date(2025, 4, 21),
|
||||
'end_hour': 16,
|
||||
'start_hour': 13,
|
||||
}),
|
||||
],
|
||||
'user_id': cls.user_eventuser.id,
|
||||
})
|
||||
|
||||
first_slot = cls.test_event.event_slot_ids.filtered(lambda s: s.start_hour == 9)
|
||||
second_slot = cls.test_event.event_slot_ids.filtered(lambda s: s.start_hour == 13)
|
||||
first_ticket = cls.test_event.event_ticket_ids.filtered(lambda t: t.name == 'Classic')
|
||||
second_ticket = cls.test_event.event_ticket_ids.filtered(lambda t: t.name == 'Better')
|
||||
|
||||
# already existing registrations
|
||||
cls.test_reg_slot_1 = cls._create_registrations_for_slot_and_ticket(cls.test_event, first_slot, first_ticket, 3)
|
||||
cls.test_reg_slot_2 = cls._create_registrations_for_slot_and_ticket(cls.test_event, second_slot, second_ticket, 1)
|
||||
|
||||
|
||||
@tagged('event_slot', 'event_registration')
|
||||
class TestEventSlotRegistration(TestEventSlotsCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.test_event_no_slot = cls.env['event.event'].create({
|
||||
'date_begin': cls.reference_beg,
|
||||
'date_end': cls.reference_end,
|
||||
'date_tz': 'Europe/Brussels',
|
||||
'name': 'Test Event No Slot',
|
||||
})
|
||||
cls.test_reg_no_slot = cls.env["event.registration"].create({
|
||||
"event_id": cls.test_event_no_slot.id,
|
||||
"name": "Test Registration No Slot",
|
||||
})
|
||||
|
||||
def test_search_event_begin_date(self):
|
||||
""" Searching on the registration 'event_begin_date' field should correctly search
|
||||
on the slot start datetime if the registration is linked to a slot
|
||||
else on the event start date.
|
||||
"""
|
||||
for search_from_date, expected in [
|
||||
(self.reference_beg, self.test_reg_no_slot + self.test_reg_slot_1 + self.test_reg_slot_2),
|
||||
(self.reference_beg + timedelta(minutes=30), self.test_reg_slot_1 + self.test_reg_slot_2),
|
||||
(self.reference_beg + timedelta(hours=1), self.test_reg_slot_2),
|
||||
]:
|
||||
self.assertEqual(
|
||||
self.env["event.registration"].search([
|
||||
('event_id', 'in', [self.test_event_no_slot.id, self.test_event.id]),
|
||||
('event_begin_date', '>=', search_from_date),
|
||||
]),
|
||||
expected,
|
||||
)
|
||||
|
||||
def test_search_event_end_date(self):
|
||||
""" Searching on the registration 'event_end_date' field should correctly search
|
||||
on the slot end datetime if the registration is linked to a slot,
|
||||
else on the event end date.
|
||||
"""
|
||||
for search_to_date, expected in [
|
||||
(self.reference_end, self.test_reg_no_slot + self.test_reg_slot_1 + self.test_reg_slot_2),
|
||||
(self.reference_beg + timedelta(hours=12), self.test_reg_slot_1 + self.test_reg_slot_2),
|
||||
(self.reference_beg + timedelta(hours=6), self.test_reg_slot_1),
|
||||
]:
|
||||
self.assertEqual(
|
||||
self.env["event.registration"].search([
|
||||
('event_id', 'in', [self.test_event_no_slot.id, self.test_event.id]),
|
||||
('event_end_date', '<=', search_to_date),
|
||||
]),
|
||||
expected,
|
||||
)
|
||||
|
||||
|
||||
@tagged('event_slot', 'event_seats')
|
||||
class TestEventSlotSeats(TestEventSlotsCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.test_event_slot_noticket = cls.test_event.copy({'event_ticket_ids': False})
|
||||
|
||||
first_slot = cls.test_event_slot_noticket.event_slot_ids.filtered(lambda s: s.start_hour == 9)
|
||||
second_slot = cls.test_event_slot_noticket.event_slot_ids.filtered(lambda s: s.start_hour == 13)
|
||||
|
||||
# already existing registrations: 3 on first slot (1 archived), 1 on second slot (2 archived)
|
||||
with cls.mock_datetime_and_now(cls, cls.reference_now):
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, first_slot, False, 1, state='open')
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, first_slot, False, 2, state='done')
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, first_slot, False, 1, active=False)
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, second_slot, False, 1)
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, second_slot, False, 2, active=False)
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, second_slot, False, 1, state='cancel')
|
||||
cls._create_registrations_for_slot_and_ticket(cls.test_event_slot_noticket, second_slot, False, 1, state='draft')
|
||||
|
||||
def test_assert_initial_values(self):
|
||||
""" Check initial values, ensure test conditions """
|
||||
test_event = self.test_event.with_user(self.user_eventregistrationdesk)
|
||||
first_slot = test_event.event_slot_ids.filtered(lambda s: s.start_hour == 9)
|
||||
second_slot = test_event.event_slot_ids.filtered(lambda s: s.start_hour == 13)
|
||||
self.assertTrue(first_slot)
|
||||
self.assertTrue(second_slot)
|
||||
self.assertEqual(first_slot.seats_available, 2)
|
||||
self.assertEqual(first_slot.seats_reserved, 3)
|
||||
self.assertEqual(second_slot.seats_available, 4)
|
||||
self.assertEqual(second_slot.seats_reserved, 1)
|
||||
|
||||
test_event_nt = self.test_event_slot_noticket.with_user(self.user_eventregistrationdesk)
|
||||
first_slot = test_event_nt.event_slot_ids.filtered(lambda s: s.start_hour == 9)
|
||||
second_slot = test_event_nt.event_slot_ids.filtered(lambda s: s.start_hour == 13)
|
||||
self.assertTrue(first_slot)
|
||||
self.assertTrue(second_slot)
|
||||
self.assertEqual(first_slot.seats_available, 2)
|
||||
self.assertEqual(first_slot.seats_reserved, 1)
|
||||
self.assertEqual(second_slot.seats_available, 4)
|
||||
self.assertEqual(second_slot.seats_reserved, 1)
|
||||
|
||||
def test_seats_slots_notickets(self):
|
||||
""" Test: slots, no tickets -> limits come from event itself """
|
||||
# self.test_event_slot_noticket.with_user(self.user_eventuser).write({'event_ticket_ids': [(5, 0)]})
|
||||
test_event = self.test_event_slot_noticket.with_user(self.user_eventregistrationdesk)
|
||||
first_slot = test_event.event_slot_ids.filtered(lambda s: s.start_hour == 9)
|
||||
second_slot = test_event.event_slot_ids.filtered(lambda s: s.start_hour == 13)
|
||||
|
||||
Registration = self.env['event.registration'].with_user(self.user_eventregistrationdesk)
|
||||
|
||||
# check ``_get_seats_availability`` tool, giving availabilities for slot / ticket combinations
|
||||
res = test_event._get_seats_availability([(first_slot, False), (second_slot, False)])
|
||||
self.assertEqual(res, [first_slot.seats_available, second_slot.seats_available])
|
||||
|
||||
# check constraints at registration creation
|
||||
for create_input, should_crash in [
|
||||
# ok for event max seats for both slots
|
||||
(((first_slot, 2), (second_slot, 2)), False),
|
||||
# not enough seats on first slot
|
||||
(((first_slot, 3),), True),
|
||||
# not enough seats on second slot
|
||||
(((second_slot, 5),), True),
|
||||
]:
|
||||
with self.subTest(create_input=create_input, should_crash=should_crash):
|
||||
create_values = []
|
||||
for slot, count in create_input:
|
||||
create_values += [
|
||||
{
|
||||
'email': f'{slot.display_name}.{idx}@test.example.com',
|
||||
'event_id': test_event.id,
|
||||
'event_slot_id': slot.id,
|
||||
'name': f'{slot.display_name} {idx}',
|
||||
} for idx in range(count)
|
||||
]
|
||||
if should_crash:
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
new = Registration.create(create_values)
|
||||
else:
|
||||
new = Registration.create(create_values)
|
||||
self.assertEqual(len(new), sum(count for _slot, count in create_input))
|
||||
new.with_user(self.user_eventmanager).unlink()
|
||||
|
||||
# check ``_verify_seats_availability`` itself
|
||||
for check_input, should_crash in [
|
||||
# ok for event max seats for both slots
|
||||
(((first_slot, False, 2), (second_slot, False, 4)), False),
|
||||
# not enough seats on first slot
|
||||
(((first_slot, False, 3),), True),
|
||||
# not enough seats on second slot
|
||||
(((second_slot, False, 5),), True),
|
||||
]:
|
||||
with self.subTest(check_input=check_input, should_crash=should_crash):
|
||||
if should_crash:
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
test_event._verify_seats_availability(check_input)
|
||||
else:
|
||||
test_event._verify_seats_availability(check_input)
|
||||
|
||||
# check constraint at write (active change) -> ok, check count
|
||||
all_slot2 = test_event.with_context(active_test=False).registration_ids.filtered(lambda r: r.event_slot_id == second_slot)
|
||||
self.assertEqual(len(all_slot2), 5, 'Test setup data: 3 active, 2 inactive')
|
||||
all_slot2.active = True
|
||||
self.assertEqual(second_slot.seats_available, 2)
|
||||
self.assertEqual(second_slot.seats_reserved, 3)
|
||||
|
||||
# move them on first slot -> crash as it would be out of limits
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
all_slot2.event_slot_id = first_slot.id
|
||||
|
||||
def test_seats_slots_tickets(self):
|
||||
""" Test: slots and tickets -> limits come from event (global) and tickets """
|
||||
test_event = self.test_event.with_user(self.user_eventregistrationdesk)
|
||||
first_slot = test_event.event_slot_ids.filtered(lambda s: s.start_hour == 9)
|
||||
second_slot = test_event.event_slot_ids.filtered(lambda s: s.start_hour == 13)
|
||||
first_ticket = test_event.event_ticket_ids.filtered(lambda t: t.name == 'Classic')
|
||||
second_ticket = test_event.event_ticket_ids.filtered(lambda t: t.name == 'Better')
|
||||
third_ticket = test_event.event_ticket_ids.filtered(lambda t: t.name == 'VIP')
|
||||
|
||||
Registration = self.env['event.registration'].with_user(self.user_eventregistrationdesk)
|
||||
|
||||
# check ``_get_seats_availability`` tool, giving availabilities for slot / ticket combinations
|
||||
res = test_event._get_seats_availability([
|
||||
(first_slot, first_ticket), (first_slot, second_ticket), (first_slot, third_ticket),
|
||||
(second_slot, first_ticket), (second_slot, second_ticket), (second_slot, third_ticket),
|
||||
])
|
||||
# first slot: 2 seats available, and VIP ticket has 1 seat anyway
|
||||
# second slot: 4 seats available, Better has 3 max and 1 taken and VIP 1 max
|
||||
self.assertEqual(res, [2, 2, 1, 4, 2, 1])
|
||||
|
||||
# check constraints at registration creation
|
||||
for create_input, should_crash in [
|
||||
(((first_slot, second_ticket, 2),), False),
|
||||
# not enough seats for first slot
|
||||
(((first_slot, first_ticket, 5),), True),
|
||||
# not enough seats on VIP ticket
|
||||
(((second_slot, third_ticket, 2),), True),
|
||||
]:
|
||||
with self.subTest(create_input=create_input, should_crash=should_crash):
|
||||
create_values = []
|
||||
for slot, ticket, count in create_input:
|
||||
create_values += [
|
||||
{
|
||||
'email': f'{slot.display_name}.{ticket.name}.{idx}@test.example.com',
|
||||
'event_id': test_event.id,
|
||||
'event_slot_id': slot.id,
|
||||
'event_ticket_id': ticket.id,
|
||||
'name': f'{slot.display_name} {ticket.name} {idx}',
|
||||
} for idx in range(count)
|
||||
]
|
||||
if should_crash:
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
new = Registration.create(create_values)
|
||||
else:
|
||||
new = Registration.create(create_values)
|
||||
self.assertEqual(len(new), sum(count for _slot, _ticket, count in create_input))
|
||||
new.with_user(self.user_eventmanager).unlink()
|
||||
|
||||
# check create constraint through embed 2many: 2 VIPs is not possible
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
test_event.with_user(self.user_eventmanager).write({
|
||||
'registration_ids': [
|
||||
(0, 0, {'event_slot_id': second_slot.id, 'event_ticket_id': third_ticket.id}),
|
||||
(0, 0, {'event_slot_id': second_slot.id, 'event_ticket_id': third_ticket.id}),
|
||||
],
|
||||
})
|
||||
# one of them is archived, ok for limit
|
||||
test_event.with_user(self.user_eventmanager).write({
|
||||
'registration_ids': [
|
||||
(0, 0, {'event_slot_id': second_slot.id, 'event_ticket_id': third_ticket.id, 'active': False}),
|
||||
(0, 0, {'event_slot_id': second_slot.id, 'event_ticket_id': third_ticket.id}),
|
||||
],
|
||||
})
|
||||
archived_vip = test_event.with_context(active_test=False).registration_ids.filtered(lambda r: r.event_slot_id == second_slot and r.event_ticket_id == third_ticket and not r.active)
|
||||
self.assertTrue(archived_vip)
|
||||
# writing on active triggers constraint on VIP
|
||||
with self.assertRaises(exceptions.ValidationError):
|
||||
archived_vip.active = True
|
||||
167
odoo-bringout-oca-ocb-event/event/tests/test_mailing.py
Normal file
167
odoo-bringout-oca-ocb-event/event/tests/test_mailing.py
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
from datetime import datetime
|
||||
|
||||
from odoo.addons.event.tests.common import EventCase
|
||||
from odoo.addons.mail.tests.common import MockEmail
|
||||
from odoo.tests import Form, tagged, users
|
||||
from odoo.tools import formataddr
|
||||
|
||||
|
||||
@tagged("event_mail", "mail_template", "mail_thread", "post_install", "-at_install")
|
||||
class TestMailing(EventCase, MockEmail):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
|
||||
# freeze some datetimes, and ensure more than 1D+1H before event starts
|
||||
# to ease time-based scheduler check
|
||||
# Since `now` is used to set the `create_date` of an event and create_date
|
||||
# has often microseconds, we set it to ensure that the scheduler we still be
|
||||
# launched if scheduled_date == create_date - microseconds
|
||||
cls.reference_now = datetime(2024, 7, 20, 14, 30, 15, 123456)
|
||||
cls.event_date_begin = datetime(2024, 7, 22, 8, 0, 0)
|
||||
cls.event_date_end = datetime(2024, 7, 24, 18, 0, 0)
|
||||
with cls.mock_datetime_and_now(cls, cls.reference_now):
|
||||
cls.test_event = cls.env['event.event'].create({
|
||||
'date_begin': cls.event_date_begin,
|
||||
'date_end': cls.event_date_end,
|
||||
'date_tz': 'Europe/Brussels',
|
||||
'event_mail_ids': False,
|
||||
'name': 'TestEvent',
|
||||
})
|
||||
cls.registrations = cls.env["event.registration"].create([
|
||||
{
|
||||
"event_id": cls.test_event.id,
|
||||
"partner_id": cls.event_customer.id,
|
||||
},
|
||||
{
|
||||
"event_id": cls.test_event.id,
|
||||
"partner_id": cls.event_customer2.id,
|
||||
},
|
||||
{
|
||||
"email": "robodoo@example.com",
|
||||
"event_id": cls.test_event.id,
|
||||
"name": "Robodoo",
|
||||
},
|
||||
{
|
||||
"email": "another.email@example.com",
|
||||
"event_id": cls.test_event.id,
|
||||
"name": "Another Email",
|
||||
"partner_id": cls.event_customer2.id,
|
||||
},
|
||||
])
|
||||
|
||||
@users("user_eventuser")
|
||||
def test_event_mail_attendees(self):
|
||||
template_form = Form(
|
||||
self.env["mail.template"].with_context(default_model="event.registration", default_name="Test Template")
|
||||
)
|
||||
template = template_form.save()
|
||||
event = self.test_event.with_user(self.env.user)
|
||||
event.write({
|
||||
'event_mail_ids': [
|
||||
(0, 0, {
|
||||
'interval_type': 'before_event',
|
||||
'interval_nbr': 0,
|
||||
'template_ref': f'mail.template,{template.id}',
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
for event_values, exp_mail_values in [
|
||||
(
|
||||
{"organizer_id": self.event_organizer.id, "user_id": self.user_eventmanager.id},
|
||||
{"email_from": self.event_organizer.email_formatted},
|
||||
),
|
||||
(
|
||||
{"organizer_id": False},
|
||||
{"email_from": self.user_eventmanager.company_id.email_formatted},
|
||||
),
|
||||
(
|
||||
{"company_id": False},
|
||||
{"email_from": self.user_eventuser.email_formatted},
|
||||
),
|
||||
]:
|
||||
with self.subTest(event_values=event_values):
|
||||
event.write(event_values)
|
||||
with self.mock_mail_gateway(), self.mock_datetime_and_now(self.event_date_begin):
|
||||
event.event_mail_ids._send_mail(self.registrations)
|
||||
|
||||
# where email == partner.email -> partner is recipient
|
||||
for customer in self.event_customer + self.event_customer2:
|
||||
self.assertMailMail(
|
||||
customer,
|
||||
"outgoing",
|
||||
fields_values=exp_mail_values,
|
||||
)
|
||||
# other registrations: emails
|
||||
self.assertMailMailWEmails(
|
||||
[
|
||||
formataddr(("Robodoo", "robodoo@example.com")),
|
||||
formataddr(("Another Email", "another.email@example.com")),
|
||||
],
|
||||
"outgoing",
|
||||
fields_values=exp_mail_values,
|
||||
)
|
||||
self.assertEqual(len(self._new_mails), 4)
|
||||
|
||||
@users("user_eventmanager")
|
||||
def test_event_mail_recipients(self):
|
||||
""" Check default / suggested recipients """
|
||||
_default_organizer = self.user_eventmanager.company_id.partner_id
|
||||
for event_values, exp_followers, exp_defaults, exp_suggested in [
|
||||
(
|
||||
{"organizer_id": self.event_organizer.id, "user_id": self.user_eventuser.id},
|
||||
self.user_eventmanager.partner_id + self.user_eventuser.partner_id,
|
||||
{"email_cc": "", "email_to": "", "partner_ids": []},
|
||||
[],
|
||||
),
|
||||
(
|
||||
{"organizer_id": False, "user_id": self.user_eventuser.id},
|
||||
self.user_eventmanager.partner_id + self.user_eventuser.partner_id,
|
||||
{"email_cc": "", "email_to": "", "partner_ids": []},
|
||||
[],
|
||||
),
|
||||
(
|
||||
{},
|
||||
self.user_eventmanager.partner_id,
|
||||
{"email_cc": "", "email_to": "", "partner_ids": []},
|
||||
[],
|
||||
),
|
||||
]:
|
||||
with self.subTest(event_values=event_values):
|
||||
test_event = self.env['event.event'].create({
|
||||
'date_begin': self.event_date_begin,
|
||||
'date_end': self.event_date_end,
|
||||
'date_tz': 'Europe/Brussels',
|
||||
'event_mail_ids': False,
|
||||
'name': 'TestEvent',
|
||||
**event_values,
|
||||
})
|
||||
self.assertEqual(test_event.message_partner_ids, exp_followers)
|
||||
defaults = test_event._message_get_default_recipients()[test_event.id]
|
||||
self.assertDictEqual(defaults, exp_defaults)
|
||||
suggested = test_event._message_get_suggested_recipients()
|
||||
self.assertEqual(suggested, exp_suggested)
|
||||
|
||||
@users("user_eventuser")
|
||||
def test_mail_template_creation(self):
|
||||
""" Check default values when creating registration templates, should
|
||||
be correctly configured by default. """
|
||||
template_form_default = Form(
|
||||
self.env["mail.template"].with_context(default_model="event.registration")
|
||||
)
|
||||
template_form_user = Form(self.env["mail.template"])
|
||||
template_form_user.model_id = self.env["ir.model"]._get("event.registration")
|
||||
|
||||
for template in (template_form_default, template_form_user):
|
||||
self.assertEqual(
|
||||
template.email_from,
|
||||
"{{ (object.event_id.organizer_id.email_formatted or object.event_id.company_id.email_formatted or user.email_formatted or '') }}"
|
||||
)
|
||||
self.assertFalse(template.email_to)
|
||||
self.assertEqual(
|
||||
template.lang,
|
||||
"{{ object.event_id.lang or object.partner_id.lang }}",
|
||||
)
|
||||
self.assertTrue(template.use_default_to)
|
||||
Loading…
Add table
Add a link
Reference in a new issue