models.py 20.9 KB
Newer Older
Skia's avatar
Skia committed
1
from django.db import models, DataError
Skia's avatar
Skia committed
2
from django.utils.translation import ugettext_lazy as _
3
from django.utils import timezone
Skia's avatar
Skia committed
4
from django.conf import settings
Skia's avatar
Skia committed
5
from django.core.urlresolvers import reverse
Skia's avatar
Skia committed
6
from django.forms import ValidationError
7
from django.contrib.sites.shortcuts import get_current_site
Skia's avatar
Skia committed
8

Skia's avatar
Skia committed
9
from datetime import timedelta
Skia's avatar
Skia committed
10
11
import random
import string
Skia's avatar
Skia committed
12
13
import os
import base64
14
import datetime
15

Skia's avatar
Skia committed
16
from club.models import Club
17
from accounting.models import CurrencyField
Skia's avatar
Skia committed
18
from core.models import Group, User, Notification
Skia's avatar
Skia committed
19
from subscription.models import Subscription
Skia's avatar
Skia committed
20

21
22
23
24
25
26
27
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
28
    amount = CurrencyField(_('amount'))
29
30
31
32

    class Meta:
        verbose_name = _('customer')
        verbose_name_plural = _('customers')
Skia's avatar
Skia committed
33
        ordering = ['account_id',]
34
35

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

Skia's avatar
Skia committed
38
39
40
41
42
43
    def generate_account_id(number):
        number = str(number)
        letter = random.choice(string.ascii_lowercase)
        while Customer.objects.filter(account_id=number+letter).exists():
            letter = random.choice(string.ascii_lowercase)
        return number+letter
44

Skia's avatar
Skia committed
45
46
47
48
49
    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
50
51
52
53
54
55
56
57
    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()

58
59
60
61
    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
62
        return ''.join(['https://', settings.SITH_URL, self.get_absolute_url()])
63
64


65
66
67
68
69
70
71
72
73
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
74
75
76
    class Meta:
        verbose_name = _('product type')

77
78
79
80
    def is_owned_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
81
        if user.is_in_group(settings.SITH_GROUP_ACCOUNTING_ADMIN_ID):
82
83
84
85
86
87
            return True
        return False

    def __str__(self):
        return self.name

Skia's avatar
Skia committed
88
89
90
    def get_absolute_url(self):
        return reverse('counter:producttype_list')

91
92
93
94
class Product(models.Model):
    """
    This describes a product, with all its related informations
    """
95
    name = models.CharField(_('name'), max_length=64)
96
    description = models.TextField(_('description'), blank=True)
97
98
    product_type = models.ForeignKey(ProductType, related_name='products', verbose_name=_("product type"), null=True, blank=True,
            on_delete=models.SET_NULL)
99
    code = models.CharField(_('code'), max_length=16, blank=True)
100
101
102
    purchase_price = CurrencyField(_('purchase price'))
    selling_price = CurrencyField(_('selling price'))
    special_selling_price = CurrencyField(_('special selling price'))
103
104
    icon = models.ImageField(upload_to='products', null=True, blank=True, verbose_name=_("icon"))
    club = models.ForeignKey(Club, related_name="products", verbose_name=_("club"))
105
106
    limit_age = models.IntegerField(_('limit age'), default=0)
    tray = models.BooleanField(_('tray price'), default=False)
107
108
    parent_product = models.ForeignKey('self', related_name='children_products', verbose_name=_("parent product"), null=True,
            blank=True, on_delete=models.SET_NULL)
Skia's avatar
Skia committed
109
    buying_groups = models.ManyToManyField(Group, related_name='products', verbose_name=_("buying groups"), blank=True)
Skia's avatar
Skia committed
110
    archived = models.BooleanField(_("archived"), default=False)
111

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

115
    def is_owned_by(self, user):
116
117
118
        """
        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) or user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID):
120
121
122
123
            return True
        return False

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

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

Skia's avatar
Skia committed
129
130
class Counter(models.Model):
    name = models.CharField(_('name'), max_length=30)
131
132
    club = models.ForeignKey(Club, related_name="counters", verbose_name=_("club"))
    products = models.ManyToManyField(Product, related_name="counters", verbose_name=_("products"), blank=True)
133
    type = models.CharField(_('counter type'),
Skia's avatar
Skia committed
134
            max_length=255,
Skia's avatar
Skia committed
135
            choices=[('BAR',_('Bar')), ('OFFICE',_('Office')), ('EBOUTIC',_('Eboutic'))])
Skia's avatar
Skia committed
136
    sellers = models.ManyToManyField(User, verbose_name=_('sellers'), related_name='counters', blank=True)
Skia's avatar
Skia committed
137
138
    edit_groups = models.ManyToManyField(Group, related_name="editable_counters", blank=True)
    view_groups = models.ManyToManyField(Group, related_name="viewable_counters", blank=True)
139
    token = models.CharField(_('token'), max_length=30, null=True, blank=True)
Skia's avatar
Skia committed
140

Skia's avatar
Skia committed
141
142
143
    class Meta:
        verbose_name = _('counter')

Skia's avatar
Skia committed
144
    def __getattribute__(self, name):
145
146
        if name == "edit_groups":
            return Group.objects.filter(name=self.club.unix_name+settings.SITH_BOARD_SUFFIX).all()
Skia's avatar
Skia committed
147
148
149
150
        return object.__getattribute__(self, name)

    def __str__(self):
        return self.name
Skia's avatar
Skia committed
151
152

    def get_absolute_url(self):
Skia's avatar
Skia committed
153
154
        if self.type == "EBOUTIC":
            return reverse('eboutic:main')
Skia's avatar
Skia committed
155
156
        return reverse('counter:details', kwargs={'counter_id': self.id})

157
    def is_owned_by(self, user):
158
159
160
        mem = self.club.get_membership_for(user)
        if mem and mem.role >= 7:
            return True
Skia's avatar
Skia committed
161
        return user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID)
162

Skia's avatar
Skia committed
163
    def can_be_viewed_by(self, user):
Skia's avatar
Skia committed
164
        if self.type == "BAR":
165
            return True
Skia's avatar
Skia committed
166
        return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP) or user in self.sellers.all()
167

168
169
170
171
172
    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()

173
    def add_barman(self, user):
Skia's avatar
Skia committed
174
175
176
177
        """
        Logs a barman in to the given counter
        A user is stored as a tuple with its login time
        """
178
179
180
        Permanency(user=user, counter=self, start=timezone.now(), end=None).save()

    def del_barman(self, user):
Skia's avatar
Skia committed
181
182
183
        """
        Logs a barman out and store its permanency
        """
184
185
186
187
        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
188

Skia's avatar
Skia committed
189
    def get_barmen_list(self):
Skia's avatar
Skia committed
190
        """
Skia's avatar
Skia committed
191
        Returns the barman list as list of User
Skia's avatar
Skia committed
192
193
194

        Also handle the timeout of the barmen
        """
195
        pl = Permanency.objects.filter(counter=self, end=None).all()
196
        bl = []
197
198
199
        for p in pl:
            if timezone.now() - p.activity < timedelta(minutes=settings.SITH_BARMAN_TIMEOUT):
                bl.append(p.user)
200
            else:
201
202
                p.end = p.activity
                p.save()
203
204
        return bl

Skia's avatar
Skia committed
205
    def get_random_barman(self):
Skia's avatar
Skia committed
206
207
208
        """
        Return a random user being currently a barman
        """
Skia's avatar
Skia committed
209
        bl = self.get_barmen_list()
Skia's avatar
Skia committed
210
        return bl[random.randrange(0, len(bl))]
Skia's avatar
Skia committed
211

Skia's avatar
Skia committed
212
213
214
215
216
217
218
    def update_activity(self):
        """
        Update the barman activity to prevent timeout
        """
        for p in Permanency.objects.filter(counter=self, end=None).all():
            p.save() # Update activity

Sli's avatar
Sli committed
219
    def is_open(self):
Skia's avatar
Skia committed
220
        return len(self.get_barmen_list()) > 0
Sli's avatar
Sli committed
221

222
223
    def is_inactive(self):
        """
224
        Returns True if the counter self is inactive from SITH_COUNTER_MINUTE_INACTIVE's value minutes, else False
225
        """
226
        return self.is_open() and ((timezone.now() - self.permanencies.order_by('-activity').first().activity) > datetime.timedelta(minutes=settings.SITH_COUNTER_MINUTE_INACTIVE))
227

Skia's avatar
Skia committed
228
    def barman_list(self):
Skia's avatar
Skia committed
229
230
231
        """
        Returns the barman id list
        """
Skia's avatar
Skia committed
232
233
        return [b.id for b in self.get_barmen_list()]

Skia's avatar
Skia committed
234
235
236
237
238
239
class Refilling(models.Model):
    """
    Handle the refilling
    """
    counter = models.ForeignKey(Counter, related_name="refillings", blank=False)
    amount = CurrencyField(_('amount'))
240
241
    operator = models.ForeignKey(User, related_name="refillings_as_operator", blank=False)
    customer = models.ForeignKey(Customer, related_name="refillings", blank=False)
242
    date = models.DateTimeField(_('date'))
Skia's avatar
Skia committed
243
    payment_method = models.CharField(_('payment method'), max_length=255,
244
            choices=settings.SITH_COUNTER_PAYMENT_METHOD, default='CASH')
245
    bank = models.CharField(_('bank'), max_length=255,
246
            choices=settings.SITH_COUNTER_BANK, default='OTHER')
Skia's avatar
Skia committed
247
    is_validated = models.BooleanField(_('is validated'), default=False)
Skia's avatar
Skia committed
248

Skia's avatar
Skia committed
249
250
251
    class Meta:
        verbose_name = _("refilling")

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

Skia's avatar
Skia committed
255
    def is_owned_by(self, user):
256
        return user.is_owner(self.counter) and self.payment_method != "CARD"
Skia's avatar
Skia committed
257

Skia's avatar
Skia committed
258
259
260
261
262
    def delete(self, *args, **kwargs):
        self.customer.amount -= self.amount
        self.customer.save()
        super(Refilling, self).delete(*args, **kwargs)

Skia's avatar
Skia committed
263
    def save(self, *args, **kwargs):
264
        if not self.date:
Skia's avatar
Skia committed
265
            self.date = timezone.now()
Skia's avatar
Skia committed
266
        self.full_clean()
Skia's avatar
Skia committed
267
268
269
270
        if not self.is_validated:
            self.customer.amount += self.amount
            self.customer.save()
            self.is_validated = True
Skia's avatar
Skia committed
271
        Notification(user=self.customer.user, url=reverse('core:user_account_detail',
Skia's avatar
Skia committed
272
                    kwargs={'user_id': self.customer.user.id, 'year': self.date.year, 'month': self.date.month}),
Skia's avatar
Skia committed
273
274
                param=str(self.amount),
                type="REFILLING",
Skia's avatar
Skia committed
275
                ).save()
Skia's avatar
Skia committed
276
        super(Refilling, self).save(*args, **kwargs)
Skia's avatar
Skia committed
277
278
279
280
281

class Selling(models.Model):
    """
    Handle the sellings
    """
282
    label = models.CharField(_("label"), max_length=64)
283
284
285
    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
286
287
    unit_price = CurrencyField(_('unit price'))
    quantity = models.IntegerField(_('quantity'))
288
289
290
291
292
    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,
            choices=[('SITH_ACCOUNT', _('Sith account')), ('CARD', _('Credit card'))], default='SITH_ACCOUNT')
Skia's avatar
Skia committed
293
    is_validated = models.BooleanField(_('is validated'), default=False)
Skia's avatar
Skia committed
294

Skia's avatar
Skia committed
295
296
297
    class Meta:
        verbose_name = _("selling")

Skia's avatar
Skia committed
298
    def __str__(self):
Skia's avatar
Skia committed
299
        return "Selling: %d x %s (%f) for %s" % (self.quantity, self.label,
Skia's avatar
Skia committed
300
301
                self.quantity*self.unit_price, self.customer.user.get_display_name())

Skia's avatar
Skia committed
302
    def is_owned_by(self, user):
303
        return user.is_owner(self.counter) and self.payment_method != "CARD"
Skia's avatar
Skia committed
304

Skia's avatar
Skia committed
305
306
307
    def can_be_viewed_by(self, user):
        return user == self.customer.user

Skia's avatar
Skia committed
308
    def delete(self, *args, **kwargs):
309
310
311
        if self.payment_method == "SITH_ACCOUNT":
            self.customer.amount += self.quantity * self.unit_price
            self.customer.save()
Skia's avatar
Skia committed
312
313
        super(Selling, self).delete(*args, **kwargs)

314
    def send_mail_customer(self):
Sli's avatar
Sli committed
315
        event = self.product.eticket.event_title or _("Unknown event")
Sli's avatar
Sli committed
316
        subject = _('Eticket bought for the event %(event)s') % {'event': event}
317
318
319
        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
320
            'event': event,
321
322
323
324
325
326
327
328
329
330
331
            'url':''.join((
                    '<a href="',
                    self.customer.get_full_url(),
                    '">',
                    self.customer.get_full_url(),
                    '</a>'
                ))
        }
        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
332
            'event': event,
333
334
335
336
337
            'url': self.customer.get_full_url(),
        }
        self.customer.user.email_user(
            subject,
            message_txt,
338
            html_message=message_html
339
340
        )

Skia's avatar
Skia committed
341
    def save(self, *args, **kwargs):
342
        if not self.date:
Skia's avatar
Skia committed
343
            self.date = timezone.now()
Skia's avatar
Skia committed
344
        self.full_clean()
Skia's avatar
Skia committed
345
346
347
348
        if not self.is_validated:
            self.customer.amount -= self.quantity * self.unit_price
            self.customer.save()
            self.is_validated = True
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
        u = User.objects.filter(id=self.customer.user.id).first()
        if u.was_subscribed():
            if self.product and self.product.id == settings.SITH_PRODUCT_SUBSCRIPTION_ONE_SEMESTER:
                sub = Subscription(
                        member=u,
                        subscription_type='un-semestre',
                        payment_method="EBOUTIC",
                        location="EBOUTIC",
                        )
                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(
                        duration=settings.SITH_SUBSCRIPTIONS[sub.subscription_type]['duration'],
                        start=sub.subscription_start)
                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(
                        member=u,
                        subscription_type='deux-semestres',
                        payment_method="EBOUTIC",
                        location="EBOUTIC",
                        )
                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(
                        duration=settings.SITH_SUBSCRIPTIONS[sub.subscription_type]['duration'],
                        start=sub.subscription_start)
                sub.save()
380
381
382
        try:
            if self.product.eticket:
                self.send_mail_customer()
Sli's avatar
Sli committed
383
        except: pass
Skia's avatar
Skia committed
384
385
386
387
        Notification(
                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}),
Skia's avatar
Skia committed
388
389
                param="%d x %s" % (self.quantity, self.label),
                type="SELLING",
Skia's avatar
Skia committed
390
                ).save()
Skia's avatar
Skia committed
391
392
        super(Selling, self).save(*args, **kwargs)

Skia's avatar
Skia committed
393
394
395
396
class Permanency(models.Model):
    """
    This class aims at storing a traceability of who was barman where and when
    """
397
398
    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
399
    start = models.DateTimeField(_('start date'))
400
401
    end = models.DateTimeField(_('end date'), null=True)
    activity = models.DateTimeField(_('last activity date'), auto_now=True)
Skia's avatar
Skia committed
402

Skia's avatar
Skia committed
403
404
405
    class Meta:
        verbose_name = _("permanency")

Skia's avatar
Skia committed
406
    def __str__(self):
Skia's avatar
Skia committed
407
408
409
410
411
        return "%s in %s from %s (last activity: %s) to %s" % (self.user, self.counter,
                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
412

Skia's avatar
Skia committed
413
414
415
416
417
418
419
420
421
422
423
424
425
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())

426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
    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
462
463
464
465
    def is_owned_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
466
        if user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID):
Skia's avatar
Skia committed
467
468
469
            return True
        return False

Skia's avatar
Skia committed
470
471
472
473
474
475
476
477
478
479
480
    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)

481
482
483
    def get_absolute_url(self):
        return reverse('counter:cash_summary_list')

Skia's avatar
Skia committed
484
485
486
487
488
489
490
491
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")
492

Skia's avatar
Skia committed
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
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
518
        return user.is_in_group(settings.SITH_GROUP_COUNTER_ADMIN_ID)
Skia's avatar
Skia committed
519
520
521
522
523

    def get_hash(self, string):
        import hashlib, hmac
        return hmac.new(bytes(self.secret, 'utf-8'), bytes(string, 'utf-8'), hashlib.sha1).hexdigest()