2025-10-06 15:25:37 +03:00

3809 lines
126 KiB
Python

"""
Core app views for hospital management system with comprehensive CRUD operations.
"""
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import (
TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView
)
from django.http import JsonResponse
from django.db.models import Count, Q
from django.utils import timezone
from django.contrib import messages
from django.urls import reverse_lazy, reverse
from accounts.models import User
from datetime import timedelta
from .models import (
Tenant, AuditLogEntry, SystemConfiguration, SystemNotification,
IntegrationLog
)
from hr.models import Department
from hr.forms import DepartmentForm
# Create aliases for models to match the views
AuditLog = AuditLogEntry
from .forms import (
TenantForm, SystemConfigurationForm, SystemNotificationForm,CoreSearchForm
)
from .utils import AuditLogger
# ============================================================================
# DASHBOARD AND OVERVIEW VIEWS
# ============================================================================
class DashboardView(LoginRequiredMixin, TemplateView):
"""
Main dashboard view.
"""
template_name = 'core/dashboard.html'
def get_context_data(self, **kwargs):
tenant = self.request.user.tenant
context = super().get_context_data(**kwargs)
if tenant:
# Get dashboard statistics
context.update({
'tenant': tenant,
'recent_audit_logs': AuditLogEntry.objects.filter(
tenant=tenant
).order_by('-timestamp')[:10],
'active_notifications': SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant=None),
is_active=True,
start_date__lte=timezone.now(),
end_date__gte=timezone.now()
).order_by('-priority', '-created_at')[:5],
'total_departments': Department.objects.filter(tenant=tenant).count(),
'total_configurations': SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
).count(),
})
return context
class TenantListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
"""
List all tenants (Super admin only).
"""
model = Tenant
template_name = 'core/tenants/tenant_list.html'
context_object_name = 'tenants'
paginate_by = 20
permission_required = 'core.view_tenant'
def get_queryset(self):
queryset = Tenant.objects.all().order_by('name')
# Apply search filter
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(name__icontains=search) |
Q(domain__icontains=search) |
Q(contact_email__icontains=search)
)
# Apply status filter
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(is_active=(status == 'active'))
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search_form'] = CoreSearchForm(self.request.GET)
return context
class TenantDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
"""
Display tenant details.
"""
model = Tenant
template_name = 'core/tenants/tenant_detail.html'
context_object_name = 'tenant'
permission_required = 'core.view_tenant'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.object
# Get tenant statistics
context.update({
'user_count': tenant.get_user_count(),
'patient_count': tenant.get_patient_count(),
'recent_audit_logs': AuditLogEntry.objects.filter(
tenant=tenant
).order_by('-timestamp')[:10],
'departments': Department.objects.filter(tenant=tenant).order_by('name'),
'configurations': SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
).order_by('category', 'key'),
})
return context
class TenantCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create new tenant.
"""
model = Tenant
form_class = TenantForm
template_name = 'core/tenants/tenant_form.html'
permission_required = 'core.add_tenant'
success_url = reverse_lazy('core:tenant_list')
def form_valid(self, form):
response = super().form_valid(form)
# Log tenant creation
AuditLogger.log_event(
tenant=None, # System level event
event_type='CREATE',
event_category='SYSTEM_ADMINISTRATION',
action='Create Tenant',
description=f'Created new tenant: {self.object.name}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Tenant "{self.object.name}" created successfully.')
return response
class TenantUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update tenant information.
"""
model = Tenant
form_class = TenantForm
template_name = 'core/tenants/tenant_form.html'
permission_required = 'core.change_tenant'
def get_success_url(self):
return reverse('core:tenant_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log tenant update
AuditLogger.log_event(
tenant=self.object,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Update Tenant',
description=f'Updated tenant: {self.object.name}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Tenant "{self.object.name}" updated successfully.')
return response
class TenantDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete tenant (soft delete to inactive).
"""
model = Tenant
template_name = 'core/tenants/tenant_confirm_delete.html'
permission_required = 'core.delete_tenant'
success_url = reverse_lazy('core:tenant_list')
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
# Soft delete - set to inactive
self.object.is_active = False
self.object.save()
# Log tenant deletion
AuditLogger.log_event(
tenant=self.object,
event_type='DELETE',
event_category='SYSTEM_ADMINISTRATION',
action='Deactivate Tenant',
description=f'Deactivated tenant: {self.object.name}',
user=request.user,
content_object=self.object,
request=request
)
messages.success(request, f'Tenant "{self.object.name}" deactivated successfully.')
return redirect(self.success_url)
class AuditLogListView(LoginRequiredMixin, ListView):
"""
Audit log listing view.
"""
model = AuditLogEntry
template_name = 'core/audit_logs/audit_log.html'
context_object_name = 'audit_logs'
paginate_by = 50
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return AuditLogEntry.objects.none()
queryset = AuditLogEntry.objects.filter(tenant=tenant)
# Apply filters
event_type = self.request.GET.get('event_type')
if event_type:
queryset = queryset.filter(event_type=event_type)
event_category = self.request.GET.get('event_category')
if event_category:
queryset = queryset.filter(event_category=event_category)
user_id = self.request.GET.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
date_from = self.request.GET.get('date_from')
if date_from:
queryset = queryset.filter(timestamp__gte=date_from)
date_to = self.request.GET.get('date_to')
if date_to:
queryset = queryset.filter(timestamp__lte=date_to)
return queryset.order_by('-timestamp')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
# Get filter options
context.update({
'event_types': AuditLogEntry.objects.filter(
tenant=tenant
).values_list('event_type', flat=True).distinct(),
'event_categories': AuditLogEntry.objects.filter(
tenant=tenant
).values_list('event_category', flat=True).distinct(),
})
return context
class AuditLogDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed audit log entry.
"""
model = AuditLogEntry
template_name = 'core/audit_logs/audit_log_detail.html'
context_object_name = 'audit_log'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return AuditLogEntry.objects.none()
return AuditLogEntry.objects.filter(tenant=tenant)
class SystemConfigurationListView(LoginRequiredMixin, ListView):
"""
System configuration view.
"""
model = SystemConfiguration
template_name = 'core/configurations/system_configuration.html'
context_object_name = 'configurations'
def get_queryset(self):
tenant = self.request.user.tenant
queryset = SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None),
is_active=True
).order_by('category', 'key')
# Apply search filter
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(key__icontains=search) |
Q(description__icontains=search) |
Q(category__icontains=search)
)
# Apply category filter
category = self.request.GET.get('category')
if category:
queryset = queryset.filter(category=category)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
# Group configurations by category
configurations = context['configurations']
grouped_configs = {}
for config in configurations:
category = config.category
if category not in grouped_configs:
grouped_configs[category] = []
grouped_configs[category].append(config)
context['grouped_configurations'] = grouped_configs
# Get categories for filter
context['categories'] = SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
).values_list('category', flat=True).distinct()
return context
class SystemConfigurationDetailView(LoginRequiredMixin, DetailView):
"""
Display system configuration details.
"""
model = SystemConfiguration
template_name = 'core/configurations/system_configuration_detail.html'
context_object_name = 'configuration'
def get_queryset(self):
tenant = self.request.user.tenant
return SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
)
class SystemConfigurationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create new system configuration.
"""
model = SystemConfiguration
form_class = SystemConfigurationForm
template_name = 'core/configurations/system_configuration_form.html'
permission_required = 'core.add_systemconfiguration'
success_url = reverse_lazy('core:system_configuration_list')
def form_valid(self, form):
# Set tenant
form.instance.tenant = self.request.user.tenant
response = super().form_valid(form)
# Log configuration creation
AuditLogger.log_event(
tenant=form.instance.tenant,
event_type='CREATE',
event_category='SYSTEM_ADMINISTRATION',
action='Create Configuration',
description=f'Created configuration: {self.object.key}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Configuration "{self.object.key}" created successfully.')
return response
class SystemConfigurationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update system configuration.
"""
model = SystemConfiguration
form_class = SystemConfigurationForm
template_name = 'core/configurations/system_configuration_form.html'
permission_required = 'core.change_systemconfiguration'
def get_queryset(self):
tenant = self.request.user.tenant
return SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
)
def get_success_url(self):
return reverse('core:system_configuration_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log configuration update
AuditLogger.log_event(
tenant=self.object.tenant,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Update Configuration',
description=f'Updated configuration: {self.object.key}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Configuration "{self.object.key}" updated successfully.')
return response
class SystemConfigurationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete system configuration.
"""
model = SystemConfiguration
template_name = 'core/configurations/system_configuration_confirm_delete.html'
permission_required = 'core.delete_systemconfiguration'
success_url = reverse_lazy('core:system_configuration_list')
def get_queryset(self):
tenant = self.request.user.tenant
return SystemConfiguration.objects.filter(tenant=tenant) # Only tenant-specific configs can be deleted
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
# Log configuration deletion
AuditLogger.log_event(
tenant=self.object.tenant,
event_type='DELETE',
event_category='SYSTEM_ADMINISTRATION',
action='Delete Configuration',
description=f'Deleted configuration: {self.object.key}',
user=request.user,
content_object=self.object,
request=request
)
messages.success(request, f'Configuration "{self.object.key}" deleted successfully.')
return super().delete(request, *args, **kwargs)
class SystemNotificationListView(LoginRequiredMixin, ListView):
"""
List system notifications.
"""
model = SystemNotification
template_name = 'core/notifications/notification_list.html'
context_object_name = 'notifications'
paginate_by = 20
def get_queryset(self):
tenant = self.request.user.tenant
queryset = SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
).order_by('-created_at')
# Apply filters
status = self.request.GET.get('status')
if status == 'active':
queryset = queryset.filter(is_active=True)
elif status == 'inactive':
queryset = queryset.filter(is_active=False)
priority = self.request.GET.get('priority')
if priority:
queryset = queryset.filter(priority=priority)
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(title__icontains=search) |
Q(message__icontains=search)
)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['priority_choices'] = SystemNotification.NotificationPriority.choices
return context
class SystemNotificationDetailView(LoginRequiredMixin, DetailView):
"""
Display notification details.
"""
model = SystemNotification
template_name = 'core/notifications/notification_detail.html'
context_object_name = 'notification'
def get_queryset(self):
tenant = self.request.user.tenant
return SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
)
class SystemNotificationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
"""
Create new system notification.
"""
model = SystemNotification
form_class = SystemNotificationForm
template_name = 'core/notifications/notification_form.html'
permission_required = 'core.add_systemnotification'
success_url = reverse_lazy('core:notification_list')
def form_valid(self, form):
# Set tenant and creator
form.instance.tenant = self.request.user.tenant
form.instance.created_by = self.request.user
response = super().form_valid(form)
# Log notification creation
AuditLogger.log_event(
tenant=form.instance.tenant,
event_type='CREATE',
event_category='SYSTEM_ADMINISTRATION',
action='Create Notification',
description=f'Created notification: {self.object.title}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Notification "{self.object.title}" created successfully.')
return response
class SystemNotificationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
"""
Update system notification.
"""
model = SystemNotification
form_class = SystemNotificationForm
template_name = 'core/notifications/notification_form.html'
permission_required = 'core.change_systemnotification'
def get_queryset(self):
tenant = self.request.user.tenant
return SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant=None)
)
def get_success_url(self):
return reverse('core:notification_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
response = super().form_valid(form)
# Log notification update
AuditLogger.log_event(
tenant=self.object.tenant,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Update Notification',
description=f'Updated notification: {self.object.title}',
user=self.request.user,
content_object=self.object,
request=self.request
)
messages.success(self.request, f'Notification "{self.object.title}" updated successfully.')
return response
class SystemNotificationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
"""
Delete system notification.
"""
model = SystemNotification
template_name = 'core/notifications/notification_confirm_delete.html'
permission_required = 'core.delete_systemnotification'
success_url = reverse_lazy('core:notification_list')
def get_queryset(self):
tenant = self.request.user.tenant
return SystemNotification.objects.filter(tenant=tenant) # Only tenant notifications can be deleted
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
# Log notification deletion
AuditLogger.log_event(
tenant=self.object.tenant,
event_type='DELETE',
event_category='SYSTEM_ADMINISTRATION',
action='Delete Notification',
description=f'Deleted notification: {self.object.title}',
user=request.user,
content_object=self.object,
request=request
)
messages.success(request, f'Notification "{self.object.title}" deleted successfully.')
return super().delete(request, *args, **kwargs)
class IntegrationLogListView(LoginRequiredMixin, ListView):
"""
List integration logs.
"""
model = IntegrationLog
template_name = 'core/integration_logs/integration_log_list.html'
context_object_name = 'logs'
paginate_by = 50
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return IntegrationLog.objects.none()
queryset = IntegrationLog.objects.filter(tenant=tenant).order_by('-timestamp')
# Apply filters
log_level = self.request.GET.get('log_level')
if log_level:
queryset = queryset.filter(log_level=log_level)
component = self.request.GET.get('component')
if component:
queryset = queryset.filter(component__icontains=component)
date_from = self.request.GET.get('date_from')
if date_from:
queryset = queryset.filter(timestamp__gte=date_from)
date_to = self.request.GET.get('date_to')
if date_to:
queryset = queryset.filter(timestamp__lte=date_to)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
tenant = self.request.user.tenant
if tenant:
context.update({
'log_levels': IntegrationLog.objects.filter(
tenant=tenant
).values_list('log_level', flat=True).distinct(),
'components': IntegrationLog.objects.filter(
tenant=tenant
).values_list('component', flat=True).distinct(),
})
return context
class IntegrationLogDetailView(LoginRequiredMixin, DetailView):
"""
Display integration log details.
"""
model = IntegrationLog
template_name = 'core/integration_logs/integration_log_detail.html'
context_object_name = 'log'
def get_queryset(self):
tenant = self.request.user.tenant
if not tenant:
return IntegrationLog.objects.none()
return IntegrationLog.objects.filter(tenant=tenant)
@login_required
def dashboard_stats(request):
"""
HTMX view for dashboard statistics.
"""
tenant = request.user.tenant
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
# Calculate statistics
now = timezone.now()
today = now.date()
week_ago = now - timedelta(days=7)
stats = {
'total_users': tenant.get_user_count(),
'total_patients': tenant.get_patient_count(),
'total_departments': Department.objects.filter(tenant=tenant, is_active=True).count(),
'audit_logs_today': AuditLogEntry.objects.filter(
tenant=tenant,
timestamp__date=today
).count(),
'audit_logs_week': AuditLogEntry.objects.filter(
tenant=tenant,
timestamp__gte=week_ago
).count(),
'active_notifications': SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant=None),
is_active=True,
start_date__lte=now,
end_date__gte=now
).count(),
'total_configurations': SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None),
is_active=True
).count(),
}
return render(request, 'core/partials/dashboard_stats.html', {'stats': stats})
@login_required
def audit_log_search(request):
"""
HTMX view for audit log search.
"""
tenant = request.user.tenant
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
search_query = request.GET.get('search', '')
queryset = AuditLogEntry.objects.filter(tenant=tenant)
if search_query:
queryset = queryset.filter(
Q(action__icontains=search_query) |
Q(description__icontains=search_query) |
Q(user_email__icontains=search_query) |
Q(object_repr__icontains=search_query)
)
audit_logs = queryset.order_by('-timestamp')[:20]
return render(request, 'core/partials/audit_log_list.html', {
'audit_logs': audit_logs
})
@login_required
def system_notifications(request):
"""
HTMX view for system notifications.
"""
tenant = getattr(request.user, 'tenant', None)
# Build base query
if tenant:
notifications = SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant=None),
is_active=True
)
else:
notifications = SystemNotification.objects.filter(
tenant=None,
is_active=True
)
# Filter by date range
notifications = notifications.filter(
start_date__lte=timezone.now()
).filter(
Q(end_date__gte=timezone.now()) | Q(end_date=None)
).order_by('-priority', '-created_at')
return render(request, 'core/partials/system_notifications.html', {
'notifications': notifications
})
@login_required
def dismiss_notification(request, notification_id):
"""
HTMX view to dismiss a notification.
"""
tenant = request.user.tenant
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
notification = get_object_or_404(
SystemNotification,
notification_id=notification_id,
is_dismissible=True
)
# Log the dismissal
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Dismiss Notification',
description=f'User dismissed notification: {notification.title}',
user=request.user,
content_object=notification,
request=request
)
return JsonResponse({'status': 'dismissed'})
@login_required
def tenant_info(request):
"""
HTMX view for tenant information.
"""
tenant = request.user.tenant
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
return render(request, 'core/partials/tenant_info.html', {
'tenant': tenant
})
@login_required
def system_health(request):
"""
HTMX view for system health status.
"""
tenant = request.user.tenant
if not tenant:
return JsonResponse({'error': 'No tenant found'}, status=400)
# Calculate system health metrics
now = timezone.now()
hour_ago = now - timedelta(hours=1)
health_data = {
'database_status': 'healthy', # Would check actual database health
'cache_status': 'healthy', # Would check cache health
'recent_errors': AuditLogEntry.objects.filter(
tenant=tenant,
event_type='ERROR',
timestamp__gte=hour_ago
).count(),
'system_load': 'normal', # Would check actual system load
'last_updated': now.strftime('%Y-%m-%d %H:%M:%S'),
'active_departments': Department.objects.filter(
tenant=tenant,
is_active=True
).count(),
'total_configurations': SystemConfiguration.objects.filter(
Q(tenant=tenant) | Q(tenant=None),
is_active=True
).count(),
}
return render(request, 'core/partials/system_health.html', {
'health_data': health_data
})
@login_required
def activate_notification(request, pk):
"""
Activate a system notification.
"""
tenant = request.user.tenant
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('core:notification_list')
notification = get_object_or_404(
SystemNotification,
pk=pk,
tenant=tenant
)
notification.is_active = True
notification.save()
# Log activation
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Activate Notification',
description=f'Activated notification: {notification.title}',
user=request.user,
content_object=notification,
request=request
)
messages.success(request, f'Notification "{notification.title}" activated successfully.')
return redirect('core:system_notification_detail', pk=pk)
@login_required
def deactivate_notification(request, pk):
"""
Deactivate a system notification.
"""
tenant = request.user.tenant
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('core:notification_list')
notification = get_object_or_404(
SystemNotification,
pk=pk,
tenant=tenant
)
notification.is_active = False
notification.save()
# Log deactivation
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Deactivate Notification',
description=f'Deactivated notification: {notification.title}',
user=request.user,
content_object=notification,
request=request
)
messages.success(request, f'Notification "{notification.title}" deactivated successfully.')
return redirect('core:system_notification_detail', pk=pk)
@login_required
def reset_configuration(request, pk):
"""
Reset configuration to default value.
"""
tenant = request.user.tenant
if not tenant:
messages.error(request, 'No tenant found.')
return redirect('core:system_configuration_list')
configuration = get_object_or_404(
SystemConfiguration,
pk=pk,
tenant=tenant
)
# Reset to default value
old_value = configuration.value
configuration.value = configuration.default_value
configuration.save()
# Log reset
AuditLogger.log_event(
tenant=tenant,
event_type='UPDATE',
event_category='SYSTEM_ADMINISTRATION',
action='Reset Configuration',
description=f'Reset configuration {configuration.key} from "{old_value}" to "{configuration.value}"',
user=request.user,
content_object=configuration,
request=request
)
messages.success(request, f'Configuration "{configuration.key}" reset to default value.')
return redirect('core:system_configuration_detail', pk=pk)
@login_required
def tenant_stats(request):
"""
HTMX view for tenant statistics.
"""
stats = {
'total_tenants': Tenant.objects.count(),
'active_tenants': Tenant.objects.filter(is_active=True).count(),
'inactive_tenants': Tenant.objects.filter(is_active=False).count(),
'tenants_by_type': Tenant.objects.values('tenant_type').annotate(count=Count('tenant_id')),
}
return render(request, 'core/partials/tenant_stats.html', {'stats': stats})
@login_required
def configuration_search(request):
"""
HTMX view for configuration search.
"""
query = request.GET.get('q', '')
configurations = []
if query:
configurations = SystemConfiguration.objects.filter(
tenant=request.user.tenant,
key__icontains=query
)[:10]
return render(request, 'core/partials/configuration_search.html', {
'configurations': configurations,
'query': query
})
@login_required
def audit_log_list_htmx(request):
"""
HTMX view for audit log list.
"""
tenant = request.user.tenant
logs = AuditLog.objects.filter(
tenant=tenant
).order_by('-timestamp')[:20]
return render(request, 'core/partials/audit_log_list.html', {
'logs': logs
})
@login_required
def activate_tenant(request, pk):
"""
Activate a tenant.
"""
tenant = get_object_or_404(Tenant, pk=pk)
tenant.is_active = True
tenant.save()
messages.success(request, f'Tenant "{tenant.name}" has been activated.')
return redirect('core:tenant_detail', pk=pk)
@login_required
def deactivate_tenant(request, pk):
"""
Deactivate a tenant.
"""
tenant = get_object_or_404(Tenant, pk=pk)
tenant.is_active = False
tenant.save()
messages.success(request, f'Tenant "{tenant.name}" has been deactivated.')
return redirect('core:tenant_detail', pk=pk)
@login_required
def reset_system_configuration(request):
"""
Reset system configuration to defaults.
"""
tenant = request.user.tenant
if request.method == 'POST':
# Reset configurations for the tenant
SystemConfiguration.objects.filter(
tenant=tenant
).delete()
messages.success(request, 'System configuration has been reset to defaults.')
return redirect('core:system_configuration_list')
return render(request, 'core/configurations/reset_configuration_confirm.html')
@login_required
def export_audit_log(request):
"""
Export audit log to CSV.
"""
tenant = request.user.tenant
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="audit_log.csv"'
writer = csv.writer(response)
writer.writerow(['Timestamp', 'User', 'Action', 'Object Type', 'Object ID', 'Changes'])
logs = AuditLog.objects.filter(
tenant=tenant
).order_by('-timestamp')
for log in logs:
writer.writerow([
log.timestamp,
log.user.username if log.user else 'System',
log.action,
log.object_type,
log.object_id,
log.changes
])
return response
class CoreSearchView(LoginRequiredMixin, ListView):
"""
Generic search view for core models.
"""
template_name = 'core/search_results.html'
context_object_name = 'results'
paginate_by = 20
def get_queryset(self):
query = self.request.GET.get('q', '')
if not query:
return []
# Search across multiple models
results = []
# Search tenants
tenants = Tenant.objects.filter(name__icontains=query)[:5]
for tenant in tenants:
results.append({
'type': 'Tenant',
'object': tenant,
'url': reverse('core:tenant_detail', args=[tenant.tenant_id])
})
# Search departments
departments = Department.objects.filter(
tenant=self.request.user.tenant,
name__icontains=query
)[:5]
for dept in departments:
results.append({
'type': 'Department',
'object': dept,
'url': reverse('core:department_detail', args=[dept.department_id])
})
return results
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['query'] = self.request.GET.get('q', '')
return context
@login_required
def tenant_search(request):
"""
AJAX search for tenants.
"""
query = request.GET.get('q', '')
tenants = []
if query:
tenants = Tenant.objects.filter(
name__icontains=query
).values('tenant_id', 'name', 'tenant_type')[:10]
return JsonResponse({'tenants': list(tenants)})
@login_required
def bulk_activate_tenants(request):
"""
Bulk activate tenants.
"""
if request.method == 'POST':
tenant_ids = request.POST.getlist('tenant_ids')
count = Tenant.objects.filter(
tenant_id__in=tenant_ids
).update(is_active=True)
messages.success(request, f'{count} tenants have been activated.')
return redirect('core:tenant_list')
@login_required
def bulk_deactivate_tenants(request):
"""
Bulk deactivate tenants.
"""
if request.method == 'POST':
tenant_ids = request.POST.getlist('tenant_ids')
count = Tenant.objects.filter(
tenant_id__in=tenant_ids
).update(is_active=False)
messages.success(request, f'{count} tenants have been deactivated.')
return redirect('core:tenant_list')
@login_required
def bulk_export_audit_logs(request):
"""
Bulk export audit logs.
"""
tenant = request.user.tenant
if request.method == 'POST':
log_ids = request.POST.getlist('log_ids')
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="selected_audit_logs.csv"'
writer = csv.writer(response)
writer.writerow(['Timestamp', 'User', 'Action', 'Object Type', 'Object ID', 'Changes'])
logs = AuditLog.objects.filter(
tenant=tenant,
log_id__in=log_ids
).order_by('-timestamp')
for log in logs:
writer.writerow([
log.timestamp,
log.user.username if log.user else 'System',
log.action,
log.object_type,
log.object_id,
log.changes
])
return response
return redirect('core:audit_log_list')
@login_required
def validate_tenant_data(request):
"""
AJAX validation for tenant data.
"""
name = request.GET.get('name', '')
errors = []
if name:
if Tenant.objects.filter(name=name).exists():
errors.append('Tenant name already exists.')
if len(name) < 3:
errors.append('Tenant name must be at least 3 characters.')
return JsonResponse({'valid': len(errors) == 0, 'errors': errors})
@login_required
def get_system_status(request):
"""
Get system status information.
"""
import psutil
from django.db import connection
# Database status
with connection.cursor() as cursor:
cursor.execute("SELECT 1")
db_status = "healthy"
# System metrics
status = {
'database': db_status,
'cpu_usage': psutil.cpu_percent(),
'memory_usage': psutil.virtual_memory().percent,
'disk_usage': psutil.disk_usage('/').percent,
'active_users': User.objects.filter(is_active=True).count(),
'total_tenants': Tenant.objects.count(),
}
return JsonResponse(status)
@login_required
def backup_configuration(request):
"""
Backup system configuration.
"""
tenant = request.user.tenant
configurations = SystemConfiguration.objects.filter(
tenant=tenant
).values('key', 'value', 'description')
backup_data = {
'tenant': str(tenant.tenant_id),
'timestamp': timezone.now().isoformat(),
'configurations': list(configurations)
}
response = HttpResponse(
json.dumps(backup_data, indent=2),
content_type='application/json'
)
response['Content-Disposition'] = 'attachment; filename="configuration_backup.json"'
return response
@login_required
def restore_configuration(request):
"""
Restore system configuration from backup.
"""
tenant = request.user.tenant
if request.method == 'POST':
backup_file = request.FILES.get('backup_file')
if backup_file:
try:
backup_data = json.loads(backup_file.read().decode('utf-8'))
# Clear existing configurations
SystemConfiguration.objects.filter(
tenant=tenant
).delete()
# Restore configurations
for config in backup_data.get('configurations', []):
SystemConfiguration.objects.create(
tenant=tenant,
key=config['key'],
value=config['value'],
description=config.get('description', '')
)
messages.success(request, 'Configuration has been restored successfully.')
return redirect('core:system_configuration_list')
except (json.JSONDecodeError, KeyError) as e:
messages.error(request, f'Invalid backup file: {e}')
else:
messages.error(request, 'Please select a backup file.')
return render(request, 'core/restore_configuration.html')
@login_required
def notification_search(request):
"""API endpoint for searching notifications."""
user = request.user
tenant = getattr(user, 'tenant', None)
# Get search parameters
search_term = request.GET.get('term', '')
notification_type = request.GET.get('notification_type', '')
is_active = request.GET.get('is_active', '')
# Base query
if user.is_superuser:
query = SystemNotification.objects.all()
elif tenant:
query = SystemNotification.objects.filter(
Q(tenant=tenant) | Q(tenant__isnull=True)
)
else:
query = SystemNotification.objects.filter(tenant__isnull=True)
# Apply filters
if search_term:
query = query.filter(
Q(title__icontains=search_term) |
Q(message__icontains=search_term)
)
if notification_type:
query = query.filter(notification_type=notification_type)
if is_active:
is_active_bool = is_active.lower() == 'true'
query = query.filter(is_active=is_active_bool)
# Only include currently visible notifications
if request.GET.get('visible_only', '') == 'true':
now = timezone.now()
query = query.filter(
is_active=True,
start_date__lte=now,
)
# Get results
results = query.order_by('-start_date')[:20]
# Format results
formatted_results = []
for notification in results:
# Check if this notification should be visible to the user
if request.GET.get('check_visibility', '') == 'true':
if not notification.is_visible_to_user(user):
continue
formatted_results.append({
'id': str(notification.notification_id),
'title': notification.title,
'message': notification.message[:100] + '...' if len(notification.message) > 100 else notification.message,
'type': notification.notification_type,
'type_display': notification.get_notification_type_display(),
'is_active': notification.is_active,
'is_dismissible': notification.is_dismissible,
'start_date': notification.start_date.isoformat(),
'end_date': notification.end_date.isoformat() if notification.end_date else None,
'url': reverse('core:system_notification_detail', args=[notification.notification_id])
})
return JsonResponse({
'status': 'success',
'results': formatted_results,
'count': len(formatted_results)
})
# Department Views
# class DepartmentListView(LoginRequiredMixin, ListView):
# """
# List departments.
# """
# model = Department
# template_name = 'core/department_list.html'
# context_object_name = 'departments'
# paginate_by = 20
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return Department.objects.none()
#
# queryset = Department.objects.filter(tenant=tenant).order_by('name')
#
# # Apply search filter
# search = self.request.GET.get('search')
# if search:
# queryset = queryset.filter(
# Q(name__icontains=search) |
# Q(description__icontains=search) |
# Q(location__icontains=search)
# )
#
# # Apply status filter
# status = self.request.GET.get('status')
# if status:
# queryset = queryset.filter(is_active=(status == 'active'))
#
# return queryset
#
#
# class DepartmentDetailView(LoginRequiredMixin, DetailView):
# """
# Display department details.
# """
# model = Department
# template_name = 'core/department_detail.html'
# context_object_name = 'department'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return Department.objects.none()
# return Department.objects.filter(tenant=tenant)
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# department = self.object
#
# # Get department statistics
# context.update({
# 'employee_count': department.current_staff_count,
# 'recent_activity': AuditLogEntry.objects.filter(
# tenant=department.tenant,
# object_id=str(department.pk),
# content_type__model='department'
# ).order_by('-timestamp')[:10],
# })
#
# return context
#
#
# class DepartmentCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create new department.
# """
# model = Department
# form_class = DepartmentForm
# template_name = 'core/department_form.html'
# permission_required = 'core.add_department'
# success_url = reverse_lazy('core:department_list')
#
# def form_valid(self, form):
# # Set tenant
# form.instance.tenant = self.request.user.tenant
# response = super().form_valid(form)
#
# # Log department creation
# AuditLogger.log_event(
# tenant=form.instance.tenant,
# event_type='CREATE',
# event_category='SYSTEM_ADMINISTRATION',
# action='Create Department',
# description=f'Created department: {self.object.name}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'Department "{self.object.name}" created successfully.')
# return response
#
#
# class DepartmentUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update department.
# """
# model = Department
# form_class = DepartmentForm
# template_name = 'core/department_form.html'
# permission_required = 'core.change_department'
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return Department.objects.none()
# return Department.objects.filter(tenant=tenant)
#
# def get_success_url(self):
# return reverse('core:department_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# response = super().form_valid(form)
#
# # Log department update
# AuditLogger.log_event(
# tenant=self.object.tenant,
# event_type='UPDATE',
# event_category='SYSTEM_ADMINISTRATION',
# action='Update Department',
# description=f'Updated department: {self.object.name}',
# user=self.request.user,
# content_object=self.object,
# request=self.request
# )
#
# messages.success(self.request, f'Department "{self.object.name}" updated successfully.')
# return response
#
#
# class DepartmentDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete department (soft delete to inactive).
# """
# model = Department
# template_name = 'core/department_confirm_delete.html'
# permission_required = 'core.delete_department'
# success_url = reverse_lazy('core:department_list')
#
# def get_queryset(self):
# tenant = self.request.user.tenant
# if not tenant:
# return Department.objects.none()
# return Department.objects.filter(tenant=tenant)
#
# def delete(self, request, *args, **kwargs):
# self.object = self.get_object()
#
# # Check if department has employees
# if self.object.get_employee_count() > 0:
# messages.error(request, 'Cannot delete department with active employees.')
# return redirect('core:department_detail', pk=self.object.pk)
#
# # Soft delete - set to inactive
# self.object.is_active = False
# self.object.save()
#
# # Log department deletion
# AuditLogger.log_event(
# tenant=self.object.tenant,
# event_type='DELETE',
# event_category='SYSTEM_ADMINISTRATION',
# action='Deactivate Department',
# description=f'Deactivated department: {self.object.name}',
# user=request.user,
# content_object=self.object,
# request=request
# )
#
# messages.success(request, f'Department "{self.object.name}" deactivated successfully.')
# return redirect(self.success_url)
#
# import json
#
# from django.contrib.contenttypes.models import ContentType
# from django.shortcuts import render, redirect, get_object_or_404
# from django.views.generic import (
# ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
# )
# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# from django.contrib.auth.decorators import login_required, permission_required
# from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
# from django.urls import reverse, reverse_lazy
# from django.db.models import Q, Count, Sum, Avg, F, ExpressionWrapper, DateTimeField
# from django.utils import timezone
# from django.utils.translation import gettext_lazy as _
# from django.contrib import messages
# from django.core.paginator import Paginator
# from django.views.decorators.http import require_POST, require_GET
# from django.views.decorators.csrf import csrf_protect
# from django.forms import modelform_factory
# from django.conf import settings
#
# from accounts.models import User
# from .models import (
# Tenant, Department, AuditLogEntry, SystemConfiguration,
# SystemNotification, NotificationDismissal, IntegrationLog
# )
# from .forms import (
# TenantForm, DepartmentForm, SystemConfigurationForm, SystemNotificationForm,
# NotificationDismissForm, IntegrationLogFilterForm, CoreSearchForm
# )
#
#
# class DashboardView(LoginRequiredMixin, TemplateView):
# """Main dashboard view for the core app."""
# template_name = 'core/dashboard.html'
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# user = self.request.user
# tenant = getattr(user, 'tenant', None)
#
# # Default to last 30 days for stats
# thirty_days_ago = timezone.now() - timezone.timedelta(days=30)
#
# # System health summary
# context['system_health'] = {
# 'active_tenants': Tenant.objects.filter(is_active=True).count(),
# 'total_departments': Department.objects.count(),
# 'system_notifications': SystemNotification.objects.filter(is_active=True,start_date__lte=timezone.now()).count(),
# }
#
# # Recent activities (audit log)
# if user.is_superuser:
# # For superusers, show system-wide logs
# context['recent_activities'] = AuditLogEntry.objects.all().order_by('-timestamp')[:10]
# elif tenant:
# # For tenant users, show tenant-specific logs
# context['recent_activities'] = AuditLogEntry.objects.filter(
# tenant=tenant
# ).order_by('-timestamp')[:10]
# else:
# context['recent_activities'] = []
#
# # Active notifications for user
# context['notifications'] = []
# active_notifications = SystemNotification.objects.filter(
# is_active=True,
# start_date__lte=timezone.now(),
# )
#
# # Filter to show relevant notifications to this user
# for notification in active_notifications:
# if notification.is_visible_to_user(user):
# context['notifications'].append(notification)
#
# # Integration health
# if user.is_superuser or (user.is_staff and user.has_perm('core.view_integrationlog')):
# # Calculate success rates for integrations
# context['integration_health'] = []
#
# integrations = IntegrationLog.objects.filter(
# timestamp__gte=thirty_days_ago
# ).values('integration_name').distinct()
#
# for integration in integrations:
# integration_name = integration['integration_name']
# logs = IntegrationLog.objects.filter(
# integration_name=integration_name,
# timestamp__gte=thirty_days_ago
# )
#
# total = logs.count()
# success = logs.filter(status='SUCCESS').count()
#
# if total > 0:
# success_rate = (success / total) * 100
# else:
# success_rate = 0
#
# context['integration_health'].append({
# 'name': integration_name,
# 'success_rate': success_rate,
# 'total': total,
# 'success': success,
# 'error': total - success
# })
#
# return context
#
#
# class TenantListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """View for listing all tenants."""
# model = Tenant
# template_name = 'core/tenant_list.html'
# context_object_name = 'tenants'
# paginate_by = 20
# permission_required = 'core.view_tenant'
#
# def get_queryset(self):
# queryset = super().get_queryset()
# user = self.request.user
#
# # Only superusers can see all tenants
# if not user.is_superuser:
# # Regular users can only see their own tenant
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(pk=user.tenant.pk)
# else:
# queryset = Tenant.objects.none()
#
# # Apply search and filters
# form = CoreSearchForm(self.request.GET)
# if form.is_valid():
# search_term = form.cleaned_data.get('search')
# org_type = form.cleaned_data.get('organization_type')
# is_active = form.cleaned_data.get('is_active')
# created_from = form.cleaned_data.get('created_from')
# created_to = form.cleaned_data.get('created_to')
#
# if search_term:
# queryset = queryset.filter(
# Q(name__icontains=search_term) |
# Q(code__icontains=search_term) |
# Q(contact_email__icontains=search_term) |
# Q(description__icontains=search_term)
# )
#
# if org_type:
# queryset = queryset.filter(organization_type=org_type)
#
# if is_active:
# is_active_bool = is_active == 'true'
# queryset = queryset.filter(is_active=is_active_bool)
#
# if created_from:
# queryset = queryset.filter(created_at__date__gte=created_from)
#
# if created_to:
# queryset = queryset.filter(created_at__date__lte=created_to)
#
# return queryset.select_related('created_by')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['search_form'] = CoreSearchForm(self.request.GET)
# return context
#
#
# class TenantDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """View for displaying tenant details."""
# model = Tenant
# template_name = 'core/tenant_detail.html'
# context_object_name = 'tenant'
# permission_required = 'core.view_tenant'
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# tenant = self.get_object()
#
# # Get departments for this tenant
# context['departments'] = Department.objects.filter(
# tenant=tenant
# ).select_related('department_head', 'parent_department')
#
# # Count users by role
# if hasattr(tenant, 'users'):
# user_roles = tenant.users.values('role').annotate(count=Count('id'))
# context['user_roles'] = user_roles
#
# # Get tenant-specific configurations
# context['configurations'] = SystemConfiguration.objects.filter(
# tenant=tenant
# ).order_by('category', 'key')
#
# # Get recent audit logs
# context['audit_logs'] = AuditLogEntry.objects.filter(
# tenant=tenant
# ).order_by('-timestamp')[:10]
#
# # Check subscription status
# context['subscription_valid'] = tenant.is_subscription_valid()
#
# # Tenant statistics
# context['active_users_count'] = tenant.get_active_users_count()
#
# # Departments by type
# dept_by_type = Department.objects.filter(
# tenant=tenant
# ).values('department_type').annotate(count=Count('department_id'))
# context['departments_by_type'] = dept_by_type
#
# return context
#
#
# class TenantCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """View for creating a new tenant."""
# model = Tenant
# form_class = TenantForm
# template_name = 'core/tenant_form.html'
# permission_required = 'core.add_tenant'
# success_url = reverse_lazy('core:tenant_list')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Create New Tenant')
# return context
#
# def form_valid(self, form):
# """Set the created_by field to the current user."""
# form.instance.created_by = self.request.user
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='CREATE',
# content_object=self.object,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Tenant "{}" was created successfully.').format(self.object.name)
# )
#
# return response
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error creating the tenant. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class TenantUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """View for updating a tenant."""
# model = Tenant
# form_class = TenantForm
# template_name = 'core/tenant_form.html'
# permission_required = 'core.change_tenant'
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Update Tenant')
# return context
#
# def get_success_url(self):
# """Return to the tenant detail page after update."""
# return reverse('core:tenant_detail', kwargs={'pk': self.object.pk})
#
# def form_valid(self, form):
# """Log the update action."""
# # Capture changes
# if self.object:
# changes = {}
# for field in form.changed_data:
# if field not in ['logo']: # Skip binary fields
# old_value = getattr(self.object, field)
# new_value = form.cleaned_data[field]
# changes[field] = {
# 'old': str(old_value),
# 'new': str(new_value)
# }
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='UPDATE',
# content_object=self.object,
# changes=changes,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Tenant "{}" was updated successfully.').format(self.object.name)
# )
#
# return response
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error updating the tenant. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class TenantDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """View for deleting a tenant."""
# model = Tenant
# template_name = 'core/tenant_confirm_delete.html'
# permission_required = 'core.delete_tenant'
# success_url = reverse_lazy('core:tenant_list')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
#
# # Count related objects to warn user
# tenant = self.get_object()
# context['departments_count'] = tenant.departments.count()
#
# # Count users if there's a relationship
# if hasattr(tenant, 'users'):
# context['users_count'] = tenant.users.count()
#
# return context
#
# def delete(self, request, *args, **kwargs):
# """Override delete to log the action."""
# self.object = self.get_object()
# name = self.object.name
#
# # Log the action before deletion
# AuditLogEntry.log_action(
# user=request.user,
# action_type='DELETE',
# content_object=self.object,
# request=request
# )
#
# # Proceed with deletion
# success_url = self.get_success_url()
# self.object.delete()
#
# messages.success(
# request,
# _('Tenant "{}" was deleted successfully.').format(name)
# )
#
# return HttpResponseRedirect(success_url)
#
#
# class DepartmentListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """View for listing departments."""
# model = Department
# template_name = 'core/department_list.html'
# context_object_name = 'departments'
# paginate_by = 20
# permission_required = 'core.view_department'
#
# def get_queryset(self):
# queryset = super().get_queryset()
# user = self.request.user
#
# # Filter by tenant
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Apply search and filters
# form = CoreSearchForm(self.request.GET)
# if form.is_valid():
# search_term = form.cleaned_data.get('search')
# dept_type = form.cleaned_data.get('department_type')
# is_active = form.cleaned_data.get('is_active')
# created_from = form.cleaned_data.get('created_from')
# created_to = form.cleaned_data.get('created_to')
#
# if search_term:
# queryset = queryset.filter(
# Q(name__icontains=search_term) |
# Q(code__icontains=search_term) |
# Q(description__icontains=search_term)
# )
#
# if dept_type:
# queryset = queryset.filter(department_type=dept_type)
#
# if is_active:
# is_active_bool = is_active == 'true'
# queryset = queryset.filter(is_active=is_active_bool)
#
# if created_from:
# queryset = queryset.filter(created_at__date__gte=created_from)
#
# if created_to:
# queryset = queryset.filter(created_at__date__lte=created_to)
#
# return queryset.select_related('tenant', 'department_head', 'parent_department')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['search_form'] = CoreSearchForm(self.request.GET)
#
# # Get tenant list for superusers
# if self.request.user.is_superuser:
# context['tenants'] = Tenant.objects.filter(is_active=True)
#
# # Department types for quick filtering
# context['department_types'] = dict(Department.DEPARTMENT_TYPE_CHOICES)
#
# return context
#
#
# class DepartmentDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """View for displaying department details."""
# model = Department
# template_name = 'core/department_detail.html'
# context_object_name = 'department'
# permission_required = 'core.view_department'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related(
# 'tenant', 'department_head', 'parent_department', 'created_by'
# )
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# department = self.get_object()
#
# # Get sub-departments
# context['sub_departments'] = department.sub_departments.all()
#
# # Get staff members
# if hasattr(department, 'staff'):
# context['staff_members'] = department.staff.all()
#
# # Get department hierarchy
# hierarchy = []
# current = department
# while current.parent_department:
# hierarchy.insert(0, current.parent_department)
# current = current.parent_department
# context['department_hierarchy'] = hierarchy
#
# # Format operating hours for display
# if department.operating_hours:
# try:
# if isinstance(department.operating_hours, str):
# hours = json.loads(department.operating_hours)
# else:
# hours = department.operating_hours
# context['operating_hours_formatted'] = hours
# except json.JSONDecodeError:
# context['operating_hours_formatted'] = None
#
# return context
#
#
# class DepartmentCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """View for creating a new department."""
# model = Department
# form_class = DepartmentForm
# template_name = 'core/department_form.html'
# permission_required = 'core.add_department'
#
# def get_form_kwargs(self):
# """Pass the current user to the form."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Create New Department')
# return context
#
# def form_valid(self, form):
# """Set the created_by field to the current user."""
# form.instance.created_by = self.request.user
#
# # Set tenant automatically for non-superusers
# if not self.request.user.is_superuser and hasattr(self.request.user, 'tenant'):
# form.instance.tenant = self.request.user.tenant
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='CREATE',
# content_object=self.object,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Department "{}" was created successfully.').format(self.object.name)
# )
#
# return response
#
# def get_success_url(self):
# """Return to the department detail page after creation."""
# return reverse('core:department_detail', kwargs={'pk': self.object.pk})
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error creating the department. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class DepartmentUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """View for updating a department."""
# model = Department
# form_class = DepartmentForm
# template_name = 'core/department_form.html'
# permission_required = 'core.change_department'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def get_form_kwargs(self):
# """Pass the current user to the form."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Update Department')
# return context
#
# def form_valid(self, form):
# """Log the update action."""
# # Capture changes
# if self.object:
# changes = {}
# for field in form.changed_data:
# old_value = getattr(self.object, field)
# new_value = form.cleaned_data[field]
# changes[field] = {
# 'old': str(old_value),
# 'new': str(new_value)
# }
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='UPDATE',
# content_object=self.object,
# changes=changes,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Department "{}" was updated successfully.').format(self.object.name)
# )
#
# return response
#
# def get_success_url(self):
# """Return to the department detail page after update."""
# return reverse('core:department_detail', kwargs={'pk': self.object.pk})
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error updating the department. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class DepartmentDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """View for deleting a department."""
# model = Department
# template_name = 'core/department_confirm_delete.html'
# permission_required = 'core.delete_department'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
#
# # Count related objects to warn user
# department = self.get_object()
# context['sub_departments_count'] = department.sub_departments.count()
#
# # Check for staff members if there's a relationship
# if hasattr(department, 'staff'):
# context['staff_count'] = department.staff.count()
#
# return context
#
# def delete(self, request, *args, **kwargs):
# """Override delete to log the action."""
# self.object = self.get_object()
# name = self.object.name
# tenant = self.object.tenant
#
# # Log the action before deletion
# AuditLogEntry.log_action(
# user=request.user,
# action_type='DELETE',
# content_object=self.object,
# request=request
# )
#
# # Proceed with deletion
# self.object.delete()
#
# messages.success(
# request,
# _('Department "{}" was deleted successfully.').format(name)
# )
#
# # Return to department list
# return HttpResponseRedirect(reverse('core:department_list'))
#
#
# class AuditLogListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """View for listing audit logs."""
# model = AuditLogEntry
# template_name = 'core/audit_log_list.html'
# context_object_name = 'audit_logs'
# paginate_by = 50
# permission_required = 'core.view_auditlogentry'
#
# def get_queryset(self):
# queryset = super().get_queryset()
# user = self.request.user
#
# # Filter by tenant for non-superusers
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Apply filters
# filters = {}
#
# action_type = self.request.GET.get('action_type')
# if action_type:
# filters['action_type'] = action_type
#
# user_id = self.request.GET.get('user')
# if user_id:
# filters['user_id'] = user_id
#
# content_type_id = self.request.GET.get('content_type')
# if content_type_id:
# filters['content_type_id'] = content_type_id
#
# date_from = self.request.GET.get('date_from')
# if date_from:
# filters['timestamp__date__gte'] = date_from
#
# date_to = self.request.GET.get('date_to')
# if date_to:
# filters['timestamp__date__lte'] = date_to
#
# # Apply search term
# search_term = self.request.GET.get('search')
# if search_term:
# queryset = queryset.filter(
# Q(username__icontains=search_term) |
# Q(object_repr__icontains=search_term) |
# Q(ip_address__icontains=search_term)
# )
#
# # Apply filters
# if filters:
# queryset = queryset.filter(**filters)
#
# return queryset.select_related('user', 'content_type').order_by('-timestamp')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
#
# # Add filter options
# context['action_types'] = dict(AuditLogEntry.ACTION_TYPE_CHOICES)
#
# # Add content types for filtering
# context['content_types'] = ContentType.objects.filter(
# id__in=AuditLogEntry.objects.values_list('content_type_id', flat=True).distinct()
# )
#
# # Add users for filtering
# user_ids = AuditLogEntry.objects.values_list('user_id', flat=True).distinct()
# context['users'] = User.objects.filter(id__in=user_ids)
#
# # Current filters
# context['current_filters'] = {
# 'action_type': self.request.GET.get('action_type', ''),
# 'user': self.request.GET.get('user', ''),
# 'content_type': self.request.GET.get('content_type', ''),
# 'date_from': self.request.GET.get('date_from', ''),
# 'date_to': self.request.GET.get('date_to', ''),
# 'search': self.request.GET.get('search', '')
# }
#
# return context
#
#
# class AuditLogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """View for displaying audit log details."""
# model = AuditLogEntry
# template_name = 'core/audit_log_detail.html'
# context_object_name = 'audit_log'
# permission_required = 'core.view_auditlogentry'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related('user', 'content_type')
#
#
# class SystemConfigurationListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """View for listing system configurations."""
# model = SystemConfiguration
# template_name = 'core/system_configuration_list.html'
# context_object_name = 'configurations'
# paginate_by = 50
# permission_required = 'core.view_systemconfiguration'
#
# def get_queryset(self):
# queryset = super().get_queryset()
# user = self.request.user
#
# # Filter by tenant for non-superusers
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
# else:
# queryset = queryset.filter(tenant__isnull=True)
#
# # Apply filters
# category = self.request.GET.get('category')
# if category:
# queryset = queryset.filter(category=category)
#
# tenant_id = self.request.GET.get('tenant')
# if tenant_id:
# if tenant_id == 'system':
# queryset = queryset.filter(tenant__isnull=True)
# else:
# queryset = queryset.filter(tenant_id=tenant_id)
#
# # Apply search
# search_term = self.request.GET.get('search')
# if search_term:
# queryset = queryset.filter(
# Q(key__icontains=search_term) |
# Q(description__icontains=search_term)
# )
#
# return queryset.select_related('tenant').order_by('category', 'key')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
#
# # Add filter options
# context['categories'] = dict(SystemConfiguration.CATEGORY_CHOICES)
#
# # Add tenants for filtering if superuser
# if self.request.user.is_superuser:
# context['tenants'] = Tenant.objects.filter(is_active=True)
#
# # Group configurations by category
# configurations_by_category = {}
#
# for config in context['configurations']:
# category = config.get_category_display()
# if category not in configurations_by_category:
# configurations_by_category[category] = []
# configurations_by_category[category].append(config)
#
# context['configurations_by_category'] = configurations_by_category
#
# # Current filters
# context['current_filters'] = {
# 'category': self.request.GET.get('category', ''),
# 'tenant': self.request.GET.get('tenant', ''),
# 'search': self.request.GET.get('search', '')
# }
#
# return context
#
#
# class SystemConfigurationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """View for displaying system configuration details."""
# model = SystemConfiguration
# template_name = 'core/system_configuration_detail.html'
# context_object_name = 'configuration'
# permission_required = 'core.view_systemconfiguration'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
# else:
# queryset = queryset.filter(tenant__isnull=True)
#
# return queryset.select_related('tenant', 'created_by')
#
#
# class SystemConfigurationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """View for creating a new system configuration."""
# model = SystemConfiguration
# form_class = SystemConfigurationForm
# template_name = 'core/system_configuration_form.html'
# permission_required = 'core.add_systemconfiguration'
#
# def get_form_kwargs(self):
# """Pass the current user to the form."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Create New Configuration')
# return context
#
# def form_valid(self, form):
# """Set the created_by field to the current user."""
# form.instance.created_by = self.request.user
#
# # Set tenant automatically for non-superusers
# if not self.request.user.is_superuser and hasattr(self.request.user, 'tenant'):
# form.instance.tenant = self.request.user.tenant
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='CREATE',
# content_object=self.object,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Configuration "{}" was created successfully.').format(self.object.key)
# )
#
# return response
#
# def get_success_url(self):
# """Return to the configuration detail page after creation."""
# return reverse('core:system_configuration_detail', kwargs={'pk': self.object.pk})
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error creating the configuration. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class SystemConfigurationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """View for updating a system configuration."""
# model = SystemConfiguration
# form_class = SystemConfigurationForm
# template_name = 'core/system_configuration_form.html'
# permission_required = 'core.change_systemconfiguration'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(
# Q(tenant=user.tenant) |
# Q(tenant__isnull=True, is_tenant_editable=True)
# )
# else:
# queryset = queryset.none()
#
# return queryset
#
# def get_form_kwargs(self):
# """Pass the current user to the form."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Update Configuration')
# return context
#
# def form_valid(self, form):
# """Log the update action."""
# # Capture changes
# if self.object:
# changes = {}
# for field in form.changed_data:
# old_value = getattr(self.object, field)
# new_value = form.cleaned_data[field]
#
# # Handle encrypted values
# if field == 'value' and self.object.is_encrypted:
# old_value = '********'
# new_value = '********'
#
# changes[field] = {
# 'old': str(old_value),
# 'new': str(new_value)
# }
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='UPDATE',
# content_object=self.object,
# changes=changes,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Configuration "{}" was updated successfully.').format(self.object.key)
# )
#
# # Check if restart is required
# if self.object.requires_restart:
# messages.warning(
# self.request,
# _('This configuration change requires a system restart to take effect.')
# )
#
# return response
#
# def get_success_url(self):
# """Return to the configuration detail page after update."""
# return reverse('core:system_configuration_detail', kwargs={'pk': self.object.pk})
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error updating the configuration. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class SystemConfigurationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """View for deleting a system configuration."""
# model = SystemConfiguration
# template_name = 'core/system_configuration_confirm_delete.html'
# permission_required = 'core.delete_systemconfiguration'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
# else:
# queryset = queryset.none()
#
# return queryset
#
# def delete(self, request, *args, **kwargs):
# """Override delete to log the action."""
# self.object = self.get_object()
# key = self.object.key
#
# # Log the action before deletion
# AuditLogEntry.log_action(
# user=request.user,
# action_type='DELETE',
# content_object=self.object,
# request=request
# )
#
# # Proceed with deletion
# self.object.delete()
#
# messages.success(
# request,
# _('Configuration "{}" was deleted successfully.').format(key)
# )
#
# # Return to configuration list
# return HttpResponseRedirect(reverse('core:system_configuration_list'))
#
#
# class SystemNotificationListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """View for listing system notifications."""
# model = SystemNotification
# template_name = 'core/system_notification_list.html'
# context_object_name = 'notifications'
# paginate_by = 20
# permission_required = 'core.view_systemnotification'
#
# def get_queryset(self):
# queryset = super().get_queryset()
# user = self.request.user
#
# # Filter by tenant for non-superusers
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
# else:
# queryset = queryset.filter(tenant__isnull=True)
#
# # Apply filters
# notification_type = self.request.GET.get('notification_type')
# if notification_type:
# queryset = queryset.filter(notification_type=notification_type)
#
# visibility = self.request.GET.get('visibility')
# if visibility:
# queryset = queryset.filter(visibility=visibility)
#
# is_active = self.request.GET.get('is_active')
# if is_active is not None:
# is_active_bool = is_active.lower() == 'true'
# queryset = queryset.filter(is_active=is_active_bool)
#
# # Apply search
# search_term = self.request.GET.get('search')
# if search_term:
# queryset = queryset.filter(
# Q(title__icontains=search_term) |
# Q(message__icontains=search_term)
# )
#
# return queryset.select_related('tenant', 'created_by').order_by('-start_date')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
#
# # Add filter options
# context['notification_types'] = dict(SystemNotification.NOTIFICATION_TYPE_CHOICES)
# context['visibility_options'] = dict(SystemNotification.VISIBILITY_CHOICES)
#
# # Current filters
# context['current_filters'] = {
# 'notification_type': self.request.GET.get('notification_type', ''),
# 'visibility': self.request.GET.get('visibility', ''),
# 'is_active': self.request.GET.get('is_active', ''),
# 'search': self.request.GET.get('search', '')
# }
#
# return context
#
#
# class SystemNotificationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """View for displaying system notification details."""
# model = SystemNotification
# template_name = 'core/system_notification_detail.html'
# context_object_name = 'notification'
# permission_required = 'core.view_systemnotification'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
# else:
# queryset = queryset.filter(tenant__isnull=True)
#
# return queryset.select_related('tenant', 'created_by')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# notification = self.get_object()
#
# # Check if user has dismissed this notification
# if notification.is_dismissible:
# context['is_dismissed'] = notification.dismissals.filter(
# pk=self.request.user.pk
# ).exists()
#
# # Get dismissal count
# context['dismissal_count'] = notification.dismissals.count()
#
# # Get user groups that can see this notification
# if notification.visibility == 'CUSTOM':
# context['target_groups'] = notification.target_groups.all()
#
# return context
#
#
# class SystemNotificationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """View for creating a new system notification."""
# model = SystemNotification
# form_class = SystemNotificationForm
# template_name = 'core/system_notification_form.html'
# permission_required = 'core.add_systemnotification'
#
# def get_form_kwargs(self):
# """Pass the current user to the form."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Create New Notification')
# return context
#
# def form_valid(self, form):
# """Set the created_by field to the current user."""
# form.instance.created_by = self.request.user
#
# # Set tenant automatically for non-superusers
# if not self.request.user.is_superuser and hasattr(self.request.user, 'tenant'):
# form.instance.tenant = self.request.user.tenant
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='CREATE',
# content_object=self.object,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Notification "{}" was created successfully.').format(self.object.title)
# )
#
# return response
#
# def get_success_url(self):
# """Return to the notification detail page after creation."""
# return reverse('core:system_notification_detail', kwargs={'pk': self.object.pk})
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error creating the notification. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class SystemNotificationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """View for updating a system notification."""
# model = SystemNotification
# form_class = SystemNotificationForm
# template_name = 'core/system_notification_form.html'
# permission_required = 'core.change_systemnotification'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
# else:
# queryset = queryset.none()
#
# return queryset
#
# def get_form_kwargs(self):
# """Pass the current user to the form."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['title'] = _('Update Notification')
# return context
#
# def form_valid(self, form):
# """Log the update action."""
# # Capture changes
# if self.object:
# changes = {}
# for field in form.changed_data:
# if field != 'target_groups': # M2M requires special handling
# old_value = getattr(self.object, field)
# new_value = form.cleaned_data[field]
# changes[field] = {
# 'old': str(old_value),
# 'new': str(new_value)
# }
#
# response = super().form_valid(form)
#
# # Log the action
# AuditLogEntry.log_action(
# user=self.request.user,
# action_type='UPDATE',
# content_object=self.object,
# changes=changes,
# request=self.request
# )
#
# messages.success(
# self.request,
# _('Notification "{}" was updated successfully.').format(self.object.title)
# )
#
# return response
#
# def get_success_url(self):
# """Return to the notification detail page after update."""
# return reverse('core:system_notification_detail', kwargs={'pk': self.object.pk})
#
# def form_invalid(self, form):
# """Handle form validation errors."""
# messages.error(
# self.request,
# _('There was an error updating the notification. Please check the form.')
# )
# return super().form_invalid(form)
#
#
# class SystemNotificationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """View for deleting a system notification."""
# model = SystemNotification
# template_name = 'core/system_notification_confirm_delete.html'
# permission_required = 'core.delete_systemnotification'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
# else:
# queryset = queryset.none()
#
# return queryset
#
# def delete(self, request, *args, **kwargs):
# """Override delete to log the action."""
# self.object = self.get_object()
# title = self.object.title
#
# # Log the action before deletion
# AuditLogEntry.log_action(
# user=request.user,
# action_type='DELETE',
# content_object=self.object,
# request=request
# )
#
# # Proceed with deletion
# self.object.delete()
#
# messages.success(
# request,
# _('Notification "{}" was deleted successfully.').format(title)
# )
#
# # Return to notification list
# return HttpResponseRedirect(reverse('core:system_notification_list'))
#
#
# class IntegrationLogListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """View for listing integration logs."""
# model = IntegrationLog
# template_name = 'core/integration_log_list.html'
# context_object_name = 'logs'
# paginate_by = 50
# permission_required = 'core.view_integrationlog'
#
# def get_queryset(self):
# queryset = super().get_queryset()
# user = self.request.user
#
# # Filter by tenant for non-superusers
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
# else:
# queryset = queryset.filter(tenant__isnull=True)
#
# # Get form data
# form = IntegrationLogFilterForm(
# self.request.GET,
# tenant=getattr(user, 'tenant', None)
# )
#
# if form.is_valid():
# # Apply filters
# integration_name = form.cleaned_data.get('integration_name')
# if integration_name:
# queryset = queryset.filter(integration_name=integration_name)
#
# event_type = form.cleaned_data.get('event_type')
# if event_type:
# queryset = queryset.filter(event_type=event_type)
#
# status = form.cleaned_data.get('status')
# if status:
# queryset = queryset.filter(status=status)
#
# direction = form.cleaned_data.get('direction')
# if direction:
# queryset = queryset.filter(direction=direction)
#
# date_from = form.cleaned_data.get('date_from')
# if date_from:
# queryset = queryset.filter(timestamp__gte=date_from)
#
# date_to = form.cleaned_data.get('date_to')
# if date_to:
# queryset = queryset.filter(timestamp__lte=date_to)
#
# correlation_id = form.cleaned_data.get('correlation_id')
# if correlation_id:
# queryset = queryset.filter(correlation_id=correlation_id)
#
# return queryset.select_related('tenant', 'user').order_by('-timestamp')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
#
# # Add filter form
# context['filter_form'] = IntegrationLogFilterForm(
# self.request.GET,
# tenant=getattr(self.request.user, 'tenant', None)
# )
#
# # Integration success rates
# logs = context['logs']
# integrations = {}
#
# for log in logs:
# name = log.integration_name
# if name not in integrations:
# integrations[name] = {'success': 0, 'total': 0}
#
# integrations[name]['total'] += 1
# if log.status == 'SUCCESS':
# integrations[name]['success'] += 1
#
# for name, data in integrations.items():
# if data['total'] > 0:
# data['success_rate'] = (data['success'] / data['total']) * 100
# else:
# data['success_rate'] = 0
#
# context['integrations'] = integrations
#
# return context
#
#
# class IntegrationLogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """View for displaying integration log details."""
# model = IntegrationLog
# template_name = 'core/integration_log_detail.html'
# context_object_name = 'log'
# permission_required = 'core.view_integrationlog'
#
# def get_queryset(self):
# """Filter by user's tenant if not superuser."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if not user.is_superuser:
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
# else:
# queryset = queryset.filter(tenant__isnull=True)
#
# return queryset.select_related('tenant', 'user', 'related_object_type')
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# log = self.get_object()
#
# # Get related logs with same correlation ID
# if log.correlation_id:
# context['related_logs'] = IntegrationLog.objects.filter(
# correlation_id=log.correlation_id
# ).exclude(pk=log.pk).order_by('-timestamp')
#
# # Format request/response data for better display
# if log.request_data:
# try:
# context['formatted_request'] = json.dumps(log.request_data, indent=2)
# except:
# context['formatted_request'] = str(log.request_data)
#
# if log.response_data:
# try:
# context['formatted_response'] = json.dumps(log.response_data, indent=2)
# except:
# context['formatted_response'] = str(log.response_data)
#
# # Get related object if available
# if log.related_object_type and log.related_object_id:
# try:
# model_class = log.related_object_type.model_class()
# context['related_object'] = model_class.objects.filter(
# pk=log.related_object_id
# ).first()
# except:
# context['related_object'] = None
#
# return context
#
#
# @login_required
# @permission_required('core.view_systemnotification')
# def dashboard_stats(request):
# """API endpoint for dashboard statistics."""
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# # Default to last 30 days for stats
# thirty_days_ago = timezone.now() - timezone.timedelta(days=30)
#
# # Basic system stats
# stats = {
# 'tenant_count': Tenant.objects.filter(is_active=True).count(),
# 'department_count': Department.objects.count(),
# 'active_notifications': SystemNotification.objects.filter(
# is_active=True,
# start_date__lte=timezone.now(),
# ).count(),
# }
#
# # Audit log stats
# if user.is_superuser:
# log_base_query = AuditLogEntry.objects
# elif tenant:
# log_base_query = AuditLogEntry.objects.filter(tenant=tenant)
# else:
# log_base_query = AuditLogEntry.objects.none()
#
# audit_logs = log_base_query.filter(timestamp__gte=thirty_days_ago)
#
# stats['audit_logs'] = {
# 'total': audit_logs.count(),
# 'by_action': dict(audit_logs.values('action_type').annotate(
# count=Count('action_type')
# ).values_list('action_type', 'count'))
# }
#
# # Integration stats
# if user.is_superuser or (user.is_staff and user.has_perm('core.view_integrationlog')):
# if tenant:
# integration_base_query = IntegrationLog.objects.filter(tenant=tenant)
# else:
# integration_base_query = IntegrationLog.objects
#
# integration_logs = integration_base_query.filter(timestamp__gte=thirty_days_ago)
#
# stats['integrations'] = {
# 'total': integration_logs.count(),
# 'success_count': integration_logs.filter(status='SUCCESS').count(),
# 'error_count': integration_logs.filter(status='ERROR').count(),
# 'by_status': dict(integration_logs.values('status').annotate(
# count=Count('status')
# ).values_list('status', 'count'))
# }
#
# return JsonResponse({'status': 'success', 'data': stats})
#
#
# @login_required
# @permission_required('core.view_auditlogentry')
# def audit_log_search(request):
# """API endpoint for searching audit logs."""
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# # Get search parameters
# search_term = request.GET.get('term', '')
# action_type = request.GET.get('action_type', '')
# date_from = request.GET.get('date_from', '')
# date_to = request.GET.get('date_to', '')
#
# # Base query
# if user.is_superuser:
# query = AuditLogEntry.objects.all()
# elif tenant:
# query = AuditLogEntry.objects.filter(tenant=tenant)
# else:
# query = AuditLogEntry.objects.none()
#
# # Apply filters
# if search_term:
# query = query.filter(
# Q(username__icontains=search_term) |
# Q(object_repr__icontains=search_term) |
# Q(ip_address__icontains=search_term)
# )
#
# if action_type:
# query = query.filter(action_type=action_type)
#
# if date_from:
# query = query.filter(timestamp__date__gte=date_from)
#
# if date_to:
# query = query.filter(timestamp__date__lte=date_to)
#
# # Get results
# results = query.order_by('-timestamp')[:100]
#
# # Format results
# formatted_results = [{
# 'id': str(log.log_id),
# 'user': log.username,
# 'action': log.get_action_type_display(),
# 'object': log.object_repr,
# 'timestamp': log.timestamp.isoformat(),
# 'url': reverse('core:audit_log_detail', args=[log.log_id])
# } for log in results]
#
# return JsonResponse({
# 'status': 'success',
# 'results': formatted_results,
# 'count': len(formatted_results)
# })
#
#
# @login_required
# def system_notifications(request):
# """API endpoint for getting active system notifications for the current user."""
# user = request.user
#
# # Get active notifications
# active_notifications = SystemNotification.objects.filter(
# is_active=True,
# start_date__lte=timezone.now(),
# )
#
# # Filter to show relevant notifications to this user
# user_notifications = []
# for notification in active_notifications:
# if notification.is_visible_to_user(user):
# user_notifications.append({
# 'id': str(notification.notification_id),
# 'title': notification.title,
# 'message': notification.message,
# 'type': notification.notification_type,
# 'is_dismissible': notification.is_dismissible,
# 'link_url': notification.link_url,
# 'link_text': notification.link_text
# })
#
# return JsonResponse({
# 'status': 'success',
# 'notifications': user_notifications
# })
#
#
# @login_required
# @require_POST
# @csrf_protect
# def dismiss_notification(request):
# """API endpoint for dismissing a notification."""
# form = NotificationDismissForm(request.POST)
#
# if form.is_valid():
# notification_id = form.cleaned_data['notification_id']
#
# try:
# notification = SystemNotification.objects.get(notification_id=notification_id)
#
# # Check if notification is dismissible
# if not notification.is_dismissible:
# return JsonResponse({
# 'status': 'error',
# 'message': _('This notification cannot be dismissed.')
# }, status=400)
#
# # Check if already dismissed
# if NotificationDismissal.objects.filter(
# notification=notification,
# user=request.user
# ).exists():
# return JsonResponse({
# 'status': 'success',
# 'message': _('Notification already dismissed.')
# })
#
# # Create dismissal record
# dismissal = NotificationDismissal.objects.create(
# notification=notification,
# user=request.user
# )
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='OTHER',
# content_object=dismissal,
# action_details={'action': 'notification_dismissed'},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Notification dismissed successfully.')
# })
#
# except SystemNotification.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Notification not found.')
# }, status=404)
#
# return JsonResponse({
# 'status': 'error',
# 'message': _('Invalid form data.'),
# 'errors': form.errors
# }, status=400)
#
#
# @login_required
# def tenant_info(request):
# """API endpoint for getting information about the current user's tenant."""
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# if not tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('No tenant associated with this user.')
# }, status=404)
#
# tenant_data = {
# 'id': str(tenant.tenant_id),
# 'name': tenant.name,
# 'code': tenant.code,
# 'organization_type': tenant.get_organization_type_display(),
# 'is_active': tenant.is_active,
# 'subscription_valid': tenant.is_subscription_valid(),
# 'department_count': tenant.departments.count(),
# 'active_users_count': tenant.get_active_users_count()
# }
#
# return JsonResponse({
# 'status': 'success',
# 'tenant': tenant_data
# })
#
#
# @login_required
# @permission_required('core.view_integrationlog')
# def system_health(request):
# """API endpoint for system health information."""
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# # Default to last 7 days for stats
# days = int(request.GET.get('days', 7))
# period_start = timezone.now() - timezone.timedelta(days=days)
#
# # Base health data
# health_data = {
# 'tenants': {
# 'active': Tenant.objects.filter(is_active=True).count(),
# 'inactive': Tenant.objects.filter(is_active=False).count(),
# },
# 'departments': Department.objects.count(),
# }
#
# # Integration health
# if user.is_superuser:
# integration_base_query = IntegrationLog.objects
# elif tenant:
# integration_base_query = IntegrationLog.objects.filter(tenant=tenant)
# else:
# integration_base_query = IntegrationLog.objects.none()
#
# integration_logs = integration_base_query.filter(timestamp__gte=period_start)
# integration_stats = {
# 'total': integration_logs.count(),
# 'success': integration_logs.filter(status='SUCCESS').count(),
# 'error': integration_logs.filter(status='ERROR').count(),
# 'warning': integration_logs.filter(status='WARNING').count(),
# 'by_integration': {}
# }
#
# # Get stats by integration
# integrations = integration_logs.values('integration_name').distinct()
# for integration in integrations:
# name = integration['integration_name']
# logs = integration_logs.filter(integration_name=name)
#
# total = logs.count()
# success = logs.filter(status='SUCCESS').count()
#
# integration_stats['by_integration'][name] = {
# 'total': total,
# 'success': success,
# 'error': logs.filter(status='ERROR').count(),
# 'success_rate': (success / total * 100) if total > 0 else 0
# }
#
# health_data['integrations'] = integration_stats
#
# # Recent system errors
# if user.is_superuser:
# recent_errors = IntegrationLog.objects.filter(
# status='ERROR',
# timestamp__gte=period_start
# ).order_by('-timestamp')[:10]
# elif tenant:
# recent_errors = IntegrationLog.objects.filter(
# tenant=tenant,
# status='ERROR',
# timestamp__gte=period_start
# ).order_by('-timestamp')[:10]
# else:
# recent_errors = IntegrationLog.objects.none()
#
# health_data['recent_errors'] = [{
# 'id': str(log.log_id),
# 'integration': log.integration_name,
# 'event_type': log.event_type,
# 'timestamp': log.timestamp.isoformat(),
# 'error_message': log.error_message,
# 'url': reverse('core:integration_log_detail', args=[log.log_id])
# } for log in recent_errors]
#
# return JsonResponse({
# 'status': 'success',
# 'data': health_data
# })
#
#
# @login_required
# @permission_required('core.change_systemnotification')
# @require_POST
# @csrf_protect
# def activate_notification(request, pk):
# """Activate a system notification."""
# try:
# notification = SystemNotification.objects.get(pk=pk)
#
# # Check permissions for tenant-specific notifications
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# if not user.is_superuser and notification.tenant and notification.tenant != tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this notification.')
# }, status=403)
#
# # Activate the notification
# notification.is_active = True
# notification.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=notification,
# changes={'is_active': {'old': 'False', 'new': 'True'}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Notification activated successfully.')
# })
#
# except SystemNotification.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Notification not found.')
# }, status=404)
#
#
# @login_required
# @permission_required('core.change_systemnotification')
# @require_POST
# @csrf_protect
# def deactivate_notification(request, pk):
# """Deactivate a system notification."""
# try:
# notification = SystemNotification.objects.get(pk=pk)
#
# # Check permissions for tenant-specific notifications
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# if not user.is_superuser and notification.tenant and notification.tenant != tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this notification.')
# }, status=403)
#
# # Deactivate the notification
# notification.is_active = False
# notification.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=notification,
# changes={'is_active': {'old': 'True', 'new': 'False'}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Notification deactivated successfully.')
# })
#
# except SystemNotification.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Notification not found.')
# }, status=404)
#
#
# @login_required
# @permission_required('core.change_systemconfiguration')
# @require_POST
# @csrf_protect
# def reset_configuration(request, pk):
# """Reset a system configuration to its default value."""
# try:
# config = SystemConfiguration.objects.get(pk=pk)
#
# # Check permissions for tenant-specific configurations
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# if not user.is_superuser:
# if config.tenant and config.tenant != tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this configuration.')
# }, status=403)
#
# if not config.is_tenant_editable:
# return JsonResponse({
# 'status': 'error',
# 'message': _('This configuration cannot be modified by tenant users.')
# }, status=403)
#
# # Get the default value
# old_value = config.value
#
# # For tenant-specific configurations, try to get the system-wide value
# if config.tenant:
# try:
# system_config = SystemConfiguration.objects.get(
# key=config.key,
# tenant=None
# )
# config.value = system_config.value
# config.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=config,
# changes={'value': {'old': old_value, 'new': config.value}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Configuration reset to system default successfully.'),
# 'new_value': config.value
# })
#
# except SystemConfiguration.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('No system-wide default value found for this configuration.')
# }, status=404)
#
# # For system-wide configurations, this operation doesn't make sense
# return JsonResponse({
# 'status': 'error',
# 'message': _('System-wide configurations cannot be reset to defaults.')
# }, status=400)
#
# except SystemConfiguration.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Configuration not found.')
# }, status=404)
# @login_required
# def department_search(request):
# """API endpoint for searching departments."""
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# # Get search parameters
# search_term = request.GET.get('term', '')
# department_type = request.GET.get('department_type', '')
# is_active = request.GET.get('is_active', '')
#
# # Base query
# if user.is_superuser:
# query = Department.objects.all()
# elif tenant:
# query = Department.objects.filter(tenant=tenant)
# else:
# query = Department.objects.none()
#
# # Apply filters
# if search_term:
# query = query.filter(
# Q(name__icontains=search_term) |
# Q(code__icontains=search_term) |
# Q(description__icontains=search_term)
# )
#
# if department_type:
# query = query.filter(department_type=department_type)
#
# if is_active:
# is_active_bool = is_active.lower() == 'true'
# query = query.filter(is_active=is_active_bool)
#
# # Get results
# results = query.order_by('name')[:20]
#
# # Format results
# formatted_results = [{
# 'id': str(department.department_id),
# 'name': department.name,
# 'code': department.code,
# 'type': department.get_department_type_display(),
# 'is_active': department.is_active,
# 'department_head': department.department_head.get_full_name() if department.department_head else None,
# 'location': department.get_full_location(),
# 'url': reverse('core:department_detail', args=[department.department_id])
# } for department in results]
#
# return JsonResponse({
# 'status': 'success',
# 'results': formatted_results,
# 'count': len(formatted_results)
# })
#
#
# @login_required
# @permission_required('core.change_tenant')
# @require_POST
# @csrf_protect
# def activate_tenant(request, pk):
# """Activate a tenant."""
# try:
# tenant = Tenant.objects.get(pk=pk)
#
# # Only superusers can activate any tenant
# if not request.user.is_superuser:
# user_tenant = getattr(request.user, 'tenant', None)
# if tenant != user_tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this tenant.')
# }, status=403)
#
# # Activate the tenant
# if tenant.is_active:
# return JsonResponse({
# 'status': 'info',
# 'message': _('Tenant is already active.')
# })
#
# tenant.is_active = True
# tenant.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=tenant,
# changes={'is_active': {'old': 'False', 'new': 'True'}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Tenant activated successfully.')
# })
#
# except Tenant.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Tenant not found.')
# }, status=404)
#
#
# @login_required
# @permission_required('core.change_tenant')
# @require_POST
# @csrf_protect
# def deactivate_tenant(request, pk):
# """Deactivate a tenant."""
# try:
# tenant = Tenant.objects.get(pk=pk)
#
# # Only superusers can deactivate any tenant
# if not request.user.is_superuser:
# user_tenant = getattr(request.user, 'tenant', None)
# if tenant != user_tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this tenant.')
# }, status=403)
#
# # Prevent deactivating your own tenant
# if tenant == getattr(request.user, 'tenant', None):
# return JsonResponse({
# 'status': 'error',
# 'message': _('You cannot deactivate your own tenant.')
# }, status=400)
#
# # Deactivate the tenant
# if not tenant.is_active:
# return JsonResponse({
# 'status': 'info',
# 'message': _('Tenant is already inactive.')
# })
#
# tenant.is_active = False
# tenant.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=tenant,
# changes={'is_active': {'old': 'True', 'new': 'False'}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Tenant deactivated successfully.')
# })
#
# except Tenant.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Tenant not found.')
# }, status=404)
#
#
# @login_required
# @permission_required('core.change_department')
# @require_POST
# @csrf_protect
# def activate_department(request, pk):
# """Activate a department."""
# try:
# department = Department.objects.get(pk=pk)
#
# # Check permissions
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# if not user.is_superuser and department.tenant != tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this department.')
# }, status=403)
#
# # Activate the department
# if department.is_active:
# return JsonResponse({
# 'status': 'info',
# 'message': _('Department is already active.')
# })
#
# department.is_active = True
# department.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=department,
# changes={'is_active': {'old': 'False', 'new': 'True'}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Department activated successfully.')
# })
#
# except Department.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Department not found.')
# }, status=404)
#
#
# @login_required
# @permission_required('core.change_department')
# @require_POST
# @csrf_protect
# def deactivate_department(request, pk):
# """Deactivate a department."""
# try:
# department = Department.objects.get(pk=pk)
#
# # Check permissions
# user = request.user
# tenant = getattr(user, 'tenant', None)
#
# if not user.is_superuser and department.tenant != tenant:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You do not have permission to modify this department.')
# }, status=403)
#
# # Check if this is the user's department
# if hasattr(user, 'department') and user.department == department:
# return JsonResponse({
# 'status': 'error',
# 'message': _('You cannot deactivate your own department.')
# }, status=400)
#
# # Deactivate the department
# if not department.is_active:
# return JsonResponse({
# 'status': 'info',
# 'message': _('Department is already inactive.')
# })
#
# department.is_active = False
# department.save()
#
# # Log the action
# AuditLogEntry.log_action(
# user=request.user,
# action_type='UPDATE',
# content_object=department,
# changes={'is_active': {'old': 'True', 'new': 'False'}},
# request=request
# )
#
# return JsonResponse({
# 'status': 'success',
# 'message': _('Department deactivated successfully.')
# })
#
# except Department.DoesNotExist:
# return JsonResponse({
# 'status': 'error',
# 'message': _('Department not found.')
# }, status=404)
#