X-Git-Url: https://git.mdrn.pl/wolnelektury.git/blobdiff_plain/750d370ba7b4df0c5c8f775d1b1443883abd2bf9..1c9e2865ce8c6ab51b2fa3e43d3661089e7b7eb8:/src/pz/models.py diff --git a/src/pz/models.py b/src/pz/models.py index 3b52961f6..4bd3673d6 100644 --- a/src/pz/models.py +++ b/src/pz/models.py @@ -1,15 +1,18 @@ +import re from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ +from .bank import parse_export_feedback, parse_payment_feedback class Campaign(models.Model): name = models.CharField(_('name'), max_length=255, unique=True) description = models.TextField(_('description'), blank=True) - class Meta: + class Meta: verbose_name = _('campaign') verbose_name_plural = _('campaigns') - + def __str__(self): return self.name @@ -17,7 +20,7 @@ class Campaign(models.Model): class Fundraiser(models.Model): name = models.CharField(_('name'), max_length=255, unique=True) - class Meta: + class Meta: verbose_name = _('fundraiser') verbose_name_plural = _('fundraisers') @@ -41,34 +44,51 @@ 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.BooleanField(_('IBAN valid'), default=False, null=True) 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')) fundraiser = models.ForeignKey(Fundraiser, models.PROTECT, blank=True, null=True, verbose_name=_('fundraiser')) fundraiser_commission = models.IntegerField(_('fundraiser commission'), null=True, blank=True) + fundraiser_bonus = models.IntegerField(_('fundraiser bonus'), 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) needs_redo = models.BooleanField(_('needs redo'), default=False) - is_cancelled = models.BooleanField(_('is cancelled'), default=False) + cancelled_at = models.DateTimeField(_('cancelled at'), null=True, blank=True) optout = models.BooleanField(_('optout'), default=False) campaign = models.ForeignKey(Campaign, models.PROTECT, null=True, blank=True, verbose_name=_('campaign')) + latest_status = models.CharField(max_length=255, blank=True) + class Meta: verbose_name = _('direct debit') verbose_name_plural = _('direct debits') + def __str__(self): + return "{} {}".format(self.payment_id, self.latest_status) + + def get_latest_status(self): + line = self.bankexportfeedbackline_set.order_by('-feedback__created_at').first() + if line is None: return "" + return line.comment + + def save(self, **kwargs): + self.iban_valid = not self.iban_warning() if self.iban else None + self.latest_status = self.get_latest_status() + super().save(**kwargs) + @classmethod def get_next_payment_id(cls): # Find the last object added. @@ -88,3 +108,98 @@ class DirectDebit(models.Model): break return payment_id + @property + def full_name(self): + return ' '.join((self.first_name, self.last_name)).strip() + + @property + def street_address(self): + street_addr = self.street + if self.building: + street_addr += ' ' + self.building + if self.flat: + street_addr += ' m. ' + self.flat + street_addr = street_addr.strip() + return street_addr + + 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 = '' + + +class BankExportFeedback(models.Model): + created_at = models.DateTimeField(auto_now_add=True) + csv = models.FileField(upload_to='pz/feedback/') + + def save(self, **kwargs): + super().save(**kwargs) + try: + self.save_payment_items() + except AssertionError: + self.save_export_feedback_items() + + def save_payment_items(self): + for payment_id, booking_date, is_dd, realised, reject_code in parse_payment_feedback(self.csv.open()): + debit = DirectDebit.objects.get(payment_id = payment_id) + b, created = self.payment_set.get_or_create( + debit=debit, + defaults={ + 'booking_date': booking_date, + 'is_dd': is_dd, + 'realised': realised, + 'reject_code': reject_code, + } + ) + if not created: + b.booking_date = booking_date + b.is_dd = is_dd + b.realised = realised + b.reject_code = reject_code + b.save() + + def save_export_feedback_items(self): + for payment_id, status, comment in parse_export_feedback(self.csv.open()): + debit = DirectDebit.objects.get(payment_id = payment_id) + b, created = self.bankexportfeedbackline_set.get_or_create( + debit=debit, + defaults={ + "status": status, + "comment": comment, + } + ) + if not created: + b.status = status + b.comment = comment + b.save() + if status == 1 and not debit.bank_acceptance_date: + debit.bank_acceptance_date = now().date() + debit.save() + + +class BankExportFeedbackLine(models.Model): + feedback = models.ForeignKey(BankExportFeedback, models.CASCADE) + debit = models.ForeignKey(DirectDebit, models.CASCADE) + status = models.SmallIntegerField() + comment = models.CharField(max_length=255) + + +class Payment(models.Model): + feedback = models.ForeignKey(BankExportFeedback, models.CASCADE) + debit = models.ForeignKey(DirectDebit, models.CASCADE) + booking_date = models.DateField() + is_dd = models.BooleanField() + realised = models.BooleanField() + reject_code = models.CharField(max_length=128, blank=True) + + + +class BankOrder(models.Model): + payment_date = models.DateField(null=True, blank=True) + sent = models.DateTimeField(null=True, blank=True) + debits = models.ManyToManyField(DirectDebit, blank=True)