Files

260 lines
13 KiB
Python

from datetime import datetime, timedelta
from freezegun import freeze_time
from unittest.mock import patch
from odoo.addons.appointment.tests.common import AppointmentCommon
from odoo.addons.google_calendar.models.res_users import ResUsers as GoogleUser
from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.addons.microsoft_calendar.models.res_users import ResUsers as MsftUser
from odoo.addons.microsoft_calendar.tests.common import TestCommon as MsftTestCommon
from odoo.addons.microsoft_calendar.utils.microsoft_calendar import MicrosoftCalendarService
from odoo.tests import tagged
from odoo.tests import users
class TestAppointmentNotificationCommon(AppointmentCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.attendee_ids = cls.env['res.partner'].create([
{'name': f'p{n}', 'email': f'p{n}@test.lan'} for n in range(2)
])
# admin is just a user that follows the appointment type and is making the booking
# apt_user is the person assigned to the booking, not a follower of the apt type.
# apt_manager is just a follower of the appointment type who doesn't otherwise have anything to do with the booking
cls.apt_type_bxls_2days.message_partner_ids = cls.admin_user.partner_id + cls.apt_manager.partner_id
(cls.admin_user + cls.apt_manager + cls.apt_user).notification_type = 'email'
cls.apt_type_resource.booked_mail_template_id = cls._create_template('calendar.attendee', {
'body_html': 'Thanks for booking!',
'subject': 'Thanks for booking, {{object.common_name}}',
})
def _create_event(self, additional_values=None):
additional_values = additional_values or {}
return self._create_meetings(
self.apt_user, [(datetime(2020, 2, 1, 10), datetime(2020, 2, 1, 11), False)],
appointment_type_id=self.apt_type_bxls_2days.id, suppress_mail=False, partners=self.attendee_ids,
meeting_values={'name': 'Test Notification Appointment', 'appointment_status': 'booked'} | additional_values
)
@tagged('post_install', '-at_install', 'mail_flow')
class TestAppointmentNotificationsMail(TestAppointmentNotificationCommon):
@freeze_time('2020-02-01 09:00:00')
@users('admin')
def test_appointment_notification_templates_mail(self):
"""Check that booking and cancelation notifications are sent to the right people when only using mail."""
with self.mock_mail_gateway():
appointment = self._create_event()
self.env.flush_all()
self.cr.precommit.run()
booked_mail = self.assertMailMail(
self.apt_manager.partner_id,
'sent',
author=self.apt_user.partner_id, # author: synchronized with email_from of template
email_values={
'subject': 'Appointment Booked: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_booked'),
'notified_partner_ids': self.apt_manager.partner_id,
},
)
self.assertFalse(
any(mail.subtype_id == self.env.ref('appointment.mt_calendar_event_booked') for mail in self._new_mails - booked_mail),
"Only internal users should receive the booking notification mail",
)
with self.mock_mail_gateway():
appointment.action_archive()
self.env.flush_all()
self.cr.precommit.run()
# one email for users, including followers of the apt type
self.assertMailMail(
(self.apt_manager.partner_id + self.apt_user.partner_id),
'sent',
author=self.apt_user.partner_id,
email_values={
'subject': 'Appointment Canceled: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_canceled'),
},
)
# one email for other attendees
self.assertMailMail(
appointment.partner_ids - self.apt_user.partner_id,
'sent',
author=self.apt_user.partner_id,
email_values={
'subject': 'Appointment Canceled: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_canceled'),
},
)
self.assertMailMail(appointment.partner_ids - appointment.partner_id, 'sent', author=appointment.partner_id)
@tagged('post_install', '-at_install', 'mail_flow')
class TestSyncOdoo2GoogleMail(TestSyncGoogle, TestAppointmentNotificationCommon):
@freeze_time('2020-02-01 09:00:00')
@patch.object(GoogleUser, '_get_google_calendar_token', lambda user: 'some-token')
@users('admin')
def test_appointment_notification_templates_gcalendar(self):
"""Check that booking and cancelation notifications are sent to the right people when syncing with google calendar."""
self.env.user.res_users_settings_id._set_google_auth_tokens('some-token', '123', 10000)
with self.mock_mail_gateway(mail_unlink_sent=False), self.mock_google_sync():
appointment = self._create_event()
appointment.google_id = 'test_google_id' # would normally be set by insert
self.env.flush_all()
self.cr.precommit.run()
self.assertGoogleEventInserted({'id': False, 'summary': 'Test Notification Appointment'})
self.assertMailMail(
self.apt_manager.partner_id + self.apt_user.partner_id,
'sent',
author=self.apt_user.partner_id, # author: synchronized with email_from of template
email_values={
'subject': 'Appointment Booked: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_booked'),
},
)
self.assertNotSentEmail(appointment.partner_ids - self.apt_user.partner_id)
with self.mock_mail_gateway(mail_unlink_sent=False), self.mock_google_sync():
appointment.action_archive()
self.env.flush_all()
self.cr.precommit.run()
self.assertGoogleEventPatched('test_google_id', {'status': 'cancelled'}, timeout=3)
self.assertMailMail(
self.apt_manager.partner_id + self.apt_user.partner_id,
'sent',
author=self.apt_user.partner_id, # author: synchronized with email_from of template
email_values={
'subject': 'Appointment Canceled: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_canceled'),
},
)
self.assertNotSentEmail(appointment.partner_ids - self.apt_user.partner_id)
@tagged('post_install', '-at_install', 'mail_flow')
class TestAppointmentNotificationsMicrosoftCalendar(MsftTestCommon, TestAppointmentNotificationCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user_public = mail_new_test_user(
cls.env, login='user_public', groups='base.group_public', name='Public User'
)
cls.public_user_booking_partner = cls.env['res.partner'].create({
'name': 'Booking attendee',
'email': 'booking.attendee@test.lan',
})
def setUp(self):
super().setUp()
# attendee user in parent class is created in setUp
sync_paused_attendee = self.attendee_user.copy(default={
'email': 'ms.sync.paused@test.lan',
'login': 'ms_sync_paused_user',
})
sync_paused_attendee.microsoft_synchronization_stopped = True
@freeze_time('2020-02-01 09:00:00')
@patch.object(MsftUser, '_get_microsoft_calendar_token', lambda user: 'some-token')
@users('admin')
def test_appointment_cancel_notification_templates_msftcalendar(self):
"""Check that booking and cancelation notifications are sent to the right people when syncing with microsoft calendar."""
with self.mock_mail_gateway(), patch.object(MicrosoftCalendarService, 'insert') as mock_insert:
mock_insert.return_value = ('test_msft_id', 'test_msft_uid')
appointment = self._create_event()
appointment.microsoft_id = 'test_msft_id' # would normally be set by insert
self.env.flush_all()
self.cr.precommit.run()
self.env.cr.postcommit.run()
mock_insert.assert_called_once()
self.assertMailMail(
self.apt_manager.partner_id + self.apt_user.partner_id,
'sent',
author=self.apt_user.partner_id, # author: synchronized with email_from of template
email_values={
'subject': 'Appointment Booked: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_booked'),
},
)
self.assertNotSentEmail(appointment.partner_ids - self.apt_user.partner_id)
with self.mock_mail_gateway(), patch.object(MicrosoftCalendarService, 'delete') as mock_delete:
appointment.action_archive()
self.env.flush_all()
self.cr.precommit.run()
self.env.cr.postcommit.run()
mock_delete.assert_called_once_with('test_msft_id', token='some-token', timeout=5)
self.assertMailMail(
self.apt_manager.partner_id + self.apt_user.partner_id,
'sent',
author=self.apt_user.partner_id, # author: synchronized with email_from of template
email_values={
'subject': 'Appointment Canceled: Bxls Appt Type',
},
fields_values={
'subtype_id': self.env.ref('appointment.mt_calendar_event_canceled'),
},
)
self.assertNotSentEmail(appointment.partner_ids - self.apt_user.partner_id)
@freeze_time('2020-02-01 09:00:00')
@users('mike@organizer.com', 'john@attendee.com', 'ms_sync_paused_user', 'user_public')
@patch.object(
MsftUser, '_get_microsoft_calendar_token',
lambda user: user.login not in ['user_public', 'john@attendee.com'] and 'some-token'
)
def test_sync_or_email_resource_appointment(self):
"""Check that resource appointments are synced even if there is no organizer, unless the attendee is not syncing."""
for with_organizer in [True, False]:
with self.subTest(with_organizer=with_organizer):
is_public = self.env.user == self.user_public
booking_partner = self.env.user.partner_id if not is_public else self.public_user_booking_partner
expected_author = booking_partner if not is_public else self.user_public.partner_id
if with_organizer:
expected_author = self.organizer_user.partner_id
with self.mock_mail_gateway(mail_unlink_sent=False), patch.object(MicrosoftCalendarService, 'insert') as mock_insert:
mock_insert.return_value = ('1', '1')
meeting = self.env['calendar.event'].with_context(mail_notify_author=True).sudo(is_public).create({
'appointment_type_id': self.apt_type_resource.id,
'name': f'Resource Appointment {booking_partner.name}',
'partner_ids': booking_partner.ids,
'start': datetime.now() + timedelta(days=1),
'stop': datetime.now() + timedelta(days=1, hours=1),
'user_id': with_organizer and self.organizer_user.id,
})
self.env.flush_all()
self.cr.precommit.run()
self.cr.postcommit.run()
# synced with the organizer (who can always sync in this test), but checked against the create user
if meeting._check_microsoft_sync_status() and self.env.user._get_microsoft_sync_status() == "sync_active":
mock_insert.assert_called_once()
# no mail sent to non-organizer partners, if any exists
if meeting.partner_ids - meeting.partner_id:
self.assertNotSentEmail(meeting.partner_ids - meeting.partner_id)
else:
mock_insert.assert_not_called()
self.assertMailMail(
booking_partner, 'sent',
author=expected_author,
fields_values={'subject': f'Thanks for booking, {booking_partner.name}'}
)
if with_organizer:
self.assertMailMail(
meeting.partner_id, 'sent',
author=expected_author,
fields_values={'subject': 'Appointment Booked: Test'}
)