Fixes #4076: Recommendations from collections.
[wolnelektury.git] / src / messaging / states.py
1 from datetime import timedelta
2 from django.apps import apps
3 from django.utils.timezone import now
4 from django.utils.translation import ugettext_lazy as _
5
6
7 class Level:
8     COLD = 10
9     TRIED = 20
10     SINGLE = 30
11     RECURRING = 40
12     OPT_OUT = 50
13
14
15 class State:
16     allow_negative_offset = False
17     level = None
18     expired = None
19
20     def __init__(self, time=None, min_days_since=None, max_days_since=None, test=False):
21         self.time = time or now()
22         self.min_days_since = min_days_since
23         self.max_days_since = max_days_since
24         self.test = test
25
26     def get_contacts(self):
27         Contact = apps.get_model('messaging', 'Contact')
28         contacts = Contact.objects.filter(level=self.level)
29
30         if self.min_days_since is not None or self.expired:
31             cutoff = self.time - timedelta(self.min_days_since or 0)
32             if self.expired:
33                 contacts = contacts.filter(expires_at__lt=cutoff)
34             else:
35                 contacts = contacts.filter(since__lt=cutoff)
36
37         if self.max_days_since is not None:
38             cutoff = self.time - timedelta(self.max_days_since)
39             if self.expired:
40                 contacts = contacts.filter(expires_at__gt=cutoff)
41             else:
42                 contacts = contacts.filter(since__gt=cutoff)
43
44         if self.expired is False:
45             contacts = contacts.exclude(expires_at__lt=self.time)
46
47         return contacts
48
49     def get_context(self, contact):
50         if self.test:
51             return self.get_example_context(contact)
52
53         Schedule = apps.get_model('club', 'Schedule')
54         schedules = Schedule.objects.filter(email=contact.email)
55         return {
56             "schedule": self.get_schedule(schedules)
57         }
58
59     def get_example_context(self, contact):
60         Schedule = apps.get_model('club', 'Schedule')
61         return {
62             "schedule": Schedule(
63                 email=contact.email,
64                 key='xxxxxxxxx',
65                 amount=100,
66                 payed_at=self.time - timedelta(2),
67                 started_at=self.time - timedelta(1),
68                 expires_at=self.time + timedelta(1),
69             )
70         }
71
72
73 class ClubSingle(State):
74     slug = 'club-single'
75     name = _('club one-time donors')
76     level = Level.SINGLE
77     expired = False
78
79     def get_schedule(self, schedules):
80         # Find first single non-expired schedule.
81         return schedules.filter(
82             monthly=False, yearly=False,
83             expires_at__gt=self.time
84         ).order_by('started_at').first()
85
86
87 class ClubSingleExpired(State):
88     slug = 'club-membership-expiring'
89     allow_negative_offset = True
90     name = _('club one-time donors with donation expiring')
91     level = Level.SINGLE
92     expired = True
93
94     def get_schedule(self, schedules):
95         # Find last single expired schedule.
96         return schedules.filter(
97             monthly=False, yearly=False,
98             expires_at__lt=self.time
99         ).order_by('-expires_at').first()
100
101
102 class ClubTried(State):
103     slug = 'club-payment-unfinished'
104     name = _('club would-be donors')
105     level = Level.TRIED
106
107     def get_schedule(self, schedules):
108         # Find last unpaid schedule.
109         return schedules.filter(
110             payed_at=None
111         ).order_by('-started_at').first()
112
113
114 class ClubRecurring(State):
115     slug = 'club-recurring'
116     name = _('club recurring donors')
117     level = Level.RECURRING
118     expired = False
119
120     def get_schedule(self, schedules):
121         # Find first recurring non-expired schedule.
122         return schedules.exclude(
123             monthly=False, yearly=False
124         ).filter(
125             expires_at__gt=self.time
126         ).order_by('started_at').first()
127
128
129 class ClubRecurringExpired(State):
130     slug = 'club-recurring-payment-problem'
131     name = _('club recurring donors with donation expired')
132     level = Level.RECURRING
133     expired = True
134
135     def get_schedule(self, schedules):
136         # Find last recurring expired schedule.
137         return schedules.exclude(
138             monthly=False, yearly=False
139         ).filter(
140             expires_at__lt=self.time
141         ).order_by('-expires_at').first()
142
143
144 class Cold(State):
145     slug = 'cold'
146     name = _('cold group')
147     level = Level.COLD
148
149     def get_context(self, contact):
150         return {}
151
152
153 states = [
154     Cold,
155     ClubTried,
156     ClubSingle,
157     ClubSingleExpired,
158     ClubRecurring,
159     ClubRecurringExpired,
160 ]
161