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
This commit is contained in:
parent
a6742c16b0
commit
82266644ca
10 changed files with 296 additions and 199 deletions
|
|
@ -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
|
||||
|
|
@ -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')
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
|
@ -84,5 +84,17 @@
|
|||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
</record>
|
||||
|
||||
<!-- Portal team coaches can access partners linked to their team's patients -->
|
||||
<record id="portal_team_coach_partner_access" model="ir.rule">
|
||||
<field name="name">Portal Team Coach Access to Partners</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="groups" eval="[(6, 0, [ref('bemade_sports_clinic.group_portal_team_coach')])]"/>
|
||||
<field name="perm_create" eval="True"/>
|
||||
<field name="perm_write" eval="True"/>
|
||||
<field name="perm_read" eval="True"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -36,61 +36,81 @@
|
|||
<input type="hidden" name="injury_id" t-att-value="injury.id"/>
|
||||
<input type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
|
||||
<!-- Top Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-12">
|
||||
<div class="d-flex justify-content-between">
|
||||
<a t-att-href="return_url" class="btn btn-secondary">
|
||||
<i class="fa fa-times"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Injury Details Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h4 class="mb-0">Injury Details</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Basic injury information -->
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="injury_date">Date of Injury</label>
|
||||
<div class="d-flex align-items-center">
|
||||
<input type="date" name="injury_date" id="injury_date" class="form-control"
|
||||
t-att-value="injury.injury_date" t-att-disabled="injury.injury_date_na"/>
|
||||
<div class="form-check ml-3">
|
||||
<input type="checkbox" name="injury_date_na" id="injury_date_na" class="form-check-input"
|
||||
t-att-checked="injury.injury_date_na"/>
|
||||
<label for="injury_date_na" class="form-check-label">N/A</label>
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted">Check N/A if exact date is unknown</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Diagnosis -->
|
||||
<div class="row mt-3">
|
||||
<div class="col-lg-12">
|
||||
<div class="form-group">
|
||||
<label for="diagnosis">Diagnosis/Description</label>
|
||||
<textarea name="diagnosis" id="diagnosis" class="form-control"
|
||||
rows="3" t-att-disabled="not is_treatment_prof and injury.stage != 'unverified'"><t t-esc="injury.diagnosis"/></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Treatment dates and status -->
|
||||
<div t-if="is_treatment_prof" class="row mt-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="external_notes">External Notes</label>
|
||||
<textarea name="external_notes" id="external_notes" class="form-control"
|
||||
rows="3"><t t-esc="injury.external_notes"/></textarea>
|
||||
<small class="text-muted">Notes visible to all team members</small>
|
||||
<label for="predicted_resolution_date">Predicted Resolution Date</label>
|
||||
<input type="date" name="predicted_resolution_date" id="predicted_resolution_date" class="form-control"
|
||||
t-att-value="injury.predicted_resolution_date"/>
|
||||
<small class="text-muted">Expected recovery timeline</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="resolution_date">Resolution Date</label>
|
||||
<input type="date" name="resolution_date" id="resolution_date" class="form-control"
|
||||
t-att-value="injury.resolution_date"/>
|
||||
<small class="text-muted">Actual recovery date (when resolved)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Fields only visible/editable to treatment professionals -->
|
||||
<!-- Status and treatment professionals -->
|
||||
<div t-if="is_treatment_prof" class="row mt-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="body_location">Body Location</label>
|
||||
<input type="text" class="form-control" name="body_location" id="body_location" t-att-value="injury.body_location"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="injury_type">Injury Type</label>
|
||||
<input type="text" class="form-control" name="injury_type" id="injury_type" t-att-value="injury.injury_type"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- More treatment professional fields -->
|
||||
<div t-if="is_treatment_prof" class="row mt-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="severity">Severity</label>
|
||||
<select name="severity" id="severity" class="form-control">
|
||||
<option value="">-- Select Severity --</option>
|
||||
<t t-foreach="severity_options" t-as="option">
|
||||
<option t-att-value="option[0]" t-att-selected="option[0] == injury.severity">
|
||||
<t t-esc="option[1]"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="stage">Status</label>
|
||||
|
|
@ -103,6 +123,19 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="form-group">
|
||||
<label for="treatment_professional_ids">Treatment Professionals</label>
|
||||
<select name="treatment_professional_ids" id="treatment_professional_ids" class="form-control" multiple="multiple">
|
||||
<t t-foreach="treatment_professionals" t-as="tp">
|
||||
<option t-att-value="tp.id" t-att-selected="tp.id in injury.treatment_professional_ids.ids">
|
||||
<t t-esc="tp.name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
<small class="text-muted">Hold Ctrl/Cmd to select multiple professionals</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Parental consent field (only visible to treatment professionals) -->
|
||||
|
|
@ -153,6 +186,25 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- External Notes Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<h4 class="mb-0">External Notes</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="form-group">
|
||||
<label for="external_notes">External Notes</label>
|
||||
<textarea name="external_notes" id="external_notes" class="form-control"
|
||||
rows="4"><t t-esc="injury.external_notes"/></textarea>
|
||||
<small class="text-muted">Notes visible to all team members</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action buttons -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-lg-12">
|
||||
|
|
@ -218,13 +270,8 @@
|
|||
<h2 t-if="context == 'injury'">Injury Treatment Notes</h2>
|
||||
<h2 t-else="">Patient Treatment Notes</h2>
|
||||
|
||||
<!-- Different back button based on context -->
|
||||
<t t-if="context == 'injury'">
|
||||
<a t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" class="btn btn-secondary">
|
||||
<i class="fa fa-arrow-left"></i> Back to Injury
|
||||
</a>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<!-- Back button only for patient context -->
|
||||
<t t-if="context == 'patient'">
|
||||
<a t-att-href="'/my/player?player_id=%s' % patient.id" class="btn btn-secondary">
|
||||
<i class="fa fa-arrow-left"></i> Back to Patient
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,20 @@
|
|||
<input type="hidden" name="patient_id" t-att-value="patient.id"/>
|
||||
<input type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
|
||||
<!-- Top Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-12">
|
||||
<div class="d-flex justify-content-between">
|
||||
<a t-att-href="return_url" class="btn btn-secondary">
|
||||
<i class="fa fa-times"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
|
|
@ -231,6 +245,20 @@
|
|||
<input type="hidden" name="contact_id" t-att-value="contact.id"/>
|
||||
<input type="hidden" name="return_url" t-att-value="return_url"/>
|
||||
|
||||
<!-- Top Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-12">
|
||||
<div class="d-flex justify-content-between">
|
||||
<a t-att-href="return_url" class="btn btn-secondary">
|
||||
<i class="fa fa-times"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
|
|
|
|||
|
|
@ -316,44 +316,44 @@
|
|||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-3">
|
||||
<h6 class="mb-1">Match Status</h6>
|
||||
<span t-if="player.match_status == 'yes'" class="badge badge-success badge-lg" style="color: #000 !important;">
|
||||
<h6 class="mb-1">Match</h6>
|
||||
<span t-if="player.match_status == 'yes'" class="text-success font-weight-bold h5">
|
||||
<i class="fa fa-check-circle"></i> Yes
|
||||
</span>
|
||||
<span t-elif="player.match_status == 'no'" class="badge badge-danger badge-lg" style="color: #fff !important;">
|
||||
<span t-elif="player.match_status == 'no'" class="text-danger font-weight-bold h5">
|
||||
<i class="fa fa-times-circle"></i> No
|
||||
</span>
|
||||
<span t-else="" class="badge badge-secondary badge-lg" style="color: #fff !important;">
|
||||
<span t-else="" class="text-muted font-weight-bold h5">
|
||||
<i class="fa fa-question-circle"></i> <span t-esc="player.match_status or 'Unknown'"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<h6 class="mb-1">Practice Status</h6>
|
||||
<span t-if="player.practice_status == 'yes'" class="badge badge-success badge-lg" style="color: #000 !important;">
|
||||
<h6 class="mb-1">Practice</h6>
|
||||
<span t-if="player.practice_status == 'yes'" class="text-success font-weight-bold h5">
|
||||
<i class="fa fa-check-circle"></i> Yes
|
||||
</span>
|
||||
<span t-elif="player.practice_status == 'no_contact'" class="badge badge-warning badge-lg" style="color: #000 !important;">
|
||||
<i class="fa fa-exclamation-triangle"></i> Yes, no contact
|
||||
<span t-elif="player.practice_status == 'no_contact'" class="text-warning font-weight-bold h5">
|
||||
<i class="fa fa-exclamation-triangle"></i> Yes, No Contact
|
||||
</span>
|
||||
<span t-elif="player.practice_status == 'no'" class="badge badge-danger badge-lg" style="color: #fff !important;">
|
||||
<span t-elif="player.practice_status == 'no'" class="text-danger font-weight-bold h5">
|
||||
<i class="fa fa-times-circle"></i> No
|
||||
</span>
|
||||
<span t-else="" class="badge badge-secondary badge-lg" style="color: #fff !important;">
|
||||
<span t-else="" class="text-muted font-weight-bold h5">
|
||||
<i class="fa fa-question-circle"></i> <span t-esc="player.practice_status or 'Unknown'"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-3" t-if="player.stage">
|
||||
<h6 class="mb-1">Status</h6>
|
||||
<span t-if="player.stage == 'healthy'" class="badge badge-success badge-lg" style="color: #000 !important;">
|
||||
<span t-if="player.stage == 'healthy'" class="text-success font-weight-bold h5">
|
||||
<i class="fa fa-heart"></i> Play OK
|
||||
</span>
|
||||
<span t-elif="player.stage == 'practice_ok'" class="badge badge-warning badge-lg" style="color: #000 !important;">
|
||||
<span t-elif="player.stage == 'practice_ok'" class="text-warning font-weight-bold h5">
|
||||
<i class="fa fa-running"></i> Practice OK
|
||||
</span>
|
||||
<span t-elif="player.stage == 'no_play'" class="badge badge-danger badge-lg" style="color: #fff !important;">
|
||||
<span t-elif="player.stage == 'no_play'" class="text-danger font-weight-bold h5">
|
||||
<i class="fa fa-ban"></i> Injured
|
||||
</span>
|
||||
<span t-else="" class="badge badge-secondary badge-lg" style="color: #fff !important;">
|
||||
<span t-else="" class="text-muted font-weight-bold h5">
|
||||
<i class="fa fa-question-circle"></i> <span t-esc="player.stage"/>
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -413,55 +413,60 @@
|
|||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Injury</th>
|
||||
<th>Status</th>
|
||||
<th>External Notes</th>
|
||||
<t t-if="is_treatment_prof">
|
||||
<th>Internal Notes</th>
|
||||
<t t-if="not is_treatment_prof">
|
||||
<th>External Notes</th>
|
||||
</t>
|
||||
<t t-if="is_treatment_prof">
|
||||
<th class="text-end">Actions</th>
|
||||
</t>
|
||||
<th class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="injuries" t-as="injury">
|
||||
<tr t-attf-class="{{ 'text-danger' if injury.stage == 'unverified' else 'text-warning' if injury.stage == 'active' else '' }}">
|
||||
<tr t-attf-class="{{ 'text-warning' if injury.stage == 'unverified' else 'text-danger' if injury.stage == 'active' else '' }}">
|
||||
<td>
|
||||
<span t-field="injury.injury_date" class="text-wrap" t-options="{'widget': 'date'}"/>
|
||||
<t t-if="is_treatment_prof">
|
||||
<a t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" style="text-decoration: none; color: inherit;">
|
||||
<span t-field="injury.injury_date" class="text-wrap" t-options="{'widget': 'date'}"/>
|
||||
</a>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-field="injury.injury_date" class="text-wrap" t-options="{'widget': 'date'}"/>
|
||||
</t>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="injury.diagnosis" class="text-wrap"/>
|
||||
<t t-if="is_treatment_prof">
|
||||
<a t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" style="text-decoration: none; color: inherit;">
|
||||
<span t-field="injury.diagnosis" class="text-wrap"/>
|
||||
</a>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-field="injury.diagnosis" class="text-wrap"/>
|
||||
</t>
|
||||
</td>
|
||||
<td>
|
||||
<span t-if="injury.stage == 'unverified'">Unverified</span>
|
||||
<span t-elif="injury.stage == 'active'">Active</span>
|
||||
<span t-elif="injury.stage == 'resolved'">Resolved</span>
|
||||
</td>
|
||||
<td>
|
||||
<div t-if="injury.external_notes" class="text-wrap">
|
||||
<span t-out="injury.external_notes"/>
|
||||
</div>
|
||||
<div t-else="" class="text-muted">No external notes</div>
|
||||
</td>
|
||||
<t t-if="is_treatment_prof">
|
||||
<t t-if="not is_treatment_prof">
|
||||
<td>
|
||||
<div t-if="injury.internal_notes" class="text-wrap">
|
||||
<span t-out="injury.internal_notes"/>
|
||||
<div t-if="injury.external_notes" class="text-wrap">
|
||||
<span t-out="injury.external_notes"/>
|
||||
</div>
|
||||
<div t-else="" class="text-muted">No external notes</div>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="is_treatment_prof">
|
||||
<td class="text-end">
|
||||
<div class="btn-group">
|
||||
<a t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" class="btn btn-sm btn-primary">
|
||||
<i class="fa fa-edit"></i> Edit
|
||||
</a>
|
||||
<a t-att-href="'/my/injury/notes?injury_id=%s' % injury.id" class="btn btn-sm btn-info">
|
||||
<i class="fa fa-clipboard-list"></i> Notes
|
||||
</a>
|
||||
<a t-att-href="'/my/injury/documents?injury_id=%s' % injury.id" class="btn btn-sm btn-secondary">
|
||||
<i class="fa fa-file-medical"></i> Docs
|
||||
</a>
|
||||
</div>
|
||||
<div t-else="" class="text-muted">No internal notes</div>
|
||||
</td>
|
||||
</t>
|
||||
<td class="text-end">
|
||||
<div class="btn-group">
|
||||
<a t-if="is_treatment_prof" t-att-href="'/my/injury/edit?injury_id=%s' % injury.id" class="btn btn-sm btn-primary">
|
||||
<i class="fa fa-edit"></i> Edit
|
||||
</a>
|
||||
<a t-if="is_treatment_prof" t-att-href="'/my/injury/notes?injury_id=%s' % injury.id" class="btn btn-sm btn-info">
|
||||
<i class="fa fa-clipboard-list"></i> Notes
|
||||
</a>
|
||||
<a t-if="is_treatment_prof" t-att-href="'/my/injury/documents?injury_id=%s' % injury.id" class="btn btn-sm btn-secondary">
|
||||
<i class="fa fa-file-medical"></i> Docs
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
|
|
@ -498,28 +503,10 @@
|
|||
<td><strong>Age:</strong></td>
|
||||
<td t-esc="player.age"/>
|
||||
</tr>
|
||||
<tr t-if="is_treatment_prof and player.last_consultation_date">
|
||||
<tr t-if="is_treatment_prof">
|
||||
<td><strong>Last Consultation:</strong></td>
|
||||
<td t-esc="player.last_consultation_date"/>
|
||||
</tr>
|
||||
<tr t-if="is_treatment_prof and player.injured_since">
|
||||
<td><strong>Injured Since:</strong></td>
|
||||
<td>
|
||||
<span t-esc="player.injured_since"/>
|
||||
<small class="text-muted ms-2">
|
||||
(<span t-esc="(datetime.date.today() - player.injured_since).days if player.injured_since else 0"/> days)
|
||||
</small>
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-if="is_treatment_prof and player.active_injury_count > 0">
|
||||
<td><strong>Active Injuries:</strong></td>
|
||||
<td>
|
||||
<span class="badge badge-warning badge-lg">
|
||||
<i class="fa fa-exclamation-triangle"></i>
|
||||
<span t-esc="player.active_injury_count"/> active
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-if="is_treatment_prof and player.allergies">
|
||||
<td><strong>Allergies:</strong></td>
|
||||
<td>
|
||||
|
|
@ -611,21 +598,21 @@
|
|||
<h5>Status Information</h5>
|
||||
<table class="table table-borderless">
|
||||
<tr>
|
||||
<td><strong>Match Status:</strong></td>
|
||||
<td>
|
||||
<span t-if="player.match_status == 'yes'" class="badge badge-success">Yes</span>
|
||||
<span t-elif="player.match_status == 'no'" class="badge badge-danger">No</span>
|
||||
<span t-else="" class="badge badge-secondary" t-esc="player.match_status"/>
|
||||
</td>
|
||||
<td><strong>Match:</strong></td>
|
||||
<td>
|
||||
<span t-if="player.match_status == 'yes'" class="text-success font-weight-bold"><i class="fa fa-check-circle"></i> Yes</span>
|
||||
<span t-elif="player.match_status == 'no'" class="text-danger font-weight-bold"><i class="fa fa-times-circle"></i> No</span>
|
||||
<span t-else="" class="text-muted" t-esc="player.match_status"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Practice Status:</strong></td>
|
||||
<td>
|
||||
<span t-if="player.practice_status == 'yes'" class="badge badge-success">Available</span>
|
||||
<span t-elif="player.practice_status == 'no_contact'" class="badge badge-warning">Available, No Contact</span>
|
||||
<span t-elif="player.practice_status == 'no'" class="badge badge-danger">Not Available</span>
|
||||
<span t-else="" class="badge badge-secondary" t-esc="player.practice_status"/>
|
||||
</td>
|
||||
<td><strong>Practice:</strong></td>
|
||||
<td>
|
||||
<span t-if="player.practice_status == 'yes'" class="text-success font-weight-bold"><i class="fa fa-check-circle"></i> Yes</span>
|
||||
<span t-elif="player.practice_status == 'no_contact'" class="text-warning font-weight-bold"><i class="fa fa-exclamation-triangle"></i> Yes, No Contact</span>
|
||||
<span t-elif="player.practice_status == 'no'" class="text-danger font-weight-bold"><i class="fa fa-times-circle"></i> No</span>
|
||||
<span t-else="" class="text-muted" t-esc="player.practice_status"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr t-if="player.predicted_return_date">
|
||||
<td><strong>Predicted Return Date:</strong></td>
|
||||
|
|
@ -636,13 +623,13 @@
|
|||
<td t-esc="player.return_date"/>
|
||||
</tr>
|
||||
<tr t-if="player.stage">
|
||||
<td><strong>Current Stage:</strong></td>
|
||||
<td>
|
||||
<span t-if="player.stage == 'healthy'" class="badge badge-success">Healthy</span>
|
||||
<span t-elif="player.stage == 'practice_ok'" class="badge badge-warning">Practice OK</span>
|
||||
<span t-elif="player.stage == 'no_play'" class="badge badge-danger">No Play</span>
|
||||
<span t-else="" class="badge badge-secondary" t-esc="player.stage"/>
|
||||
</td>
|
||||
<td><strong>Status:</strong></td>
|
||||
<td>
|
||||
<span t-if="player.stage == 'healthy'" class="text-success font-weight-bold"><i class="fa fa-heart"></i> Play OK</span>
|
||||
<span t-elif="player.stage == 'practice_ok'" class="text-warning font-weight-bold"><i class="fa fa-running"></i> Practice OK</span>
|
||||
<span t-elif="player.stage == 'no_play'" class="text-danger font-weight-bold"><i class="fa fa-ban"></i> Injured</span>
|
||||
<span t-else="" class="text-muted" t-esc="player.stage"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,19 +11,7 @@
|
|||
<form action="/my/patient/injury/create" method="post" class="mt-3">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input type="hidden" name="patient_id" t-att-value="patient.id"/>
|
||||
<div class="form-group row">
|
||||
<label for="team_id" class="col-md-3 col-form-label">Team</label>
|
||||
<div class="col-md-9">
|
||||
<select class="form-control" id="team_id" name="team_id" required="required">
|
||||
<t t-if="not default_team_id">
|
||||
<option value="">-- Select Team --</option>
|
||||
</t>
|
||||
<t t-foreach="teams" t-as="team">
|
||||
<option t-att-value="team.id" t-att-selected="team.id == default_team_id"><t t-esc="team.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="injury_date" class="col-md-3 col-form-label">Injury Date</label>
|
||||
<div class="col-md-9">
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<group>
|
||||
<group col="2">
|
||||
<field name="patient_id" invisible="1"/>
|
||||
<field name="team_id"/>
|
||||
<field name="team_id" groups="base.group_no_one"/>
|
||||
<span colspan="2">
|
||||
<label for="injury_date"/>
|
||||
<field name="injury_date" widget="date" class="oe_inline"/>
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
multi_edit="True">
|
||||
<field name="patient_id" column_invisible="True"/>
|
||||
<field name="injury_date" widget="date"/>
|
||||
<field name="team_id"/>
|
||||
<field name="team_id" groups="base.group_no_one"/>
|
||||
<field name="diagnosis"/>
|
||||
<field name="predicted_resolution_date" widget="date"/>
|
||||
<field name="resolution_date" widget="date"/>
|
||||
|
|
|
|||
|
|
@ -341,6 +341,20 @@
|
|||
<input type="hidden" name="activity_id" t-att-value="activity.id"/>
|
||||
<input type="hidden" name="return_url" value="/my/activities"/>
|
||||
|
||||
<!-- Top Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-12">
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="/my/activities" class="btn btn-secondary">
|
||||
<i class="fa fa-times"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fa fa-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
|
|
|
|||
Loading…
Reference in a new issue