--- /dev/null
+# Generated by Django 2.2.9 on 2020-01-13 10:21
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('club', '0021_auto_20191127_1545'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='payuorder',
+ name='completed_at',
+ field=models.DateTimeField(blank=True, null=True),
+ ),
+ ]
--- /dev/null
+import json
+from django.db import migrations
+
+
+def populate_completed_at(apps, schema_editor):
+ PayUOrder = apps.get_model('club', 'PayUOrder')
+ for order in PayUOrder.objects.filter(status='COMPLETED'):
+ for n in order.notification_set.order_by('received_at'):
+ if json.loads(n.body)['order']['status'] == 'COMPLETED':
+ order.completed_at = n.received_at
+ order.save()
+ break
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('club', '0022_payuorder_completed_at'),
+ ]
+
+ operations = [
+ migrations.RunPython(
+ populate_completed_at,
+ migrations.RunPython.noop,
+ )
+ ]
from django.contrib.sites.models import Site
from django.db import models
from django.urls import reverse
+from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from . import POSS
('CANCELED', _('Canceled')),
('REJECTED', _('Rejected')),
])
+ completed_at = models.DateTimeField(null=True, blank=True)
class Meta:
abstract = True
status = self.get_status()
if self.order.status not in (status, 'COMPLETED'):
self.order.status = status
+ if status == 'COMPLETED':
+ self.order.completed_at = now()
self.order.save()
self.order.status_updated()
--- /dev/null
+{% extends request.session.from_app|yesno:"base/app.html,base/base.html" %}
+{% load chunks i18n %}
+
+
+{% block titleextra %}Towarzystwo Przyjaciół Wolnych Lektur{% endblock %}
+
+
+{% block body %}
+ <div class="white-box normal-text">
+ <h1>{% blocktrans with year=view.kwargs.year email=object.email %}Summary of donations in the year {{ year }} for the address {{ email }}.{% endblocktrans %}</h1>
+
+ <table class="table">
+ <thead>
+ <tr>
+ <th>{% trans "Date" %}</th>
+ <th>{% trans "Amount" %}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for order in payments %}
+ <tr>
+ <td>{{ order.completed_at.date }}</td>
+ <td>{{ order.get_amount }} zł</td>
+ </tr>
+ {% endfor %}
+ <tr>
+ <th>{% trans "Total" %}:</th>
+ <th>{{ total_amount|default:0 }} zł</th>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+{% endblock %}
path('plan/<key>/', banner_exempt(views.ScheduleView.as_view()), name='club_schedule'),
path('plan/<key>/dziekujemy/', banner_exempt(views.ScheduleThanksView.as_view()), name='club_thanks'),
+ path('plan/<key>/zestawienie/<int:year>/', banner_exempt(views.YearSummaryView.as_view()), name='club_year_summary'),
path('przylacz/<key>/', views.claim, name='club_claim'),
path('anuluj/<key>/', views.cancel, name='club_cancel'),
#
from django.conf import settings
from django.contrib.auth.decorators import login_required
+from django.db.models import Sum
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.utils.decorators import method_decorator
ctx['active_menu_item'] = 'club'
return ctx
+
+class YearSummaryView(DetailView):
+ model = models.Schedule
+ slug_field = slug_url_kwarg = 'key'
+ template_name = 'club/year_summary.html'
+
+ def get_context_data(self, *args, **kwargs):
+ ctx = super().get_context_data(*args, **kwargs)
+ ctx['payments'] = models.PayUOrder.objects.filter(
+ status='COMPLETED',
+ completed_at__year=self.kwargs['year'],
+ schedule__email=self.object.email,
+ ).order_by('completed_at')
+ ctx['total_amount'] = ctx['payments'].aggregate(s=Sum('schedule__amount'))['s']
+ return ctx
@media screen and (max-width: 62.5em) {
.mobile-margins {margin-left: 1em; margin-right: 1em;}
}
+
+
+table.table {
+ margin: auto;
+ border-collapse: collapse;
+
+ td, th {
+ border: 1px solid #444;
+ padding: .5em;
+ text-align: center;
+ }
+}