Basically usable funding workflow.
[wolnelektury.git] / apps / funding / models.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 from django.core.urlresolvers import reverse
6 from django.db import models
7 from django.utils.translation import ugettext_lazy as _, ugettext as __
8 from datetime import date, datetime
9 from catalogue.models import Book
10
11
12 class Offer(models.Model):
13     author = models.CharField(_('author'), max_length=255)
14     title = models.CharField(_('title'), max_length=255)
15     slug = models.SlugField(_('slug'))
16     book = models.ForeignKey(Book, null=True, blank=True,
17         help_text=_('Published book.'))
18     redakcja_url = models.URLField(_('redakcja URL'), blank=True)
19     target = models.DecimalField(_('target'), decimal_places=2, max_digits=10)
20     start = models.DateField(_('start'))
21     end = models.DateField(_('end'))
22     due = models.DateField(_('due'),
23         help_text=_('When will it be published if the money is raised.'))
24
25     class Meta:
26         verbose_name = _('offer')
27         verbose_name_plural = _('offers')
28         ordering = ['-end']
29
30     def __unicode__(self):
31         return u"%s – %s" % (self.author, self.title)
32
33     def get_absolute_url(self):
34         return reverse('funding_offer', args=[self.slug])
35
36     def is_current(self):
37         return self.start <= date.today() <= self.end
38
39     @classmethod
40     def current(cls):
41         today = date.today()
42         objects = cls.objects.filter(start__lte=today, end__gte=today)
43         try:
44             return objects[0]
45         except IndexError:
46             return None
47
48     @classmethod
49     def public(cls):
50         today = date.today()
51         return cls.objects.filter(start__lte=today)        
52
53     def get_perks(self, amount=None):
54         perks = Perk.objects.filter(
55                 models.Q(offer=self) | models.Q(offer=None)
56             )
57         if amount is not None:
58             perks = perks.filter(price__lte=amount)
59         return perks
60
61     def fund(self, name, email, amount, anonymous=False):
62         funding = self.funding_set.create(
63             name=name, email=email, amount=amount,
64             anonymous=anonymous,
65             payed_at=datetime.now())
66         funding.perks = self.get_perks(amount)
67         return funding
68
69     def sum(self):
70         return self.funding_set.aggregate(s=models.Sum('amount'))['s'] or 0
71
72     def state(self):
73         if self.sum() >= self.target:
74             return 'win'
75         elif self.start <= date.today() <= self.end:
76             return 'running'
77         else:
78             return 'lose'
79
80
81 class Perk(models.Model):
82     offer = models.ForeignKey(Offer, verbose_name=_('offer'), null=True, blank=True)
83     price = models.DecimalField(_('price'), decimal_places=2, max_digits=10)
84     name = models.CharField(_('name'), max_length=255)
85     description = models.TextField(_('description'), blank=True)
86
87     class Meta:
88         verbose_name = _('perk')
89         verbose_name_plural = _('perks')
90         ordering = ['-price']
91
92     def __unicode__(self):
93         return "%s (%s%s)" % (self.name, self.price, u" for %s" % self.offer if self.offer else "")
94
95
96 class Funding(models.Model):
97     offer = models.ForeignKey(Offer, verbose_name=_('offer'))
98     name = models.CharField(_('name'), max_length=127)
99     email = models.EmailField(_('email'))
100     amount = models.DecimalField(_('amount'), decimal_places=2, max_digits=10)
101     payed_at = models.DateTimeField(_('payed at'))
102     perks = models.ManyToManyField(Perk, verbose_name=_('perks'), blank=True)
103     anonymous = models.BooleanField(_('anonymous'))
104
105     class Meta:
106         verbose_name = _('funding')
107         verbose_name_plural = _('fundings')
108         ordering = ['-payed_at']
109
110     def __unicode__(self):
111         return "%s payed %s for %s" % (self.name, self.amount, self.offer)
112
113
114 class Spent(models.Model):
115     amount = models.DecimalField(_('amount'), decimal_places=2, max_digits=10)
116     timestamp = models.DateField(_('when'))
117     book = models.ForeignKey(Book)
118
119     class Meta:
120         verbose_name = _('money spent on a book')
121         verbose_name_plural = _('money spent on books')
122         ordering = ['-timestamp']
123
124     def __unicode__(self):
125         return u"Spent: %s" % unicode(self.book)