"""Область данных портала. Не заменяет права на разделы и действия.""" from django.db.models import Q from django.shortcuts import get_object_or_404 ALL_LOCATIONS_PERMISSION = 'locations.view_all_locations' def has_all_locations(user): if not user or not user.is_authenticated or not user.is_active: return False preview = getattr(user, '_access_preview_perms', None) if preview is not None: return ALL_LOCATIONS_PERMISSION in preview return user.is_superuser or user.has_perm(ALL_LOCATIONS_PERMISSION) def accessible_pharmacies(user): from apps.locations.models import Pharmacy qs = Pharmacy.objects.all() if not user or not user.is_authenticated or not user.is_active: return qs.none() if has_all_locations(user): return qs # Preview не должен наследовать назначения администратора. if getattr(user, '_access_preview_perms', None) is not None: return qs.none() return qs.filter( Q(pk=user.user_pharmacy_id) | Q(head_pharmacist=user) | Q(curator=user) | Q(responsible_manager=user) | Q(location_access_groups__group__in=user.groups.all()) ).distinct() def accessible_locations(user): from apps.locations.models import Location qs = Location.objects.all() if not user or not user.is_authenticated or not user.is_active: return qs.none() if has_all_locations(user): return qs if getattr(user, '_access_preview_perms', None) is not None: return qs.none() return qs.filter( Q(pk__in=accessible_pharmacies(user).values('pk')) | Q(pk=user.user_location_id) | Q(location_access_groups__group__in=user.groups.all()) ).distinct() def scoped_queryset(user, queryset, field='location'): """Объекты с FK на локацию/аптеку; NULL доступен только всей сети.""" if has_all_locations(user): return queryset ids = accessible_locations(user).values('pk') condition = Q(**{f'{field}__in': ids}) if field == 'location': employee_field = {'it_manager.ticket': 'requester', 'it_manager.equipment': 'assigned_to'}.get(queryset.model._meta.label_lower) if employee_field: from apps.employees.models import Employee condition |= Q(location__isnull=True, **{f'{employee_field}__in': scoped_employees(user, Employee.objects.all())}) return queryset.filter(condition) def require_location(user, pk): """Чужой/несуществующий ID одинаково даёт 404 до записи данных.""" from django.http import Http404 if not str(pk).isdigit(): raise Http404 return get_object_or_404(accessible_locations(user), pk=pk) def scoped_employees(user, queryset): if has_all_locations(user): return queryset ids = accessible_locations(user).values('pk') return queryset.filter(Q(pk=user.pk) | Q(user_pharmacy_id__in=ids) | Q(user_location_id__in=ids))