admin.py 8.32 KB
Newer Older
1
"""Registers admin interfaces for the registrations module"""
2 3
from django.contrib import admin, messages
from django.contrib.admin.utils import model_ngettext
4
from django.forms import Field
5 6 7
from django.utils.html import format_html
from django.utils.translation import ugettext_lazy as _

8
from payments.widgets import PaymentWidget
Thom Wiggers's avatar
Thom Wiggers committed
9
from . import services
10 11 12 13 14 15
from .models import Entry, Registration, Renewal, Reference


class ReferenceInline(admin.StackedInline):
    model = Reference
    extra = 0
16 17 18


def _show_message(admin, request, n, message, error):
19
    """Show a message in the Django Admin"""
20 21 22 23 24 25 26 27 28 29 30
    if n == 0:
        admin.message_user(request, error, messages.ERROR)
    else:
        admin.message_user(request, message % {
            "count": n,
            "items": model_ngettext(admin.opts, n)
        }, messages.SUCCESS)


@admin.register(Registration)
class RegistrationAdmin(admin.ModelAdmin):
31 32
    """Manage the registrations"""

33 34 35 36 37
    list_display = ('name', 'email', 'status', 'membership_type',
                    'created_at', 'payment_status', 'no_references',
                    'reference_count')
    list_filter = ('status', 'programme', 'membership_type', 'no_references',
                   'payment__type', 'payment__amount')
38
    inlines = (ReferenceInline,)
39 40 41 42 43 44 45 46 47
    search_fields = ('first_name', 'last_name', 'email', 'phone_number',
                     'student_number',)
    date_hierarchy = 'created_at'
    fieldsets = (
        (_('Application information'), {
            'fields': ('created_at',
                       'updated_at',
                       'username',
                       'length',
48
                       'contribution',
49 50
                       'membership_type',
                       'status',
51 52
                       'payment',
                       'remarks')
53 54 55 56 57
        }),
        (_('Personal information'), {
            'fields': ('first_name',
                       'last_name',
                       'birthday',
58
                       'optin_birthday',
59
                       'email',
60
                       'optin_mailinglist',
61 62 63 64 65 66
                       'phone_number',)
        }),
        (_('Address'), {
            'fields': ('address_street',
                       'address_street2',
                       'address_postal_code',
67 68
                       'address_city',
                       'address_country',)
69 70 71 72 73 74 75 76 77
        }),
        (_('University information'), {
            'fields': ('student_number',
                       'programme',
                       'starting_year',)
        }),
    )
    actions = ['accept_selected', 'reject_selected']

78 79 80 81
    def reference_count(self, obj):
        return obj.reference_set.count()
    reference_count.short_description = _('references')

82 83 84 85 86 87 88 89
    def formfield_for_dbfield(self, db_field, request, **kwargs):
        field = super().formfield_for_dbfield(db_field, request, **kwargs)
        if db_field.name == 'payment':
            return Field(widget=PaymentWidget,
                         initial=field.initial,
                         required=False)
        return field

90 91
    def changeform_view(self, request, object_id=None, form_url='',
                        extra_context=None):
92 93 94 95
        """
        Renders the change formview
        Only allow when the entry has not been processed yet
        """
96
        obj = None
97 98
        can_review = False
        can_resend = False
99
        can_revert = False
100 101 102
        if (object_id is not None and
                request.user.has_perm('registrations.review_entries')):
            obj = Entry.objects.get(id=object_id)
103
            can_review = obj.status == Entry.STATUS_REVIEW
Thom Wiggers's avatar
Thom Wiggers committed
104 105
            can_revert = obj.status in [
                    Entry.STATUS_ACCEPTED, Entry.STATUS_REJECTED]
106 107 108 109
            try:
                can_resend = obj.registration.status == Entry.STATUS_CONFIRM
            except Registration.DoesNotExist:
                pass
110
        return super().changeform_view(
111 112 113 114
            request, object_id, form_url, {
                'entry': obj,
                'can_review': can_review,
                'can_resend': can_resend,
115
                'can_revert': can_revert,
116
            })
117 118 119

    def get_readonly_fields(self, request, obj=None):
        if obj is None or not (obj.status == Entry.STATUS_REJECTED or
120 121
                               obj.status == Entry.STATUS_ACCEPTED or
                               obj.status == Entry.STATUS_COMPLETED):
122
            return ['status', 'created_at', 'updated_at']
123
        else:
124 125 126 127 128
            return [
                field.name for field in self.model._meta.get_fields()
                if not field.name in['payment', 'no_references']
                and field.editable
            ]
129 130 131 132 133 134 135

    @staticmethod
    def name(obj):
        return obj.get_full_name()

    @staticmethod
    def payment_status(obj):
136 137
        payment = obj.payment
        if payment:
138 139 140 141 142
            processed_str = (_('Processed') if payment.processed else
                             _('Unprocessed'))
            return format_html('<a href="{link}">{title}</a>'
                               .format(link=payment.get_admin_url(),
                                       title=processed_str))
143
        return '-'
144 145

    def reject_selected(self, request, queryset):
146
        """Reject the selected entries"""
147
        if request.user.has_perm('registrations.review_entries'):
148
            rows_updated = services.reject_entries(request.user.pk, queryset)
149 150 151 152 153 154
            _show_message(
                self, request, rows_updated,
                message=_("Successfully rejected %(count)d %(items)s."),
                error=_('The selected registration(s) could not be rejected.')
            )
    reject_selected.short_description = _('Reject selected registrations')
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
155
    reject_selected.allowed_permissions = ('review',)
156 157

    def accept_selected(self, request, queryset):
158
        """Accept the selected entries"""
159
        if request.user.has_perm('registrations.review_entries'):
160
            rows_updated = services.accept_entries(request.user.pk, queryset)
161 162 163 164 165 166
            _show_message(
                self, request, rows_updated,
                message=_("Successfully accepted %(count)d %(items)s."),
                error=_('The selected registration(s) could not be accepted.')
            )
    accept_selected.short_description = _('Accept selected registrations')
Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
167 168 169 170 171
    accept_selected.allowed_permissions = ('review',)

    def has_review_permission(self, request):
        """Does the user have the review permission?"""
        return request.user.has_perm('registrations.review_entries')
172

173 174 175 176 177
    def save_model(self, request, obj, form, change):
        if not (obj.status == Entry.STATUS_REJECTED or
                obj.status == Entry.STATUS_ACCEPTED or
                obj.status == Entry.STATUS_COMPLETED):
            super().save_model(request, obj, form, change)
178

179 180 181

@admin.register(Renewal)
class RenewalAdmin(RegistrationAdmin):
182 183
    """Manage the renewals"""

184 185 186 187 188
    list_display = ('name', 'email', 'status', 'membership_type',
                    'created_at', 'payment_status', 'no_references',
                    'reference_count')
    list_filter = ('status', 'membership_type', 'no_references',
                   'payment__type', 'payment__amount')
189 190 191 192 193 194 195 196 197 198
    search_fields = ('member__first_name', 'member__last_name',
                     'member__email', 'member__profile__phone_number',
                     'member__profile__student_number',)
    date_hierarchy = 'created_at'
    fieldsets = (
                    (_('Application information'), {
                        'fields': (
                            'created_at',
                            'updated_at',
                            'length',
199
                            'contribution',
200 201
                            'membership_type',
                            'status',
202
                            'payment',
203 204 205 206
                            'remarks',
                            'member',)
                    }),
    )
207
    actions = RegistrationAdmin.actions
208 209

    def get_readonly_fields(self, request, obj=None):
210
        """Make all fields read-only and add member if needed"""
211 212 213 214 215 216 217 218
        fields = super().get_readonly_fields(request, obj)
        if 'member' not in fields and obj is not None:
            return fields + ['member']
        return fields

    @staticmethod
    def name(obj):
        return obj.member.get_full_name()
219
    name.short_description = _('name')
220 221 222 223

    @staticmethod
    def email(obj):
        return obj.member.email