bemade-addons/bemade_sports_clinic/tests/test_injury_notifications.py
Denis Durepos c0834eb327 [REF] bemade_sports_clinic: Remove injury models and simplify data model
- Removed models/injury_models.py and all its references
- Converted relational fields to character fields:
  - body_location_id → body_location
  - injury_type_id → injury_type
- Updated portal templates to use text inputs instead of dropdowns
- Updated controller code to process the new field formats
- Removed related access rights from security CSV
- Modified test files to accommodate the new structure

This refactoring simplifies the data model by removing unnecessary
classifications that were adding complexity without significant benefit.
The direct text fields maintain the same functionality while reducing
the database overhead and simplifying the UI.
2025-07-16 11:37:50 -04:00

297 lines
13 KiB
Python

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)