models.py 22.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#

Krophil's avatar
Krophil committed
25
from django.db import models
Skia's avatar
Skia committed
26
from django.utils.translation import ugettext_lazy as _
27
from django.utils import timezone
Skia's avatar
Skia committed
28
from django.conf import settings
Skia's avatar
Skia committed
29
from django.core.urlresolvers import reverse
Skia's avatar
Skia committed
30
from django.forms import ValidationError
31
from django.utils.functional import cached_property
Skia's avatar
Skia committed
32

33
from datetime import timedelta, date
Skia's avatar
Skia committed
34
35
import random
import string
Skia's avatar
Skia committed
36
37
import os
import base64
38
import datetime
39

Skia's avatar
Skia committed
40
from club.models import Club
41
from accounting.models import CurrencyField
Skia's avatar
Skia committed
42
from core.models import Group, User, Notification
Skia's avatar
Skia committed
43
from subscription.models import Subscription
Skia's avatar
Skia committed
44

Krophil's avatar
Krophil committed
45

46
47
48
49
50
51
52
class Customer(models.Model):
    """
    This class extends a user to make a customer. It adds some basic customers informations, such as the accound ID, and
    is used by other accounting classes as reference to the customer, rather than using User
    """
    user = models.OneToOneField(User, primary_key=True)
    account_id = models.CharField(_('account id'), max_length=10, unique=True)
Skia's avatar
Skia committed
53
    amount = CurrencyField(_('amount'))
Sli's avatar
Sli committed
54
    recorded_products = models.IntegerField(_('recorded product'), default=0)
55
56
57
58

    class Meta:
        verbose_name = _('customer')
        verbose_name_plural = _('customers')
Krophil's avatar
Krophil committed
59
        ordering = ['account_id', ]
60
61

    def __str__(self):
Skia's avatar
Skia committed
62
        return "%s - %s" % (self.user.username, self.account_id)
63

Sli's avatar
Sli committed
64
65
66
67
68
69
70
    @property
    def can_record(self):
        return self.recorded_products > -settings.SITH_RECORD_LIMIT

    def can_record_more(self, number):
        return self.recorded_products - number >= -settings.SITH_RECORD_LIMIT

71
72
73
74
75
    @property
    def can_buy(self):
        return (self.user.subscriptions.last() and
                (date.today() - self.user.subscriptions.last().subscription_end) < timedelta(days=90))

Skia's avatar
Skia committed
76
77
78
    def generate_account_id(number):
        number = str(number)
        letter = random.choice(string.ascii_lowercase)
Krophil's avatar
Krophil committed
79
        while Customer.objects.filter(account_id=number + letter).exists():
Skia's avatar
Skia committed
80
            letter = random.choice(string.ascii_lowercase)
Krophil's avatar
Krophil committed
81
        return number + letter
82

Skia's avatar
Skia committed
83
84
85
86
87
    def save(self, *args, **kwargs):
        if self.amount < 0:
            raise ValidationError(_("Not enough money"))
        super(Customer, self).save(*args, **kwargs)

Skia's avatar
Skia committed
88
89
90
91
92
93
94
95
    def recompute_amount(self):
        self.amount = 0
        for r in self.refillings.all():
            self.amount += r.amount
        for s in self.buyings.filter(payment_method="SITH_ACCOUNT"):
            self.amount -= s.quantity * s.unit_price
            self.save()

96
97
98
99
    def get_absolute_url(self):
        return reverse('core:user_account', kwargs={'user_id': self.user.pk})

    def get_full_url(self):
Sli's avatar
Sli committed
100
        return ''.join(['https://', settings.SITH_URL, self.get_absolute_url()])
101
102


103
104
105
106
107
108
109
110
111
class ProductType(models.Model):
    """
    This describes a product type
    Useful only for categorizing, changes are made at the product level for now
    """
    name = models.CharField(_('name'), max_length=30)
    description = models.TextField(_('description'), null=True, blank=True)
    icon = models.ImageField(upload_to='products', null=True, blank=True)

Skia's avatar
Skia committed
112
113
114
    class Meta:
        verbose_name = _('product type')

115
116
117
118
    def is_owned_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
119
        if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
120
121
122
123
124
125
            return True
        return False

    def __str__(self):
        return self.name

Skia's avatar
Skia committed
126
127
128
    def get_absolute_url(self):
        return reverse('counter:producttype_list')

Krophil's avatar
Krophil committed
129

130
131
132
133
class Product(models.Model):
    """
    This describes a product, with all its related informations
    """
134
    name = models.CharField(_('name'), max_length=64)
135
    description = models.TextField(_('description'), blank=True)
136
    product_type = models.ForeignKey(ProductType, related_name='products', verbose_name=_("product type"), null=True, blank=True,
Krophil's avatar
Krophil committed
137
                                     on_delete=models.SET_NULL)
138
    code = models.CharField(_('code'), max_length=16, blank=True)
139
140
141
    purchase_price = CurrencyField(_('purchase price'))
    selling_price = CurrencyField(_('selling price'))
    special_selling_price = CurrencyField(_('special selling price'))
142
143
    icon = models.ImageField(upload_to='products', null=True, blank=True, verbose_name=_("icon"))
    club = models.ForeignKey(Club, related_name="products", verbose_name=_("club"))
144
145
    limit_age = models.IntegerField(_('limit age'), default=0)
    tray = models.BooleanField(_('tray price'), default=False)
146
    parent_product = models.ForeignKey('self', related_name='children_products', verbose_name=_("parent product"), null=True,
Krophil's avatar
Krophil committed
147
                                       blank=True, on_delete=models.SET_NULL)
Skia's avatar
Skia committed
148
    buying_groups = models.ManyToManyField(Group, related_name='products', verbose_name=_("buying groups"), blank=True)
Skia's avatar
Skia committed
149
    archived = models.BooleanField(_("archived"), default=False)
150

Skia's avatar
Skia committed
151
152
153
    class Meta:
        verbose_name = _('product')

Sli's avatar
Sli committed
154
155
    @property
    def is_record_product(self):
Sli's avatar
Sli committed
156
        return settings.SITH_RECORD_PRODUCT == self.id
Sli's avatar
Sli committed
157
158
159

    @property
    def is_unrecord_product(self):
Sli's avatar
Sli committed
160
        return settings.SITH_UNRECORD_PRODUCT == self.id
Sli's avatar
Sli committed
161

162
    def is_owned_by(self, user):
163
164
165
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
166
        if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID) or user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID):
167
168
169
170
            return True
        return False

    def __str__(self):
Skia's avatar
Skia committed
171
        return "%s (%s)" % (self.name, self.code)
172

Skia's avatar
Skia committed
173
174
175
    def get_absolute_url(self):
        return reverse('counter:product_list')

Krophil's avatar
Krophil committed
176

Skia's avatar
Skia committed
177
178
class Counter(models.Model):
    name = models.CharField(_('name'), max_length=30)
179
180
    club = models.ForeignKey(Club, related_name="counters", verbose_name=_("club"))
    products = models.ManyToManyField(Product, related_name="counters", verbose_name=_("products"), blank=True)
181
    type = models.CharField(_('counter type'),
Krophil's avatar
Krophil committed
182
183
                            max_length=255,
                            choices=[('BAR', _('Bar')), ('OFFICE', _('Office')), ('EBOUTIC', _('Eboutic'))])
Skia's avatar
Skia committed
184
    sellers = models.ManyToManyField(User, verbose_name=_('sellers'), related_name='counters', blank=True)
Skia's avatar
Skia committed
185
186
    edit_groups = models.ManyToManyField(Group, related_name="editable_counters", blank=True)
    view_groups = models.ManyToManyField(Group, related_name="viewable_counters", blank=True)
187
    token = models.CharField(_('token'), max_length=30, null=True, blank=True)
Skia's avatar
Skia committed
188

Skia's avatar
Skia committed
189
190
191
    class Meta:
        verbose_name = _('counter')

Skia's avatar
Skia committed
192
    def __getattribute__(self, name):
193
        if name == "edit_groups":
Krophil's avatar
Krophil committed
194
            return Group.objects.filter(name=self.club.unix_name + settings.SITH_BOARD_SUFFIX).all()
Skia's avatar
Skia committed
195
196
197
198
        return object.__getattribute__(self, name)

    def __str__(self):
        return self.name
Skia's avatar
Skia committed
199
200

    def get_absolute_url(self):
Skia's avatar
Skia committed
201
202
        if self.type == "EBOUTIC":
            return reverse('eboutic:main')
Skia's avatar
Skia committed
203
204
        return reverse('counter:details', kwargs={'counter_id': self.id})

205
    def is_owned_by(self, user):
206
207
208
        mem = self.club.get_membership_for(user)
        if mem and mem.role >= 7:
            return True
Skia's avatar
Skia committed
209
        return user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID)
210

Skia's avatar
Skia committed
211
    def can_be_viewed_by(self, user):
Skia's avatar
Skia committed
212
        if self.type == "BAR":
213
            return True
Skia's avatar
Skia committed
214
        return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user in self.sellers.all()
215

216
217
218
219
220
    def gen_token(self):
        """Generate a new token for this counter"""
        self.token = ''.join(random.choice(string.ascii_letters + string.digits) for x in range(30))
        self.save()

221
    def add_barman(self, user):
Skia's avatar
Skia committed
222
223
224
225
        """
        Logs a barman in to the given counter
        A user is stored as a tuple with its login time
        """
226
227
228
        Permanency(user=user, counter=self, start=timezone.now(), end=None).save()

    def del_barman(self, user):
Skia's avatar
Skia committed
229
230
231
        """
        Logs a barman out and store its permanency
        """
232
233
234
235
        perm = Permanency.objects.filter(counter=self, user=user, end=None).all()
        for p in perm:
            p.end = p.activity
            p.save()
Skia's avatar
Skia committed
236

237
238
239
240
    @cached_property
    def barmen_list(self):
        return self.get_barmen_list()

Skia's avatar
Skia committed
241
    def get_barmen_list(self):
Skia's avatar
Skia committed
242
        """
Skia's avatar
Skia committed
243
        Returns the barman list as list of User
Skia's avatar
Skia committed
244
245
246

        Also handle the timeout of the barmen
        """
247
        pl = Permanency.objects.filter(counter=self, end=None).all()
248
        bl = []
249
250
251
        for p in pl:
            if timezone.now() - p.activity < timedelta(minutes=settings.SITH_BARMAN_TIMEOUT):
                bl.append(p.user)
252
            else:
253
254
                p.end = p.activity
                p.save()
255
256
        return bl

Skia's avatar
Skia committed
257
    def get_random_barman(self):
Skia's avatar
Skia committed
258
259
260
        """
        Return a random user being currently a barman
        """
Skia's avatar
Skia committed
261
        bl = self.get_barmen_list()
Skia's avatar
Skia committed
262
        return bl[random.randrange(0, len(bl))]
Skia's avatar
Skia committed
263

Skia's avatar
Skia committed
264
265
266
267
268
    def update_activity(self):
        """
        Update the barman activity to prevent timeout
        """
        for p in Permanency.objects.filter(counter=self, end=None).all():
Krophil's avatar
Krophil committed
269
            p.save()  # Update activity
Skia's avatar
Skia committed
270

Sli's avatar
Sli committed
271
    def is_open(self):
272
        return len(self.barmen_list) > 0
Sli's avatar
Sli committed
273

274
275
    def is_inactive(self):
        """
276
        Returns True if the counter self is inactive from SITH_COUNTER_MINUTE_INACTIVE's value minutes, else False
277
        """
278
        return self.is_open() and ((timezone.now() - self.permanencies.order_by('-activity').first().activity) > datetime.timedelta(minutes=settings.SITH_COUNTER_MINUTE_INACTIVE))
279

Skia's avatar
Skia committed
280
    def barman_list(self):
Skia's avatar
Skia committed
281
282
283
        """
        Returns the barman id list
        """
Skia's avatar
Skia committed
284
285
        return [b.id for b in self.get_barmen_list()]

Krophil's avatar
Krophil committed
286

Skia's avatar
Skia committed
287
288
289
290
291
292
class Refilling(models.Model):
    """
    Handle the refilling
    """
    counter = models.ForeignKey(Counter, related_name="refillings", blank=False)
    amount = CurrencyField(_('amount'))
293
294
    operator = models.ForeignKey(User, related_name="refillings_as_operator", blank=False)
    customer = models.ForeignKey(Customer, related_name="refillings", blank=False)
295
    date = models.DateTimeField(_('date'))
Skia's avatar
Skia committed
296
    payment_method = models.CharField(_('payment method'), max_length=255,
Krophil's avatar
Krophil committed
297
                                      choices=settings.SITH_COUNTER_PAYMENT_METHOD, default='CASH')
298
    bank = models.CharField(_('bank'), max_length=255,
Krophil's avatar
Krophil committed
299
                            choices=settings.SITH_COUNTER_BANK, default='OTHER')
Skia's avatar
Skia committed
300
    is_validated = models.BooleanField(_('is validated'), default=False)
Skia's avatar
Skia committed
301

Skia's avatar
Skia committed
302
303
304
    class Meta:
        verbose_name = _("refilling")

Skia's avatar
Skia committed
305
    def __str__(self):
Skia's avatar
Skia committed
306
        return "Refilling: %.2f for %s" % (self.amount, self.customer.user.get_display_name())
Skia's avatar
Skia committed
307

Skia's avatar
Skia committed
308
    def is_owned_by(self, user):
309
        return user.is_owner(self.counter) and self.payment_method != "CARD"
Skia's avatar
Skia committed
310

Skia's avatar
Skia committed
311
312
313
314
315
    def delete(self, *args, **kwargs):
        self.customer.amount -= self.amount
        self.customer.save()
        super(Refilling, self).delete(*args, **kwargs)

Skia's avatar
Skia committed
316
    def save(self, *args, **kwargs):
317
        if not self.date:
Skia's avatar
Skia committed
318
            self.date = timezone.now()
Skia's avatar
Skia committed
319
        self.full_clean()
Skia's avatar
Skia committed
320
321
322
323
        if not self.is_validated:
            self.customer.amount += self.amount
            self.customer.save()
            self.is_validated = True
Skia's avatar
Skia committed
324
        Notification(user=self.customer.user, url=reverse('core:user_account_detail',
Krophil's avatar
Krophil committed
325
326
327
328
                                                          kwargs={'user_id': self.customer.user.id, 'year': self.date.year, 'month': self.date.month}),
                     param=str(self.amount),
                     type="REFILLING",
                     ).save()
Skia's avatar
Skia committed
329
        super(Refilling, self).save(*args, **kwargs)
Skia's avatar
Skia committed
330

Krophil's avatar
Krophil committed
331

Skia's avatar
Skia committed
332
333
334
335
class Selling(models.Model):
    """
    Handle the sellings
    """
336
    label = models.CharField(_("label"), max_length=64)
337
338
339
    product = models.ForeignKey(Product, related_name="sellings", null=True, blank=True, on_delete=models.SET_NULL)
    counter = models.ForeignKey(Counter, related_name="sellings", null=True, blank=False, on_delete=models.SET_NULL)
    club = models.ForeignKey(Club, related_name="sellings", null=True, blank=False, on_delete=models.SET_NULL)
Skia's avatar
Skia committed
340
341
    unit_price = CurrencyField(_('unit price'))
    quantity = models.IntegerField(_('quantity'))
342
343
344
345
    seller = models.ForeignKey(User, related_name="sellings_as_operator", null=True, blank=False, on_delete=models.SET_NULL)
    customer = models.ForeignKey(Customer, related_name="buyings", null=True, blank=False, on_delete=models.SET_NULL)
    date = models.DateTimeField(_('date'))
    payment_method = models.CharField(_('payment method'), max_length=255,
Krophil's avatar
Krophil committed
346
                                      choices=[('SITH_ACCOUNT', _('Sith account')), ('CARD', _('Credit card'))], default='SITH_ACCOUNT')
Skia's avatar
Skia committed
347
    is_validated = models.BooleanField(_('is validated'), default=False)
Skia's avatar
Skia committed
348

Skia's avatar
Skia committed
349
350
351
    class Meta:
        verbose_name = _("selling")

Skia's avatar
Skia committed
352
    def __str__(self):
Skia's avatar
Skia committed
353
        return "Selling: %d x %s (%f) for %s" % (self.quantity, self.label,
Krophil's avatar
Krophil committed
354
                                                 self.quantity * self.unit_price, self.customer.user.get_display_name())
Skia's avatar
Skia committed
355

Skia's avatar
Skia committed
356
    def is_owned_by(self, user):
357
        return user.is_owner(self.counter) and self.payment_method != "CARD"
Skia's avatar
Skia committed
358

Skia's avatar
Skia committed
359
360
361
    def can_be_viewed_by(self, user):
        return user == self.customer.user

Skia's avatar
Skia committed
362
    def delete(self, *args, **kwargs):
363
364
365
        if self.payment_method == "SITH_ACCOUNT":
            self.customer.amount += self.quantity * self.unit_price
            self.customer.save()
Skia's avatar
Skia committed
366
367
        super(Selling, self).delete(*args, **kwargs)

368
    def send_mail_customer(self):
Sli's avatar
Sli committed
369
        event = self.product.eticket.event_title or _("Unknown event")
Sli's avatar
Sli committed
370
        subject = _('Eticket bought for the event %(event)s') % {'event': event}
371
372
373
        message_html = _(
            "You bought an eticket for the event %(event)s.\nYou can download it on this page %(url)s."
        ) % {
Sli's avatar
Sli committed
374
            'event': event,
Krophil's avatar
Krophil committed
375
376
377
378
379
380
381
            'url': ''.join((
                '<a href="',
                self.customer.get_full_url(),
                '">',
                self.customer.get_full_url(),
                '</a>'
            ))
382
383
384
385
        }
        message_txt = _(
            "You bought an eticket for the event %(event)s.\nYou can download it on this page %(url)s."
        ) % {
Sli's avatar
Sli committed
386
            'event': event,
387
388
389
390
391
            'url': self.customer.get_full_url(),
        }
        self.customer.user.email_user(
            subject,
            message_txt,
392
            html_message=message_html
393
394
        )

Skia's avatar
Skia committed
395
    def save(self, *args, **kwargs):
396
        if not self.date:
Skia's avatar
Skia committed
397
            self.date = timezone.now()
Skia's avatar
Skia committed
398
        self.full_clean()
Skia's avatar
Skia committed
399
400
401
402
        if not self.is_validated:
            self.customer.amount -= self.quantity * self.unit_price
            self.customer.save()
            self.is_validated = True
403
        u = User.objects.filter(id=self.customer.user.id).first()
404
        if u.was_subscribed:
405
406
            if self.product and self.product.id == settings.SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER:
                sub = Subscription(
Krophil's avatar
Krophil committed
407
408
409
410
411
                    member=u,
                    subscription_type='un-semestre',
                    payment_method="EBOUTIC",
                    location="EBOUTIC",
                )
412
413
414
415
                sub.subscription_start = Subscription.compute_start()
                sub.subscription_start = Subscription.compute_start(
                    duration=settings.SITH_SUBSCRIPTIONS[sub.subscription_type]['duration'])
                sub.subscription_end = Subscription.compute_end(
Krophil's avatar
Krophil committed
416
417
                    duration=settings.SITH_SUBSCRIPTIONS[sub.subscription_type]['duration'],
                    start=sub.subscription_start)
418
419
420
421
                sub.save()
            elif self.product and self.product.id == settings.SITH_PRODUCT_SUBSCRIPTION_TWO_SEMESTERS:
                u = User.objects.filter(id=self.customer.user.id).first()
                sub = Subscription(
Krophil's avatar
Krophil committed
422
423
424
425
426
                    member=u,
                    subscription_type='deux-semestres',
                    payment_method="EBOUTIC",
                    location="EBOUTIC",
                )
427
428
429
430
                sub.subscription_start = Subscription.compute_start()
                sub.subscription_start = Subscription.compute_start(
                    duration=settings.SITH_SUBSCRIPTIONS[sub.subscription_type]['duration'])
                sub.subscription_end = Subscription.compute_end(
Krophil's avatar
Krophil committed
431
432
                    duration=settings.SITH_SUBSCRIPTIONS[sub.subscription_type]['duration'],
                    start=sub.subscription_start)
433
                sub.save()
434
435
436
        try:
            if self.product.eticket:
                self.send_mail_customer()
Krophil's avatar
Krophil committed
437
438
        except:
            pass
Skia's avatar
Skia committed
439
        Notification(
Krophil's avatar
Krophil committed
440
441
442
443
444
445
            user=self.customer.user,
            url=reverse('core:user_account_detail',
                        kwargs={'user_id': self.customer.user.id, 'year': self.date.year, 'month': self.date.month}),
            param="%d x %s" % (self.quantity, self.label),
            type="SELLING",
        ).save()
Skia's avatar
Skia committed
446
447
        super(Selling, self).save(*args, **kwargs)

Krophil's avatar
Krophil committed
448

Skia's avatar
Skia committed
449
450
451
452
class Permanency(models.Model):
    """
    This class aims at storing a traceability of who was barman where and when
    """
453
454
    user = models.ForeignKey(User, related_name="permanencies", verbose_name=_("user"))
    counter = models.ForeignKey(Counter, related_name="permanencies", verbose_name=_("counter"))
Skia's avatar
Skia committed
455
    start = models.DateTimeField(_('start date'))
Skia's avatar
Skia committed
456
    end = models.DateTimeField(_('end date'), null=True, db_index=True)
457
    activity = models.DateTimeField(_('last activity date'), auto_now=True)
Skia's avatar
Skia committed
458

Skia's avatar
Skia committed
459
460
461
    class Meta:
        verbose_name = _("permanency")

Skia's avatar
Skia committed
462
    def __str__(self):
Skia's avatar
Skia committed
463
        return "%s in %s from %s (last activity: %s) to %s" % (self.user, self.counter,
Krophil's avatar
Krophil committed
464
465
466
467
468
                                                               self.start.strftime("%Y-%m-%d %H:%M:%S"),
                                                               self.activity.strftime("%Y-%m-%d %H:%M:%S"),
                                                               self.end.strftime("%Y-%m-%d %H:%M:%S") if self.end else "",
                                                               )

Skia's avatar
Skia committed
469

Skia's avatar
Skia committed
470
471
472
473
474
475
476
477
478
479
480
481
482
class CashRegisterSummary(models.Model):
    user = models.ForeignKey(User, related_name="cash_summaries", verbose_name=_("user"))
    counter = models.ForeignKey(Counter, related_name="cash_summaries", verbose_name=_("counter"))
    date = models.DateTimeField(_('date'))
    comment = models.TextField(_('comment'), null=True, blank=True)
    emptied = models.BooleanField(_('emptied'), default=False)

    class Meta:
        verbose_name = _("cash register summary")

    def __str__(self):
        return "At %s by %s - Total: %s €" % (self.counter, self.user, self.get_total())

483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
    def __getattribute__(self, name):
        if name[:5] == 'check':
            checks = self.items.filter(check=True).order_by('value').all()
        if name == 'ten_cents':
            return self.items.filter(value=0.1, check=False).first()
        elif name == 'twenty_cents':
            return self.items.filter(value=0.2, check=False).first()
        elif name == 'fifty_cents':
            return self.items.filter(value=0.5, check=False).first()
        elif name == 'one_euro':
            return self.items.filter(value=1, check=False).first()
        elif name == 'two_euros':
            return self.items.filter(value=2, check=False).first()
        elif name == 'five_euros':
            return self.items.filter(value=5, check=False).first()
        elif name == 'ten_euros':
            return self.items.filter(value=10, check=False).first()
        elif name == 'twenty_euros':
            return self.items.filter(value=20, check=False).first()
        elif name == 'fifty_euros':
            return self.items.filter(value=50, check=False).first()
        elif name == 'hundred_euros':
            return self.items.filter(value=100, check=False).first()
        elif name == 'check_1':
            return checks[0] if 0 < len(checks) else None
        elif name == 'check_2':
            return checks[1] if 1 < len(checks) else None
        elif name == 'check_3':
            return checks[2] if 2 < len(checks) else None
        elif name == 'check_4':
            return checks[3] if 3 < len(checks) else None
        elif name == 'check_5':
            return checks[4] if 4 < len(checks) else None
        else:
            return object.__getattribute__(self, name)

Skia's avatar
Skia committed
519
520
521
522
    def is_owned_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
523
        if user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID):
Skia's avatar
Skia committed
524
525
526
            return True
        return False

Skia's avatar
Skia committed
527
528
529
530
531
532
533
534
535
536
537
    def get_total(self):
        t = 0
        for it in self.items.all():
            t += it.quantity * it.value
        return t

    def save(self, *args, **kwargs):
        if not self.id:
            self.date = timezone.now()
        return super(CashRegisterSummary, self).save(*args, **kwargs)

538
539
540
    def get_absolute_url(self):
        return reverse('counter:cash_summary_list')

Krophil's avatar
Krophil committed
541

Skia's avatar
Skia committed
542
543
544
545
546
547
548
549
class CashRegisterSummaryItem(models.Model):
    cash_summary = models.ForeignKey(CashRegisterSummary, related_name="items", verbose_name=_("cash summary"))
    value = CurrencyField(_("value"))
    quantity = models.IntegerField(_('quantity'), default=0)
    check = models.BooleanField(_('check'), default=False)

    class Meta:
        verbose_name = _("cash register summary item")
550

Krophil's avatar
Krophil committed
551

Skia's avatar
Skia committed
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
class Eticket(models.Model):
    """
    Eticket can be linked to a product an allows PDF generation
    """
    product = models.OneToOneField(Product, related_name='eticket', verbose_name=_("product"))
    banner = models.ImageField(upload_to='etickets', null=True, blank=True, verbose_name=_("banner"))
    event_date = models.DateField(_('event date'), null=True, blank=True)
    event_title = models.CharField(_('event title'), max_length=64, null=True, blank=True)
    secret = models.CharField(_('secret'), max_length=64, unique=True)

    def __str__(self):
        return "%s" % (self.product.name)

    def get_absolute_url(self):
        return reverse('counter:eticket_list')

    def save(self, *args, **kwargs):
        if not self.id:
            self.secret = base64.b64encode(os.urandom(32))
        return super(Eticket, self).save(*args, **kwargs)

    def is_owned_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
577
        return user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID)
Skia's avatar
Skia committed
578
579

    def get_hash(self, string):
Krophil's avatar
Krophil committed
580
581
        import hashlib
        import hmac
Skia's avatar
Skia committed
582
        return hmac.new(bytes(self.secret, 'utf-8'), bytes(string, 'utf-8'), hashlib.sha1).hexdigest()