Skip to content

Commit

Permalink
Merge branch 'master' into 867-feature-tilføj-regions-dropdown-i-admi…
Browse files Browse the repository at this point in the history
…n-delen-under-oprettelse-af-aktiviteter
  • Loading branch information
mhewel authored Mar 29, 2024
2 parents a79b085 + 0225a1b commit d130b6c
Show file tree
Hide file tree
Showing 13 changed files with 294 additions and 99 deletions.
17 changes: 9 additions & 8 deletions members/admin/activityinvite_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,21 @@ class Meta:
verbose_name = "Invitation"
verbose_name_plural = "Invitationer"

def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj=obj, change=change, **kwargs)
return form

list_display = (
"activity_department_union_link",
"activity_department_link",
"activity_link",
"pk",
"person_link",
"activity_link",
"person_age_years",
"person_zipcode",
"invite_dtm",
"expire_dtm",
"rejected_at",
"price_in_dkk",
"price_note",
"extra_email_info",
"participating",
"activity_department_union_link",
"activity_department_link",
)
list_filter = (
ActivityInviteUnionListFilter,
Expand All @@ -156,7 +156,6 @@ def get_form(self, request, obj=None, change=False, **kwargs):
search_help_text = mark_safe(
"Du kan søge på forening, afdeling, aktivitet eller person. <br>Vandret dato-filter er for aktivitetens startdato."
)
list_display_links = None
form = ActivityInviteAdminForm

# Only show invitation to own activities
Expand All @@ -177,6 +176,8 @@ def get_queryset(self, request):
"invite_dtm",
"expire_dtm",
"rejected_at",
"price_in_dkk",
"price_note",
),
},
),
Expand Down
73 changes: 43 additions & 30 deletions members/admin/admin_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,17 @@ class MassInvitationForm(forms.Form):
expire = forms.DateField(
label="Udløber",
widget=AdminDateWidget(),
initial=timezone.now() + timedelta(days=30 * 3),
initial=timezone.now() + timedelta(days=14),
)
email_text = forms.CharField(
label="Email ekstra info", widget=forms.Textarea, required=False
)
special_price_in_dkk = forms.DecimalField(
label="Særpris", max_digits=10, decimal_places=2, required=False
)
special_price_note = forms.CharField(
label="Note om særpris", widget=forms.Textarea, required=False
)

# Lookup all the selected persons - to show confirmation list
# Check if it's called from Waiting List
Expand Down Expand Up @@ -107,6 +113,35 @@ class MassInvitationForm(forms.Form):
pk=mass_invitation_form.cleaned_data["activity"]
)

if mass_invitation_form.cleaned_data["special_price_in_dkk"] is None:
special_price_in_dkk = activity.price_in_dkk
else:
special_price_in_dkk = mass_invitation_form.cleaned_data[
"special_price_in_dkk"
]

if (
special_price_in_dkk != activity.price_in_dkk
and mass_invitation_form.cleaned_data["special_price_note"] == ""
):
messages.error(
request,
"Fejl - ingen personer blev inviteret! Du skal angive en begrundelse for den særlige pris. Noten er ikke synlig for deltageren.",
)
return

min_amount = activity.get_min_amount(activity.activitytype.id)

if (
special_price_in_dkk is not None
and special_price_in_dkk < min_amount
):
messages.error(
request,
f"Prisen er for lav. Denne type aktivitet skal koste mindst {min_amount} kr.",
)
return

# validate activity belongs to user and matches selected department
if (
int(mass_invitation_form.cleaned_data["department"])
Expand Down Expand Up @@ -189,37 +224,15 @@ class MassInvitationForm(forms.Form):
expire_dtm=mass_invitation_form.cleaned_data[
"expire"
],
extra_email_info=mass_invitation_form.cleaned_data[
"email_text"
],
price_in_dkk=special_price_in_dkk,
price_note=mass_invitation_form.cleaned_data[
"special_price_note"
],
)

email_info = mass_invitation_form.cleaned_data[
"email_text"
]

mail_context = {
"activity": activity,
"activity_invite": invitation,
"person": current_person,
"family": current_person.family,
"email_extra_info": email_info,
}
invitation.save()
if current_person.email and (
current_person.email
!= current_person.family.email
):
# If invited has own email, also send to that.
template.makeEmail(
[current_person, current_person.family],
mail_context,
True,
)
else:
# otherwise use only family
template.makeEmail(
current_person.family,
mail_context,
True,
)
persons_invited.append(current_person.name)

except Exception as E:
Expand Down
33 changes: 28 additions & 5 deletions members/admin/inlines.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from django.db import models
from django.forms import Textarea
from django.urls import reverse
from django.utils import timezone
from django.utils.html import format_html

from members.models import (
Expand All @@ -26,15 +25,31 @@ class ActivityInviteInline(admin.TabularInline):
can_delete = False
raw_id_fields = ("activity",)

fieldsets = (
(
None,
{
"description": '<p>Invitationer til en aktivitet laves nemmere via "person" oversigten. Gå derind og filtrer efter f.eks. børn på venteliste til din afdeling og sorter efter opskrivningsdato, eller filter medlemmer på forrige sæson. Herefter kan du vælge de personer på listen, du ønsker at invitere og vælge "Inviter alle valgte til en aktivitet" fra rullemenuen foroven.</p>',
"fields": (
"person",
"activity",
"invite_dtm",
"expire_dtm",
"rejected_at",
"price_in_dkk",
"price_note",
),
},
),
)

# Limit the activity possible to invite to: Not finished and belonging to user
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "activity" and not request.user.is_superuser:
departments = Department.objects.filter(
adminuserinformation__user=request.user
)
kwargs["queryset"] = Activity.objects.filter(
end_date__gt=timezone.now(), department__in=departments
)
kwargs["queryset"] = Activity.objects.filter(department__in=departments)
return super(ActivityInviteInline, self).formfield_for_foreignkey(
db_field, request, **kwargs
)
Expand All @@ -45,12 +60,20 @@ def get_queryset(self, request):
if request.user.is_superuser:
return qs
return qs.filter(
activity__end_date__gt=timezone.now(),
activity__department__in=AdminUserInformation.get_departments_admin(
request.user
),
)

def get_readonly_fields(self, request, obj=None):
if not request.user.is_superuser:
return [
"activity",
"invite_dtm",
]
else:
return []


class ActivityParticipantInline(admin.TabularInline):
model = ActivityParticipant
Expand Down
21 changes: 4 additions & 17 deletions members/forms/activity_signup_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from crispy_forms.bootstrap import FormActions

from members.models.activityparticipant import ActivityParticipant
from members.models.payment import Payment


class ActivitySignupForm(forms.Form):
Expand Down Expand Up @@ -32,7 +31,7 @@ def __init__(self, *args, **kwargs):
css_class="row",
),
Fieldset(
"Tilmeldings oplysninger",
"Tilmeldingsoplysninger",
Div(
Div(
Field("note", aria_describedby="noteHelp"),
Expand All @@ -48,14 +47,10 @@ def __init__(self, *args, **kwargs):
),
css_class="row",
),
),
Fieldset(
"Betaling",
Field("payment_option", aria_describedby="paymentHelp"),
HTML(
'<span class="paymentHelp"><p>Vælg kun <i>"andet er aftalt"</i>, <u>hvis</u> der er en klar aftale med den aktivitets ansvarlige, ellers vil tilmeldingen blive annulleret igen.{% if activity.will_reserve %} Denne betaling vil kun blive reserveret på dit kort. Vi hæver den først endeligt d. 1/1 det år aktiviteten starter for at sikre, at {{ person.name }} er meldt korrekt ind i foreningen i kalenderåret.{% endif %}</p></span>'
),
FormActions(
HTML(
'<span class="paymentHelp"><p>{% if activity.will_reserve %} Denne betaling vil kun blive reserveret på dit kort. Vi hæver den først endeligt d. 1/1 det år aktiviteten starter for at sikre, at {{ person.name }} er meldt korrekt ind i foreningen i kalenderåret.{% endif %}</p></span>'
),
Submit(
"submit", "Tilmeld og betal", css_class="button-success"
),
Expand Down Expand Up @@ -95,11 +90,3 @@ def __init__(self, *args, **kwargs):
required=True,
choices=(("YES", "Ja"), ("NO", "Nej")),
)
payment_option = forms.ChoiceField(
label="Vælg betalings metode",
required=True,
choices=(
(Payment.CREDITCARD, "Betalingskort / MobilePay"),
(Payment.OTHER, "Andet er aftalt"),
),
)
4 changes: 2 additions & 2 deletions members/management/commands/create_membership_activities.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ def handle(self, *args, **options):

localDepartments = str.join(
", ",
Department.objects.filter(union=curUnion).values_list(
Department.objects.filter(union=curUnion, closed_dtm=None).values_list(
"name", flat=True
),
)

try:
department = Department.objects.get(name=localDepartments)
department = Department.objects.get(name=curUnion.name)
except Exception:
print("Using backup main department at %s" % (curUnion.name))
pass
Expand Down
12 changes: 12 additions & 0 deletions members/management/commands/set_correct_prices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.core.management.base import BaseCommand
from members.models.activityinvite import ActivityInvite


class Command(BaseCommand):
help = "This command populates the price in dkk for the activity invites based on the activities if no note has been made. This is due to wrong code"

def handle(self, *args, **options):
for activityInvite in ActivityInvite.objects.all():
if activityInvite.price_note == "":
activityInvite.price_in_dkk = activityInvite.activity.price_in_dkk
activityInvite.save()
30 changes: 30 additions & 0 deletions members/migrations/0044_activityinvite_price_in_dkk_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 4.2.3 on 2023-11-19 13:46

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("members", "0043_alter_union_name"),
]

operations = [
migrations.AddField(
model_name="activityinvite",
name="price_in_dkk",
field=models.DecimalField(
blank=True,
decimal_places=2,
default=500,
help_text="Hvis det er et forløb / en sæsonaktivitet fratrækkes der automatisk 100 kr. til Coding Pirates Denmark pr. deltager. Denne pris overskriver prisen på aktiviteten. Angiv kun en pris hvis denne deltager skal have en anden pris end angivet i aktiviteten. Hvis prisen er under 100 kr. for et forløb / en sæsonaktivitet bliver barnet ikke medlem af foreningen og har ikke stemmeret til generalforsamlingen. Hvis der angives en anden pris, skal noten udfyldes med en begrundelse for denne prisoverskrivelse. Denne note er synlig for den inviterede deltager.",
max_digits=10,
null=True,
verbose_name="Pris",
),
),
migrations.AddField(
model_name="activityinvite",
name="price_note",
field=models.TextField(blank=True, verbose_name="Note om særpris"),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 4.2.3 on 2024-03-02 17:00

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("members", "0044_activityinvite_price_in_dkk_and_more"),
]

operations = [
migrations.AddField(
model_name="activityinvite",
name="extra_email_info",
field=models.TextField(blank=True, verbose_name="Ekstra email info"),
),
migrations.AlterField(
model_name="activityinvite",
name="price_in_dkk",
field=models.DecimalField(
blank=True,
decimal_places=2,
help_text="Hvis det er et forløb / en sæsonaktivitet fratrækkes der automatisk 100 kr. til Coding Pirates Denmark pr. deltager. Denne pris overskriver prisen på aktiviteten. Angiv kun en pris hvis denne deltager skal have en anden pris end angivet i aktiviteten. Hvis prisen er under 100 kr. for et forløb / en sæsonaktivitet bliver barnet ikke medlem af foreningen og har ikke stemmeret til generalforsamlingen. Hvis der angives en anden pris, skal noten udfyldes med en begrundelse for denne prisoverskrivelse. Denne note er synlig for den inviterede deltager.",
max_digits=10,
null=True,
verbose_name="Pris",
),
),
]
23 changes: 16 additions & 7 deletions members/models/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ class Meta:
verbose_name_plural = "Aktiviteter"
ordering = ["department__address__zipcode", "start_date"]

MEMBERSHIP_MIN_AMOUNT = 75
ACTIVITY_MIN_AMOUNT = 100
NO_MINIMUM_AMOUNT = 0

department = models.ForeignKey(
"Department", on_delete=models.CASCADE, verbose_name="Afdeling"
)
Expand Down Expand Up @@ -98,15 +102,20 @@ def participants(self):

participants.short_description = "Deltagere"

def clean(self):
errors = {}
min_amount = 0
def get_min_amount(self, activitytype):
min_amount = self.NO_MINIMUM_AMOUNT

if activitytype == "FORENINGSMEDLEMSKAB":
min_amount = self.MEMBERSHIP_MIN_AMOUNT

if self.activitytype.id == "FORENINGSMEDLEMSKAB":
min_amount = 75
if activitytype == "FORLØB":
min_amount = self.ACTIVITY_MIN_AMOUNT

if self.activitytype.id == "FORLØB":
min_amount = 100
return min_amount

def clean(self):
errors = {}
min_amount = self.get_min_amount(self.activitytype.id)

if self.price_in_dkk < min_amount:
errors[
Expand Down
Loading

0 comments on commit d130b6c

Please sign in to comment.