from django.db.models import Q from .models import PaymentAccessConfiguration, PaymentNotice def is_staff(user): profile = getattr(user, 'staff_profile', None) return bool(user.is_authenticated and user.is_active and user.account_type == 'STAFF' and (profile is None or profile.is_active)) def has_permission(user, codename, unit=None): if not is_staff(user): return False if user.has_perm(f'payments.{codename}'): return True if unit is None or not unit.is_active: return False return user.unit_memberships.filter(is_active=True, unit=unit).filter( Q(permissions__content_type__app_label='payments', permissions__codename=codename) | Q(unit__permissions__content_type__app_label='payments', unit__permissions__codename=codename) ).exists() def config(): # No get_or_create on a read request; defaults keep initial view/create open only. return PaymentAccessConfiguration.objects.first() or PaymentAccessConfiguration() def can_create(user, unit=None): if unit is None and is_staff(user): from apps.tickets.policies import TicketPolicy unit = TicketPolicy.primary_unit(user) return is_staff(user) and (config().open_create or has_permission(user, 'add_paymentnotice', unit)) def can_manage_banks(user): profile = getattr(user, 'staff_profile', None) return is_staff(user) and (user.is_superuser or getattr(profile, 'role', '') == 'CEO' or has_permission(user, 'manage_company_bankaccounts')) def may_delete_notice(user, notice): role = getattr(getattr(user, 'staff_profile', None), 'role', '') return is_staff(user) and (notice.created_by_id == user.pk or user.is_superuser or role in {'CEO', 'GENERAL_ADMIN'}) def can_delete_notice(user, notice): return may_delete_notice(user, notice) and not notice.deleted_at and not notice.receipts.exists() def notice_actions(queryset, user): """Allow deletion actors to reach this notice without broadening other lists.""" queryset = queryset.filter(deleted_at__isnull=True) if not is_staff(user): return queryset.none() role = getattr(getattr(user, 'staff_profile', None), 'role', '') if user.is_superuser or role in {'CEO', 'GENERAL_ADMIN'}: return queryset return queryset.filter(Q(created_by=user) | Q(pk__in=visible(queryset, user).values('pk'))) def visible(queryset, user): if queryset.model == PaymentNotice: queryset = queryset.filter(deleted_at__isnull=True) if not user.is_authenticated or not user.is_active: return queryset.none() if user.account_type == 'CUSTOMER': return queryset.filter(customer=user) if not is_staff(user): return queryset.none() if config().open_view or user.has_perm('payments.view_all_payments') or user.is_superuser: return queryset permission = f'view_{queryset.model._meta.model_name}' if user.has_perm(f'payments.{permission}'): return queryset units = user.unit_memberships.filter(is_active=True, unit__is_active=True).filter( Q(permissions__content_type__app_label='payments', permissions__codename=permission) | Q(unit__permissions__content_type__app_label='payments', unit__permissions__codename=permission) ).values_list('unit_id', flat=True) return queryset.filter(owning_unit_id__in=units).distinct() def can_decide(user, receipt, cycle, senior=False): # Selection in the approval policy grants the role for this cycle. Requiring # an additional Django permission made selected non-admin staff unable to vote. return (is_staff(user) and receipt.submitted_by_id != user.pk and visible(type(receipt).objects.filter(pk=receipt.pk), user).exists() and cycle.assignments.filter(user=user, is_senior=senior).exists())