diff --git a/amelie/members/static/img/board_happy_birthday.jpg b/amelie/members/static/img/board_happy_birthday.jpg index 39309a7b..d1f68faf 100644 Binary files a/amelie/members/static/img/board_happy_birthday.jpg and b/amelie/members/static/img/board_happy_birthday.jpg differ diff --git a/amelie/personal_tab/debt_collection.py b/amelie/personal_tab/debt_collection.py index a042bf05..38eceb05 100644 --- a/amelie/personal_tab/debt_collection.py +++ b/amelie/personal_tab/debt_collection.py @@ -1,6 +1,7 @@ import datetime from django.db import transaction +from django.conf import settings from django.db.models import Sum, Q from django.template.defaultfilters import date as _date from django.utils import timezone, translation @@ -188,9 +189,10 @@ def generate_cookie_corner_instructions(end_date): person = Person.objects.get(id=p['person']) transactions = all_transactions.filter(person=person) price = transactions.aggregate(Sum('price'))['price__sum'] + above_maximum = False if price == 0: - continue + continue authorization = authorization_cookie_corner(person) instruction = None @@ -211,13 +213,17 @@ def generate_cookie_corner_instructions(end_date): instruction = DebtCollectionInstruction(amount=price, authorization=authorization, description=description, amendment=authorization.next_amendment()) + + if price > settings.MAXIMUM_DIRECT_DEBIT_AMOUNT: + above_maximum = True row = { 'person': person, 'authorization': authorization, 'sum': price, 'instruction': instruction, - 'transactions': transactions + 'transactions': transactions, + 'above_maximum': above_maximum, } if price < 0: diff --git a/amelie/personal_tab/templates/lists/debt_collection_proposal_cookie_corner.html b/amelie/personal_tab/templates/lists/debt_collection_proposal_cookie_corner.html index a4723d0f..bf153d2d 100644 --- a/amelie/personal_tab/templates/lists/debt_collection_proposal_cookie_corner.html +++ b/amelie/personal_tab/templates/lists/debt_collection_proposal_cookie_corner.html @@ -16,10 +16,16 @@ {% for row in rows %} {% if enabled %} - - - + {% if not row.above_maximum %} + + + + {% else %} + +

+ + {% endif %} {% endif %} @@ -46,7 +52,11 @@ {% if row.instruction.description %} + {% if not row.above_maximum %} {{ row.instruction.description }} + {% else %} + {% blocktrans with maximum=maximum_debit_amount|floatformat:2 %}This person's balance is higher than € {{ maximum }}, so they cannot be debited.{% endblocktrans %} + {% endif %} {% endif %} diff --git a/amelie/personal_tab/views.py b/amelie/personal_tab/views.py index e602e704..afa5cd14 100644 --- a/amelie/personal_tab/views.py +++ b/amelie/personal_tab/views.py @@ -2013,7 +2013,8 @@ def debt_collection_new(request): 'contribution_instructions': contribution_instructions, 'contribution_totals': contribution_totals, 'cookie_corner_instructions': cookie_corner_instructions, - 'cookie_corner_totals': cookie_corner_totals + 'cookie_corner_totals': cookie_corner_totals, + 'maximum_debit_amount': settings.MAXIMUM_DIRECT_DEBIT_AMOUNT, }) diff --git a/amelie/room_duty/templates/room_duty/table/fill.html b/amelie/room_duty/templates/room_duty/table/fill.html index dfa9c3f6..0661fd73 100644 --- a/amelie/room_duty/templates/room_duty/table/fill.html +++ b/amelie/room_duty/templates/room_duty/table/fill.html @@ -12,41 +12,43 @@

{% blocktrans %}Fill in {{ table }} availability{% endblocktrans %}

{% for error in form.non_field_errors %} {{ error|safe }} {% endfor %} -
+ {% csrf_token %} - - - - - - - - {% for room_duty, availability, form in availabilities %} - - {% for error in form.non_field_errors %} - - {% endfor %} - - - - - +
+
{% trans "Begin" %}{% trans "End" %}{% trans "Availability" %}{% trans "Comments" %}
{{ error }} - {{ room_duty.begin|date:"D d/m H:i" }} - - {{ room_duty.end|date:"D d/m H:i" }} - - {{ form.availability.errors|safe }} - {{ form.availability }} - - {{ form.hungover.errors|safe }} - - - {{ form.comments.errors|safe }} - {{ form.comments }} -
+ + + + + - {% endfor %} -
{% trans "Begin" %}{% trans "End" %}{% trans "Availability" %}{% trans "Comments" %}
+ {% for room_duty, availability, form in availabilities %} + + {% for error in form.non_field_errors %} + {{ error }} + {% endfor %} + + {{ room_duty.begin|date:"D d/m H:i" }} + + + {{ room_duty.end|date:"D d/m H:i" }} + + + {{ form.availability.errors|safe }} + {{ form.availability }} + + + {{ form.hungover.errors|safe }} + + + + {{ form.comments.errors|safe }} + {{ form.comments }} + + + {% endfor %} + +
diff --git a/amelie/room_duty/templates/room_duty/table/overview.html b/amelie/room_duty/templates/room_duty/table/overview.html index 30db7cb4..63dc534f 100644 --- a/amelie/room_duty/templates/room_duty/table/overview.html +++ b/amelie/room_duty/templates/room_duty/table/overview.html @@ -95,55 +95,57 @@

{% trans "Fill in" %} - - - - - - {% for person in table.persons %} - - {% endfor %} - - {% for room_duty in room_duties %} - {% with room_duty.begin|timezone:"Europe/Amsterdam" as rd_begin %} - - - - - {% for availability, checkbox in room_duty.template_data %} -
{% trans "Begin" %}{% trans "End" %}{% trans "Assignment" %}{{ person.first_name }}
{{ room_duty.begin|date:"D d/m H:i" }}{{ room_duty.end|date:"D d/m H:i" }}{{ room_duty.participant_names|join:", " }} +
+ + + + + + {% for person in table.persons %} + + {% endfor %} + + {% for room_duty in room_duties %} + {% with room_duty.begin|timezone:"Europe/Amsterdam" as rd_begin %} + + + + + {% for availability, checkbox in room_duty.template_data %} + + + {% endfor %} + + {% endwith %} + {% endfor %} + + + {% for person in table.persons %} + {% endfor %} - {% endwith %} - {% endfor %} - - - {% for person in table.persons %} - - {% endfor %} - -
{% trans "Begin" %}{% trans "End" %}{% trans "Assignment" %}{{ person.first_name }}
{{ room_duty.begin|date:"D d/m H:i" }}{{ room_duty.end|date:"D d/m H:i" }}{{ room_duty.participant_names|join:", " }} - {{ checkbox.tag }} - {{ checkbox.tag.errors }} + {{ checkbox.tag }} + {{ checkbox.tag.errors }} - {% if availability == None %} - - - {% else %} - {{ availability.availability }}{% if availability.hungover %}B{% endif %} - {% if availability.comments %} - - + {% if availability == None %} + - + {% else %} + {{ availability.availability }}{% if availability.hungover %}B{% endif %} + {% if availability.comments %} + + + {% endif %} {% endif %} - {% endif %} -
{% trans 'Total' %}{{ person.room_duty_stats_table.total|escapejs }}
{% trans 'Total' %}{{ person.room_duty_stats_table.total|escapejs }}
+
+ @@ -152,32 +154,34 @@

{% trans 'Statistics' %}

- - - - {% for person in table.persons %} - - {% endfor %} - - - - {% for person in table.persons %} - - {% endfor %} - - - - {% for person in table.persons %} - - {% endfor %} - - - - {% for person in table.persons %} - - {% endfor %} - -
{{ person.first_name }}
{% trans 'Morning office duties' %}{{ person.room_duty_stats.morning|escapejs }}
{% trans 'Afternoon office duties' %}{{ person.room_duty_stats.afternoon|escapejs }}
{% trans 'Total' %}{{ person.room_duty_stats.total|escapejs }}
+
+ + + + {% for person in table.persons %} + + {% endfor %} + + + + {% for person in table.persons %} + + {% endfor %} + + + + {% for person in table.persons %} + + {% endfor %} + + + + {% for person in table.persons %} + + {% endfor %} + +
{{ person.first_name }}
{% trans 'Morning office duties' %}{{ person.room_duty_stats.morning|escapejs }}
{% trans 'Afternoon office duties' %}{{ person.room_duty_stats.afternoon|escapejs }}
{% trans 'Total' %}{{ person.room_duty_stats.total|escapejs }}
+
{% endblock %} diff --git a/amelie/settings/environ.py b/amelie/settings/environ.py index 705ab77f..f6d52148 100644 --- a/amelie/settings/environ.py +++ b/amelie/settings/environ.py @@ -488,6 +488,10 @@ def custom_show_toolbar(request): # Cookie corner Wrapped COOKIE_CORNER_WRAPPED_YEAR = env.int("COOKIE_CORNER_WRAPPED_YEAR", default=COOKIE_CORNER_WRAPPED_YEAR) +# The maximum amount Inter-Actief can debit from a person per direct debit +MAXIMUM_DIRECT_DEBIT_AMOUNT = Decimal(env("MAXIMUM_DIRECT_DEBIT_AMOUNT", default=MAXIMUM_DIRECT_DEBIT_AMOUNT)) + + # Printer configuration # Maximum file size for printed files, in bytes (i.e. 50MB = 50 * 1024 * 1024 bytes) diff --git a/amelie/settings/generic.py b/amelie/settings/generic.py index 812f179c..0c0256fb 100644 --- a/amelie/settings/generic.py +++ b/amelie/settings/generic.py @@ -74,6 +74,9 @@ # The direct debit debtor ID of Inter-Actief that needs to be printed on the autorization forms DIRECT_DEBIT_DEBTOR_ID = 'NL81ZZZ400749470000' +# The maximum amount Inter-Actief can debit from a person per direct debit +MAXIMUM_DIRECT_DEBIT_AMOUNT = 250.00 + # The ID of the personal_tab.PaymentMethod object representing an early termination (no payment needed). MEMBERS_EARLY_TERMINATION_PAYMENT_METHOD_ID = 10 # The ID of the personal_tab.PaymentMethod object representing a Forgiven payment (no payment needed). @@ -605,7 +608,7 @@ } TREASURER_EMAIL = 'Penningmeester Inter-Actief ' TREASURER_EMAIL_COMMITTEE_OVERRIDE = { - "SocCie": "Sociƫteitscommissie ", + "SocCie": "Quaestor SocCie ", "Kick-IT": "Kick-IT ", } PERSONAL_TAB_DECLARATION_MAX_FILE_SIZE = 20 * 1024 * 1024 # 20 MB total, because email size limit is 25 MB diff --git a/pyproject.toml b/pyproject.toml index c63e4106..95cb726d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,11 +100,11 @@ dependencies = [ # Google API Client "google-api-python-client>=2.192.0,<3", - "google-auth>=2.49.1,<2.57", + "google-auth>=2.49.1,<2.59", "pyOpenSSL>=26.0.0,<26.5.0", # Development - "django-debug-toolbar>=3.7,<7.2", + "django-debug-toolbar>=3.7,<8.1", "django-rosetta>=0.10.3,<0.11", "docutils>=0.19,<0.24", "pyinotify", @@ -115,7 +115,7 @@ dependencies = [ "mozilla-django-oidc>=5.0.2,<5.1", # Sentry error logging - "sentry-sdk>=2.54.0,<2.69", + "sentry-sdk>=2.54.0,<2.70", # Health checks for Django "django-health-check[psutil,celery,rabbitmq,redis]>=4.0,<4.6",