PZ: add basic operations.
authorRadek Czajka <rczajka@rczajka.pl>
Thu, 30 Sep 2021 08:17:05 +0000 (10:17 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Thu, 30 Sep 2021 08:17:05 +0000 (10:17 +0200)
src/pz/admin.py
src/pz/bank.py [new file with mode: 0644]
src/pz/migrations/0002_auto_20210928_2116.py [new file with mode: 0644]
src/pz/migrations/0003_directdebit_iban_valid.py [new file with mode: 0644]
src/pz/migrations/0004_auto_20210929_1938.py [new file with mode: 0644]
src/pz/models.py

index 8677931..0be845b 100644 (file)
@@ -1,5 +1,8 @@
 from django.contrib import admin
 from django.utils.translation import gettext_lazy as _
+from django.utils.timezone import now
+from fnpdjango.actions import export_as_csv_action
+from . import bank
 from . import models
 
 
@@ -8,7 +11,33 @@ admin.site.register(models.Campaign)
 
 @admin.register(models.DirectDebit)
 class DirectDebitAdmin(admin.ModelAdmin):
-    list_display = ['acquisition_date', 'amount', 'first_name', 'last_name']
+    list_display = [
+        'payment_id', 'acquisition_date',
+        'iban_valid',
+        'bank_submission_date',
+        'bank_acceptance_date',
+        'amount', 'first_name', 'last_name',
+    ]
+    date_hierarchy = 'acquisition_date'
+    search_fields = [
+        'payment_id', 'first_name', 'last_name', 'street', 'building', 'town', 'flat',
+        'phone', 'email', 'iban',
+        'notes',
+        'fundraiser_bill',
+    ]
+    list_filter = [
+        'iban_valid',
+        'agree_fundraising',
+        'agree_newsletter',
+        'fundraiser',
+        'campaign',
+        'is_cancelled',
+        'needs_redo',
+        'optout',
+        'amount',
+        'sex',
+        'is_consumer',
+    ]
     fieldsets = [
         (None, {
             "fields": [
@@ -18,7 +47,7 @@ class DirectDebitAdmin(admin.ModelAdmin):
                 ('town', 'flat'),
                 ('postal_code', 'phone'),
                 'email',
-                'iban',
+                ('iban', 'iban_valid', 'iban_warning'),
                 'payment_id',
                 'agree_contact',
                 'agree_fundraising',
@@ -40,7 +69,15 @@ class DirectDebitAdmin(admin.ModelAdmin):
             ]
         })
     ]
-    readonly_fields = ['agree_contact']
+    readonly_fields = ['agree_contact', 'iban_valid', 'iban_warning']
+
+    def set_bank_submission(m,r,q):
+        q.update(bank_submission_date=now())
+    actions = [
+        bank.bank_export,
+        set_bank_submission,
+        export_as_csv_action(),
+    ]
 
     def agree_contact(self, obj):
         return _('obligatory')
diff --git a/src/pz/bank.py b/src/pz/bank.py
new file mode 100644 (file)
index 0000000..e1e91b7
--- /dev/null
@@ -0,0 +1,40 @@
+import csv
+from django.http import HttpResponse
+from django.utils.translation import ugettext_lazy as _
+
+
+def bank_export(modeladmin, request, queryset):
+    response = HttpResponse(content_type='text/csv; charset=cp1250')
+    response['Content-Disposition'] = 'attachment; filename=export.csv'
+    writer = csv.writer(response)
+    writer.writerow([
+        'Identyfikator płatności (IDP)',
+        'Nazwa Płatnika',
+        'Adres Płatnika Ulica + numer domu',
+        'Adres Płatnika kod+miejscowość',
+        'Numer kierunkowy banku Płatnika',
+        'Numer rachunku bankowego Płatnika',
+        'Identyfikator Odbiorcy (NIP Odbiorcy)',
+        'Osobowość prawna Płatnika (Osoba fizyczna)'
+    ])
+
+    # TODO: ansi encoding
+
+    for obj in queryset:
+        street_addr = obj.street
+        if obj.building:
+            street_addr += ' ' + obj.building
+        if obj.flat:
+            street_addr += ' m. ' + obj.flat
+        street_addr = street_addr.strip()
+        writer.writerow([
+            obj.payment_id,
+            ' '.join([obj.first_name, obj.last_name]).strip(),
+            street_addr,
+            ' '.join([obj.postal_code, obj.town]).strip(),
+            obj.iban[2:10],
+            obj.iban,
+            '9521877087',
+            'OF'
+        ])
+    return response
diff --git a/src/pz/migrations/0002_auto_20210928_2116.py b/src/pz/migrations/0002_auto_20210928_2116.py
new file mode 100644 (file)
index 0000000..c9c3061
--- /dev/null
@@ -0,0 +1,44 @@
+# Generated by Django 2.2.19 on 2021-09-28 19:16
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('pz', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='directdebit',
+            name='acquisition_date',
+            field=models.DateField(blank=True, help_text='Date from the form', null=True, verbose_name='acquisition date'),
+        ),
+        migrations.AlterField(
+            model_name='directdebit',
+            name='agree_fundraising',
+            field=models.BooleanField(default=False, verbose_name='agree fundraising'),
+        ),
+        migrations.AlterField(
+            model_name='directdebit',
+            name='agree_newsletter',
+            field=models.BooleanField(default=False, verbose_name='agree newsletter'),
+        ),
+        migrations.AlterField(
+            model_name='directdebit',
+            name='amount',
+            field=models.IntegerField(blank=True, null=True, verbose_name='amount'),
+        ),
+        migrations.AlterField(
+            model_name='directdebit',
+            name='campaign',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='pz.Campaign', verbose_name='campaign'),
+        ),
+        migrations.AlterField(
+            model_name='directdebit',
+            name='fundraiser',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='pz.Fundraiser', verbose_name='fundraiser'),
+        ),
+    ]
diff --git a/src/pz/migrations/0003_directdebit_iban_valid.py b/src/pz/migrations/0003_directdebit_iban_valid.py
new file mode 100644 (file)
index 0000000..f3bd309
--- /dev/null
@@ -0,0 +1,18 @@
+# Generated by Django 2.2.19 on 2021-09-29 17:15
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('pz', '0002_auto_20210928_2116'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='directdebit',
+            name='iban_valid',
+            field=models.BooleanField(default=False, verbose_name='IBAN valid'),
+        ),
+    ]
diff --git a/src/pz/migrations/0004_auto_20210929_1938.py b/src/pz/migrations/0004_auto_20210929_1938.py
new file mode 100644 (file)
index 0000000..dc093a7
--- /dev/null
@@ -0,0 +1,18 @@
+# Generated by Django 2.2.19 on 2021-09-29 17:38
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('pz', '0003_directdebit_iban_valid'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='directdebit',
+            name='iban_valid',
+            field=models.NullBooleanField(default=False, verbose_name='IBAN valid'),
+        ),
+    ]
index 3b52961..8b6db0e 100644 (file)
@@ -41,12 +41,13 @@ class DirectDebit(models.Model):
     phone = models.CharField(_('phone'), max_length=255, blank=True)
     email = models.CharField(_('e-mail'), max_length=255, blank=True)
     iban = models.CharField(_('IBAN'), max_length=255, blank=True)
+    iban_valid = models.NullBooleanField(_('IBAN valid'), default=False)
     is_consumer = models.BooleanField(_('is a consumer'), default=True)
     payment_id = models.CharField(_('payment identifier'), max_length=255, blank=True, unique=True)
-    agree_fundraising = models.BooleanField(_('agree fundraising'))
-    agree_newsletter = models.BooleanField(_('agree newsletter'))
+    agree_fundraising = models.BooleanField(_('agree fundraising'), default=False)
+    agree_newsletter = models.BooleanField(_('agree newsletter'), default=False)
 
-    acquisition_date = models.DateField(_('acquisition date'), help_text=_('Date from the form'))
+    acquisition_date = models.DateField(_('acquisition date'), help_text=_('Date from the form'), null=True, blank=True)
     submission_date = models.DateField(_('submission date'), null=True, blank=True, help_text=_('Date the fundaiser submitted the form'))
     bank_submission_date = models.DateField(_('bank submission date'), null=True, blank=True, help_text=_('Date when the form data is submitted to the bank'))
     bank_acceptance_date = models.DateField(_('bank accepted date'), null=True, blank=True, help_text=_('Date when bank accepted the form'))
@@ -55,7 +56,7 @@ class DirectDebit(models.Model):
     fundraiser_commission = models.IntegerField(_('fundraiser commission'), null=True, blank=True)
     fundraiser_bill = models.CharField(_('fundaiser bill number'), max_length=255, blank=True)
 
-    amount = models.IntegerField(_('amount'))
+    amount = models.IntegerField(_('amount'), null=True, blank=True)
 
     notes = models.TextField(_('notes'), blank=True)
 
@@ -69,6 +70,10 @@ class DirectDebit(models.Model):
         verbose_name = _('direct debit')
         verbose_name_plural = _('direct debits')
 
+    def save(self, **kwargs):
+        self.iban_valid = not self.iban_warning() if self.iban else None
+        super().save(**kwargs)
+
     @classmethod
     def get_next_payment_id(cls):
         # Find the last object added.
@@ -88,3 +93,12 @@ class DirectDebit(models.Model):
                 break
         return payment_id
 
+    def iban_warning(self):
+        if not self.iban:
+            return 'No IBAN'
+        if len(self.iban) != 26:
+            return 'Bad IBAN length'
+        if int(self.iban[2:] + '2521' + self.iban[:2]) % 97 != 1:
+            return 'This IBAN number looks invalid'
+        return ''
+    iban_warning.short_description = ''