[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.
This commit is contained in:
parent
8c9d60c550
commit
c0834eb327
20 changed files with 318 additions and 186 deletions
|
|
@ -17,6 +17,9 @@
|
|||
- [x] Added field to the therapist portal UI for injury creation
|
||||
- [x] Updated portal controller to handle the parental consent field
|
||||
|
||||
- [ ] **Fix configuration issues**
|
||||
- [ ] Fix injury update chatter links pointing to example.com before going live
|
||||
|
||||
|
||||
## Medium Priority
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
# Check if user has access to any team this patient belongs to
|
||||
patient_id_int = int(patient_id)
|
||||
accessible_teams = request.env['sports.team'].search([
|
||||
('staff_ids.user_ids', 'in', user.id),
|
||||
('staff_ids.user_ids', '=', user.id),
|
||||
('patient_ids', 'in', patient_id_int)
|
||||
])
|
||||
|
||||
# Medical professionals might have specific access
|
||||
is_medical = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_medical = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
if not patient.exists() or (not accessible_teams and not is_medical):
|
||||
raise UserError(_('You do not have access to this patient.'))
|
||||
|
|
@ -42,7 +42,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
patient = self._check_access_to_patient(patient_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
return_url = post.get('return_url', f'/my/player?player_id={patient_id}')
|
||||
|
||||
|
|
@ -78,7 +82,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
patient = self._check_access_to_patient(patient_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
# Get the selected team
|
||||
team_id = post.get('team_id')
|
||||
|
|
@ -86,7 +94,7 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
return request.redirect(f'/my/patient/injury/new?patient_id={patient_id}')
|
||||
|
||||
# Check if the current user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Prepare values for injury creation
|
||||
vals = {
|
||||
|
|
@ -115,18 +123,17 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
user = request.env.user
|
||||
# Determine if user is a coach or treatment professional
|
||||
is_portal_coach = user.has_group('bemade_sports_clinic.group_portal_team_coach')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
has_treatment_attr = hasattr(user, 'is_treatment_professional') and user.is_treatment_professional
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional') or \
|
||||
user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Detailed logging of the current user's status
|
||||
_logger.info(f"Current user: {user.name} (ID: {user.id})")
|
||||
_logger.info(f"Is portal coach: {is_portal_coach}")
|
||||
_logger.info(f"Is in portal treatment professional group: {is_treatment_prof}")
|
||||
_logger.info(f"Has is_treatment_professional=True: {has_treatment_attr}")
|
||||
_logger.info(f"Is in treatment professional group: {is_treatment_prof}")
|
||||
|
||||
# If user is a treatment professional, add them to the treatment professionals
|
||||
# Make sure to check both the group membership and the is_treatment_professional field
|
||||
if is_treatment_prof or has_treatment_attr:
|
||||
# Only check group membership, not computed field
|
||||
if is_treatment_prof:
|
||||
_logger.info(f"Adding current user {user.name} (ID: {user.id}) to treatment professionals")
|
||||
injury.sudo().write({
|
||||
'treatment_professional_ids': [(4, user.id)]
|
||||
|
|
@ -229,13 +236,13 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
# Check if user is part of the team staff
|
||||
is_team_staff = team.staff_ids.filtered(lambda s: s.user_ids and user.id in s.user_ids.ids)
|
||||
# Or if user is a medical professional with broader access
|
||||
is_medical = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_medical = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
if not is_team_staff and not is_medical:
|
||||
raise UserError(_('You do not have access to this injury.'))
|
||||
else:
|
||||
# If no team is specified, only medical professionals can access
|
||||
if not user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
if not user.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
raise UserError(_('You do not have access to this injury.'))
|
||||
|
||||
return injury
|
||||
|
|
@ -249,27 +256,31 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
injury = self._check_access_to_injury(injury_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
return_url = post.get('return_url', f'/my/player?player_id={injury.patient_id.id}')
|
||||
|
||||
# Get possible injury stages - treatment professionals can change stage
|
||||
stages = []
|
||||
user = request.env.user
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
if is_treatment_prof:
|
||||
stage_selection = request.env['sports.patient.injury']._fields['stage'].selection
|
||||
stages = [(k, v) for k, v in stage_selection]
|
||||
|
||||
# Get body locations for dropdown
|
||||
body_locations = request.env['sports.body.location'].search([])
|
||||
# These were previously fetched from models that have been removed
|
||||
body_locations = []
|
||||
injury_types = []
|
||||
|
||||
# Get possible injury types for dropdown
|
||||
injury_types = request.env['sports.injury.type'].search([])
|
||||
|
||||
# Get possible severity options
|
||||
severity_options = request.env['sports.patient.injury']._fields['severity'].selection
|
||||
# Get possible severity options if field exists
|
||||
severity_options = []
|
||||
if 'severity' in request.env['sports.patient.injury']._fields:
|
||||
severity_options = request.env['sports.patient.injury']._fields['severity'].selection
|
||||
|
||||
# Get parental consent options if treatment professional
|
||||
parental_consent_options = None
|
||||
|
|
@ -303,11 +314,15 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
injury = self._check_access_to_injury(injury_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
# Get user's role
|
||||
user = request.env.user
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Prepare values for injury update
|
||||
vals = {}
|
||||
|
|
@ -321,11 +336,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
# Fields only treatment professionals can update
|
||||
if is_treatment_prof:
|
||||
# Only add fields that were actually submitted
|
||||
if post.get('body_location_id'):
|
||||
vals['body_location_id'] = int(post.get('body_location_id'))
|
||||
if post.get('body_location'):
|
||||
vals['body_location'] = post.get('body_location')
|
||||
|
||||
if post.get('injury_type_id'):
|
||||
vals['injury_type_id'] = int(post.get('injury_type_id'))
|
||||
if post.get('injury_type'):
|
||||
vals['injury_type'] = post.get('injury_type')
|
||||
|
||||
if post.get('severity'):
|
||||
vals['severity'] = post.get('severity')
|
||||
|
|
@ -380,7 +395,7 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
return request.redirect('/my/players')
|
||||
|
||||
# Get user's role
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
if injury_id:
|
||||
# Injury context
|
||||
|
|
@ -388,7 +403,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
injury = self._check_access_to_injury(injury_id)
|
||||
patient = injury.patient_id
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
# Get notes for this injury
|
||||
notes = request.env['sports.treatment.note'].sudo().search(
|
||||
|
|
@ -412,7 +431,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
patient = self._check_access_to_patient(patient_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
# Get all notes for this patient
|
||||
notes = request.env['sports.treatment.note'].sudo().search(
|
||||
|
|
@ -445,7 +468,7 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
return request.redirect('/my/players')
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
if not is_treatment_prof:
|
||||
# Determine redirect URL based on context
|
||||
if injury_id:
|
||||
|
|
@ -470,15 +493,24 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
self._add_treatment_note(patient, note_content, injury)
|
||||
return request.redirect(f'/my/injury/notes?injury_id={injury_id}&success=note_added')
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
else:
|
||||
# Patient context
|
||||
try:
|
||||
patient = self._check_access_to_patient(patient_id)
|
||||
self._add_treatment_note(patient, note_content)
|
||||
return request.redirect(f'/my/injury/notes?patient_id={patient_id}&success=note_added')
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
self._add_treatment_note(patient, note_content)
|
||||
return request.redirect(f'/my/injury/notes?patient_id={patient_id}&success=note_added')
|
||||
|
||||
@http.route(['/my/injury/documents'], type='http', auth='user', website=True)
|
||||
def view_injury_documents(self, injury_id=None, **post):
|
||||
|
|
@ -489,7 +521,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
injury = self._check_access_to_injury(injury_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
# Get documents for this injury
|
||||
documents = request.env['sports.injury.document'].sudo().search(
|
||||
|
|
@ -498,7 +534,7 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
)
|
||||
|
||||
# Get user's role
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Document categories
|
||||
categories = [('medical', 'Medical'), ('xray', 'X-Ray'), ('mri', 'MRI'),
|
||||
|
|
@ -528,7 +564,11 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
try:
|
||||
injury = self._check_access_to_injury(injury_id)
|
||||
except UserError as e:
|
||||
return request.render('portal.403', {'error': str(e)})
|
||||
return request.render('http_routing.http_error', {
|
||||
'status_code': 403,
|
||||
'status_message': 'Forbidden',
|
||||
'error_message': str(e)
|
||||
})
|
||||
|
||||
# Check if file was uploaded
|
||||
attachment = post.get('attachment')
|
||||
|
|
@ -601,7 +641,7 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
return request.not_found()
|
||||
|
||||
# Check if user is a treatment professional (only they can delete documents)
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
if not is_treatment_prof:
|
||||
return request.redirect(f'/my/injury/documents?injury_id={document.injury_id.id}&error=permission_denied')
|
||||
|
||||
|
|
@ -619,7 +659,7 @@ class PatientInjuryPortal(CustomerPortal):
|
|||
injury = request.env['sports.patient.injury'].browse(int(injury_id))
|
||||
|
||||
# Check access - user must be a treatment professional or admin
|
||||
if not (request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional') or
|
||||
if not (request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional') or
|
||||
request.env.user.has_group('base.group_system')):
|
||||
return request.redirect('/my')
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
# Check if user has access to any team this patient belongs to
|
||||
patient_id_int = int(patient_id)
|
||||
accessible_teams = request.env['sports.team'].search([
|
||||
('staff_ids.user_id', '=', user.id),
|
||||
('staff_ids.user_ids', '=', user.id),
|
||||
('patient_ids', 'in', patient_id_int)
|
||||
])
|
||||
|
||||
# Medical professionals might have specific access
|
||||
is_medical = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_medical = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
if not patient.exists() or (not accessible_teams and not is_medical):
|
||||
raise UserError(_('You do not have access to this patient.'))
|
||||
|
|
@ -42,7 +42,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
|
||||
# Check if user is a treatment professional
|
||||
user = request.env.user
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Get teams this player is a member of
|
||||
teams = patient.team_ids
|
||||
|
|
@ -72,7 +72,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
return request.render('portal.403', {'error': str(e)})
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Prepare values for patient update
|
||||
vals = {}
|
||||
|
|
@ -131,7 +131,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
|
||||
# Check if user is a treatment professional
|
||||
user = request.env.user
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Regular coaches shouldn't be able to add emergency contacts
|
||||
if not is_treatment_prof:
|
||||
|
|
@ -160,7 +160,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
return request.render('portal.403', {'error': str(e)})
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Regular coaches shouldn't be able to add emergency contacts
|
||||
if not is_treatment_prof:
|
||||
|
|
@ -216,7 +216,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
return_url = post.get('return_url', f'/my/player?player_id={patient.id}')
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Regular coaches shouldn't be able to edit emergency contacts
|
||||
if not is_treatment_prof:
|
||||
|
|
@ -251,7 +251,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
return request.render('portal.403', {'error': str(e)})
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Regular coaches shouldn't be able to edit emergency contacts
|
||||
if not is_treatment_prof:
|
||||
|
|
@ -311,7 +311,7 @@ class PlayerManagementPortal(CustomerPortal):
|
|||
return request.render('portal.403', {'error': str(e)})
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Regular coaches shouldn't be able to delete emergency contacts
|
||||
if not is_treatment_prof:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class TaskManagementPortal(CustomerPortal):
|
|||
record = request.env[model_name].browse(int(record_id))
|
||||
|
||||
# Check if user is a treatment professional
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Check if record exists
|
||||
if not record.exists():
|
||||
|
|
@ -27,7 +27,7 @@ class TaskManagementPortal(CustomerPortal):
|
|||
if model_name == 'sports.patient':
|
||||
patient_id_int = int(record_id)
|
||||
accessible_teams = request.env['sports.team'].search([
|
||||
('staff_ids.user_id', '=', user.id),
|
||||
('staff_ids.user_ids', '=', user.id),
|
||||
('patient_ids', 'in', patient_id_int)
|
||||
])
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ class TaskManagementPortal(CustomerPortal):
|
|||
domain = [('partner_id', 'in', team.staff_ids.mapped('partner_id').ids)]
|
||||
|
||||
# Only treatment professionals can see and assign all users
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
if not is_treatment_prof:
|
||||
domain.append(('id', '=', request.env.user.id))
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ class TaskManagementPortal(CustomerPortal):
|
|||
return request.redirect(f'{return_url}&error=missing_fields')
|
||||
|
||||
# Check if the assigned user is valid
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
assigned_user = request.env['res.users'].browse(int(user_id))
|
||||
|
||||
# Only treatment professionals can assign to other users
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class TeamStaffPortal(CustomerPortal):
|
|||
def _prepare_teams_domain(cls):
|
||||
user = http.request.env.user
|
||||
return [
|
||||
('staff_ids.user_ids', 'in', user.id),
|
||||
('staff_ids.user_ids', '=', user.id),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
|
|
@ -99,9 +99,33 @@ class TeamStaffPortal(CustomerPortal):
|
|||
if not player:
|
||||
raise UserError(_('This player could not be found.'))
|
||||
|
||||
# Check if user is a treatment professional
|
||||
# Check if user is a treatment professional (portal version)
|
||||
user = http.request.env.user
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Debug output
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
_logger.info(f"DEBUG - User: {user.name} (login: {user.login}) is treatment prof: {is_treatment_prof}")
|
||||
_logger.info(f"DEBUG - User groups: {', '.join([g.name for g in user.groups_id])}")
|
||||
_logger.info(f"DEBUG - XML ID check: {user.has_group('bemade_sports_clinic.group_portal_treatment_professional')}")
|
||||
|
||||
# More detailed debugging
|
||||
_logger.info(f"DEBUG - Player ID: {player_id}, Team ID: {team_id}")
|
||||
if team_id:
|
||||
_logger.info(f"DEBUG - Team name: {team.name if team else 'Team not found'}")
|
||||
_logger.info(f"DEBUG - Team staff: {[(s.partner_id.name, s.role) for s in team.staff_ids]}")
|
||||
_logger.info(f"DEBUG - Player teams: {[t.name for t in player.team_ids]}")
|
||||
|
||||
# Check team staff role
|
||||
staff_records = http.request.env['sports.team.staff'].sudo().search([('partner_id', '=', user.partner_id.id)])
|
||||
_logger.info(f"DEBUG - User's team staff roles: {[(s.team_id.name, s.role) for s in staff_records]}")
|
||||
_logger.info(f"DEBUG - User's partner ID: {user.partner_id.id}")
|
||||
|
||||
# Check if user should have therapist role
|
||||
has_therapist_role = any(s.role in ['head_therapist', 'therapist'] for s in staff_records)
|
||||
_logger.info(f"DEBUG - User has therapist role: {has_therapist_role}")
|
||||
|
||||
|
||||
# Show all injuries to treatment professionals, but only active ones to coaches
|
||||
if is_treatment_prof:
|
||||
|
|
|
|||
|
|
@ -166,15 +166,17 @@
|
|||
<field name="login">therapist</field>
|
||||
<field name="password">therapist</field>
|
||||
<field name="groups_id" eval="[(5, 0, 0),
|
||||
(4, ref('base.group_portal'))]"/>
|
||||
(4, ref('base.group_portal')),
|
||||
(4, ref('bemade_sports_clinic.group_portal_treatment_professional'))]"/>
|
||||
<!-- Note: Portal users should not be directly assigned to treatment_professional group -->
|
||||
<!-- The is_treatment_professional flag will be set based on staff role instead -->
|
||||
<!-- Treatment professional status is determined by team staff role and appropriate security groups -->
|
||||
</record>
|
||||
<record id="carabins_coach_user" model="res.users" context="{'no_reset_password': True}">
|
||||
<field name="partner_id" ref="partner_coach_team_carabins"/>
|
||||
<field name="login">coach</field>
|
||||
<field name="password">coach</field>
|
||||
<field name="groups_id" eval="[Command.clear()]"/>
|
||||
<field name="groups_id" eval="[(5, 0, 0), (4, ref('base.group_portal')), (4, ref('group_portal_team_coach'))]"/>
|
||||
<!-- Coach portal access explicitly granted -->
|
||||
</record>
|
||||
<!-- Users should be either internal users or portal users, not both -->
|
||||
<record id="group_sports_clinic_admin" model="res.groups">
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class Patient(models.Model):
|
|||
comodel_name="sports.patient.contact",
|
||||
inverse_name="patient_id",
|
||||
string="Patient Contacts",
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user",
|
||||
groups="bemade_sports_clinic.group_sports_clinic_user,bemade_sports_clinic.group_portal_treatment_professional",
|
||||
)
|
||||
team_ids = fields.Many2many(
|
||||
comodel_name="sports.team",
|
||||
|
|
|
|||
|
|
@ -63,7 +63,10 @@ class PatientInjury(models.Model):
|
|||
column1="patient_injury_id",
|
||||
column2="treatment_pro_id",
|
||||
string="Treatment Professionals",
|
||||
domain=[("is_treatment_professional", "=", True)],
|
||||
domain=lambda self: [('groups_id', 'in', [
|
||||
self.env.ref('bemade_sports_clinic.group_sports_clinic_treatment_professional').id,
|
||||
self.env.ref('bemade_sports_clinic.group_portal_treatment_professional').id
|
||||
])],
|
||||
tracking=True,
|
||||
)
|
||||
predicted_resolution_date = fields.Date(tracking=True)
|
||||
|
|
@ -93,6 +96,30 @@ class PatientInjury(models.Model):
|
|||
tracking=True,
|
||||
)
|
||||
|
||||
# Fields for injury categorization - using Char instead of foreign keys
|
||||
body_location = fields.Char(
|
||||
string="Body Location",
|
||||
help="The anatomical location of the injury",
|
||||
tracking=True,
|
||||
)
|
||||
|
||||
injury_type = fields.Char(
|
||||
string="Injury Type",
|
||||
help="The type of injury (e.g., sprain, fracture, strain)",
|
||||
tracking=True,
|
||||
)
|
||||
|
||||
severity = fields.Selection(
|
||||
selection=[
|
||||
("mild", "Mild"),
|
||||
("moderate", "Moderate"),
|
||||
("severe", "Severe"),
|
||||
],
|
||||
string="Severity",
|
||||
help="The assessed severity of the injury",
|
||||
tracking=True,
|
||||
)
|
||||
|
||||
# Relations to new models
|
||||
# Now treatment notes are linked to patient primarily, but can be optionally linked to injuries
|
||||
treatment_note_ids = fields.One2many(
|
||||
|
|
|
|||
|
|
@ -4,36 +4,12 @@ from odoo import models, fields, api, _, Command
|
|||
class User(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
is_treatment_professional = fields.Boolean(
|
||||
compute="_compute_is_treatment_professional", store=True
|
||||
)
|
||||
|
||||
accessible_team_ids = fields.Many2many(
|
||||
comodel_name="sports.team",
|
||||
compute="_compute_accessible_team_ids",
|
||||
inverse="_inverse_accessible_team_ids",
|
||||
)
|
||||
|
||||
@api.depends("groups_id", "partner_id", "partner_id.staff_ids", "partner_id.staff_ids.role")
|
||||
def _compute_is_treatment_professional(self):
|
||||
for rec in self:
|
||||
# Check if user has the security group
|
||||
has_security_group = rec.has_group(
|
||||
"bemade_sports_clinic.group_sports_clinic_treatment_professional"
|
||||
)
|
||||
|
||||
# Check if user is linked to any team staff as head therapist or therapist
|
||||
is_therapist_staff = False
|
||||
if rec.partner_id:
|
||||
staff_records = self.env['sports.team.staff'].sudo().search([
|
||||
('partner_id', '=', rec.partner_id.id),
|
||||
('role', 'in', ['head_therapist', 'therapist'])
|
||||
])
|
||||
is_therapist_staff = bool(staff_records)
|
||||
|
||||
# Set field based on either condition
|
||||
rec.is_treatment_professional = has_security_group or is_therapist_staff
|
||||
|
||||
def _compute_accessible_team_ids(self):
|
||||
for rec in self:
|
||||
rec.accessible_team_ids = rec.partner_id.teams_served_ids
|
||||
|
|
|
|||
|
|
@ -234,10 +234,11 @@ class TeamStaff(models.Model):
|
|||
# Update treatment professional group membership for new records
|
||||
res._update_treatment_professional_group()
|
||||
|
||||
# Recompute the is_treatment_professional field on affected users
|
||||
# Update group membership based on staff roles
|
||||
affected_users = res.mapped('user_ids')
|
||||
if affected_users:
|
||||
affected_users.sudo()._compute_is_treatment_professional()
|
||||
for user in affected_users.sudo():
|
||||
self._update_treatment_professional_group(user)
|
||||
|
||||
# Handle follower recomputation
|
||||
res.team_id.mapped("patient_ids").recompute_followers()
|
||||
|
|
@ -269,12 +270,43 @@ class TeamStaff(models.Model):
|
|||
# No therapist roles left, remove from treatment professional group
|
||||
users = self.env['res.users'].sudo().search([('partner_id', '=', partner.id)])
|
||||
treatment_prof_group = self.env.ref('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
portal_treatment_prof_group = self.env.ref('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
for user in users:
|
||||
if user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
# Handle internal and portal users differently
|
||||
if not user.has_group('base.group_portal'):
|
||||
if user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(3, treatment_prof_group.id)]})
|
||||
else:
|
||||
if user.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(3, portal_treatment_prof_group.id)]})
|
||||
|
||||
# Update group membership directly for each affected user
|
||||
# Use a new recordset (empty) to avoid using the deleted recordset
|
||||
empty_staff = self.env['sports.team.staff']
|
||||
if affected_users:
|
||||
for user in affected_users.sudo():
|
||||
# Check if this user still has any therapist roles through their partner
|
||||
has_therapist_role = bool(self.env['sports.team.staff'].sudo().search_count([
|
||||
('partner_id', '=', user.partner_id.id),
|
||||
('role', 'in', ['head_therapist', 'therapist']),
|
||||
]))
|
||||
|
||||
treatment_prof_group = self.env.ref('bemade_sports_clinic.group_sports_clinic_treatment_professional')
|
||||
portal_treatment_prof_group = self.env.ref('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Apply appropriate group membership based on user type and therapist roles
|
||||
if not user.has_group('base.group_portal'):
|
||||
# Internal user
|
||||
if has_therapist_role and not user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(4, treatment_prof_group.id)]})
|
||||
elif not has_therapist_role and user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(3, treatment_prof_group.id)]})
|
||||
|
||||
# Recompute is_treatment_professional on all affected users
|
||||
affected_users.sudo().invalidate_model(['is_treatment_professional'])
|
||||
else:
|
||||
# Portal user
|
||||
if has_therapist_role and not user.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(4, portal_treatment_prof_group.id)]})
|
||||
elif not has_therapist_role and user.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(3, portal_treatment_prof_group.id)]})
|
||||
|
||||
return res
|
||||
|
||||
|
|
@ -323,34 +355,69 @@ class TeamStaff(models.Model):
|
|||
('role', 'in', ['head_therapist', 'therapist'])
|
||||
])
|
||||
|
||||
def _update_treatment_professional_group(self):
|
||||
def _update_treatment_professional_group(self, specific_user=None):
|
||||
"""Update treatment professional status based on staff role.
|
||||
|
||||
This method ensures that users with therapist roles have the appropriate
|
||||
group memberships. It handles both internal and portal users appropriately.
|
||||
|
||||
For internal users, this manages group membership directly.
|
||||
For portal users, it ensures the is_treatment_professional flag is recomputed.
|
||||
For portal users, it manages the portal treatment professional group.
|
||||
|
||||
Args:
|
||||
specific_user (res.users, optional): If provided, only update this specific user.
|
||||
Otherwise, update all users for the staff records.
|
||||
"""
|
||||
# Skip if in module installation context to avoid demo data conflicts
|
||||
if self.env.context.get('module'):
|
||||
return
|
||||
|
||||
treatment_prof_group = self._get_treatment_professional_group()
|
||||
portal_treatment_prof_group = self.env.ref('bemade_sports_clinic.group_portal_treatment_professional')
|
||||
|
||||
# Process staff members with users
|
||||
if specific_user:
|
||||
# Process only the specific user
|
||||
staff = self.filtered(lambda s: specific_user in s.user_ids)
|
||||
if not staff:
|
||||
# Check if the user has any therapist roles through their partner
|
||||
has_therapist_role = bool(self._get_staff_with_therapist_roles(specific_user.partner_id.id))
|
||||
users_to_process = specific_user
|
||||
else:
|
||||
# Check if this partner has any staff records with therapist roles
|
||||
has_therapist_role = bool(self._get_staff_with_therapist_roles(specific_user.partner_id.id))
|
||||
users_to_process = specific_user
|
||||
|
||||
# Apply the appropriate group membership
|
||||
if not users_to_process.has_group('base.group_portal'):
|
||||
# Internal user
|
||||
if has_therapist_role and not users_to_process.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
users_to_process.sudo().write({'groups_id': [(4, treatment_prof_group.id)]})
|
||||
elif not has_therapist_role and users_to_process.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||
users_to_process.sudo().write({'groups_id': [(3, treatment_prof_group.id)]})
|
||||
else:
|
||||
# Portal user
|
||||
if has_therapist_role and not users_to_process.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
users_to_process.sudo().write({'groups_id': [(4, portal_treatment_prof_group.id)]})
|
||||
elif not has_therapist_role and users_to_process.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
users_to_process.sudo().write({'groups_id': [(3, portal_treatment_prof_group.id)]})
|
||||
return
|
||||
|
||||
# Process staff members with users if no specific user provided
|
||||
for staff in self.filtered('user_ids'):
|
||||
# Check if this partner has any staff records with therapist roles
|
||||
has_therapist_role = bool(self._get_staff_with_therapist_roles(staff.partner_id.id))
|
||||
|
||||
# Process each user linked to this partner
|
||||
for user in staff.user_ids:
|
||||
# Always ensure the computed field is up-to-date
|
||||
user.sudo().invalidate_model(['is_treatment_professional'])
|
||||
|
||||
# Only manage group membership for internal users
|
||||
# Handle internal users
|
||||
if user.has_group('base.group_user'):
|
||||
self._update_user_group_membership(user, has_therapist_role, treatment_prof_group)
|
||||
# Handle portal users
|
||||
elif user.has_group('base.group_portal'):
|
||||
if has_therapist_role and not user.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(4, portal_treatment_prof_group.id)]})
|
||||
elif not has_therapist_role and user.has_group('bemade_sports_clinic.group_portal_treatment_professional'):
|
||||
user.sudo().write({'groups_id': [(3, portal_treatment_prof_group.id)]})
|
||||
|
||||
def write(self, values):
|
||||
old_roles = {record.id: record.role for record in self}
|
||||
|
|
@ -359,11 +426,6 @@ class TeamStaff(models.Model):
|
|||
# If role changed or team changed, handle group membership updates
|
||||
if 'role' in values or 'team_id' in values:
|
||||
self._update_treatment_professional_group()
|
||||
|
||||
# Recompute the `is_treatment_professional` field on affected users
|
||||
affected_users = self.mapped('user_ids')
|
||||
if affected_users:
|
||||
affected_users.sudo()._compute_is_treatment_professional()
|
||||
|
||||
# Handle team changes for follower recomputation
|
||||
if "team_id" in values:
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ access_patient_admin,Admin Access for Patients,model_sports_patient,group_sports
|
|||
access_patient_portal,Portal Access for Patients,model_sports_patient,base.group_portal,1,1,1,0
|
||||
access_patient_portal_coach,Portal Coach Access for Patients,model_sports_patient,bemade_sports_clinic.group_portal_team_coach,1,1,1,0
|
||||
access_patient_contact_user,User Access for Patient Contacts,model_sports_patient_contact,group_sports_clinic_user,1,1,1,1
|
||||
access_patient_contact_portal_tp,Portal TP Access for Patient Contacts,model_sports_patient_contact,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0
|
||||
access_injury_treatment_pro,Treatment Professional Access for Injuries,model_sports_patient_injury,group_sports_clinic_treatment_professional,1,1,1,1
|
||||
access_injury_portal,Portal Access for Injuries,model_sports_patient_injury,base.group_portal,1,0,0,0
|
||||
access_team_user,User Access for Teams,model_sports_team,group_sports_clinic_user,1,1,1,0
|
||||
|
|
@ -21,3 +22,4 @@ access_injury_document_user,User Access for Injury Documents,model_sports_injury
|
|||
access_injury_document_treatment_pro,Treatment Professional Access for Injury Documents,model_sports_injury_document,group_sports_clinic_treatment_professional,1,1,1,1
|
||||
access_injury_document_portal,Portal Access for Injury Documents,model_sports_injury_document,base.group_portal,1,0,0,0
|
||||
access_injury_document_admin,Admin Access for Injury Documents,model_sports_injury_document,group_sports_clinic_admin,1,1,1,1
|
||||
|
||||
|
|
|
|||
|
|
|
@ -67,7 +67,7 @@ class TestEndToEndWorkflows(TransactionCase):
|
|||
cls.coach_staff = cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.coach_partner.id,
|
||||
'is_treatment_professional': False,
|
||||
# Role coach doesn't grant treatment professional status
|
||||
'role': 'coach',
|
||||
'user_id': cls.coach_user.id,
|
||||
})
|
||||
|
|
@ -75,7 +75,7 @@ class TestEndToEndWorkflows(TransactionCase):
|
|||
cls.therapist_staff = cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.therapist_partner.id,
|
||||
'is_treatment_professional': True,
|
||||
# Role therapist automatically grants treatment professional status
|
||||
'role': 'therapist',
|
||||
'user_id': cls.therapist_user.id,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -68,18 +68,18 @@ class TestInjuryAssignment(TransactionCase):
|
|||
'team_ids': [(4, cls.team.id)],
|
||||
})
|
||||
|
||||
# Create team staff
|
||||
# Create team staff with therapist role (which automatically grants treatment professional access)
|
||||
cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.partner_therapist.id,
|
||||
'is_treatment_professional': True,
|
||||
'role': 'head_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_coach.id,
|
||||
'is_treatment_professional': False,
|
||||
'role': 'head_coach', # This role does not grant treatment professional access
|
||||
'user_id': cls.user_coach.id,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -110,28 +110,28 @@ class TestInjuryNotifications(TransactionCase):
|
|||
cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.partner_therapist.id,
|
||||
'is_treatment_professional': True,
|
||||
'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,
|
||||
'is_treatment_professional': True,
|
||||
'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,
|
||||
'is_treatment_professional': False,
|
||||
'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,
|
||||
'is_treatment_professional': False,
|
||||
'role': 'portal_coach', # This role does not grant treatment professional access
|
||||
'user_id': cls.user_portal_coach.id,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -85,15 +85,13 @@ class TestPortalIntegration(HttpCase):
|
|||
cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.therapist_partner.id,
|
||||
'is_treatment_professional': True,
|
||||
'role': 'therapist',
|
||||
'role': 'therapist',
|
||||
'user_id': cls.therapist_user.id,
|
||||
})
|
||||
|
||||
cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.coach_partner.id,
|
||||
'is_treatment_professional': False,
|
||||
'role': 'coach',
|
||||
'user_id': cls.coach_user.id,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ class TestSecurityIntegration(HttpCase):
|
|||
cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.therapist_partner.id,
|
||||
'is_treatment_professional': True,
|
||||
# Role therapist automatically grants treatment professional status
|
||||
'role': 'therapist',
|
||||
'user_id': cls.therapist_user.id,
|
||||
})
|
||||
|
|
@ -110,7 +110,7 @@ class TestSecurityIntegration(HttpCase):
|
|||
cls.env['sports.team.staff'].create({
|
||||
'team_id': cls.team.id,
|
||||
'partner_id': cls.coach_partner.id,
|
||||
'is_treatment_professional': False,
|
||||
# Role coach doesn't grant treatment professional status
|
||||
'role': 'coach',
|
||||
'user_id': cls.coach_user.id,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -77,10 +77,10 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
|
||||
self.assertFalse(self.user_head_therapist.is_treatment_professional)
|
||||
self.assertFalse(self.user_therapist.is_treatment_professional)
|
||||
self.assertFalse(self.user_portal_therapist.is_treatment_professional)
|
||||
self.assertFalse(self.user_coach.is_treatment_professional)
|
||||
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_portal_treatment_professional'))
|
||||
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
|
||||
# 1. Create a head therapist staff record
|
||||
head_therapist_staff = self.env['sports.team.staff'].create({
|
||||
|
|
@ -90,11 +90,11 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify head therapist gets treatment professional group and flag
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional']) # Force recomputation
|
||||
# No need to invalidate models anymore as we check group membership directly # Force recomputation
|
||||
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Head therapist user should be added to treatment professional group")
|
||||
self.assertTrue(self.user_head_therapist.is_treatment_professional,
|
||||
"Head therapist is_treatment_professional flag should be True")
|
||||
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Head therapist should be in treatment professional group")
|
||||
|
||||
# 2. Create a therapist staff record
|
||||
therapist_staff = self.env['sports.team.staff'].create({
|
||||
|
|
@ -104,11 +104,11 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify therapist gets treatment professional group and flag
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional']) # Force recomputation
|
||||
# No need to invalidate models anymore as we check group membership directly # Force recomputation
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Therapist user should be added to treatment professional group")
|
||||
self.assertTrue(self.user_therapist.is_treatment_professional,
|
||||
"Therapist is_treatment_professional flag should be True")
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Therapist should be in treatment professional group")
|
||||
|
||||
# 3. Create a coach staff record - should NOT be in treatment professional group
|
||||
coach_staff = self.env['sports.team.staff'].create({
|
||||
|
|
@ -118,32 +118,32 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify coach does NOT get treatment professional group or flag
|
||||
self.user_coach.invalidate_model(['is_treatment_professional']) # Force recomputation
|
||||
# No need to invalidate models anymore as we check group membership directly # Force recomputation
|
||||
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Coach should NOT be added to treatment professional group")
|
||||
self.assertFalse(self.user_coach.is_treatment_professional,
|
||||
"Coach is_treatment_professional flag should be False")
|
||||
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Coach should NOT have treatment professional group membership")
|
||||
|
||||
# 4. Test changing roles - change head therapist to coach
|
||||
head_therapist_staff.write({'role': 'coach'})
|
||||
|
||||
# Verify head therapist loses treatment professional group and flag
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional']) # Force recomputation
|
||||
# No need to invalidate models anymore as we check group membership directly # Force recomputation
|
||||
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Former head therapist should be removed from treatment professional group")
|
||||
self.assertFalse(self.user_head_therapist.is_treatment_professional,
|
||||
"Former head therapist is_treatment_professional flag should be False")
|
||||
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Former head therapist should NOT have treatment professional group membership")
|
||||
|
||||
# 5. Test manual group assignment for internal users still affects is_treatment_professional
|
||||
# 5. Test manual group assignment for internal users
|
||||
# Use the internal user therapist instead of the portal user coach
|
||||
self.user_therapist.write({'groups_id': [(4, self.treatment_prof_group.id)]})
|
||||
|
||||
# Verify therapist now has treatment professional flag due to group membership
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional']) # Force recomputation
|
||||
# No need to invalidate models anymore as we check group membership directly # Force recomputation
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Therapist should have treatment professional group after manual assignment")
|
||||
self.assertTrue(self.user_therapist.is_treatment_professional,
|
||||
"Therapist is_treatment_professional flag should be True after group assignment")
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Therapist should be in treatment professional group after direct group assignment")
|
||||
|
||||
def test_group_membership_preserved_across_role_changes(self):
|
||||
"""Test that group membership is correctly managed when roles change."""
|
||||
|
|
@ -155,21 +155,21 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify user is in treatment professional group
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
|
||||
# Change role to non-therapist role
|
||||
staff.write({'role': 'other'})
|
||||
|
||||
# Verify user is removed from treatment professional group
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
|
||||
# Change back to therapist role
|
||||
staff.write({'role': 'therapist'})
|
||||
|
||||
# Verify user is added back to treatment professional group
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
|
||||
def test_multiple_team_assignments(self):
|
||||
|
|
@ -193,17 +193,17 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify user is in treatment professional group due to any therapist role
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertTrue(self.user_head_therapist.is_treatment_professional)
|
||||
|
||||
# Remove therapist role on team 2
|
||||
therapist_staff.write({'role': 'other'})
|
||||
|
||||
# Verify user loses treatment professional status
|
||||
self.user_head_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_head_therapist.is_treatment_professional)
|
||||
|
||||
def test_role_removal_through_deletion(self):
|
||||
"""Test that deleting staff records properly removes treatment professional status."""
|
||||
|
|
@ -215,17 +215,17 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify user gets treatment professional group
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertTrue(self.user_therapist.is_treatment_professional)
|
||||
|
||||
# Delete the staff record
|
||||
therapist_staff.unlink()
|
||||
|
||||
# Verify user loses treatment professional status after deletion
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertFalse(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_therapist.is_treatment_professional)
|
||||
|
||||
def test_multiple_role_assignments_deletion(self):
|
||||
"""Test that deleting one therapist role preserves status if other therapist roles exist."""
|
||||
|
|
@ -247,30 +247,30 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
})
|
||||
|
||||
# Verify user has treatment professional status
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
|
||||
# Delete one staff record but not the other
|
||||
therapist_staff1.unlink()
|
||||
|
||||
# Verify user still has treatment professional status (from the second record)
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertTrue(self.user_therapist.is_treatment_professional)
|
||||
|
||||
# Delete the second staff record
|
||||
therapist_staff2.unlink()
|
||||
|
||||
# Verify user loses treatment professional status
|
||||
self.user_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertFalse(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_therapist.is_treatment_professional)
|
||||
|
||||
def test_portal_user_as_treatment_professional(self):
|
||||
"""Test that portal users can be treatment professionals via the flag without group membership."""
|
||||
# Verify initially the portal user is not a treatment professional
|
||||
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||
self.assertFalse(self.user_portal_therapist.is_treatment_professional)
|
||||
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_portal_treatment_professional'))
|
||||
|
||||
# Verify the user is a portal user and not an internal user
|
||||
self.assertTrue(self.user_portal_therapist.has_group('base.group_portal'))
|
||||
|
|
@ -285,11 +285,11 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
|
||||
# Verify portal user gets treatment professional flag but NOT the group
|
||||
# (would conflict with portal user type)
|
||||
self.user_portal_therapist.invalidate_model(['is_treatment_professional'])
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||
"Portal user should NOT be added to treatment professional group (would conflict with user type)")
|
||||
self.assertTrue(self.user_portal_therapist.is_treatment_professional,
|
||||
"Portal user with therapist role should have is_treatment_professional flag set to True")
|
||||
self.assertTrue(self.user_portal_therapist.has_group('bemade_sports_clinic.group_portal_treatment_professional'),
|
||||
"Portal user with therapist role should be in portal treatment professional group")
|
||||
|
||||
# Verify user is still a portal user and not an internal user
|
||||
self.assertTrue(self.user_portal_therapist.has_group('base.group_portal'))
|
||||
|
|
@ -299,6 +299,6 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
|||
portal_therapist_staff.write({'role': 'other'})
|
||||
|
||||
# Verify portal user loses treatment professional status
|
||||
self.user_portal_therapist.invalidate_model(['is_treatment_professional'])
|
||||
self.assertFalse(self.user_portal_therapist.is_treatment_professional,
|
||||
"Portal user should have is_treatment_professional flag set to False when role is changed")
|
||||
# No need to invalidate models anymore as we check group membership directly
|
||||
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_portal_treatment_professional'),
|
||||
"Portal user should NOT have portal treatment professional group when role is changed")
|
||||
|
|
|
|||
|
|
@ -64,28 +64,14 @@
|
|||
<div t-if="is_treatment_prof" class="row mt-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="body_location_id">Body Location</label>
|
||||
<select name="body_location_id" id="body_location_id" class="form-control">
|
||||
<option value="">-- Select Location --</option>
|
||||
<t t-foreach="body_locations" t-as="location">
|
||||
<option t-att-value="location.id" t-att-selected="location.id == injury.body_location_id.id">
|
||||
<t t-esc="location.name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
<label for="body_location">Body Location</label>
|
||||
<input type="text" class="form-control" name="body_location" id="body_location" t-att-value="injury.body_location"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="injury_type_id">Injury Type</label>
|
||||
<select name="injury_type_id" id="injury_type_id" class="form-control">
|
||||
<option value="">-- Select Type --</option>
|
||||
<t t-foreach="injury_types" t-as="type">
|
||||
<option t-att-value="type.id" t-att-selected="type.id == injury.injury_type_id.id">
|
||||
<t t-esc="type.name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
<label for="injury_type">Injury Type</label>
|
||||
<input type="text" class="form-control" name="injury_type" id="injury_type" t-att-value="injury.injury_type"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,11 +19,23 @@
|
|||
<!-- Add a dedicated page for Sports Clinic permissions -->
|
||||
<page name="access_rights" position="after">
|
||||
<page name="sports_clinic_access" string="Sports Clinic Access Rights" groups="base.group_system">
|
||||
<group>
|
||||
<field name="groups_id" widget="many2many_checkboxes"
|
||||
domain="[('category_id','=',ref('bemade_sports_clinic.module_category_sports_clinic_management'))]"
|
||||
readonly="0" nolabel="1"/>
|
||||
<div class="alert alert-info" role="alert">
|
||||
<p><strong>Role-Based Access Rights:</strong></p>
|
||||
<p>Sports Clinic access rights are automatically managed based on team roles:</p>
|
||||
<ul>
|
||||
<li><strong>Treatment Professional access</strong> is granted to users with Therapist or Head Therapist roles in any team</li>
|
||||
<li><strong>Coach access</strong> is granted to users with Coach, Head Coach, or Manager roles in any team</li>
|
||||
</ul>
|
||||
<p>For portal users, these roles determine what they can access in the portal interface. For internal users, corresponding security groups are also assigned.</p>
|
||||
<p>When a user has multiple roles, treatment professional access takes precedence and grants additional permissions (e.g., parental consent field visibility).</p>
|
||||
</div>
|
||||
|
||||
<group string="Team Roles">
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<field name="share" invisible="1"/>
|
||||
</group>
|
||||
|
||||
<field name="partner_id" widget="res_partner_many2one" readonly="1" options="{'always_reload': True}"/>
|
||||
</page>
|
||||
</page>
|
||||
</field>
|
||||
|
|
|
|||
|
|
@ -359,13 +359,13 @@
|
|||
</t>
|
||||
<td class="text-end">
|
||||
<div class="btn-group">
|
||||
<a t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" class="btn btn-sm btn-primary">
|
||||
<a t-if="is_treatment_prof" t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" class="btn btn-sm btn-primary">
|
||||
<i class="fa fa-edit"></i> Edit
|
||||
</a>
|
||||
<a t-att-href="'/my/injury/notes?injury_id=%s' % injury.id" class="btn btn-sm btn-info">
|
||||
<a t-if="is_treatment_prof" t-att-href="'/my/injury/notes?injury_id=%s' % injury.id" class="btn btn-sm btn-info">
|
||||
<i class="fa fa-clipboard-list"></i> Notes
|
||||
</a>
|
||||
<a t-att-href="'/my/injury/documents?injury_id=%s' % injury.id" class="btn btn-sm btn-secondary">
|
||||
<a t-if="is_treatment_prof" t-att-href="'/my/injury/documents?injury_id=%s' % injury.id" class="btn btn-sm btn-secondary">
|
||||
<i class="fa fa-file-medical"></i> Docs
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue