bemade-addons/bemade_sports_clinic/controllers/task_management_portal.py
Denis Durepos ca57ec8f16 [IMP] bemade_sports_clinic: Refactor portal views and enhance treatment notes
- Refactor portal templates to eliminate intra-module template inheritance
- Integrate emergency contacts section into player injuries template
- Add full internal admin views for treatment notes with chatter support
- Fix ORM warning in test_rights by using proper ORM commands
- Update manifest to reflect new functionality (v18.0.1.9.0)

This refactoring improves template stability by removing XPath errors and
provides treatment professionals with better access to emergency contacts
and treatment notes both in portal and backend interfaces.
2025-07-11 21:47:50 -04:00

241 lines
10 KiB
Python

import logging
from odoo import http, fields, _
from odoo.exceptions import UserError, ValidationError
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal, pager
from datetime import timedelta
_logger = logging.getLogger(__name__)
class TaskManagementPortal(CustomerPortal):
"""Controller for task management functionality in the portal"""
def _check_access_to_task_model(self, model_name, record_id):
"""Verify the user has access to the record"""
user = request.env.user
record = request.env[model_name].browse(int(record_id))
# Check if user is a treatment professional
is_treatment_prof = user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
# Check if record exists
if not record.exists():
raise UserError(_('Record not found.'))
# For patient records, check team access
if model_name == 'sports.patient':
patient_id_int = int(record_id)
accessible_teams = request.env['sports.team'].search([
('staff_ids.user_id', '=', user.id),
('patient_ids', 'in', patient_id_int)
])
if not accessible_teams and not is_treatment_prof:
raise UserError(_('You do not have access to this patient.'))
# For injury records, check team access through the patient
elif model_name == 'sports.patient.injury':
patient = record.patient_id
team = record.team_id
if team:
is_team_staff = team.staff_ids.filtered(
lambda s: user.partner_id in s.user_ids.partner_id
)
if not is_team_staff and not is_treatment_prof:
raise UserError(_('You do not have access to this injury.'))
else:
raise UserError(_('This injury is not associated with a team.'))
return record
@http.route(['/my/activities'], type='http', auth='user', website=True)
def view_activities(self, **kw):
"""Display list of activities assigned to the current user"""
user = request.env.user
partner = user.partner_id
# Get all activities assigned to this user
activities = request.env['mail.activity'].search([
('user_id', '=', user.id),
('res_model', 'in', ['sports.patient', 'sports.patient.injury']),
], order='date_deadline asc')
# Group activities by model
patient_activities = activities.filtered(lambda a: a.res_model == 'sports.patient')
injury_activities = activities.filtered(lambda a: a.res_model == 'sports.patient.injury')
# Get activity types for filtering
activity_types = request.env['mail.activity.type'].search([])
values = {
'activities': activities,
'patient_activities': patient_activities,
'injury_activities': injury_activities,
'activity_types': activity_types,
'page_name': 'activities',
}
return request.render('bemade_sports_clinic.portal_my_activities', values)
@http.route(['/my/activity/create'], type='http', auth='user', website=True)
def create_activity_form(self, model=None, res_id=None, **kw):
"""Display form to create a new activity"""
# Validate model and res_id
valid_models = ['sports.patient', 'sports.patient.injury']
if model not in valid_models or not res_id:
return request.redirect('/my/activities')
try:
record = self._check_access_to_task_model(model, res_id)
except UserError as e:
return request.render('portal.403', {'error': str(e)})
# Get activity types
activity_types = request.env['mail.activity.type'].search([])
# Get users that can be assigned to activities
domain = []
# If this is an injury record, filter by team staff
if model == 'sports.patient.injury':
team = record.team_id
if team:
domain = [('partner_id', 'in', team.staff_ids.mapped('partner_id').ids)]
# Only treatment professionals can see and assign all users
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
if not is_treatment_prof:
domain.append(('id', '=', request.env.user.id))
assignable_users = request.env['res.users'].search(domain)
# Prepare record name for display
record_name = record.name if hasattr(record, 'name') else record.display_name
# Default return URL
if model == 'sports.patient':
return_url = f'/my/player?player_id={res_id}'
else: # sports.patient.injury
return_url = f'/my/player?player_id={record.patient_id.id}'
values = {
'activity_types': activity_types,
'assignable_users': assignable_users,
'record': record,
'record_name': record_name,
'model': model,
'res_id': res_id,
'default_user_id': request.env.user.id,
'return_url': kw.get('return_url', return_url),
'page_name': 'create_activity',
}
return request.render('bemade_sports_clinic.portal_create_activity', values)
@http.route(['/my/activity/save'], type='http', auth='user', website=True, methods=['POST'])
def create_activity_submit(self, **post):
"""Process form submission to create a new activity"""
model = post.get('model')
res_id = post.get('res_id')
# Validate model and res_id
valid_models = ['sports.patient', 'sports.patient.injury']
if model not in valid_models or not res_id:
return request.redirect('/my/activities')
try:
record = self._check_access_to_task_model(model, res_id)
except UserError as e:
return request.render('portal.403', {'error': str(e)})
# Validate required fields
activity_type_id = post.get('activity_type_id')
summary = post.get('summary')
user_id = post.get('user_id')
date_deadline = post.get('date_deadline')
if not activity_type_id or not summary or not user_id or not date_deadline:
return_url = post.get('return_url', '/my/activities')
return request.redirect(f'{return_url}&error=missing_fields')
# Check if the assigned user is valid
is_treatment_prof = request.env.user.has_group('bemade_sports_clinic.group_sports_clinic_treatment_professional')
assigned_user = request.env['res.users'].browse(int(user_id))
# Only treatment professionals can assign to other users
if not is_treatment_prof and assigned_user.id != request.env.user.id:
return_url = post.get('return_url', '/my/activities')
return request.redirect(f'{return_url}&error=invalid_user')
# Create the activity
vals = {
'activity_type_id': int(activity_type_id),
'summary': summary,
'note': post.get('note', ''),
'user_id': int(user_id),
'date_deadline': date_deadline,
'res_model_id': request.env['ir.model']._get_id(model),
'res_id': int(res_id),
}
activity = request.env['mail.activity'].sudo().create(vals)
# Redirect to the return URL or activities page
return_url = post.get('return_url', '/my/activities')
return request.redirect(f'{return_url}&success=activity_created')
@http.route(['/my/activity/complete'], type='http', auth='user', website=True, methods=['POST'])
def complete_activity(self, activity_id, **post):
"""Mark an activity as done"""
activity = request.env['mail.activity'].browse(int(activity_id))
# Check if the activity exists and belongs to the current user
if not activity.exists() or activity.user_id != request.env.user:
return request.redirect('/my/activities')
# Add feedback if provided
feedback = post.get('feedback', '')
# Mark the activity as done
activity.sudo().action_feedback(feedback=feedback)
# Redirect to activities page
return request.redirect('/my/activities')
@http.route(['/my/activity/cancel'], type='http', auth='user', website=True, methods=['POST'])
def cancel_activity(self, activity_id, **post):
"""Cancel an activity"""
activity = request.env['mail.activity'].browse(int(activity_id))
# Check if the activity exists and belongs to the current user
if not activity.exists() or activity.user_id != request.env.user:
return request.redirect('/my/activities')
# Cancel the activity
activity.sudo().unlink()
# Redirect to activities page
return request.redirect('/my/activities')
@http.route(['/my/activity/reschedule'], type='http', auth='user', website=True, methods=['POST'])
def reschedule_activity(self, activity_id, **post):
"""Reschedule an activity to a new date"""
activity = request.env['mail.activity'].browse(int(activity_id))
# Check if the activity exists and belongs to the current user
if not activity.exists() or activity.user_id != request.env.user:
return request.redirect('/my/activities')
# Get new deadline
new_deadline = post.get('new_deadline')
if not new_deadline:
return request.redirect('/my/activities')
# Update the deadline
activity.sudo().write({'date_deadline': new_deadline})
# Redirect to activities page
return request.redirect('/my/activities')