[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] Added field to the therapist portal UI for injury creation
|
||||||
- [x] Updated portal controller to handle the parental consent field
|
- [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
|
## Medium Priority
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,12 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
# Check if user has access to any team this patient belongs to
|
# Check if user has access to any team this patient belongs to
|
||||||
patient_id_int = int(patient_id)
|
patient_id_int = int(patient_id)
|
||||||
accessible_teams = request.env['sports.team'].search([
|
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)
|
('patient_ids', 'in', patient_id_int)
|
||||||
])
|
])
|
||||||
|
|
||||||
# Medical professionals might have specific access
|
# 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):
|
if not patient.exists() or (not accessible_teams and not is_medical):
|
||||||
raise UserError(_('You do not have access to this patient.'))
|
raise UserError(_('You do not have access to this patient.'))
|
||||||
|
|
@ -42,7 +42,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
patient = self._check_access_to_patient(patient_id)
|
patient = self._check_access_to_patient(patient_id)
|
||||||
except UserError as e:
|
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}')
|
return_url = post.get('return_url', f'/my/player?player_id={patient_id}')
|
||||||
|
|
||||||
|
|
@ -78,7 +82,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
patient = self._check_access_to_patient(patient_id)
|
patient = self._check_access_to_patient(patient_id)
|
||||||
except UserError as e:
|
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
|
# Get the selected team
|
||||||
team_id = post.get('team_id')
|
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}')
|
return request.redirect(f'/my/patient/injury/new?patient_id={patient_id}')
|
||||||
|
|
||||||
# Check if the current user is a treatment professional
|
# 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
|
# Prepare values for injury creation
|
||||||
vals = {
|
vals = {
|
||||||
|
|
@ -115,18 +123,17 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
user = request.env.user
|
user = request.env.user
|
||||||
# Determine if user is a coach or treatment professional
|
# Determine if user is a coach or treatment professional
|
||||||
is_portal_coach = user.has_group('bemade_sports_clinic.group_portal_team_coach')
|
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')
|
is_treatment_prof = user.has_group('bemade_sports_clinic.group_portal_treatment_professional') or \
|
||||||
has_treatment_attr = hasattr(user, 'is_treatment_professional') and user.is_treatment_professional
|
user.has_group('bemade_sports_clinic.group_portal_treatment_professional')
|
||||||
|
|
||||||
# Detailed logging of the current user's status
|
# Detailed logging of the current user's status
|
||||||
_logger.info(f"Current user: {user.name} (ID: {user.id})")
|
_logger.info(f"Current user: {user.name} (ID: {user.id})")
|
||||||
_logger.info(f"Is portal coach: {is_portal_coach}")
|
_logger.info(f"Is portal coach: {is_portal_coach}")
|
||||||
_logger.info(f"Is in portal treatment professional group: {is_treatment_prof}")
|
_logger.info(f"Is in treatment professional group: {is_treatment_prof}")
|
||||||
_logger.info(f"Has is_treatment_professional=True: {has_treatment_attr}")
|
|
||||||
|
|
||||||
# If user is a treatment professional, add them to the treatment professionals
|
# 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
|
# Only check group membership, not computed field
|
||||||
if is_treatment_prof or has_treatment_attr:
|
if is_treatment_prof:
|
||||||
_logger.info(f"Adding current user {user.name} (ID: {user.id}) to treatment professionals")
|
_logger.info(f"Adding current user {user.name} (ID: {user.id}) to treatment professionals")
|
||||||
injury.sudo().write({
|
injury.sudo().write({
|
||||||
'treatment_professional_ids': [(4, user.id)]
|
'treatment_professional_ids': [(4, user.id)]
|
||||||
|
|
@ -229,13 +236,13 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
# Check if user is part of the team staff
|
# 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)
|
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
|
# 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:
|
if not is_team_staff and not is_medical:
|
||||||
raise UserError(_('You do not have access to this injury.'))
|
raise UserError(_('You do not have access to this injury.'))
|
||||||
else:
|
else:
|
||||||
# If no team is specified, only medical professionals can access
|
# 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.'))
|
raise UserError(_('You do not have access to this injury.'))
|
||||||
|
|
||||||
return injury
|
return injury
|
||||||
|
|
@ -249,26 +256,30 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
injury = self._check_access_to_injury(injury_id)
|
injury = self._check_access_to_injury(injury_id)
|
||||||
except UserError as e:
|
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}')
|
return_url = post.get('return_url', f'/my/player?player_id={injury.patient_id.id}')
|
||||||
|
|
||||||
# Get possible injury stages - treatment professionals can change stage
|
# Get possible injury stages - treatment professionals can change stage
|
||||||
stages = []
|
stages = []
|
||||||
user = request.env.user
|
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:
|
if is_treatment_prof:
|
||||||
stage_selection = request.env['sports.patient.injury']._fields['stage'].selection
|
stage_selection = request.env['sports.patient.injury']._fields['stage'].selection
|
||||||
stages = [(k, v) for k, v in stage_selection]
|
stages = [(k, v) for k, v in stage_selection]
|
||||||
|
|
||||||
# Get body locations for dropdown
|
# These were previously fetched from models that have been removed
|
||||||
body_locations = request.env['sports.body.location'].search([])
|
body_locations = []
|
||||||
|
injury_types = []
|
||||||
|
|
||||||
# Get possible injury types for dropdown
|
# Get possible severity options if field exists
|
||||||
injury_types = request.env['sports.injury.type'].search([])
|
severity_options = []
|
||||||
|
if 'severity' in request.env['sports.patient.injury']._fields:
|
||||||
# Get possible severity options
|
|
||||||
severity_options = request.env['sports.patient.injury']._fields['severity'].selection
|
severity_options = request.env['sports.patient.injury']._fields['severity'].selection
|
||||||
|
|
||||||
# Get parental consent options if treatment professional
|
# Get parental consent options if treatment professional
|
||||||
|
|
@ -303,11 +314,15 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
injury = self._check_access_to_injury(injury_id)
|
injury = self._check_access_to_injury(injury_id)
|
||||||
except UserError as e:
|
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
|
# Get user's role
|
||||||
user = request.env.user
|
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
|
# Prepare values for injury update
|
||||||
vals = {}
|
vals = {}
|
||||||
|
|
@ -321,11 +336,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
# Fields only treatment professionals can update
|
# Fields only treatment professionals can update
|
||||||
if is_treatment_prof:
|
if is_treatment_prof:
|
||||||
# Only add fields that were actually submitted
|
# Only add fields that were actually submitted
|
||||||
if post.get('body_location_id'):
|
if post.get('body_location'):
|
||||||
vals['body_location_id'] = int(post.get('body_location_id'))
|
vals['body_location'] = post.get('body_location')
|
||||||
|
|
||||||
if post.get('injury_type_id'):
|
if post.get('injury_type'):
|
||||||
vals['injury_type_id'] = int(post.get('injury_type_id'))
|
vals['injury_type'] = post.get('injury_type')
|
||||||
|
|
||||||
if post.get('severity'):
|
if post.get('severity'):
|
||||||
vals['severity'] = post.get('severity')
|
vals['severity'] = post.get('severity')
|
||||||
|
|
@ -380,7 +395,7 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
return request.redirect('/my/players')
|
return request.redirect('/my/players')
|
||||||
|
|
||||||
# Get user's role
|
# 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:
|
if injury_id:
|
||||||
# Injury context
|
# Injury context
|
||||||
|
|
@ -388,7 +403,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
injury = self._check_access_to_injury(injury_id)
|
injury = self._check_access_to_injury(injury_id)
|
||||||
patient = injury.patient_id
|
patient = injury.patient_id
|
||||||
except UserError as e:
|
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
|
# Get notes for this injury
|
||||||
notes = request.env['sports.treatment.note'].sudo().search(
|
notes = request.env['sports.treatment.note'].sudo().search(
|
||||||
|
|
@ -412,7 +431,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
patient = self._check_access_to_patient(patient_id)
|
patient = self._check_access_to_patient(patient_id)
|
||||||
except UserError as e:
|
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
|
# Get all notes for this patient
|
||||||
notes = request.env['sports.treatment.note'].sudo().search(
|
notes = request.env['sports.treatment.note'].sudo().search(
|
||||||
|
|
@ -445,7 +468,7 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
return request.redirect('/my/players')
|
return request.redirect('/my/players')
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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:
|
if not is_treatment_prof:
|
||||||
# Determine redirect URL based on context
|
# Determine redirect URL based on context
|
||||||
if injury_id:
|
if injury_id:
|
||||||
|
|
@ -470,15 +493,24 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
self._add_treatment_note(patient, note_content, injury)
|
self._add_treatment_note(patient, note_content, injury)
|
||||||
return request.redirect(f'/my/injury/notes?injury_id={injury_id}&success=note_added')
|
return request.redirect(f'/my/injury/notes?injury_id={injury_id}&success=note_added')
|
||||||
except UserError as e:
|
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:
|
else:
|
||||||
# Patient context
|
# Patient context
|
||||||
try:
|
try:
|
||||||
patient = self._check_access_to_patient(patient_id)
|
patient = self._check_access_to_patient(patient_id)
|
||||||
|
except UserError as 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)
|
self._add_treatment_note(patient, note_content)
|
||||||
return request.redirect(f'/my/injury/notes?patient_id={patient_id}&success=note_added')
|
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)})
|
|
||||||
|
|
||||||
@http.route(['/my/injury/documents'], type='http', auth='user', website=True)
|
@http.route(['/my/injury/documents'], type='http', auth='user', website=True)
|
||||||
def view_injury_documents(self, injury_id=None, **post):
|
def view_injury_documents(self, injury_id=None, **post):
|
||||||
|
|
@ -489,7 +521,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
injury = self._check_access_to_injury(injury_id)
|
injury = self._check_access_to_injury(injury_id)
|
||||||
except UserError as e:
|
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
|
# Get documents for this injury
|
||||||
documents = request.env['sports.injury.document'].sudo().search(
|
documents = request.env['sports.injury.document'].sudo().search(
|
||||||
|
|
@ -498,7 +534,7 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get user's role
|
# 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
|
# Document categories
|
||||||
categories = [('medical', 'Medical'), ('xray', 'X-Ray'), ('mri', 'MRI'),
|
categories = [('medical', 'Medical'), ('xray', 'X-Ray'), ('mri', 'MRI'),
|
||||||
|
|
@ -528,7 +564,11 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
try:
|
try:
|
||||||
injury = self._check_access_to_injury(injury_id)
|
injury = self._check_access_to_injury(injury_id)
|
||||||
except UserError as e:
|
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
|
# Check if file was uploaded
|
||||||
attachment = post.get('attachment')
|
attachment = post.get('attachment')
|
||||||
|
|
@ -601,7 +641,7 @@ class PatientInjuryPortal(CustomerPortal):
|
||||||
return request.not_found()
|
return request.not_found()
|
||||||
|
|
||||||
# Check if user is a treatment professional (only they can delete documents)
|
# 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:
|
if not is_treatment_prof:
|
||||||
return request.redirect(f'/my/injury/documents?injury_id={document.injury_id.id}&error=permission_denied')
|
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))
|
injury = request.env['sports.patient.injury'].browse(int(injury_id))
|
||||||
|
|
||||||
# Check access - user must be a treatment professional or admin
|
# 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')):
|
request.env.user.has_group('base.group_system')):
|
||||||
return request.redirect('/my')
|
return request.redirect('/my')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
# Check if user has access to any team this patient belongs to
|
# Check if user has access to any team this patient belongs to
|
||||||
patient_id_int = int(patient_id)
|
patient_id_int = int(patient_id)
|
||||||
accessible_teams = request.env['sports.team'].search([
|
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)
|
('patient_ids', 'in', patient_id_int)
|
||||||
])
|
])
|
||||||
|
|
||||||
# Medical professionals might have specific access
|
# 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):
|
if not patient.exists() or (not accessible_teams and not is_medical):
|
||||||
raise UserError(_('You do not have access to this patient.'))
|
raise UserError(_('You do not have access to this patient.'))
|
||||||
|
|
@ -42,7 +42,7 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# Check if user is a treatment professional
|
||||||
user = request.env.user
|
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
|
# Get teams this player is a member of
|
||||||
teams = patient.team_ids
|
teams = patient.team_ids
|
||||||
|
|
@ -72,7 +72,7 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
return request.render('portal.403', {'error': str(e)})
|
return request.render('portal.403', {'error': str(e)})
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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
|
# Prepare values for patient update
|
||||||
vals = {}
|
vals = {}
|
||||||
|
|
@ -131,7 +131,7 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# Check if user is a treatment professional
|
||||||
user = request.env.user
|
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
|
# Regular coaches shouldn't be able to add emergency contacts
|
||||||
if not is_treatment_prof:
|
if not is_treatment_prof:
|
||||||
|
|
@ -160,7 +160,7 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
return request.render('portal.403', {'error': str(e)})
|
return request.render('portal.403', {'error': str(e)})
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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
|
# Regular coaches shouldn't be able to add emergency contacts
|
||||||
if not is_treatment_prof:
|
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}')
|
return_url = post.get('return_url', f'/my/player?player_id={patient.id}')
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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
|
# Regular coaches shouldn't be able to edit emergency contacts
|
||||||
if not is_treatment_prof:
|
if not is_treatment_prof:
|
||||||
|
|
@ -251,7 +251,7 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
return request.render('portal.403', {'error': str(e)})
|
return request.render('portal.403', {'error': str(e)})
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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
|
# Regular coaches shouldn't be able to edit emergency contacts
|
||||||
if not is_treatment_prof:
|
if not is_treatment_prof:
|
||||||
|
|
@ -311,7 +311,7 @@ class PlayerManagementPortal(CustomerPortal):
|
||||||
return request.render('portal.403', {'error': str(e)})
|
return request.render('portal.403', {'error': str(e)})
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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
|
# Regular coaches shouldn't be able to delete emergency contacts
|
||||||
if not is_treatment_prof:
|
if not is_treatment_prof:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class TaskManagementPortal(CustomerPortal):
|
||||||
record = request.env[model_name].browse(int(record_id))
|
record = request.env[model_name].browse(int(record_id))
|
||||||
|
|
||||||
# Check if user is a treatment professional
|
# 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
|
# Check if record exists
|
||||||
if not record.exists():
|
if not record.exists():
|
||||||
|
|
@ -27,7 +27,7 @@ class TaskManagementPortal(CustomerPortal):
|
||||||
if model_name == 'sports.patient':
|
if model_name == 'sports.patient':
|
||||||
patient_id_int = int(record_id)
|
patient_id_int = int(record_id)
|
||||||
accessible_teams = request.env['sports.team'].search([
|
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)
|
('patient_ids', 'in', patient_id_int)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
@ -106,7 +106,7 @@ class TaskManagementPortal(CustomerPortal):
|
||||||
domain = [('partner_id', 'in', team.staff_ids.mapped('partner_id').ids)]
|
domain = [('partner_id', 'in', team.staff_ids.mapped('partner_id').ids)]
|
||||||
|
|
||||||
# Only treatment professionals can see and assign all users
|
# 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:
|
if not is_treatment_prof:
|
||||||
domain.append(('id', '=', request.env.user.id))
|
domain.append(('id', '=', request.env.user.id))
|
||||||
|
|
||||||
|
|
@ -162,7 +162,7 @@ class TaskManagementPortal(CustomerPortal):
|
||||||
return request.redirect(f'{return_url}&error=missing_fields')
|
return request.redirect(f'{return_url}&error=missing_fields')
|
||||||
|
|
||||||
# Check if the assigned user is valid
|
# 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))
|
assigned_user = request.env['res.users'].browse(int(user_id))
|
||||||
|
|
||||||
# Only treatment professionals can assign to other users
|
# Only treatment professionals can assign to other users
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class TeamStaffPortal(CustomerPortal):
|
||||||
def _prepare_teams_domain(cls):
|
def _prepare_teams_domain(cls):
|
||||||
user = http.request.env.user
|
user = http.request.env.user
|
||||||
return [
|
return [
|
||||||
('staff_ids.user_ids', 'in', user.id),
|
('staff_ids.user_ids', '=', user.id),
|
||||||
]
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -99,9 +99,33 @@ class TeamStaffPortal(CustomerPortal):
|
||||||
if not player:
|
if not player:
|
||||||
raise UserError(_('This player could not be found.'))
|
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
|
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
|
# Show all injuries to treatment professionals, but only active ones to coaches
|
||||||
if is_treatment_prof:
|
if is_treatment_prof:
|
||||||
|
|
|
||||||
|
|
@ -166,15 +166,17 @@
|
||||||
<field name="login">therapist</field>
|
<field name="login">therapist</field>
|
||||||
<field name="password">therapist</field>
|
<field name="password">therapist</field>
|
||||||
<field name="groups_id" eval="[(5, 0, 0),
|
<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 -->
|
<!-- 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>
|
||||||
<record id="carabins_coach_user" model="res.users" context="{'no_reset_password': True}">
|
<record id="carabins_coach_user" model="res.users" context="{'no_reset_password': True}">
|
||||||
<field name="partner_id" ref="partner_coach_team_carabins"/>
|
<field name="partner_id" ref="partner_coach_team_carabins"/>
|
||||||
<field name="login">coach</field>
|
<field name="login">coach</field>
|
||||||
<field name="password">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>
|
</record>
|
||||||
<!-- Users should be either internal users or portal users, not both -->
|
<!-- Users should be either internal users or portal users, not both -->
|
||||||
<record id="group_sports_clinic_admin" model="res.groups">
|
<record id="group_sports_clinic_admin" model="res.groups">
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class Patient(models.Model):
|
||||||
comodel_name="sports.patient.contact",
|
comodel_name="sports.patient.contact",
|
||||||
inverse_name="patient_id",
|
inverse_name="patient_id",
|
||||||
string="Patient Contacts",
|
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(
|
team_ids = fields.Many2many(
|
||||||
comodel_name="sports.team",
|
comodel_name="sports.team",
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,10 @@ class PatientInjury(models.Model):
|
||||||
column1="patient_injury_id",
|
column1="patient_injury_id",
|
||||||
column2="treatment_pro_id",
|
column2="treatment_pro_id",
|
||||||
string="Treatment Professionals",
|
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,
|
tracking=True,
|
||||||
)
|
)
|
||||||
predicted_resolution_date = fields.Date(tracking=True)
|
predicted_resolution_date = fields.Date(tracking=True)
|
||||||
|
|
@ -93,6 +96,30 @@ class PatientInjury(models.Model):
|
||||||
tracking=True,
|
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
|
# Relations to new models
|
||||||
# Now treatment notes are linked to patient primarily, but can be optionally linked to injuries
|
# Now treatment notes are linked to patient primarily, but can be optionally linked to injuries
|
||||||
treatment_note_ids = fields.One2many(
|
treatment_note_ids = fields.One2many(
|
||||||
|
|
|
||||||
|
|
@ -4,36 +4,12 @@ from odoo import models, fields, api, _, Command
|
||||||
class User(models.Model):
|
class User(models.Model):
|
||||||
_inherit = "res.users"
|
_inherit = "res.users"
|
||||||
|
|
||||||
is_treatment_professional = fields.Boolean(
|
|
||||||
compute="_compute_is_treatment_professional", store=True
|
|
||||||
)
|
|
||||||
|
|
||||||
accessible_team_ids = fields.Many2many(
|
accessible_team_ids = fields.Many2many(
|
||||||
comodel_name="sports.team",
|
comodel_name="sports.team",
|
||||||
compute="_compute_accessible_team_ids",
|
compute="_compute_accessible_team_ids",
|
||||||
inverse="_inverse_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):
|
def _compute_accessible_team_ids(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
rec.accessible_team_ids = rec.partner_id.teams_served_ids
|
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
|
# Update treatment professional group membership for new records
|
||||||
res._update_treatment_professional_group()
|
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')
|
affected_users = res.mapped('user_ids')
|
||||||
if affected_users:
|
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
|
# Handle follower recomputation
|
||||||
res.team_id.mapped("patient_ids").recompute_followers()
|
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
|
# No therapist roles left, remove from treatment professional group
|
||||||
users = self.env['res.users'].sudo().search([('partner_id', '=', partner.id)])
|
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')
|
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:
|
for user in users:
|
||||||
|
# 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'):
|
if user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'):
|
||||||
user.sudo().write({'groups_id': [(3, treatment_prof_group.id)]})
|
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)]})
|
||||||
|
|
||||||
# Recompute is_treatment_professional on all affected users
|
# Update group membership directly for each affected user
|
||||||
affected_users.sudo().invalidate_model(['is_treatment_professional'])
|
# 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)]})
|
||||||
|
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
|
return res
|
||||||
|
|
||||||
|
|
@ -323,34 +355,69 @@ class TeamStaff(models.Model):
|
||||||
('role', 'in', ['head_therapist', 'therapist'])
|
('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.
|
"""Update treatment professional status based on staff role.
|
||||||
|
|
||||||
This method ensures that users with therapist roles have the appropriate
|
This method ensures that users with therapist roles have the appropriate
|
||||||
group memberships. It handles both internal and portal users appropriately.
|
group memberships. It handles both internal and portal users appropriately.
|
||||||
|
|
||||||
For internal users, this manages group membership directly.
|
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
|
# Skip if in module installation context to avoid demo data conflicts
|
||||||
if self.env.context.get('module'):
|
if self.env.context.get('module'):
|
||||||
return
|
return
|
||||||
|
|
||||||
treatment_prof_group = self._get_treatment_professional_group()
|
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'):
|
for staff in self.filtered('user_ids'):
|
||||||
# Check if this partner has any staff records with therapist roles
|
# 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))
|
has_therapist_role = bool(self._get_staff_with_therapist_roles(staff.partner_id.id))
|
||||||
|
|
||||||
# Process each user linked to this partner
|
# Process each user linked to this partner
|
||||||
for user in staff.user_ids:
|
for user in staff.user_ids:
|
||||||
# Always ensure the computed field is up-to-date
|
# Handle internal users
|
||||||
user.sudo().invalidate_model(['is_treatment_professional'])
|
|
||||||
|
|
||||||
# Only manage group membership for internal users
|
|
||||||
if user.has_group('base.group_user'):
|
if user.has_group('base.group_user'):
|
||||||
self._update_user_group_membership(user, has_therapist_role, treatment_prof_group)
|
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):
|
def write(self, values):
|
||||||
old_roles = {record.id: record.role for record in self}
|
old_roles = {record.id: record.role for record in self}
|
||||||
|
|
@ -360,11 +427,6 @@ class TeamStaff(models.Model):
|
||||||
if 'role' in values or 'team_id' in values:
|
if 'role' in values or 'team_id' in values:
|
||||||
self._update_treatment_professional_group()
|
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
|
# Handle team changes for follower recomputation
|
||||||
if "team_id" in values:
|
if "team_id" in values:
|
||||||
to_recompute = self.env["sports.patient"]
|
to_recompute = self.env["sports.patient"]
|
||||||
|
|
|
||||||
|
|
@ -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,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_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_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_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_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
|
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_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_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
|
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({
|
cls.coach_staff = cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.coach_partner.id,
|
'partner_id': cls.coach_partner.id,
|
||||||
'is_treatment_professional': False,
|
# Role coach doesn't grant treatment professional status
|
||||||
'role': 'coach',
|
'role': 'coach',
|
||||||
'user_id': cls.coach_user.id,
|
'user_id': cls.coach_user.id,
|
||||||
})
|
})
|
||||||
|
|
@ -75,7 +75,7 @@ class TestEndToEndWorkflows(TransactionCase):
|
||||||
cls.therapist_staff = cls.env['sports.team.staff'].create({
|
cls.therapist_staff = cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.therapist_partner.id,
|
'partner_id': cls.therapist_partner.id,
|
||||||
'is_treatment_professional': True,
|
# Role therapist automatically grants treatment professional status
|
||||||
'role': 'therapist',
|
'role': 'therapist',
|
||||||
'user_id': cls.therapist_user.id,
|
'user_id': cls.therapist_user.id,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -68,18 +68,18 @@ class TestInjuryAssignment(TransactionCase):
|
||||||
'team_ids': [(4, cls.team.id)],
|
'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({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.partner_therapist.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,
|
'user_id': cls.user_therapist.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.partner_coach.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,
|
'user_id': cls.user_coach.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,28 +110,28 @@ class TestInjuryNotifications(TransactionCase):
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.partner_therapist.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,
|
'user_id': cls.user_therapist.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.partner_portal_therapist.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,
|
'user_id': cls.user_portal_therapist.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.partner_coach.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,
|
'user_id': cls.user_coach.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.partner_portal_coach.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,
|
'user_id': cls.user_portal_coach.id,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,6 @@ class TestPortalIntegration(HttpCase):
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.therapist_partner.id,
|
'partner_id': cls.therapist_partner.id,
|
||||||
'is_treatment_professional': True,
|
|
||||||
'role': 'therapist',
|
'role': 'therapist',
|
||||||
'user_id': cls.therapist_user.id,
|
'user_id': cls.therapist_user.id,
|
||||||
})
|
})
|
||||||
|
|
@ -93,7 +92,6 @@ class TestPortalIntegration(HttpCase):
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.coach_partner.id,
|
'partner_id': cls.coach_partner.id,
|
||||||
'is_treatment_professional': False,
|
|
||||||
'role': 'coach',
|
'role': 'coach',
|
||||||
'user_id': cls.coach_user.id,
|
'user_id': cls.coach_user.id,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ class TestSecurityIntegration(HttpCase):
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.therapist_partner.id,
|
'partner_id': cls.therapist_partner.id,
|
||||||
'is_treatment_professional': True,
|
# Role therapist automatically grants treatment professional status
|
||||||
'role': 'therapist',
|
'role': 'therapist',
|
||||||
'user_id': cls.therapist_user.id,
|
'user_id': cls.therapist_user.id,
|
||||||
})
|
})
|
||||||
|
|
@ -110,7 +110,7 @@ class TestSecurityIntegration(HttpCase):
|
||||||
cls.env['sports.team.staff'].create({
|
cls.env['sports.team.staff'].create({
|
||||||
'team_id': cls.team.id,
|
'team_id': cls.team.id,
|
||||||
'partner_id': cls.coach_partner.id,
|
'partner_id': cls.coach_partner.id,
|
||||||
'is_treatment_professional': False,
|
# Role coach doesn't grant treatment professional status
|
||||||
'role': 'coach',
|
'role': 'coach',
|
||||||
'user_id': cls.coach_user.id,
|
'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_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_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
|
|
||||||
self.assertFalse(self.user_head_therapist.is_treatment_professional)
|
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
self.assertFalse(self.user_therapist.is_treatment_professional)
|
self.assertFalse(self.user_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'))
|
||||||
self.assertFalse(self.user_coach.is_treatment_professional)
|
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
|
|
||||||
# 1. Create a head therapist staff record
|
# 1. Create a head therapist staff record
|
||||||
head_therapist_staff = self.env['sports.team.staff'].create({
|
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
|
# 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'),
|
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")
|
"Head therapist user should be added to treatment professional group")
|
||||||
self.assertTrue(self.user_head_therapist.is_treatment_professional,
|
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Head therapist is_treatment_professional flag should be True")
|
"Head therapist should be in treatment professional group")
|
||||||
|
|
||||||
# 2. Create a therapist staff record
|
# 2. Create a therapist staff record
|
||||||
therapist_staff = self.env['sports.team.staff'].create({
|
therapist_staff = self.env['sports.team.staff'].create({
|
||||||
|
|
@ -104,11 +104,11 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Verify therapist gets treatment professional group and flag
|
# 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'),
|
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Therapist user should be added to treatment professional group")
|
"Therapist user should be added to treatment professional group")
|
||||||
self.assertTrue(self.user_therapist.is_treatment_professional,
|
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Therapist is_treatment_professional flag should be True")
|
"Therapist should be in treatment professional group")
|
||||||
|
|
||||||
# 3. Create a coach staff record - should NOT 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({
|
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
|
# 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'),
|
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Coach should NOT be added to treatment professional group")
|
"Coach should NOT be added to treatment professional group")
|
||||||
self.assertFalse(self.user_coach.is_treatment_professional,
|
self.assertFalse(self.user_coach.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Coach is_treatment_professional flag should be False")
|
"Coach should NOT have treatment professional group membership")
|
||||||
|
|
||||||
# 4. Test changing roles - change head therapist to coach
|
# 4. Test changing roles - change head therapist to coach
|
||||||
head_therapist_staff.write({'role': 'coach'})
|
head_therapist_staff.write({'role': 'coach'})
|
||||||
|
|
||||||
# Verify head therapist loses treatment professional group and flag
|
# 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'),
|
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")
|
"Former head therapist should be removed from treatment professional group")
|
||||||
self.assertFalse(self.user_head_therapist.is_treatment_professional,
|
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Former head therapist is_treatment_professional flag should be False")
|
"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
|
# Use the internal user therapist instead of the portal user coach
|
||||||
self.user_therapist.write({'groups_id': [(4, self.treatment_prof_group.id)]})
|
self.user_therapist.write({'groups_id': [(4, self.treatment_prof_group.id)]})
|
||||||
|
|
||||||
# Verify therapist now has treatment professional flag due to group membership
|
# 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'),
|
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Therapist should have treatment professional group after manual assignment")
|
"Therapist should have treatment professional group after manual assignment")
|
||||||
self.assertTrue(self.user_therapist.is_treatment_professional,
|
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'),
|
||||||
"Therapist is_treatment_professional flag should be True after group assignment")
|
"Therapist should be in treatment professional group after direct group assignment")
|
||||||
|
|
||||||
def test_group_membership_preserved_across_role_changes(self):
|
def test_group_membership_preserved_across_role_changes(self):
|
||||||
"""Test that group membership is correctly managed when roles change."""
|
"""Test that group membership is correctly managed when roles change."""
|
||||||
|
|
@ -155,21 +155,21 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Verify user is in treatment professional group
|
# 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'))
|
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
|
|
||||||
# Change role to non-therapist role
|
# Change role to non-therapist role
|
||||||
staff.write({'role': 'other'})
|
staff.write({'role': 'other'})
|
||||||
|
|
||||||
# Verify user is removed from treatment professional group
|
# 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'))
|
self.assertFalse(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
|
|
||||||
# Change back to therapist role
|
# Change back to therapist role
|
||||||
staff.write({'role': 'therapist'})
|
staff.write({'role': 'therapist'})
|
||||||
|
|
||||||
# Verify user is added back to treatment professional group
|
# 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'))
|
self.assertTrue(self.user_head_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
|
|
||||||
def test_multiple_team_assignments(self):
|
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
|
# 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.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
|
# Remove therapist role on team 2
|
||||||
therapist_staff.write({'role': 'other'})
|
therapist_staff.write({'role': 'other'})
|
||||||
|
|
||||||
# Verify user loses treatment professional status
|
# 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.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):
|
def test_role_removal_through_deletion(self):
|
||||||
"""Test that deleting staff records properly removes treatment professional status."""
|
"""Test that deleting staff records properly removes treatment professional status."""
|
||||||
|
|
@ -215,17 +215,17 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Verify user gets treatment professional group
|
# 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.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
self.assertTrue(self.user_therapist.is_treatment_professional)
|
|
||||||
|
|
||||||
# Delete the staff record
|
# Delete the staff record
|
||||||
therapist_staff.unlink()
|
therapist_staff.unlink()
|
||||||
|
|
||||||
# Verify user loses treatment professional status after deletion
|
# 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.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):
|
def test_multiple_role_assignments_deletion(self):
|
||||||
"""Test that deleting one therapist role preserves status if other therapist roles exist."""
|
"""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
|
# 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'))
|
self.assertTrue(self.user_therapist.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
|
|
||||||
# Delete one staff record but not the other
|
# Delete one staff record but not the other
|
||||||
therapist_staff1.unlink()
|
therapist_staff1.unlink()
|
||||||
|
|
||||||
# Verify user still has treatment professional status (from the second record)
|
# 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.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional'))
|
||||||
self.assertTrue(self.user_therapist.is_treatment_professional)
|
|
||||||
|
|
||||||
# Delete the second staff record
|
# Delete the second staff record
|
||||||
therapist_staff2.unlink()
|
therapist_staff2.unlink()
|
||||||
|
|
||||||
# Verify user loses treatment professional status
|
# 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.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):
|
def test_portal_user_as_treatment_professional(self):
|
||||||
"""Test that portal users can be treatment professionals via the flag without group membership."""
|
"""Test that portal users can be treatment professionals via the flag without group membership."""
|
||||||
# Verify initially the portal user is not a treatment professional
|
# 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.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
|
# Verify the user is a portal user and not an internal user
|
||||||
self.assertTrue(self.user_portal_therapist.has_group('base.group_portal'))
|
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
|
# Verify portal user gets treatment professional flag but NOT the group
|
||||||
# (would conflict with portal user type)
|
# (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'),
|
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)")
|
"Portal user should NOT be added to treatment professional group (would conflict with user type)")
|
||||||
self.assertTrue(self.user_portal_therapist.is_treatment_professional,
|
self.assertTrue(self.user_portal_therapist.has_group('bemade_sports_clinic.group_portal_treatment_professional'),
|
||||||
"Portal user with therapist role should have is_treatment_professional flag set to True")
|
"Portal user with therapist role should be in portal treatment professional group")
|
||||||
|
|
||||||
# Verify user is still a portal user and not an internal user
|
# Verify user is still a portal user and not an internal user
|
||||||
self.assertTrue(self.user_portal_therapist.has_group('base.group_portal'))
|
self.assertTrue(self.user_portal_therapist.has_group('base.group_portal'))
|
||||||
|
|
@ -299,6 +299,6 @@ class TestTreatmentProfessionalConsistency(TransactionCase):
|
||||||
portal_therapist_staff.write({'role': 'other'})
|
portal_therapist_staff.write({'role': 'other'})
|
||||||
|
|
||||||
# Verify portal user loses treatment professional status
|
# Verify portal user loses treatment professional status
|
||||||
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.is_treatment_professional,
|
self.assertFalse(self.user_portal_therapist.has_group('bemade_sports_clinic.group_portal_treatment_professional'),
|
||||||
"Portal user should have is_treatment_professional flag set to False when role is changed")
|
"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 t-if="is_treatment_prof" class="row mt-3">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="body_location_id">Body Location</label>
|
<label for="body_location">Body Location</label>
|
||||||
<select name="body_location_id" id="body_location_id" class="form-control">
|
<input type="text" class="form-control" name="body_location" id="body_location" t-att-value="injury.body_location"/>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="injury_type_id">Injury Type</label>
|
<label for="injury_type">Injury Type</label>
|
||||||
<select name="injury_type_id" id="injury_type_id" class="form-control">
|
<input type="text" class="form-control" name="injury_type" id="injury_type" t-att-value="injury.injury_type"/>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,23 @@
|
||||||
<!-- Add a dedicated page for Sports Clinic permissions -->
|
<!-- Add a dedicated page for Sports Clinic permissions -->
|
||||||
<page name="access_rights" position="after">
|
<page name="access_rights" position="after">
|
||||||
<page name="sports_clinic_access" string="Sports Clinic Access Rights" groups="base.group_system">
|
<page name="sports_clinic_access" string="Sports Clinic Access Rights" groups="base.group_system">
|
||||||
<group>
|
<div class="alert alert-info" role="alert">
|
||||||
<field name="groups_id" widget="many2many_checkboxes"
|
<p><strong>Role-Based Access Rights:</strong></p>
|
||||||
domain="[('category_id','=',ref('bemade_sports_clinic.module_category_sports_clinic_management'))]"
|
<p>Sports Clinic access rights are automatically managed based on team roles:</p>
|
||||||
readonly="0" nolabel="1"/>
|
<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>
|
</group>
|
||||||
|
|
||||||
|
<field name="partner_id" widget="res_partner_many2one" readonly="1" options="{'always_reload': True}"/>
|
||||||
</page>
|
</page>
|
||||||
</page>
|
</page>
|
||||||
</field>
|
</field>
|
||||||
|
|
|
||||||
|
|
@ -359,13 +359,13 @@
|
||||||
</t>
|
</t>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<div class="btn-group">
|
<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
|
<i class="fa fa-edit"></i> Edit
|
||||||
</a>
|
</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
|
<i class="fa fa-clipboard-list"></i> Notes
|
||||||
</a>
|
</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
|
<i class="fa fa-file-medical"></i> Docs
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue