Year summaries.
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 13 Jan 2020 10:44:12 +0000 (11:44 +0100)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 13 Jan 2020 10:44:12 +0000 (11:44 +0100)
src/club/migrations/0022_payuorder_completed_at.py [new file with mode: 0644]
src/club/migrations/0023_completed_at.py [new file with mode: 0644]
src/club/payu/models.py
src/club/templates/club/year_summary.html [new file with mode: 0644]
src/club/urls.py
src/club/views.py
src/wolnelektury/static/scss/main/base.scss

diff --git a/src/club/migrations/0022_payuorder_completed_at.py b/src/club/migrations/0022_payuorder_completed_at.py
new file mode 100644 (file)
index 0000000..916f4e0
--- /dev/null
@@ -0,0 +1,18 @@
+# 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),
+        ),
+    ]
diff --git a/src/club/migrations/0023_completed_at.py b/src/club/migrations/0023_completed_at.py
new file mode 100644 (file)
index 0000000..d23c289
--- /dev/null
@@ -0,0 +1,26 @@
+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,
+        )
+    ]
index f7c3535..5764f88 100644 (file)
@@ -7,6 +7,7 @@ from urllib.request import HTTPError
 from django.contrib.sites.models import Site
 from django.db import models
 from django.urls import reverse
 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
 
 from django.utils.translation import ugettext_lazy as _
 from . import POSS
 
@@ -36,6 +37,7 @@ class Order(models.Model):
         ('CANCELED', _('Canceled')),
         ('REJECTED', _('Rejected')),
     ])
         ('CANCELED', _('Canceled')),
         ('REJECTED', _('Rejected')),
     ])
+    completed_at = models.DateTimeField(null=True, blank=True)
 
     class Meta:
         abstract = True
 
     class Meta:
         abstract = True
@@ -150,5 +152,7 @@ class Notification(models.Model):
         status = self.get_status()
         if self.order.status not in (status, 'COMPLETED'):
             self.order.status = status
         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()
             self.order.save()
             self.order.status_updated()
diff --git a/src/club/templates/club/year_summary.html b/src/club/templates/club/year_summary.html
new file mode 100644 (file)
index 0000000..20ed198
--- /dev/null
@@ -0,0 +1,33 @@
+{% 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 %}
index 7a3795a..8bbb849 100644 (file)
@@ -12,6 +12,7 @@ urlpatterns = [
 
     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>/', 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'),
 
     path('przylacz/<key>/', views.claim, name='club_claim'),
     path('anuluj/<key>/', views.cancel, name='club_cancel'),
index 920180a..d673cc0 100644 (file)
@@ -3,6 +3,7 @@
 #
 from django.conf import settings
 from django.contrib.auth.decorators import login_required
 #
 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
 from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404, render
 from django.utils.decorators import method_decorator
@@ -168,3 +169,18 @@ class ScheduleThanksView(DetailView):
         ctx['active_menu_item'] = 'club'
         return ctx
 
         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
index 870f7a1..0c8dc89 100755 (executable)
@@ -226,3 +226,15 @@ ul.plain {
 @media screen and (max-width: 62.5em) {
   .mobile-margins {margin-left: 1em; margin-right: 1em;}
 }
 @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;
+    }
+}