From 82266644ca321a98d703b8feac377dcf28bbb27d Mon Sep 17 00:00:00 2001 From: Denis Durepos Date: Sun, 27 Jul 2025 15:08:08 -0400 Subject: [PATCH] Portal UI enhancements: injury form improvements, coach ACL fixes, and color scheme updates - Updated injury form fields and layout for portal consistency - Removed team field from portal injury forms and made debug-only in internal views - Fixed injury list color scheme (unverified=yellow, active=red) and added clickable links for treatment professionals - Added comprehensive ACL permissions for coaches: res.partner, sports.patient.injury, mail.followers, mail.template - Added record rule for coaches to access partner records - Improved patient injury table in portal: role-based column visibility and navigation - Enhanced status field color coding with Bootstrap text classes - Added save/cancel buttons at top and bottom of edit forms - Moved external notes field to end of injury detail form for better workflow --- bemade_sports_clinic/TODO.md | 7 + .../controllers/patient_injury_portal.py | 118 +++++++------ .../security/ir.model.access.csv | 4 + .../security/sports_clinic_portal_rules.xml | 12 ++ .../injury_management_portal_templates.xml | 129 +++++++++----- .../player_management_portal_templates.xml | 28 +++ .../views/sports_clinic_portal_views.xml | 165 ++++++++---------- .../views/sports_patient_injury_portal.xml | 14 +- .../views/sports_patient_injury_views.xml | 4 +- .../task_management_portal_templates.xml | 14 ++ 10 files changed, 296 insertions(+), 199 deletions(-) diff --git a/bemade_sports_clinic/TODO.md b/bemade_sports_clinic/TODO.md index 0b31851..06bbd23 100644 --- a/bemade_sports_clinic/TODO.md +++ b/bemade_sports_clinic/TODO.md @@ -153,3 +153,10 @@ - Keep this file updated as new TODOs are identified - Reference relevant issue numbers when available - Delete or check off items as they are completed + +## MC's notes +- [ ]Change action button colors to Fit Crew color scheme (instead of the weird turquoise) +- [ ]Confirm followers added correctly when therapist adds player to team +- [x]Remove Team from injury detail (including from model - was not there before) +- [ ]Fix treatment professional selection in injury detail +- [ ]Add patient address add/edit to coach/therapist portal \ No newline at end of file diff --git a/bemade_sports_clinic/controllers/patient_injury_portal.py b/bemade_sports_clinic/controllers/patient_injury_portal.py index ff341d9..3cbbb5d 100644 --- a/bemade_sports_clinic/controllers/patient_injury_portal.py +++ b/bemade_sports_clinic/controllers/patient_injury_portal.py @@ -51,12 +51,6 @@ class PatientInjuryPortal(CustomerPortal): return_url = post.get('return_url', f'/my/player?player_id={patient_id}') - # Get patient's teams for the dropdown - teams = patient.team_ids - - # Pre-selected team ID (when player is only on one team) - default_team_id = teams[0].id if len(teams) == 1 else None - # Check if user is a treatment professional # Use request.env.user.has_group() directly to avoid security violations is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional') @@ -64,8 +58,6 @@ class PatientInjuryPortal(CustomerPortal): values = { 'patient': patient, - 'teams': teams, # Pass teams to the template for dropdown - 'default_team_id': default_team_id, # Will be None if multiple teams 'return_url': return_url, 'page_name': 'report_injury', 'is_treatment_prof': is_treatment_prof, # Pass flag to template for conditional display @@ -90,31 +82,30 @@ class PatientInjuryPortal(CustomerPortal): 'error_message': str(e) }) - # Get the selected team - team_id = post.get('team_id') - if not team_id: - return request.redirect(f'/my/patient/injury/new?patient_id={patient_id}') + # Since team_id is no longer in the portal form, we'll use the patient's first team + # or None if the patient has multiple teams (let the model handle assignment) + patient_teams = patient.team_ids + team_id = patient_teams[0].id if len(patient_teams) == 1 else None # Check if the current user is a treatment professional is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional') # Prepare values for injury creation vals = { - 'patient_id': int(patient_id), - 'diagnosis': post.get('diagnosis'), - 'external_notes': post.get('external_notes'), - # Set stage based on user role - treatment professionals create active injuries + 'patient_id': patient.id, + 'diagnosis': post.get('diagnosis', ''), + 'injury_date': post.get('injury_date'), + 'external_notes': post.get('external_notes', ''), 'stage': 'active' if is_treatment_prof else 'unverified', - 'patient_name': patient.name, - # Store which team the injury was reported for - 'team_id': int(team_id), - # Store parental consent value - 'parental_consent': post.get('parental_consent', 'no'), } - # Handle dates - if post.get('injury_date'): - vals['injury_date'] = post.get('injury_date') + # Only add team_id if we have a single team for the patient + if team_id: + vals['team_id'] = int(team_id) + + # Handle optional fields + if post.get('parental_consent'): + vals['parental_consent'] = post.get('parental_consent') if post.get('predicted_resolution_date'): vals['predicted_resolution_date'] = post.get('predicted_resolution_date') @@ -227,24 +218,28 @@ class PatientInjuryPortal(CustomerPortal): user = request.env.user injury = request.env['sports.patient.injury'].browse(int(injury_id)) - # Check if user has access to the team this injury is associated with + # Check if user has access to this injury based on patient's team ownership if not injury.exists(): raise UserError(_('Injury not found.')) - # Get the team from the injury - team = injury.team_id + # Get the patient's teams + patient_teams = injury.patient_id.team_ids - if team: - # 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 + if patient_teams: + # Check if user is part of any of the patient's team staff + user_teams = request.env['sports.team.staff'].search([ + ('team_id', 'in', patient_teams.ids), + ('user_ids', '=', user.id) + ]) + + # Medical professionals might have specific access # Use request.env.user.has_group() directly to avoid security violations is_medical = request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional') - if not is_team_staff and not is_medical: + if not user_teams 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 patient has no teams, only medical professionals can access # Use request.env.user.has_group() directly to avoid security violations if not request.env.user.has_group('bemade_sports_clinic.group_portal_treatment_professional'): raise UserError(_('You do not have access to this injury.')) @@ -278,14 +273,10 @@ class PatientInjuryPortal(CustomerPortal): stage_selection = request.env['sports.patient.injury']._fields['stage'].selection stages = [(k, v) for k, v in stage_selection] - # These were previously fetched from models that have been removed - body_locations = [] - injury_types = [] - - # 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 treatment professionals for the multi-select field + treatment_professionals = request.env['res.users'].search([ + ('groups_id', 'in', request.env.ref('bemade_sports_clinic.group_portal_treatment_professional').id) + ]) # Get parental consent options if treatment professional parental_consent_options = None @@ -295,9 +286,7 @@ class PatientInjuryPortal(CustomerPortal): values = { 'injury': injury, 'stages': stages, - 'body_locations': body_locations, - 'injury_types': injury_types, - 'severity_options': severity_options, + 'treatment_professionals': treatment_professionals, 'parental_consent_options': parental_consent_options, 'return_url': return_url, 'is_treatment_prof': is_treatment_prof, @@ -339,18 +328,39 @@ class PatientInjuryPortal(CustomerPortal): 'external_notes': post.get('external_notes', injury.external_notes or ''), }) + # Handle injury date and N/A checkbox + if post.get('injury_date_na'): + vals['injury_date_na'] = True + vals['injury_date'] = False # Clear the date if N/A is checked + else: + vals['injury_date_na'] = False + if post.get('injury_date'): + vals['injury_date'] = post.get('injury_date') + + + + # Handle resolution dates + if post.get('predicted_resolution_date'): + vals['predicted_resolution_date'] = post.get('predicted_resolution_date') + + if post.get('resolution_date'): + vals['resolution_date'] = post.get('resolution_date') + + # Handle treatment professionals (multi-select) + if post.get('treatment_professional_ids'): + # Convert to list if it's a single value + prof_ids = post.get('treatment_professional_ids') + if isinstance(prof_ids, str): + prof_ids = [prof_ids] + elif not isinstance(prof_ids, list): + prof_ids = [prof_ids] + + # Convert to integers and set using Odoo's many2many syntax + prof_ids = [int(pid) for pid in prof_ids if pid] + vals['treatment_professional_ids'] = [(6, 0, prof_ids)] + # Fields only treatment professionals can update if is_treatment_prof: - # Only add fields that were actually submitted - if post.get('body_location'): - vals['body_location'] = post.get('body_location') - - if post.get('injury_type'): - vals['injury_type'] = post.get('injury_type') - - if post.get('severity'): - vals['severity'] = post.get('severity') - if post.get('internal_notes'): vals['internal_notes'] = post.get('internal_notes') diff --git a/bemade_sports_clinic/security/ir.model.access.csv b/bemade_sports_clinic/security/ir.model.access.csv index 5fd86fc..8a88dbf 100644 --- a/bemade_sports_clinic/security/ir.model.access.csv +++ b/bemade_sports_clinic/security/ir.model.access.csv @@ -10,6 +10,7 @@ access_patient_contact_portal_tp,Portal TP Access for Patient Contacts,model_spo 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,1,0 access_injury_portal_tp,Portal Treatment Prof Access for Injuries,model_sports_patient_injury,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 +access_injury_portal_coach,Portal Coach Access for Injuries,model_sports_patient_injury,bemade_sports_clinic.group_portal_team_coach,1,1,1,0 access_team_user,User Access for Teams,model_sports_team,group_sports_clinic_user,1,1,1,0 access_team_admin,Admin Access for Teams,model_sports_team,group_sports_clinic_admin,1,1,1,1 access_team_treatment_pro,Treatment Professional Access for Teams,model_sports_team,group_sports_clinic_treatment_professional,1,1,1,0 @@ -36,10 +37,13 @@ access_mail_alias_portal_tp,Portal TP Access for Aliases,mail.model_mail_alias,b access_ir_model_portal_tp,Portal TP Access for Models,base.model_ir_model,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 access_mail_message_subtype_portal_tp,Portal TP Access for Message Subtypes,mail.model_mail_message_subtype,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 access_mail_template_portal_tp,Portal TP Access for Mail Templates,mail.model_mail_template,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 +access_mail_template_portal_coach,Portal Coach Access for Mail Templates,mail.model_mail_template,bemade_sports_clinic.group_portal_team_coach,1,0,0,0 access_mail_notification_portal_tp,Portal TP Access for Mail Notifications,mail.model_mail_notification,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 access_ir_attachment_portal_tp,Portal TP Access for Attachments,base.model_ir_attachment,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 access_res_users_portal_tp,Portal TP Access for Users,base.model_res_users,bemade_sports_clinic.group_portal_treatment_professional,1,0,0,0 access_res_partner_portal_tp,Portal TP Access for Partners,base.model_res_partner,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 +access_res_partner_portal_coach,Portal Coach Access for Partners,base.model_res_partner,bemade_sports_clinic.group_portal_team_coach,1,1,1,0 access_mail_followers_portal_tp,Portal TP Access for Followers,mail.model_mail_followers,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 +access_mail_followers_portal_coach,Portal Coach Access for Followers,mail.model_mail_followers,bemade_sports_clinic.group_portal_team_coach,1,1,1,0 access_bus_bus_portal_tp,Portal TP Access for Bus Messages,bus.model_bus_bus,bemade_sports_clinic.group_portal_treatment_professional,1,1,1,0 diff --git a/bemade_sports_clinic/security/sports_clinic_portal_rules.xml b/bemade_sports_clinic/security/sports_clinic_portal_rules.xml index 7d2308c..f1cdd66 100644 --- a/bemade_sports_clinic/security/sports_clinic_portal_rules.xml +++ b/bemade_sports_clinic/security/sports_clinic_portal_rules.xml @@ -84,5 +84,17 @@ [(1, '=', 1)] + + + + Portal Team Coach Access to Partners + + + + + + + [(1, '=', 1)] + diff --git a/bemade_sports_clinic/views/injury_management_portal_templates.xml b/bemade_sports_clinic/views/injury_management_portal_templates.xml index 6f6558a..4b27592 100644 --- a/bemade_sports_clinic/views/injury_management_portal_templates.xml +++ b/bemade_sports_clinic/views/injury_management_portal_templates.xml @@ -36,61 +36,81 @@ + +
+
+
+ + Cancel + + +
+
+
+

Injury Details

+
+
+ +
+ +
+ + +
+
+ Check N/A if exact date is unknown +
+
+ +
+ + +
+
+
+ + + + +
- - - Notes visible to all team members + + + Expected recovery timeline +
+
+
+
+ + + Actual recovery date (when resolved)
- +
-
-
- - -
-
-
-
- - -
-
-
- - -
-
-
- - -
-
@@ -103,6 +123,19 @@
+
+
+ + + Hold Ctrl/Cmd to select multiple professionals +
+
@@ -153,6 +186,25 @@
+ +
+
+

External Notes

+
+
+
+
+
+ + + Notes visible to all team members +
+
+
+
+
+
@@ -218,13 +270,8 @@

Injury Treatment Notes

Patient Treatment Notes

- - - - Back to Injury - - - + + Back to Patient diff --git a/bemade_sports_clinic/views/player_management_portal_templates.xml b/bemade_sports_clinic/views/player_management_portal_templates.xml index a1a4bed..8677fab 100644 --- a/bemade_sports_clinic/views/player_management_portal_templates.xml +++ b/bemade_sports_clinic/views/player_management_portal_templates.xml @@ -15,6 +15,20 @@ + +
+
+
+ + Cancel + + +
+
+
+
@@ -231,6 +245,20 @@ + +
+
+
+ + Cancel + + +
+
+
+
diff --git a/bemade_sports_clinic/views/sports_clinic_portal_views.xml b/bemade_sports_clinic/views/sports_clinic_portal_views.xml index 055314d..cd4017b 100644 --- a/bemade_sports_clinic/views/sports_clinic_portal_views.xml +++ b/bemade_sports_clinic/views/sports_clinic_portal_views.xml @@ -316,44 +316,44 @@
-
Match Status
- +
Match
+ Yes - + No - +
-
Practice Status
- +
Practice
+ Yes - - Yes, no contact + + Yes, No Contact - + No - +
Status
- + Play OK - + Practice OK - + Injured - +
@@ -413,55 +413,60 @@ Date Injury - Status - External Notes - - Internal Notes + + External Notes + + + Actions - Actions - + - + + + + + + + + - + + + + + + + + - - Unverified - Active - Resolved - - -
- -
-
No external notes
- - + -
- +
+ +
+
No external notes
+ + + + + -
No internal notes
- - - @@ -498,28 +503,10 @@ Age: - + Last Consultation: - - Injured Since: - - - - ( days) - - - - - Active Injuries: - - - - active - - - Allergies: @@ -611,21 +598,21 @@
Status Information
- - + + - - + + @@ -636,13 +623,13 @@ - - + +
Match Status: - Yes - No - - Match: + Yes + No + +
Practice Status: - Available - Available, No Contact - Not Available - - Practice: + Yes + Yes, No Contact + No + +
Predicted Return Date:
Current Stage: - Healthy - Practice OK - No Play - - Status: + Play OK + Practice OK + Injured + +
diff --git a/bemade_sports_clinic/views/sports_patient_injury_portal.xml b/bemade_sports_clinic/views/sports_patient_injury_portal.xml index 11bef52..3e2fc2d 100644 --- a/bemade_sports_clinic/views/sports_patient_injury_portal.xml +++ b/bemade_sports_clinic/views/sports_patient_injury_portal.xml @@ -11,19 +11,7 @@
-
- -
- -
-
+
diff --git a/bemade_sports_clinic/views/sports_patient_injury_views.xml b/bemade_sports_clinic/views/sports_patient_injury_views.xml index 4be27f2..2e42fa3 100644 --- a/bemade_sports_clinic/views/sports_patient_injury_views.xml +++ b/bemade_sports_clinic/views/sports_patient_injury_views.xml @@ -30,7 +30,7 @@ - +