bemade-addons/bemade_sports_clinic/tests/test_injury_notifications.py

298 lines
13 KiB
Python
Raw Normal View History

from odoo.tests import TransactionCase, tagged
from unittest.mock import patch
@tagged("-at_install", "post_install")
class TestInjuryNotifications(TransactionCase):
"""Test the notification system for injury updates to ensure only appropriate users
receive the different types of notifications (internal vs external)."""
@classmethod
def setUpClass(cls):
super().setUpClass()
# Get security groups
cls.treatment_prof_group = cls.env.ref('bemade_sports_clinic.group_sports_clinic_treatment_professional')
cls.user_group = cls.env.ref('bemade_sports_clinic.group_sports_clinic_user')
cls.portal_treatment_prof_group = cls.env.ref('bemade_sports_clinic.group_portal_treatment_professional')
cls.portal_coach_group = cls.env.ref('bemade_sports_clinic.group_portal_team_coach')
# Create a test organization
cls.organization = cls.env['sports.organization'].create({
'name': 'Test Organization',
})
# Create a test team
cls.team = cls.env['sports.team'].create({
'name': 'Test Team',
'organization_id': cls.organization.id,
})
# Create test partners for different roles
cls.partner_therapist = cls.env['res.partner'].create({
'name': 'Therapist Partner',
'email': 'test.therapist@example.com',
})
cls.partner_portal_therapist = cls.env['res.partner'].create({
'name': 'Portal Therapist Partner',
'email': 'test.portal.therapist@example.com',
})
cls.partner_coach = cls.env['res.partner'].create({
'name': 'Coach Partner',
'email': 'test.coach@example.com',
})
cls.partner_portal_coach = cls.env['res.partner'].create({
'name': 'Portal Coach Partner',
'email': 'test.portal.coach@example.com',
})
cls.partner_athlete = cls.env['res.partner'].create({
'name': 'Athlete Partner',
'email': 'test.athlete@example.com',
})
# Create users for each partner with appropriate roles
# 1. Internal Therapist User
cls.user_therapist = cls.env['res.users'].create({
'name': 'Test Therapist',
'login': 'test.therapist@example.com',
'partner_id': cls.partner_therapist.id,
'groups_id': [
(4, cls.env.ref('base.group_user').id),
(4, cls.treatment_prof_group.id)
],
})
# 2. Portal Therapist User
cls.user_portal_therapist = cls.env['res.users'].create({
'name': 'Test Portal Therapist',
'login': 'test.portal.therapist@example.com',
'partner_id': cls.partner_portal_therapist.id,
'groups_id': [
(4, cls.env.ref('base.group_portal').id),
(4, cls.portal_treatment_prof_group.id)
],
})
# 3. Internal Coach User
cls.user_coach = cls.env['res.users'].create({
'name': 'Test Coach',
'login': 'test.coach@example.com',
'partner_id': cls.partner_coach.id,
'groups_id': [
(4, cls.env.ref('base.group_user').id),
(4, cls.user_group.id)
],
})
# 4. Portal Coach User
cls.user_portal_coach = cls.env['res.users'].create({
'name': 'Test Portal Coach',
'login': 'test.portal.coach@example.com',
'partner_id': cls.partner_portal_coach.id,
'groups_id': [
(4, cls.env.ref('base.group_portal').id),
(4, cls.portal_coach_group.id)
],
})
# Create a patient
cls.patient = cls.env['sports.patient'].create({
'first_name': 'Test',
'last_name': 'Athlete',
'team_ids': [(4, cls.team.id)],
})
# Create team staff
cls.env['sports.team.staff'].create({
'team_id': cls.team.id,
'partner_id': cls.partner_therapist.id,
'role': 'therapist', # This role grants treatment professional access
'user_id': cls.user_therapist.id,
})
cls.env['sports.team.staff'].create({
'team_id': cls.team.id,
'partner_id': cls.partner_portal_therapist.id,
'role': 'portal_therapist', # This role grants treatment professional access
'user_id': cls.user_portal_therapist.id,
})
cls.env['sports.team.staff'].create({
'team_id': cls.team.id,
'partner_id': cls.partner_coach.id,
'role': 'coach', # This role does not grant treatment professional access
'user_id': cls.user_coach.id,
})
cls.env['sports.team.staff'].create({
'team_id': cls.team.id,
'partner_id': cls.partner_portal_coach.id,
'role': 'portal_coach', # This role does not grant treatment professional access
'user_id': cls.user_portal_coach.id,
})
# Create an injury for testing notifications
cls.injury = cls.env['sports.patient.injury'].create({
'patient_id': cls.patient.id,
'team_id': cls.team.id,
'diagnosis': 'Initial diagnosis',
})
# Make all users follow the injury
cls.injury.message_subscribe([
cls.partner_therapist.id,
cls.partner_portal_therapist.id,
cls.partner_coach.id,
cls.partner_portal_coach.id,
])
def _get_followers_by_subtype(self, injury, subtype_xmlid):
"""Helper to get followers who are subscribed to a specific message subtype"""
subtype = self.env.ref(subtype_xmlid)
followers = self.env['mail.followers'].search([
('res_model', '=', 'sports.patient.injury'),
('res_id', '=', injury.id),
])
result = []
for follower in followers:
if subtype.id in follower.subtype_ids.ids:
result.append(follower.partner_id)
return result
def test_subscription_management(self):
"""Test that _manage_treatment_professional_subscriptions correctly sets
subscription preferences based on user roles."""
# Force recompute subscriptions
self.injury._manage_treatment_professional_subscriptions()
# Get followers by subtype
external_followers = self._get_followers_by_subtype(
self.injury, 'bemade_sports_clinic.subtype_patient_injury_external_update')
internal_followers = self._get_followers_by_subtype(
self.injury, 'bemade_sports_clinic.subtype_patient_injury_internal_update')
# All followers should be subscribed to external updates
self.assertIn(self.partner_therapist, external_followers)
self.assertIn(self.partner_portal_therapist, external_followers)
self.assertIn(self.partner_coach, external_followers)
self.assertIn(self.partner_portal_coach, external_followers)
# Only treatment professionals should be subscribed to internal updates
self.assertIn(self.partner_therapist, internal_followers)
self.assertIn(self.partner_portal_therapist, internal_followers)
self.assertNotIn(self.partner_coach, internal_followers)
self.assertNotIn(self.partner_portal_coach, internal_followers)
def test_internal_note_notifications(self):
"""Test that when internal notes are updated, only treatment professionals
receive notifications."""
# Create a patch to intercept the notification sending process
with patch('odoo.addons.mail.models.mail_thread.MailThread._notify_record_by_email') as notify_mock:
# Update the internal notes
self.injury.write({'internal_notes': 'This is a confidential internal note'})
# Check that notify_record_by_email was called
notify_mock.assert_called()
# Extract the partners who were notified
call_args = notify_mock.call_args_list[0][0] # Get args of first call
notified_partners = call_args[1]['partners'] # Extract partners from kwargs
notified_partner_ids = [p['id'] for p in notified_partners]
# Verify that only treatment professionals received the notification
self.assertIn(self.partner_therapist.id, notified_partner_ids)
self.assertIn(self.partner_portal_therapist.id, notified_partner_ids)
self.assertNotIn(self.partner_coach.id, notified_partner_ids)
self.assertNotIn(self.partner_portal_coach.id, notified_partner_ids)
def test_external_note_notifications(self):
"""Test that when external notes are updated, all followers receive notifications."""
# Create a patch to intercept the notification sending process
with patch('odoo.addons.mail.models.mail_thread.MailThread._notify_record_by_email') as notify_mock:
# Update the external notes
self.injury.write({'external_notes': 'This is a public external note'})
# Check that notify_record_by_email was called
notify_mock.assert_called()
# Extract the partners who were notified
call_args = notify_mock.call_args_list[0][0] # Get args of first call
notified_partners = call_args[1]['partners'] # Extract partners from kwargs
notified_partner_ids = [p['id'] for p in notified_partners]
# Verify that all followers received the notification
self.assertIn(self.partner_therapist.id, notified_partner_ids)
self.assertIn(self.partner_portal_therapist.id, notified_partner_ids)
self.assertIn(self.partner_coach.id, notified_partner_ids)
self.assertIn(self.partner_portal_coach.id, notified_partner_ids)
def test_treatment_professional_assignment_updates_subscriptions(self):
"""Test that adding/removing treatment professionals updates their subscription settings."""
# Create a new injury without any treatment professionals
new_injury = self.env['sports.patient.injury'].create({
'patient_id': self.patient.id,
'team_id': self.team.id,
'diagnosis': 'Test subscription updates',
})
# Make all users follow the new injury
new_injury.message_subscribe([
self.partner_therapist.id,
self.partner_portal_therapist.id,
self.partner_coach.id,
self.partner_portal_coach.id,
])
# Add a treatment professional
new_injury.write({
'treatment_professional_ids': [(4, self.user_therapist.id)]
})
# Check that the added therapist is now subscribed to internal notes
internal_followers = self._get_followers_by_subtype(
new_injury, 'bemade_sports_clinic.subtype_patient_injury_internal_update')
self.assertIn(self.partner_therapist, internal_followers)
# Now remove the treatment professional
new_injury.write({
'treatment_professional_ids': [(3, self.user_therapist.id)]
})
# The subscription to internal notes should remain (we don't remove it)
# because the user is still a treatment professional
internal_followers_after = self._get_followers_by_subtype(
new_injury, 'bemade_sports_clinic.subtype_patient_injury_internal_update')
self.assertIn(self.partner_therapist, internal_followers_after)
def test_portal_treatment_prof_gets_notifications(self):
"""Test that portal users who are treatment professionals receive internal note notifications."""
# Subscribe portal therapist to the injury if not already subscribed
self.injury.message_subscribe([self.partner_portal_therapist.id])
# Force recompute subscriptions
self.injury._manage_treatment_professional_subscriptions()
# Create a patch to intercept the notification sending process
with patch('odoo.addons.mail.models.mail_thread.MailThread._notify_record_by_email') as notify_mock:
# Update the internal notes
self.injury.write({'internal_notes': 'This note should reach portal therapists'})
# Check that notify_record_by_email was called
notify_mock.assert_called()
# Extract the partners who were notified
call_args = notify_mock.call_args_list[0][0] # Get args of first call
notified_partners = call_args[1]['partners'] # Extract partners from kwargs
notified_partner_ids = [p['id'] for p in notified_partners]
# Verify that portal therapist received the notification
self.assertIn(self.partner_portal_therapist.id, notified_partner_ids)