We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Prevent event registrations cancelling when registration is paid (or where you were present)
### Is your feature request related to a problem? Please describe.
Currently it is technically possible to pay for an event and afterwards cancel your registration. That should not be possible (at least not by users themselves). This never was a real problem in practice but now with Thalia Pay the problem appears.

### Describe the solution you'd like
When a payment exists for an event registration, don't allow cancelling. Also when paying with Thalia Pay we might want to make explicit that after paying you can't cancel anymore (without maybe contacting the board). 

### Motivation

### Describe alternatives you've considered
- Only really creating the payment at the date of the event → too complex (code)
- As proposed here, but do allow cancellation when the payment is a TPay payment that is not processed yet → too complex (for users)
- Keeping things as it is (allow cancelling and accept people may pay without joining - it could be considered a feature) → felt undesirable, also without TPay

### Additional context


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `website/events/services.py`
Content:
```
1 from collections import OrderedDict
2 
3 from django.utils import timezone
4 from django.utils.datetime_safe import date
5 from django.utils.translation import gettext_lazy as _, get_language
6 
7 from events import emails
8 from events.exceptions import RegistrationError
9 from events.models import EventRegistration, RegistrationInformationField, Event
10 from payments.api.fields import PaymentTypeField
11 from payments.services import create_payment, delete_payment
12 from utils.snippets import datetime_to_lectureyear
13 
14 
15 def is_user_registered(member, event):
16     """
17     Returns if the user is registered for the specified event
18 
19     :param member: the user
20     :param event: the event
21     :return: None if registration is not required or no member else True/False
22     """
23     if not event.registration_required or not member.is_authenticated:
24         return None
25 
26     return event.registrations.filter(member=member, date_cancelled=None).count() > 0
27 
28 
29 def event_permissions(member, event, name=None):
30     """
31     Returns a dictionary with the available event permissions of the user
32 
33     :param member: the user
34     :param event: the event
35     :param name: the name of a non member registration
36     :return: the permission dictionary
37     """
38     perms = {
39         "create_registration": False,
40         "cancel_registration": False,
41         "update_registration": False,
42     }
43     if not member:
44         return perms
45     if not (member.is_authenticated or name):
46         return perms
47 
48     registration = None
49     try:
50         registration = EventRegistration.objects.get(
51             event=event, member=member, name=name
52         )
53     except EventRegistration.DoesNotExist:
54         pass
55 
56     perms["create_registration"] = (
57         (registration is None or registration.date_cancelled is not None)
58         and event.registration_allowed
59         and (name or member.can_attend_events)
60     )
61     perms["cancel_registration"] = (
62         registration is not None
63         and registration.date_cancelled is None
64         and (event.cancellation_allowed or name)
65     )
66     perms["update_registration"] = (
67         registration is not None
68         and registration.date_cancelled is None
69         and event.has_fields()
70         and event.registration_allowed
71         and (name or member.can_attend_events)
72     )
73     return perms
74 
75 
76 def is_organiser(member, event):
77     if member and member.is_authenticated:
78         if member.is_superuser or member.has_perm("events.override_organiser"):
79             return True
80 
81         if event:
82             return member.get_member_groups().filter(pk=event.organiser.pk).count() != 0
83 
84     return False
85 
86 
87 def create_registration(member, event):
88     """
89     Creates a new user registration for an event
90 
91     :param member: the user
92     :param event: the event
93     :return: returns the registration if successful
94     """
95     if event_permissions(member, event)["create_registration"]:
96         registration = None
97         try:
98             registration = EventRegistration.objects.get(event=event, member=member)
99         except EventRegistration.DoesNotExist:
100             pass
101 
102         if registration is None:
103             return EventRegistration.objects.create(event=event, member=member)
104         elif registration.date_cancelled is not None:
105             if registration.is_late_cancellation():
106                 raise RegistrationError(
107                     _(
108                         "You cannot re-register anymore "
109                         "since you've cancelled after the "
110                         "deadline."
111                     )
112                 )
113             else:
114                 registration.date = timezone.now()
115                 registration.date_cancelled = None
116                 registration.save()
117 
118         return registration
119     elif event_permissions(member, event)["cancel_registration"]:
120         raise RegistrationError(_("You were already registered."))
121     else:
122         raise RegistrationError(_("You may not register."))
123 
124 
125 def cancel_registration(member, event):
126     """
127     Cancel a user registration for an event
128 
129     :param member: the user
130     :param event: the event
131     """
132     registration = None
133     try:
134         registration = EventRegistration.objects.get(event=event, member=member)
135     except EventRegistration.DoesNotExist:
136         pass
137 
138     if event_permissions(member, event)["cancel_registration"] and registration:
139         if registration.payment is not None:
140             delete_payment(registration)
141         if registration.queue_position == 0:
142             emails.notify_first_waiting(event)
143 
144             if event.send_cancel_email and event.after_cancel_deadline:
145                 emails.notify_organiser(event, registration)
146 
147         # Note that this doesn"t remove the values for the
148         # information fields that the user entered upon registering.
149         # But this is regarded as a feature, not a bug. Especially
150         # since the values will still appear in the backend.
151         registration.date_cancelled = timezone.now()
152         registration.save()
153     else:
154         raise RegistrationError(_("You are not registered for this event."))
155 
156 
157 def update_registration(
158     member=None, event=None, name=None, registration=None, field_values=None
159 ):
160     """
161     Updates a user registration of an event
162 
163     :param request: http request
164     :param member: the user
165     :param event: the event
166     :param name: the name of a registration not associated with a user
167     :param registration: the registration
168     :param field_values: values for the information fields
169     """
170     if not registration:
171         try:
172             registration = EventRegistration.objects.get(
173                 event=event, member=member, name=name
174             )
175         except EventRegistration.DoesNotExist as error:
176             raise RegistrationError(
177                 _("You are not registered for this event.")
178             ) from error
179     else:
180         member = registration.member
181         event = registration.event
182         name = registration.name
183 
184     if (
185         not event_permissions(member, event, name)["update_registration"]
186         or not field_values
187     ):
188         return
189 
190     for field_id, field_value in field_values:
191         field = RegistrationInformationField.objects.get(
192             id=field_id.replace("info_field_", "")
193         )
194 
195         if (
196             field.type == RegistrationInformationField.INTEGER_FIELD
197             and field_value is None
198         ):
199             field_value = 0
200         elif (
201             field.type == RegistrationInformationField.BOOLEAN_FIELD
202             and field_value is None
203         ):
204             field_value = False
205         elif (
206             field.type == RegistrationInformationField.TEXT_FIELD
207             and field_value is None
208         ):
209             field_value = ""
210 
211         field.set_value_for(registration, field_value)
212 
213 
214 def registration_fields(request, member=None, event=None, registration=None, name=None):
215     """
216     Returns information about the registration fields of a registration
217 
218     :param member: the user (optional if registration provided)
219     :param name: the name of a non member registration
220                  (optional if registration provided)
221     :param event: the event (optional if registration provided)
222     :param registration: the registration (optional if member & event provided)
223     :return: the fields
224     """
225 
226     if registration is None:
227         try:
228             registration = EventRegistration.objects.get(
229                 event=event, member=member, name=name
230             )
231         except EventRegistration.DoesNotExist as error:
232             raise RegistrationError(
233                 _("You are not registered for this event.")
234             ) from error
235         except EventRegistration.MultipleObjectsReturned as error:
236             raise RegistrationError(
237                 _("Unable to find the right registration.")
238             ) from error
239     else:
240         member = registration.member
241         event = registration.event
242         name = registration.name
243 
244     perms = event_permissions(member, event, name)[
245         "update_registration"
246     ] or is_organiser(request.member, event)
247     if perms and registration:
248         information_fields = registration.information_fields
249         fields = OrderedDict()
250 
251         for information_field in information_fields:
252             field = information_field["field"]
253 
254             fields["info_field_{}".format(field.id)] = {
255                 "type": field.type,
256                 "label": getattr(field, "{}_{}".format("name", get_language())),
257                 "description": getattr(
258                     field, "{}_{}".format("description", get_language())
259                 ),
260                 "value": information_field["value"],
261                 "required": field.required,
262             }
263 
264         return fields
265     else:
266         raise RegistrationError(_("You are not allowed to update this registration."))
267 
268 
269 def update_registration_by_organiser(registration, member, data):
270     if not is_organiser(member, registration.event):
271         raise RegistrationError(_("You are not allowed to update this registration."))
272 
273     if "payment" in data:
274         if data["payment"]["type"] == PaymentTypeField.NO_PAYMENT:
275             if registration.payment is not None:
276                 delete_payment(registration)
277         else:
278             registration.payment = create_payment(
279                 payable=registration,
280                 processed_by=member,
281                 pay_type=data["payment"]["type"],
282             )
283 
284     if "present" in data:
285         registration.present = data["present"]
286 
287     registration.save()
288 
289 
290 def generate_category_statistics():
291     """
292     Generate statistics about events, number of events per category
293     :return: Dict with key, value resp. being category, event count.
294     """
295     year = datetime_to_lectureyear(timezone.now())
296 
297     data = {}
298     for i in range(5):
299         year_start = date(year=year - i, month=9, day=1)
300         year_end = date(year=year - i + 1, month=9, day=1)
301         data[str(year - i)] = {
302             str(display): Event.objects.filter(
303                 category=key, start__gte=year_start, end__lte=year_end
304             ).count()
305             for key, display in Event.EVENT_CATEGORIES
306         }
307 
308     return data
309
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/website/events/services.py b/website/events/services.py
--- a/website/events/services.py
+++ b/website/events/services.py
@@ -62,6 +62,7 @@
         registration is not None
         and registration.date_cancelled is None
         and (event.cancellation_allowed or name)
+        and registration.payment is None
     )
     perms["update_registration"] = (
         registration is not None
@@ -136,8 +137,6 @@
         pass
 
     if event_permissions(member, event)["cancel_registration"] and registration:
-        if registration.payment is not None:
-            delete_payment(registration)
         if registration.queue_position == 0:
             emails.notify_first_waiting(event)
 
@@ -151,7 +150,7 @@
         registration.date_cancelled = timezone.now()
         registration.save()
     else:
-        raise RegistrationError(_("You are not registered for this event."))
+        raise RegistrationError(_("You are not allowed to deregister for this event."))
 
 
 def update_registration(

{"golden_diff": "diff --git a/website/events/services.py b/website/events/services.py\n--- a/website/events/services.py\n+++ b/website/events/services.py\n@@ -62,6 +62,7 @@\n         registration is not None\n         and registration.date_cancelled is None\n         and (event.cancellation_allowed or name)\n+        and registration.payment is None\n     )\n     perms[\"update_registration\"] = (\n         registration is not None\n@@ -136,8 +137,6 @@\n         pass\n \n     if event_permissions(member, event)[\"cancel_registration\"] and registration:\n-        if registration.payment is not None:\n-            delete_payment(registration)\n         if registration.queue_position == 0:\n             emails.notify_first_waiting(event)\n \n@@ -151,7 +150,7 @@\n         registration.date_cancelled = timezone.now()\n         registration.save()\n     else:\n-        raise RegistrationError(_(\"You are not registered for this event.\"))\n+        raise RegistrationError(_(\"You are not allowed to deregister for this event.\"))\n \n \n def update_registration(\n", "issue": "Prevent event registrations cancelling when registration is paid (or where you were present)\n### Is your feature request related to a problem? Please describe.\r\nCurrently it is technically possible to pay for an event and afterwards cancel your registration. That should not be possible (at least not by users themselves). This never was a real problem in practice but now with Thalia Pay the problem appears.\r\n\r\n### Describe the solution you'd like\r\nWhen a payment exists for an event registration, don't allow cancelling. Also when paying with Thalia Pay we might want to make explicit that after paying you can't cancel anymore (without maybe contacting the board). \r\n\r\n### Motivation\r\n\r\n### Describe alternatives you've considered\r\n- Only really creating the payment at the date of the event \u2192 too complex (code)\r\n- As proposed here, but do allow cancellation when the payment is a TPay payment that is not processed yet \u2192 too complex (for users)\r\n- Keeping things as it is (allow cancelling and accept people may pay without joining - it could be considered a feature) \u2192 felt undesirable, also without TPay\r\n\r\n### Additional context\r\n\n", "before_files": [{"content": "from collections import OrderedDict\n\nfrom django.utils import timezone\nfrom django.utils.datetime_safe import date\nfrom django.utils.translation import gettext_lazy as _, get_language\n\nfrom events import emails\nfrom events.exceptions import RegistrationError\nfrom events.models import EventRegistration, RegistrationInformationField, Event\nfrom payments.api.fields import PaymentTypeField\nfrom payments.services import create_payment, delete_payment\nfrom utils.snippets import datetime_to_lectureyear\n\n\ndef is_user_registered(member, event):\n    \"\"\"\n    Returns if the user is registered for the specified event\n\n    :param member: the user\n    :param event: the event\n    :return: None if registration is not required or no member else True/False\n    \"\"\"\n    if not event.registration_required or not member.is_authenticated:\n        return None\n\n    return event.registrations.filter(member=member, date_cancelled=None).count() > 0\n\n\ndef event_permissions(member, event, name=None):\n    \"\"\"\n    Returns a dictionary with the available event permissions of the user\n\n    :param member: the user\n    :param event: the event\n    :param name: the name of a non member registration\n    :return: the permission dictionary\n    \"\"\"\n    perms = {\n        \"create_registration\": False,\n        \"cancel_registration\": False,\n        \"update_registration\": False,\n    }\n    if not member:\n        return perms\n    if not (member.is_authenticated or name):\n        return perms\n\n    registration = None\n    try:\n        registration = EventRegistration.objects.get(\n            event=event, member=member, name=name\n        )\n    except EventRegistration.DoesNotExist:\n        pass\n\n    perms[\"create_registration\"] = (\n        (registration is None or registration.date_cancelled is not None)\n        and event.registration_allowed\n        and (name or member.can_attend_events)\n    )\n    perms[\"cancel_registration\"] = (\n        registration is not None\n        and registration.date_cancelled is None\n        and (event.cancellation_allowed or name)\n    )\n    perms[\"update_registration\"] = (\n        registration is not None\n        and registration.date_cancelled is None\n        and event.has_fields()\n        and event.registration_allowed\n        and (name or member.can_attend_events)\n    )\n    return perms\n\n\ndef is_organiser(member, event):\n    if member and member.is_authenticated:\n        if member.is_superuser or member.has_perm(\"events.override_organiser\"):\n            return True\n\n        if event:\n            return member.get_member_groups().filter(pk=event.organiser.pk).count() != 0\n\n    return False\n\n\ndef create_registration(member, event):\n    \"\"\"\n    Creates a new user registration for an event\n\n    :param member: the user\n    :param event: the event\n    :return: returns the registration if successful\n    \"\"\"\n    if event_permissions(member, event)[\"create_registration\"]:\n        registration = None\n        try:\n            registration = EventRegistration.objects.get(event=event, member=member)\n        except EventRegistration.DoesNotExist:\n            pass\n\n        if registration is None:\n            return EventRegistration.objects.create(event=event, member=member)\n        elif registration.date_cancelled is not None:\n            if registration.is_late_cancellation():\n                raise RegistrationError(\n                    _(\n                        \"You cannot re-register anymore \"\n                        \"since you've cancelled after the \"\n                        \"deadline.\"\n                    )\n                )\n            else:\n                registration.date = timezone.now()\n                registration.date_cancelled = None\n                registration.save()\n\n        return registration\n    elif event_permissions(member, event)[\"cancel_registration\"]:\n        raise RegistrationError(_(\"You were already registered.\"))\n    else:\n        raise RegistrationError(_(\"You may not register.\"))\n\n\ndef cancel_registration(member, event):\n    \"\"\"\n    Cancel a user registration for an event\n\n    :param member: the user\n    :param event: the event\n    \"\"\"\n    registration = None\n    try:\n        registration = EventRegistration.objects.get(event=event, member=member)\n    except EventRegistration.DoesNotExist:\n        pass\n\n    if event_permissions(member, event)[\"cancel_registration\"] and registration:\n        if registration.payment is not None:\n            delete_payment(registration)\n        if registration.queue_position == 0:\n            emails.notify_first_waiting(event)\n\n            if event.send_cancel_email and event.after_cancel_deadline:\n                emails.notify_organiser(event, registration)\n\n        # Note that this doesn\"t remove the values for the\n        # information fields that the user entered upon registering.\n        # But this is regarded as a feature, not a bug. Especially\n        # since the values will still appear in the backend.\n        registration.date_cancelled = timezone.now()\n        registration.save()\n    else:\n        raise RegistrationError(_(\"You are not registered for this event.\"))\n\n\ndef update_registration(\n    member=None, event=None, name=None, registration=None, field_values=None\n):\n    \"\"\"\n    Updates a user registration of an event\n\n    :param request: http request\n    :param member: the user\n    :param event: the event\n    :param name: the name of a registration not associated with a user\n    :param registration: the registration\n    :param field_values: values for the information fields\n    \"\"\"\n    if not registration:\n        try:\n            registration = EventRegistration.objects.get(\n                event=event, member=member, name=name\n            )\n        except EventRegistration.DoesNotExist as error:\n            raise RegistrationError(\n                _(\"You are not registered for this event.\")\n            ) from error\n    else:\n        member = registration.member\n        event = registration.event\n        name = registration.name\n\n    if (\n        not event_permissions(member, event, name)[\"update_registration\"]\n        or not field_values\n    ):\n        return\n\n    for field_id, field_value in field_values:\n        field = RegistrationInformationField.objects.get(\n            id=field_id.replace(\"info_field_\", \"\")\n        )\n\n        if (\n            field.type == RegistrationInformationField.INTEGER_FIELD\n            and field_value is None\n        ):\n            field_value = 0\n        elif (\n            field.type == RegistrationInformationField.BOOLEAN_FIELD\n            and field_value is None\n        ):\n            field_value = False\n        elif (\n            field.type == RegistrationInformationField.TEXT_FIELD\n            and field_value is None\n        ):\n            field_value = \"\"\n\n        field.set_value_for(registration, field_value)\n\n\ndef registration_fields(request, member=None, event=None, registration=None, name=None):\n    \"\"\"\n    Returns information about the registration fields of a registration\n\n    :param member: the user (optional if registration provided)\n    :param name: the name of a non member registration\n                 (optional if registration provided)\n    :param event: the event (optional if registration provided)\n    :param registration: the registration (optional if member & event provided)\n    :return: the fields\n    \"\"\"\n\n    if registration is None:\n        try:\n            registration = EventRegistration.objects.get(\n                event=event, member=member, name=name\n            )\n        except EventRegistration.DoesNotExist as error:\n            raise RegistrationError(\n                _(\"You are not registered for this event.\")\n            ) from error\n        except EventRegistration.MultipleObjectsReturned as error:\n            raise RegistrationError(\n                _(\"Unable to find the right registration.\")\n            ) from error\n    else:\n        member = registration.member\n        event = registration.event\n        name = registration.name\n\n    perms = event_permissions(member, event, name)[\n        \"update_registration\"\n    ] or is_organiser(request.member, event)\n    if perms and registration:\n        information_fields = registration.information_fields\n        fields = OrderedDict()\n\n        for information_field in information_fields:\n            field = information_field[\"field\"]\n\n            fields[\"info_field_{}\".format(field.id)] = {\n                \"type\": field.type,\n                \"label\": getattr(field, \"{}_{}\".format(\"name\", get_language())),\n                \"description\": getattr(\n                    field, \"{}_{}\".format(\"description\", get_language())\n                ),\n                \"value\": information_field[\"value\"],\n                \"required\": field.required,\n            }\n\n        return fields\n    else:\n        raise RegistrationError(_(\"You are not allowed to update this registration.\"))\n\n\ndef update_registration_by_organiser(registration, member, data):\n    if not is_organiser(member, registration.event):\n        raise RegistrationError(_(\"You are not allowed to update this registration.\"))\n\n    if \"payment\" in data:\n        if data[\"payment\"][\"type\"] == PaymentTypeField.NO_PAYMENT:\n            if registration.payment is not None:\n                delete_payment(registration)\n        else:\n            registration.payment = create_payment(\n                payable=registration,\n                processed_by=member,\n                pay_type=data[\"payment\"][\"type\"],\n            )\n\n    if \"present\" in data:\n        registration.present = data[\"present\"]\n\n    registration.save()\n\n\ndef generate_category_statistics():\n    \"\"\"\n    Generate statistics about events, number of events per category\n    :return: Dict with key, value resp. being category, event count.\n    \"\"\"\n    year = datetime_to_lectureyear(timezone.now())\n\n    data = {}\n    for i in range(5):\n        year_start = date(year=year - i, month=9, day=1)\n        year_end = date(year=year - i + 1, month=9, day=1)\n        data[str(year - i)] = {\n            str(display): Event.objects.filter(\n                category=key, start__gte=year_start, end__lte=year_end\n            ).count()\n            for key, display in Event.EVENT_CATEGORIES\n        }\n\n    return data\n", "path": "website/events/services.py"}], "after_files": [{"content": "from collections import OrderedDict\n\nfrom django.utils import timezone\nfrom django.utils.datetime_safe import date\nfrom django.utils.translation import gettext_lazy as _, get_language\n\nfrom events import emails\nfrom events.exceptions import RegistrationError\nfrom events.models import EventRegistration, RegistrationInformationField, Event\nfrom payments.api.fields import PaymentTypeField\nfrom payments.services import create_payment, delete_payment\nfrom utils.snippets import datetime_to_lectureyear\n\n\ndef is_user_registered(member, event):\n    \"\"\"\n    Returns if the user is registered for the specified event\n\n    :param member: the user\n    :param event: the event\n    :return: None if registration is not required or no member else True/False\n    \"\"\"\n    if not event.registration_required or not member.is_authenticated:\n        return None\n\n    return event.registrations.filter(member=member, date_cancelled=None).count() > 0\n\n\ndef event_permissions(member, event, name=None):\n    \"\"\"\n    Returns a dictionary with the available event permissions of the user\n\n    :param member: the user\n    :param event: the event\n    :param name: the name of a non member registration\n    :return: the permission dictionary\n    \"\"\"\n    perms = {\n        \"create_registration\": False,\n        \"cancel_registration\": False,\n        \"update_registration\": False,\n    }\n    if not member:\n        return perms\n    if not (member.is_authenticated or name):\n        return perms\n\n    registration = None\n    try:\n        registration = EventRegistration.objects.get(\n            event=event, member=member, name=name\n        )\n    except EventRegistration.DoesNotExist:\n        pass\n\n    perms[\"create_registration\"] = (\n        (registration is None or registration.date_cancelled is not None)\n        and event.registration_allowed\n        and (name or member.can_attend_events)\n    )\n    perms[\"cancel_registration\"] = (\n        registration is not None\n        and registration.date_cancelled is None\n        and (event.cancellation_allowed or name)\n        and registration.payment is None\n    )\n    perms[\"update_registration\"] = (\n        registration is not None\n        and registration.date_cancelled is None\n        and event.has_fields()\n        and event.registration_allowed\n        and (name or member.can_attend_events)\n    )\n    return perms\n\n\ndef is_organiser(member, event):\n    if member and member.is_authenticated:\n        if member.is_superuser or member.has_perm(\"events.override_organiser\"):\n            return True\n\n        if event:\n            return member.get_member_groups().filter(pk=event.organiser.pk).count() != 0\n\n    return False\n\n\ndef create_registration(member, event):\n    \"\"\"\n    Creates a new user registration for an event\n\n    :param member: the user\n    :param event: the event\n    :return: returns the registration if successful\n    \"\"\"\n    if event_permissions(member, event)[\"create_registration\"]:\n        registration = None\n        try:\n            registration = EventRegistration.objects.get(event=event, member=member)\n        except EventRegistration.DoesNotExist:\n            pass\n\n        if registration is None:\n            return EventRegistration.objects.create(event=event, member=member)\n        elif registration.date_cancelled is not None:\n            if registration.is_late_cancellation():\n                raise RegistrationError(\n                    _(\n                        \"You cannot re-register anymore \"\n                        \"since you've cancelled after the \"\n                        \"deadline.\"\n                    )\n                )\n            else:\n                registration.date = timezone.now()\n                registration.date_cancelled = None\n                registration.save()\n\n        return registration\n    elif event_permissions(member, event)[\"cancel_registration\"]:\n        raise RegistrationError(_(\"You were already registered.\"))\n    else:\n        raise RegistrationError(_(\"You may not register.\"))\n\n\ndef cancel_registration(member, event):\n    \"\"\"\n    Cancel a user registration for an event\n\n    :param member: the user\n    :param event: the event\n    \"\"\"\n    registration = None\n    try:\n        registration = EventRegistration.objects.get(event=event, member=member)\n    except EventRegistration.DoesNotExist:\n        pass\n\n    if event_permissions(member, event)[\"cancel_registration\"] and registration:\n        if registration.queue_position == 0:\n            emails.notify_first_waiting(event)\n\n            if event.send_cancel_email and event.after_cancel_deadline:\n                emails.notify_organiser(event, registration)\n\n        # Note that this doesn\"t remove the values for the\n        # information fields that the user entered upon registering.\n        # But this is regarded as a feature, not a bug. Especially\n        # since the values will still appear in the backend.\n        registration.date_cancelled = timezone.now()\n        registration.save()\n    else:\n        raise RegistrationError(_(\"You are not allowed to deregister for this event.\"))\n\n\ndef update_registration(\n    member=None, event=None, name=None, registration=None, field_values=None\n):\n    \"\"\"\n    Updates a user registration of an event\n\n    :param request: http request\n    :param member: the user\n    :param event: the event\n    :param name: the name of a registration not associated with a user\n    :param registration: the registration\n    :param field_values: values for the information fields\n    \"\"\"\n    if not registration:\n        try:\n            registration = EventRegistration.objects.get(\n                event=event, member=member, name=name\n            )\n        except EventRegistration.DoesNotExist as error:\n            raise RegistrationError(\n                _(\"You are not registered for this event.\")\n            ) from error\n    else:\n        member = registration.member\n        event = registration.event\n        name = registration.name\n\n    if (\n        not event_permissions(member, event, name)[\"update_registration\"]\n        or not field_values\n    ):\n        return\n\n    for field_id, field_value in field_values:\n        field = RegistrationInformationField.objects.get(\n            id=field_id.replace(\"info_field_\", \"\")\n        )\n\n        if (\n            field.type == RegistrationInformationField.INTEGER_FIELD\n            and field_value is None\n        ):\n            field_value = 0\n        elif (\n            field.type == RegistrationInformationField.BOOLEAN_FIELD\n            and field_value is None\n        ):\n            field_value = False\n        elif (\n            field.type == RegistrationInformationField.TEXT_FIELD\n            and field_value is None\n        ):\n            field_value = \"\"\n\n        field.set_value_for(registration, field_value)\n\n\ndef registration_fields(request, member=None, event=None, registration=None, name=None):\n    \"\"\"\n    Returns information about the registration fields of a registration\n\n    :param member: the user (optional if registration provided)\n    :param name: the name of a non member registration\n                 (optional if registration provided)\n    :param event: the event (optional if registration provided)\n    :param registration: the registration (optional if member & event provided)\n    :return: the fields\n    \"\"\"\n\n    if registration is None:\n        try:\n            registration = EventRegistration.objects.get(\n                event=event, member=member, name=name\n            )\n        except EventRegistration.DoesNotExist as error:\n            raise RegistrationError(\n                _(\"You are not registered for this event.\")\n            ) from error\n        except EventRegistration.MultipleObjectsReturned as error:\n            raise RegistrationError(\n                _(\"Unable to find the right registration.\")\n            ) from error\n    else:\n        member = registration.member\n        event = registration.event\n        name = registration.name\n\n    perms = event_permissions(member, event, name)[\n        \"update_registration\"\n    ] or is_organiser(request.member, event)\n    if perms and registration:\n        information_fields = registration.information_fields\n        fields = OrderedDict()\n\n        for information_field in information_fields:\n            field = information_field[\"field\"]\n\n            fields[\"info_field_{}\".format(field.id)] = {\n                \"type\": field.type,\n                \"label\": getattr(field, \"{}_{}\".format(\"name\", get_language())),\n                \"description\": getattr(\n                    field, \"{}_{}\".format(\"description\", get_language())\n                ),\n                \"value\": information_field[\"value\"],\n                \"required\": field.required,\n            }\n\n        return fields\n    else:\n        raise RegistrationError(_(\"You are not allowed to update this registration.\"))\n\n\ndef update_registration_by_organiser(registration, member, data):\n    if not is_organiser(member, registration.event):\n        raise RegistrationError(_(\"You are not allowed to update this registration.\"))\n\n    if \"payment\" in data:\n        if data[\"payment\"][\"type\"] == PaymentTypeField.NO_PAYMENT:\n            if registration.payment is not None:\n                delete_payment(registration)\n        else:\n            registration.payment = create_payment(\n                payable=registration,\n                processed_by=member,\n                pay_type=data[\"payment\"][\"type\"],\n            )\n\n    if \"present\" in data:\n        registration.present = data[\"present\"]\n\n    registration.save()\n\n\ndef generate_category_statistics():\n    \"\"\"\n    Generate statistics about events, number of events per category\n    :return: Dict with key, value resp. being category, event count.\n    \"\"\"\n    year = datetime_to_lectureyear(timezone.now())\n\n    data = {}\n    for i in range(5):\n        year_start = date(year=year - i, month=9, day=1)\n        year_end = date(year=year - i + 1, month=9, day=1)\n        data[str(year - i)] = {\n            str(display): Event.objects.filter(\n                category=key, start__gte=year_start, end__lte=year_end\n            ).count()\n            for key, display in Event.EVENT_CATEGORIES\n        }\n\n    return data\n", "path": "website/events/services.py"}]}