1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/whatsapp_event/tests/test_whatsapp_schedule.py
2024-12-10 09:04:09 +07:00

310 lines
15 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
from contextlib import contextmanager
from datetime import datetime, timedelta
from freezegun import freeze_time
from unittest.mock import patch
from itertools import zip_longest
from odoo import exceptions
from odoo.addons.event.tests.common import EventCase
from odoo.addons.whatsapp.tests.common import WhatsAppCommon
from odoo.tests import tagged, users
from odoo.tools import mute_logger
@tagged('event_mail')
class TestWhatsappSchedule(EventCase, WhatsAppCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
# test subscription whatsapp template
cls.whatsapp_template_sub = cls.env['whatsapp.template'].create({
'body': "{{1}} registration confirmation.",
'name': "Test subscription",
'model_id': cls.env['ir.model']._get_id('event.registration'),
'status': 'approved',
'phone_field': 'phone',
'wa_account_id': cls.whatsapp_account.id,
})
cls.whatsapp_template_sub.variable_ids.write({
'field_type': "field",
'field_name': "event_id",
})
# test reminder whatsapp template
cls.whatsapp_template_rem = cls.env['whatsapp.template'].create({
'body': "{{1}} reminder.",
'name': "Test reminder",
'model_id': cls.env['ir.model']._get_id('event.registration'),
'status': 'approved',
'phone_field': 'phone',
'wa_account_id': cls.whatsapp_account.id,
})
cls.whatsapp_template_rem.variable_ids.write({
'field_type': "field",
'field_name': "event_id",
})
# test event
cls.reference_now = datetime(2023, 3, 10, 14, 30, 15, 0)
cls.test_event = cls.env['event.event'].create({
'date_begin': cls.reference_now + timedelta(days=5),
'date_end': cls.reference_now + timedelta(days=10),
'date_tz': 'Europe/Brussels',
'event_mail_ids': [
(5, 0),
(0, 0, { # right at subscription
'interval_unit': 'now',
'interval_type': 'after_sub',
'notification_type': 'whatsapp',
'template_ref': 'whatsapp.template,%i' % cls.whatsapp_template_sub.id}),
(0, 0, { # 3 days before event
'interval_nbr': 3,
'interval_unit': 'days',
'interval_type': 'before_event',
'notification_type': 'whatsapp',
'template_ref': 'whatsapp.template,%i' % cls.whatsapp_template_rem.id}),
],
'name': 'Test Event',
})
with cls.mock_datetime_and_now(cls, cls.reference_now):
cls.test_attendees = cls.env["event.registration"].create([
{
"event_id": cls.test_event.id,
"name": f"WA attendee {idx}",
"email": f"_test_reg_{idx}@example.com",
"phone": f"+324560000{idx}{idx}",
} for idx in range(2)
])
@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
@users('user_eventmanager')
def test_assert_initial_values(self):
""" Be sure of our initial setup """
sub_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "after_sub")
self.assertEqual(len(sub_scheduler), 1)
self.assertEqual(sub_scheduler.mail_count_done, 2)
self.assertTrue(sub_scheduler.mail_done)
self.assertEqual(sub_scheduler.scheduled_date, self.test_event.create_date.replace(microsecond=0),
'event: incorrect scheduled date for checking controller')
before_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "before_event")
self.assertEqual(len(before_scheduler), 1)
self.assertEqual(before_scheduler.mail_count_done, 0)
self.assertFalse(before_scheduler.mail_done)
self.assertEqual(before_scheduler.scheduled_date, self.test_event.date_begin + timedelta(days=-3))
@users('user_eventmanager')
def test_whatsapp_schedule(self):
test_event = self.env['event.event'].browse(self.test_event.ids)
with self.mockWhatsappGateway():
new_regs = self._create_registrations(test_event, 3)
# check subscription scheduler
sub_scheduler = self.env['event.mail'].search([('event_id', '=', test_event.id), ('interval_type', '=', 'after_sub')])
# verify that subscription scheduler was auto-executed after each registration
self.assertEqual(len(sub_scheduler.mail_registration_ids), 5, "2 pre-existing + 3 new")
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'), test_event.registration_ids)
self.assertTrue(sub_scheduler.mail_done)
self.assertEqual(sub_scheduler.mail_count_done, 5, "2 pre-existing + 3 new")
# verify that message sent correctly after each registration
for registration in new_regs:
self.assertWAMessageFromRecord(registration, status='outgoing')
# check before event scheduler
before_scheduler = self.env['event.mail'].search([('event_id', '=', test_event.id), ('interval_type', '=', 'before_event')])
# execute event reminder scheduler explicitly
with self.mock_datetime_and_now(test_event.date_begin + timedelta(days=-3, hours=1)), \
self.mockWhatsappGateway():
before_scheduler.execute()
self.assertTrue(before_scheduler.mail_done)
self.assertEqual(before_scheduler.mail_count_done, 5, "2 pre-existing + 3 new")
test_event.date_begin = self.reference_now + timedelta(hours=1)
self.assertGreater(self.reference_now, before_scheduler.scheduled_date, 'Scheduler scheduled_date should trigger it.')
for registration, state in zip_longest(test_event.registration_ids, ['draft', 'open', 'open', 'done'], fillvalue='cancel'):
registration.state = state
before_scheduler.mail_done = False
with self.mock_datetime_and_now(self.reference_now), self.mockWhatsappGateway():
before_scheduler.execute()
for registration in test_event.registration_ids.filtered(lambda reg: reg.state in ('open', 'done')):
with self.subTest(registration_state=registration.state):
self.assertWAMessageFromRecord(registration, status='outgoing')
self.assertEqual(len(self._new_wa_msg), 3, 'Whatsapp messages should not be send to draft and cancel registrations')
self.assertEqual(before_scheduler.filtered(lambda r: r.notification_type == 'whatsapp').mail_count_done, 3,
'Wrong Whatsapp Sent Count! Probably msg sent to unconfirmed attendees were not included into the Sent Count')
@mute_logger('odoo.addons.event.models.event_mail')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_global_composer(self):
# Simulate a fail during composer usage e.g. invalid field path, template
# model change, ... to check defensive behavior
cron = self.env.ref("event.event_mail_scheduler").sudo()
before_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "before_event")
def _patched_composer_send(self, *args, **kwargs):
raise exceptions.ValidationError('Some error')
with patch.object(type(self.env["whatsapp.composer"]), "_send_whatsapp_template", _patched_composer_send):
with self.mock_datetime_and_now(self.reference_now + timedelta(days=3)), \
self.mockWhatsappGateway():
cron.method_direct_trigger()
self.assertFalse(before_scheduler.mail_done)
@mute_logger('odoo.addons.event.models.event_mail',
'odoo.addons.whatsapp_event.models.event_mail',
'odoo.addons.whatsapp_event.models.event_mail_registration')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_global_no_registrations(self):
""" Be sure no registrations = no crash in wa composer """
cron = self.env.ref("event.event_mail_scheduler").sudo()
self.test_event.registration_ids.unlink()
with self.mock_datetime_and_now(self.reference_now + timedelta(days=3)), \
self.mockWhatsappGateway():
cron.method_direct_trigger()
@mute_logger('odoo.addons.whatsapp_event.models.event_mail')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_global_template_draft(self):
""" Test flow where scheduler fails due to template ref being in draft
when sending global event communication (i.e. only through cron). """
cron = self.env.ref("event.event_mail_scheduler").sudo()
before_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "before_event")
# ensure there is a single draft template (crash in composer)
self.env["whatsapp.template"].sudo().search(
[("model_id", "=", self.env["ir.model"]._get_id("event.registration"))]
).unlink()
tpl_draft = self.env['whatsapp.template'].sudo().create({
"body": "Test reminder",
"model_id": self.env["ir.model"]._get_id("event.registration"),
"name": "Draft Fail",
"phone_field": "phone",
"status": "draft",
"wa_account_id": self.whatsapp_account.id,
})
before_scheduler.template_ref = tpl_draft
with self.mock_datetime_and_now(self.reference_now + timedelta(days=3)), \
self.mockWhatsappGateway():
cron.method_direct_trigger()
self.assertFalse(before_scheduler.mail_done)
@mute_logger('odoo.addons.whatsapp_event.models.event_mail')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_global_template_removed(self):
""" Test flow where scheduler fails due to template ref being removed
when sending global event communication (i.e. only through cron). """
cron = self.env.ref("event.event_mail_scheduler").sudo()
before_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "before_event")
# make before event scheduler crash, remove linked template
self.whatsapp_template_rem.sudo().unlink()
test_event = self.env['event.event'].browse(self.test_event.ids)
with self.mockWhatsappGateway():
_new_regs = self._create_registrations(test_event, 3)
# execute event reminder scheduler explicitly: should not crash, just skip
with self.mock_datetime_and_now(self.reference_now + timedelta(days=3)), \
self.mockWhatsappGateway():
cron.method_direct_trigger()
self.assertFalse(before_scheduler.mail_done)
@mute_logger('odoo.addons.whatsapp_event.models.event_mail_registration')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_registration_composer(self):
""" Simulate a fail during composer usage e.g. invalid field path, template
# model change, ... to check defensive behavior """
onsub_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "after_sub")
def _patched_composer_send(self, *args, **kwargs):
raise exceptions.ValidationError('Some error')
with patch.object(type(self.env["whatsapp.composer"]), "_send_whatsapp_template", _patched_composer_send):
with self.mockWhatsappGateway():
registration = self.env['event.registration'].create({
"email": "test@email.com",
"event_id": self.test_event.id,
"name": "Mitchell Admin",
"phone": "(255)-595-8393",
})
self.assertTrue(registration.exists(), "Registration record should exist after creation.")
self.assertEqual(onsub_scheduler.mail_count_done, 2)
self.assertFalse(onsub_scheduler.mail_done)
@mute_logger('odoo.addons.whatsapp_event.models.event_mail')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_registration_template_draft(self):
""" Test flow where scheduler fails due to template being draft. """
# ensure there is a single draft template (crash in composer)
self.env["whatsapp.template"].sudo().search(
[("model_id", "=", self.env["ir.model"]._get_id("event.registration"))]
).unlink()
tpl_draft = self.env['whatsapp.template'].sudo().create({
"body": "Test reminder",
"model_id": self.env["ir.model"]._get_id("event.registration"),
"name": "Draft Fail",
"phone_field": "phone",
"status": "draft",
"wa_account_id": self.whatsapp_account.id,
})
self.test_event.write({
'event_mail_ids': [
(5, 0),
(0, 0, { # right at subscription
'interval_unit': 'now',
'interval_type': 'after_sub',
'notification_type': 'whatsapp',
'template_ref': 'whatsapp.template,%i' % tpl_draft.id}),
]
})
with self.mockWhatsappGateway():
registration = self.env['event.registration'].create({
"email": "test@email.com",
"event_id": self.test_event.id,
"name": "Mitchell Admin",
"phone": "(255)-595-8393",
})
self.assertTrue(registration.exists(), "Registration record should exist after creation.")
sub_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "after_sub")
self.assertFalse(sub_scheduler.mail_done)
@mute_logger('odoo.addons.whatsapp_event.models.event_mail')
@users('user_eventmanager')
def test_whatsapp_schedule_fail_registration_template_removed(self):
""" Test flow where scheduler fails due to template being removed. """
# make on subscription scheduler crash, remove linked template
self.whatsapp_template_sub.sudo().unlink()
with self.mockWhatsappGateway():
registration = self.env['event.registration'].create({
"email": "test@email.com",
"event_id": self.test_event.id,
"name": "Mitchell Admin",
"phone": "(255)-595-8393",
})
self.assertTrue(registration.exists(), "Registration record should exist after creation.")
sub_scheduler = self.test_event.event_mail_ids.filtered(lambda s: s.interval_type == "after_sub")
self.assertFalse(sub_scheduler.mail_done)