""" PX Sources UI views - HTML template rendering """ from django.contrib import messages from django.contrib.auth.decorators import login_required from django.db import models from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.utils.translation import gettext_lazy as _ from .models import PXSource, SourceUser from apps.accounts.models import User @login_required def source_list(request): """ List all PX sources """ sources = PXSource.objects.all() # Filter by active status is_active = request.GET.get('is_active') if is_active: sources = sources.filter(is_active=is_active == 'true') # Search search = request.GET.get('search') if search: sources = sources.filter( models.Q(name_en__icontains=search) | models.Q(name_ar__icontains=search) | models.Q(description__icontains=search) ) sources = sources.order_by('name_en') context = { 'sources': sources, 'is_active': is_active, 'search': search, } return render(request, 'px_sources/source_list.html', context) @login_required def source_detail(request, pk): """ View source details """ source = get_object_or_404(PXSource, pk=pk) usage_records = source.usage_records.select_related( 'content_type', 'hospital', 'user' ).order_by('-created_at')[:20] # Get source users for this source source_users = source.source_users.select_related('user').order_by('-created_at') # Get available users (not already assigned to this source) assigned_user_ids = source_users.values_list('user_id', flat=True) available_users = User.objects.exclude(id__in=assigned_user_ids).order_by('email') context = { 'source': source, 'usage_records': usage_records, 'source_users': source_users, 'available_users': available_users, } return render(request, 'px_sources/source_detail.html', context) @login_required def source_create(request): """ Create a new PX source """ # if not (request.user.is_px_admin() or request.user.is_hospital_admin()): # messages.error(request, _("You don't have permission to create sources.")) # return redirect('px_sources:source_list') if request.method == 'POST': try: source = PXSource( name_en=request.POST.get('name_en'), name_ar=request.POST.get('name_ar', ''), description=request.POST.get('description', ''), is_active=request.POST.get('is_active') == 'on', ) source.save() messages.success(request, _("Source created successfully!")) return redirect('px_sources:source_detail', pk=source.pk) except Exception as e: messages.error(request, _("Error creating source: {}").format(str(e))) context = {} return render(request, 'px_sources/source_form.html', context) @login_required def source_edit(request, pk): """ Edit an existing PX source """ if not (request.user.is_px_admin() or request.user.is_hospital_admin()): messages.error(request, _("You don't have permission to edit sources.")) return redirect('px_sources:source_detail', pk=pk) source = get_object_or_404(PXSource, pk=pk) if request.method == 'POST': try: source.name_en = request.POST.get('name_en') source.name_ar = request.POST.get('name_ar', '') source.description = request.POST.get('description', '') source.is_active = request.POST.get('is_active') == 'on' source.save() messages.success(request, _("Source updated successfully!")) return redirect('px_sources:source_detail', pk=source.pk) except Exception as e: messages.error(request, _("Error updating source: {}").format(str(e))) context = { 'source': source, } return render(request, 'px_sources/source_form.html', context) @login_required def source_delete(request, pk): """ Delete a PX source """ if not request.user.is_px_admin(): messages.error(request, _("You don't have permission to delete sources.")) return redirect('px_sources:source_detail', pk=pk) source = get_object_or_404(PXSource, pk=pk) if request.method == 'POST': source_name = source.name_en source.delete() messages.success(request, _("Source '{}' deleted successfully!").format(source_name)) return redirect('px_sources:source_list') context = { 'source': source, } return render(request, 'px_sources/source_confirm_delete.html', context) @login_required def source_toggle_status(request, pk): """ Toggle source active status (AJAX) """ if not (request.user.is_px_admin() or request.user.is_hospital_admin()): return JsonResponse({'error': 'Permission denied'}, status=403) if request.method != 'POST': return JsonResponse({'error': 'Method not allowed'}, status=405) source = get_object_or_404(PXSource, pk=pk) source.is_active = not source.is_active source.save() return JsonResponse({ 'success': True, 'is_active': source.is_active, 'message': 'Source {} successfully'.format( 'activated' if source.is_active else 'deactivated' ) }) @login_required def ajax_search_sources(request): """ AJAX endpoint for searching sources """ term = request.GET.get('term', '') queryset = PXSource.objects.filter(is_active=True) if term: queryset = queryset.filter( models.Q(name_en__icontains=term) | models.Q(name_ar__icontains=term) | models.Q(description__icontains=term) ) sources = queryset.order_by('name_en')[:20] results = [ { 'id': str(source.id), 'text': source.name_en, 'name_en': source.name_en, 'name_ar': source.name_ar, } for source in sources ] return JsonResponse({'results': results}) @login_required def source_user_dashboard(request): """ Dashboard for source users. Shows: - User's assigned source - Statistics (complaints, inquiries from their source) - Create buttons for complaints/inquiries - Tables of recent complaints/inquiries from their source """ # Get source user profile source_user = SourceUser.get_active_source_user(request.user) if not source_user: messages.error( request, _("You are not assigned as a source user. Please contact your administrator.") ) return redirect('/') # Get source source = source_user.source # Get complaints from this source (recent 5) from apps.complaints.models import Complaint complaints = Complaint.objects.filter(source=source).select_related( 'patient', 'hospital', 'assigned_to' ).order_by('-created_at')[:5] # Get inquiries from this source (recent 5) from apps.complaints.models import Inquiry inquiries = Inquiry.objects.filter(source=source).select_related( 'patient', 'hospital', 'assigned_to' ).order_by('-created_at')[:5] # Calculate statistics total_complaints = Complaint.objects.filter(source=source).count() total_inquiries = Inquiry.objects.filter(source=source).count() open_complaints = Complaint.objects.filter(source=source, status='open').count() open_inquiries = Inquiry.objects.filter(source=source, status='open').count() context = { 'source_user': source_user, 'source': source, 'complaints': complaints, 'inquiries': inquiries, 'total_complaints': total_complaints, 'total_inquiries': total_inquiries, 'open_complaints': open_complaints, 'open_inquiries': open_inquiries, 'can_create_complaints': source_user.can_create_complaints, 'can_create_inquiries': source_user.can_create_inquiries, } return render(request, 'px_sources/source_user_dashboard.html', context) @login_required def ajax_source_choices(request): """ AJAX endpoint for getting source choices for dropdowns """ queryset = PXSource.get_active_sources() choices = [ { 'id': str(source.id), 'name_en': source.name_en, 'name_ar': source.name_ar, } for source in queryset ] return JsonResponse({'choices': choices}) @login_required def source_user_create(request, pk): """ Create a new source user for a specific PX source. Only PX admins can create source users. """ # if not request.user.is_px_admin(): # messages.error(request, _("You don't have permission to create source users.")) # return redirect('px_sources:source_detail', pk=pk) source = get_object_or_404(PXSource, pk=pk) if request.method == 'POST': user_id = request.POST.get('user') user = get_object_or_404(User, pk=user_id) try: # Check if user already has a source user profile if SourceUser.objects.filter(user=user).exists(): messages.error(request, _("User already has a source profile. A user can only manage one source.")) return redirect('px_sources:source_detail', pk=pk) source_user = SourceUser.objects.create( user=user, source=source, is_active=request.POST.get('is_active') == 'on', can_create_complaints=request.POST.get('can_create_complaints') == 'on', can_create_inquiries=request.POST.get('can_create_inquiries') == 'on', ) messages.success(request, _("Source user created successfully!")) return redirect('px_sources:source_detail', pk=pk) except Exception as e: messages.error(request, _("Error creating source user: {}").format(str(e))) context = { 'source': source, 'available_users': User.objects.exclude( id__in=source.source_users.values_list('user_id', flat=True) ).order_by('email'), } return render(request, 'px_sources/source_user_form.html', context) @login_required def source_user_edit(request, pk, user_pk): """ Edit an existing source user. Only PX admins can edit source users. """ if not request.user.is_px_admin(): messages.error(request, _("You don't have permission to edit source users.")) return redirect('px_sources:source_detail', pk=pk) source = get_object_or_404(PXSource, pk=pk) source_user = get_object_or_404(SourceUser, pk=user_pk, source=source) if request.method == 'POST': try: source_user.is_active = request.POST.get('is_active') == 'on' source_user.can_create_complaints = request.POST.get('can_create_complaints') == 'on' source_user.can_create_inquiries = request.POST.get('can_create_inquiries') == 'on' source_user.save() messages.success(request, _("Source user updated successfully!")) return redirect('px_sources:source_detail', pk=pk) except Exception as e: messages.error(request, _("Error updating source user: {}").format(str(e))) context = { 'source': source, 'source_user': source_user, } return render(request, 'px_sources/source_user_form.html', context) @login_required def source_user_delete(request, pk, user_pk): """ Delete a source user. Only PX admins can delete source users. """ if not request.user.is_px_admin(): messages.error(request, _("You don't have permission to delete source users.")) return redirect('px_sources:source_detail', pk=pk) source = get_object_or_404(PXSource, pk=pk) source_user = get_object_or_404(SourceUser, pk=user_pk, source=source) if request.method == 'POST': user_name = source_user.user.get_full_name() or source_user.user.email source_user.delete() messages.success(request, _("Source user '{}' deleted successfully!").format(user_name)) return redirect('px_sources:source_detail', pk=pk) context = { 'source': source, 'source_user': source_user, } return render(request, 'px_sources/source_user_confirm_delete.html', context) @login_required def source_user_toggle_status(request, pk, user_pk): """ Toggle source user active status (AJAX). Only PX admins can toggle status. """ if not request.user.is_px_admin(): return JsonResponse({'error': 'Permission denied'}, status=403) if request.method != 'POST': return JsonResponse({'error': 'Method not allowed'}, status=405) source = get_object_or_404(PXSource, pk=pk) source_user = get_object_or_404(SourceUser, pk=user_pk, source=source) source_user.is_active = not source_user.is_active source_user.save() return JsonResponse({ 'success': True, 'is_active': source_user.is_active, 'message': 'Source user {} successfully'.format( 'activated' if source_user.is_active else 'deactivated' ) }) @login_required def source_user_complaint_list(request): """ List complaints for the current Source User. Shows only complaints from their assigned source. """ # Get source user profile source_user = SourceUser.get_active_source_user(request.user) if not source_user: messages.error( request, _("You are not assigned as a source user. Please contact your administrator.") ) return redirect('/') source = source_user.source # Get complaints from this source from apps.complaints.models import Complaint from django.db.models import Q complaints_queryset = Complaint.objects.filter(source=source).select_related( 'patient', 'hospital', 'assigned_to', 'created_by' ) # Apply filters status_filter = request.GET.get('status') if status_filter: complaints_queryset = complaints_queryset.filter(status=status_filter) priority_filter = request.GET.get('priority') if priority_filter: complaints_queryset = complaints_queryset.filter(priority=priority_filter) category_filter = request.GET.get('category') if category_filter: complaints_queryset = complaints_queryset.filter(category=category_filter) # Search search = request.GET.get('search') if search: complaints_queryset = complaints_queryset.filter( Q(title__icontains=search) | Q(description__icontains=search) | Q(patient__first_name__icontains=search) | Q(patient__last_name__icontains=search) ) # Order and paginate complaints_queryset = complaints_queryset.order_by('-created_at') from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger paginator = Paginator(complaints_queryset, 20) # 20 per page page = request.GET.get('page') try: complaints = paginator.page(page) except PageNotAnInteger: complaints = paginator.page(1) except EmptyPage: complaints = paginator.page(paginator.num_pages) context = { 'complaints': complaints, 'source_user': source_user, 'source': source, 'status_filter': status_filter, 'priority_filter': priority_filter, 'category_filter': category_filter, 'search': search, 'complaints_count': complaints_queryset.count(), } return render(request, 'px_sources/source_user_complaint_list.html', context) @login_required def source_user_inquiry_list(request): """ List inquiries for the current Source User. Shows only inquiries from their assigned source. """ # Get source user profile source_user = SourceUser.get_active_source_user(request.user) if not source_user: messages.error( request, _("You are not assigned as a source user. Please contact your administrator.") ) return redirect('/') source = source_user.source # Get inquiries from this source from apps.complaints.models import Inquiry from django.db.models import Q inquiries_queryset = Inquiry.objects.filter(source=source).select_related( 'patient', 'hospital', 'assigned_to', 'created_by' ) # Apply filters status_filter = request.GET.get('status') if status_filter: inquiries_queryset = inquiries_queryset.filter(status=status_filter) category_filter = request.GET.get('category') if category_filter: inquiries_queryset = inquiries_queryset.filter(category=category_filter) # Search search = request.GET.get('search') if search: inquiries_queryset = inquiries_queryset.filter( Q(subject__icontains=search) | Q(message__icontains=search) | Q(contact_name__icontains=search) ) # Order and paginate inquiries_queryset = inquiries_queryset.order_by('-created_at') from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger paginator = Paginator(inquiries_queryset, 20) # 20 per page page = request.GET.get('page') try: inquiries = paginator.page(page) except PageNotAnInteger: inquiries = paginator.page(1) except EmptyPage: inquiries = paginator.page(paginator.num_pages) context = { 'inquiries': inquiries, 'source_user': source_user, 'source': source, 'status_filter': status_filter, 'category_filter': category_filter, 'search': search, 'inquiries_count': inquiries_queryset.count(), } return render(request, 'px_sources/source_user_inquiry_list.html', context)