Skip to content

Commit 5a407c3

Browse files
authored
Move grant summary under Conference (#4005)
1 parent 0a4908c commit 5a407c3

File tree

12 files changed

+393
-298
lines changed

12 files changed

+393
-298
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from .conference import (
2+
ConferenceAdmin,
3+
DeadlineAdmin,
4+
AudienceLevelAdmin,
5+
SpeakerVoucherAdmin,
6+
TopicAdmin,
7+
)
8+
9+
__all__ = [
10+
"AudienceLevelAdmin",
11+
"ConferenceAdmin",
12+
"DeadlineAdmin",
13+
"SpeakerVoucherAdmin",
14+
"TopicAdmin",
15+
]
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from django.contrib import admin, messages
2+
from conferences.models import SpeakerVoucher
3+
from pretix import create_voucher
4+
from schedule.tasks import send_speaker_voucher_email
5+
6+
7+
@admin.action(description="Send voucher via email")
8+
def send_voucher_via_email(modeladmin, request, queryset):
9+
is_filtered_by_conference = (
10+
queryset.values_list("conference_id").distinct().count() == 1
11+
)
12+
13+
if not is_filtered_by_conference:
14+
messages.error(request, "Please select only one conference")
15+
return
16+
17+
count = 0
18+
for speaker_voucher in queryset.filter(pretix_voucher_id__isnull=False):
19+
send_speaker_voucher_email.delay(speaker_voucher_id=speaker_voucher.id)
20+
count = count + 1
21+
22+
messages.success(request, f"{count} Voucher emails scheduled!")
23+
24+
25+
@admin.action(description="Create speaker vouchers on Pretix")
26+
def create_speaker_vouchers_on_pretix(modeladmin, request, queryset):
27+
is_filtered_by_conference = (
28+
queryset.values_list("conference_id").distinct().count() == 1
29+
)
30+
31+
if not is_filtered_by_conference:
32+
messages.error(request, "Please select only one conference")
33+
return
34+
35+
conference = queryset.only("conference_id").first().conference
36+
37+
if not conference.pretix_speaker_voucher_quota_id:
38+
messages.error(
39+
request,
40+
"Please configure the speaker voucher quota ID in the conference settings",
41+
)
42+
return
43+
44+
count = 0
45+
46+
for speaker_voucher in queryset.filter(pretix_voucher_id__isnull=True):
47+
if speaker_voucher.voucher_type == SpeakerVoucher.VoucherType.SPEAKER:
48+
price_mode = "set"
49+
value = "0.00"
50+
elif speaker_voucher.voucher_type == SpeakerVoucher.VoucherType.CO_SPEAKER:
51+
price_mode = "percent"
52+
value = "25.00"
53+
54+
pretix_voucher = create_voucher(
55+
conference=speaker_voucher.conference,
56+
code=speaker_voucher.voucher_code,
57+
comment=f"Voucher for user_id={speaker_voucher.user_id}",
58+
tag="speakers",
59+
quota_id=speaker_voucher.conference.pretix_speaker_voucher_quota_id,
60+
price_mode=price_mode,
61+
value=value,
62+
)
63+
64+
pretix_voucher_id = pretix_voucher["id"]
65+
speaker_voucher.pretix_voucher_id = pretix_voucher_id
66+
speaker_voucher.save()
67+
count = count + 1
68+
69+
messages.success(request, f"{count} Vouchers created on Pretix!")
Lines changed: 12 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@
1919
from itertools import permutations
2020
from unicodedata import normalize
2121
from conferences.models import SpeakerVoucher
22-
from pretix import create_voucher
2322
from schedule.models import ScheduleItem
24-
from schedule.tasks import send_speaker_voucher_email
2523
from sponsors.models import SponsorLevel
2624
from voting.models import IncludedEvent
2725
import re
28-
from .models import (
26+
from conferences.models import (
2927
AudienceLevel,
3028
Conference,
3129
Deadline,
@@ -34,6 +32,8 @@
3432
KeynoteSpeaker,
3533
Topic,
3634
)
35+
from conferences.admin.views import grants_summary
36+
from .actions import send_voucher_via_email, create_speaker_vouchers_on_pretix
3737

3838

3939
def validate_deadlines_form(forms):
@@ -100,7 +100,10 @@ class IncludedEventInline(admin.TabularInline):
100100

101101

102102
@admin.register(Conference)
103-
class ConferenceAdmin(OrderedInlineModelAdminMixin, admin.ModelAdmin):
103+
class ConferenceAdmin(
104+
OrderedInlineModelAdminMixin,
105+
admin.ModelAdmin,
106+
):
104107
list_display = (
105108
"name",
106109
"code",
@@ -201,6 +204,11 @@ def get_urls(self):
201204
self.admin_site.admin_view(self.schedule_builder),
202205
name="schedule_builder",
203206
),
207+
path(
208+
"<int:object_id>/grants-summary/",
209+
self.admin_site.admin_view(grants_summary),
210+
name="grants_summary",
211+
),
204212
] + super().get_urls()
205213

206214
def schedule_builder(self, request, object_id):
@@ -471,71 +479,6 @@ def get_queryset(self, request):
471479
return Keynote.all_objects.all()
472480

473481

474-
@admin.action(description="Send voucher via email")
475-
def send_voucher_via_email(modeladmin, request, queryset):
476-
is_filtered_by_conference = (
477-
queryset.values_list("conference_id").distinct().count() == 1
478-
)
479-
480-
if not is_filtered_by_conference:
481-
messages.error(request, "Please select only one conference")
482-
return
483-
484-
count = 0
485-
for speaker_voucher in queryset.filter(pretix_voucher_id__isnull=False):
486-
send_speaker_voucher_email.delay(speaker_voucher_id=speaker_voucher.id)
487-
count = count + 1
488-
489-
messages.success(request, f"{count} Voucher emails scheduled!")
490-
491-
492-
@admin.action(description="Create speaker vouchers on Pretix")
493-
def create_speaker_vouchers_on_pretix(modeladmin, request, queryset):
494-
is_filtered_by_conference = (
495-
queryset.values_list("conference_id").distinct().count() == 1
496-
)
497-
498-
if not is_filtered_by_conference:
499-
messages.error(request, "Please select only one conference")
500-
return
501-
502-
conference = queryset.only("conference_id").first().conference
503-
504-
if not conference.pretix_speaker_voucher_quota_id:
505-
messages.error(
506-
request,
507-
"Please configure the speaker voucher quota ID in the conference settings",
508-
)
509-
return
510-
511-
count = 0
512-
513-
for speaker_voucher in queryset.filter(pretix_voucher_id__isnull=True):
514-
if speaker_voucher.voucher_type == SpeakerVoucher.VoucherType.SPEAKER:
515-
price_mode = "set"
516-
value = "0.00"
517-
elif speaker_voucher.voucher_type == SpeakerVoucher.VoucherType.CO_SPEAKER:
518-
price_mode = "percent"
519-
value = "25.00"
520-
521-
pretix_voucher = create_voucher(
522-
conference=speaker_voucher.conference,
523-
code=speaker_voucher.voucher_code,
524-
comment=f"Voucher for user_id={speaker_voucher.user_id}",
525-
tag="speakers",
526-
quota_id=speaker_voucher.conference.pretix_speaker_voucher_quota_id,
527-
price_mode=price_mode,
528-
value=value,
529-
)
530-
531-
pretix_voucher_id = pretix_voucher["id"]
532-
speaker_voucher.pretix_voucher_id = pretix_voucher_id
533-
speaker_voucher.save()
534-
count = count + 1
535-
536-
messages.success(request, f"{count} Vouchers created on Pretix!")
537-
538-
539482
class SpeakerVoucherForm(forms.ModelForm):
540483
class Meta:
541484
model = SpeakerVoucher

backend/conferences/admin/views.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from django.shortcuts import render
2+
from grants.summary import GrantSummary
3+
from django.contrib.admin import site as admin_site
4+
5+
6+
def grants_summary(request, object_id):
7+
context = GrantSummary().calculate(conference_id=object_id)
8+
9+
return render(
10+
request,
11+
"admin/grants/grant_summary.html",
12+
{**context, **admin_site.each_context(request)},
13+
)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% extends "admin/change_form.html" %}
2+
{% block object-tools-items %}
3+
<li>
4+
<a href="{% url 'admin:grants_summary' object_id=original.id %}" class="button">
5+
Grants Summary
6+
</a>
7+
</li>
8+
{{ block.super }}
9+
{% endblock %}

backend/conferences/tests/test_admin.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,15 @@
1919

2020
from conferences.admin import (
2121
ConferenceAdmin,
22-
DeadlineForm,
22+
)
23+
from conferences.admin.actions import (
2324
create_speaker_vouchers_on_pretix,
2425
send_voucher_via_email,
26+
)
27+
from conferences.admin.conference import (
2528
validate_deadlines_form,
2629
walk_conference_videos_folder,
30+
DeadlineForm,
2731
)
2832
from conferences.models import SpeakerVoucher
2933
from schedule.models import ScheduleItem
@@ -185,8 +189,10 @@ def test_send_voucher_via_email(
185189
rf,
186190
mocker,
187191
):
188-
mocker.patch("conferences.admin.messages")
189-
mock_send_email = mocker.patch("conferences.admin.send_speaker_voucher_email")
192+
mocker.patch("conferences.admin.actions.messages")
193+
mock_send_email = mocker.patch(
194+
"conferences.admin.actions.send_speaker_voucher_email"
195+
)
190196

191197
conference = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
192198
schedule_item_1 = ScheduleItemFactory(
@@ -229,8 +235,10 @@ def test_send_voucher_via_email_requires_filtering_by_conference(
229235
rf,
230236
mocker,
231237
):
232-
mock_messages = mocker.patch("conferences.admin.messages")
233-
mock_send_email = mocker.patch("conferences.admin.send_speaker_voucher_email")
238+
mock_messages = mocker.patch("conferences.admin.actions.messages")
239+
mock_send_email = mocker.patch(
240+
"conferences.admin.actions.send_speaker_voucher_email"
241+
)
234242

235243
conference = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
236244
conference_2 = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
@@ -274,14 +282,14 @@ def test_send_voucher_via_email_requires_filtering_by_conference(
274282

275283
def test_create_speaker_vouchers_on_pretix(rf, mocker):
276284
mock_create_voucher = mocker.patch(
277-
"conferences.admin.create_voucher",
285+
"conferences.admin.actions.create_voucher",
278286
side_effect=[
279287
{"id": 1},
280288
{"id": 2},
281289
{"id": 3},
282290
],
283291
)
284-
mocker.patch("conferences.admin.messages")
292+
mocker.patch("conferences.admin.actions.messages")
285293

286294
conference = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
287295

@@ -354,12 +362,12 @@ def test_create_speaker_vouchers_on_pretix(rf, mocker):
354362

355363
def test_create_speaker_vouchers_on_pretix_only_for_missing_ones(rf, mocker):
356364
mock_create_voucher = mocker.patch(
357-
"conferences.admin.create_voucher",
365+
"conferences.admin.actions.create_voucher",
358366
side_effect=[
359367
{"id": 1},
360368
],
361369
)
362-
mocker.patch("conferences.admin.messages")
370+
mocker.patch("conferences.admin.actions.messages")
363371

364372
conference = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
365373

@@ -402,13 +410,13 @@ def test_create_speaker_vouchers_on_pretix_doesnt_work_with_multiple_conferences
402410
rf, mocker
403411
):
404412
mock_create_voucher = mocker.patch(
405-
"conferences.admin.create_voucher",
413+
"conferences.admin.actions.create_voucher",
406414
side_effect=[
407415
{"id": 1},
408416
{"id": 2},
409417
],
410418
)
411-
mock_messages = mocker.patch("conferences.admin.messages")
419+
mock_messages = mocker.patch("conferences.admin.actions.messages")
412420

413421
conference = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
414422
conference_2 = ConferenceFactory(pretix_speaker_voucher_quota_id=123)
@@ -451,13 +459,13 @@ def test_create_speaker_vouchers_on_pretix_doesnt_work_without_pretix_config(
451459
rf, mocker
452460
):
453461
mock_create_voucher = mocker.patch(
454-
"conferences.admin.create_voucher",
462+
"conferences.admin.actions.create_voucher",
455463
side_effect=[
456464
{"id": 1},
457465
{"id": 2},
458466
],
459467
)
460-
mock_messages = mocker.patch("conferences.admin.messages")
468+
mock_messages = mocker.patch("conferences.admin.actions.messages")
461469

462470
conference = ConferenceFactory(pretix_speaker_voucher_quota_id=None)
463471

@@ -507,7 +515,7 @@ def test_video_uploaded_path_matcher(
507515
marcsed = UserFactory(id=99, name="Marcsed", full_name="Marcsed Cazzęfa")
508516

509517
mocker.patch(
510-
"conferences.admin.walk_conference_videos_folder",
518+
"conferences.admin.conference.walk_conference_videos_folder",
511519
return_value=[
512520
"conf/video-1/1-Kim Kitsuragi.mp4",
513521
"conf/video-2/2-Opening.mp4",

0 commit comments

Comments
 (0)