PZ: add basic operations.
[wolnelektury.git] / src / pz / models.py
1 from django.db import models
2 from django.utils.translation import ugettext_lazy as _
3
4
5 class Campaign(models.Model):
6     name = models.CharField(_('name'), max_length=255, unique=True)
7     description = models.TextField(_('description'), blank=True)
8
9     class Meta: 
10         verbose_name = _('campaign')
11         verbose_name_plural = _('campaigns')
12    
13     def __str__(self):
14         return self.name
15
16
17 class Fundraiser(models.Model):
18     name = models.CharField(_('name'), max_length=255, unique=True)
19
20     class Meta: 
21         verbose_name = _('fundraiser')
22         verbose_name_plural = _('fundraisers')
23
24     def __str__(self):
25         return self.name
26
27
28 class DirectDebit(models.Model):
29     first_name = models.CharField(_('first name'), max_length=255, blank=True)
30     last_name = models.CharField(_('last name'), max_length=255, blank=True)
31     sex = models.CharField(_('sex'), max_length=1, blank=True, choices=[
32         ('M', _('M')),
33         ('F', _('F')),
34     ])
35     date_of_birth = models.DateField(_('date of birth'), null=True, blank=True)
36     street = models.CharField(_('street'), max_length=255, blank=True)
37     building = models.CharField(_('building'), max_length=255, blank=True)
38     flat = models.CharField(_('flat'), max_length=255, blank=True)
39     town = models.CharField(_('town'), max_length=255, blank=True)
40     postal_code = models.CharField(_('postal code'),  max_length=255, blank=True)
41     phone = models.CharField(_('phone'), max_length=255, blank=True)
42     email = models.CharField(_('e-mail'), max_length=255, blank=True)
43     iban = models.CharField(_('IBAN'), max_length=255, blank=True)
44     iban_valid = models.NullBooleanField(_('IBAN valid'), default=False)
45     is_consumer = models.BooleanField(_('is a consumer'), default=True)
46     payment_id = models.CharField(_('payment identifier'), max_length=255, blank=True, unique=True)
47     agree_fundraising = models.BooleanField(_('agree fundraising'), default=False)
48     agree_newsletter = models.BooleanField(_('agree newsletter'), default=False)
49
50     acquisition_date = models.DateField(_('acquisition date'), help_text=_('Date from the form'), null=True, blank=True)
51     submission_date = models.DateField(_('submission date'), null=True, blank=True, help_text=_('Date the fundaiser submitted the form'))
52     bank_submission_date = models.DateField(_('bank submission date'), null=True, blank=True, help_text=_('Date when the form data is submitted to the bank'))
53     bank_acceptance_date = models.DateField(_('bank accepted date'), null=True, blank=True, help_text=_('Date when bank accepted the form'))
54
55     fundraiser = models.ForeignKey(Fundraiser, models.PROTECT, blank=True, null=True, verbose_name=_('fundraiser'))
56     fundraiser_commission = models.IntegerField(_('fundraiser commission'), null=True, blank=True)
57     fundraiser_bill = models.CharField(_('fundaiser bill number'), max_length=255, blank=True)
58
59     amount = models.IntegerField(_('amount'), null=True, blank=True)
60
61     notes = models.TextField(_('notes'), blank=True)
62
63     needs_redo = models.BooleanField(_('needs redo'), default=False)
64     is_cancelled = models.BooleanField(_('is cancelled'), default=False)
65     optout = models.BooleanField(_('optout'), default=False)
66
67     campaign = models.ForeignKey(Campaign, models.PROTECT, null=True, blank=True, verbose_name=_('campaign'))
68
69     class Meta:
70         verbose_name = _('direct debit')
71         verbose_name_plural = _('direct debits')
72
73     def save(self, **kwargs):
74         self.iban_valid = not self.iban_warning() if self.iban else None
75         super().save(**kwargs)
76
77     @classmethod
78     def get_next_payment_id(cls):
79         # Find the last object added.
80         last = cls.objects.order_by('-id').first()
81         if last is None:
82             return ''
83         match = re.match(r'^(.*?)(\d+)$', last.payment_id)
84         if match is None:
85             return ''
86         prefix = match.group(1)
87         number = int(match.group(2))
88         number_length = len(match.group(2))
89         while True:
90             number += 1
91             payment_id = f'{prefix}{number:0{number_length}}'
92             if not cls.objects.filter(payment_id=payment_id).exists():
93                 break
94         return payment_id
95
96     def iban_warning(self):
97         if not self.iban:
98             return 'No IBAN'
99         if len(self.iban) != 26:
100             return 'Bad IBAN length'
101         if int(self.iban[2:] + '2521' + self.iban[:2]) % 97 != 1:
102             return 'This IBAN number looks invalid'
103         return ''
104     iban_warning.short_description = ''