models.py 8.97 KB
Newer Older
Skia's avatar
Skia committed
1
2
from django.db import models
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

7
from datetime import timedelta
8
from random import randrange
9

Skia's avatar
Skia committed
10
from club.models import Club
11
12
from accounting.models import CurrencyField
from core.models import Group, User
Skia's avatar
Skia committed
13

14
15
16
17
18
19
20
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
21
    amount = CurrencyField(_('amount'))
22
23
24
25
26
27
28
29

    class Meta:
        verbose_name = _('customer')
        verbose_name_plural = _('customers')

    def __str__(self):
        return self.user.username

30
31
32
    def generate_account_id():
        return randrange(0, 4000) # TODO: improve me!

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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)

    def is_owned_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
        if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']):
            return True
        return False

    def __str__(self):
        return self.name

class Product(models.Model):
    """
    This describes a product, with all its related informations
    """
    name = models.CharField(_('name'), max_length=30)
    description = models.TextField(_('description'), blank=True)
    product_type = models.ForeignKey(ProductType, related_name='products', null=True, blank=True)
    code = models.CharField(_('code'), max_length=10)
    purchase_price = CurrencyField(_('purchase price'))
    selling_price = CurrencyField(_('selling price'))
    special_selling_price = CurrencyField(_('special selling price'))
    icon = models.ImageField(upload_to='products', null=True, blank=True)
    club = models.ForeignKey(Club, related_name="products")

67
    def is_owned_by(self, user):
68
69
70
71
72
73
74
75
76
77
        """
        Method to see if that object can be edited by the given user
        """
        if user.is_in_group(settings.SITH_GROUPS['accounting-admin']['name']):
            return True
        return False

    def __str__(self):
        return self.name

Skia's avatar
Skia committed
78
79
80
    def get_absolute_url(self):
        return reverse('counter:product_list')

Skia's avatar
Skia committed
81
82
83
84
class Counter(models.Model):
    name = models.CharField(_('name'), max_length=30)
    club = models.ForeignKey(Club, related_name="counters")
    products = models.ManyToManyField(Product, related_name="counters", blank=True)
Skia's avatar
Skia committed
85
86
    type = models.CharField(_('subscription type'),
            max_length=255,
Skia's avatar
Skia committed
87
            choices=[('BAR',_('Bar')), ('OFFICE',_('Office')), ('EBOUTIC',_('Eboutic'))])
Skia's avatar
Skia committed
88
89
    edit_groups = models.ManyToManyField(Group, related_name="editable_counters", blank=True)
    view_groups = models.ManyToManyField(Group, related_name="viewable_counters", blank=True)
Skia's avatar
Skia committed
90
    barmen_session = {}
Skia's avatar
Skia committed
91
92
93

    def __getattribute__(self, name):
        if name == "owner_group":
94
            return Group.objects.filter(name=self.club.unix_name+settings.SITH_BOARD_SUFFIX).first()
Skia's avatar
Skia committed
95
96
97
98
        return object.__getattribute__(self, name)

    def __str__(self):
        return self.name
Skia's avatar
Skia committed
99
100

    def get_absolute_url(self):
Skia's avatar
Skia committed
101
102
        if self.type == "EBOUTIC":
            return reverse('eboutic:main')
Skia's avatar
Skia committed
103
104
        return reverse('counter:details', kwargs={'counter_id': self.id})

105
106
107
    def can_be_edited_by(self, user):
        return user.is_in_group(settings.SITH_GROUPS['counter-admin']['name'])

Skia's avatar
Skia committed
108
    def can_be_viewed_by(self, user):
Skia's avatar
Skia committed
109
        return user.is_in_group(settings.SITH_MAIN_BOARD_GROUP)
110

Skia's avatar
Skia committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
    def add_barman(counter_id, user_id):
        """
        Logs a barman in to the given counter
        A user is stored as a tuple with its login time
        """
        counter_id = int(counter_id)
        user_id = int(user_id)
        if counter_id not in Counter.barmen_session.keys():
            Counter.barmen_session[counter_id] = {'users': {(user_id, timezone.now())}, 'time': timezone.now()}
        else:
            Counter.barmen_session[counter_id]['users'].add((user_id, timezone.now()))

    def del_barman(counter_id, user_id):
        """
        Logs a barman out and store its permanency
        """
        counter_id = int(counter_id)
        user_id = int(user_id)
        user_tuple = None
        for t in Counter.barmen_session[counter_id]['users']:
            if t[0] == user_id: user_tuple = t
        Counter.barmen_session[counter_id]['users'].remove(user_tuple)
        u = User.objects.filter(id=user_id).first()
        c = Counter.objects.filter(id=counter_id).first()
        Permanency(user=u, counter=c, start=user_tuple[1], end=Counter.barmen_session[counter_id]['time']).save()

137
    def get_barmen_list(counter_id):
Skia's avatar
Skia committed
138
        """
Skia's avatar
Skia committed
139
        Returns the barman list as list of User
Skia's avatar
Skia committed
140
141
142

        Also handle the timeout of the barmen
        """
143
        bl = []
Skia's avatar
Skia committed
144
        counter_id = int(counter_id)
145
        if counter_id in list(Counter.barmen_session.keys()):
Skia's avatar
Skia committed
146
147
            for b in Counter.barmen_session[counter_id]['users']:
                # Reminder: user is stored as a tuple with its login time
Skia's avatar
Skia committed
148
                bl.append(User.objects.filter(id=b[0]).first())
149
150
151
            if (timezone.now() - Counter.barmen_session[counter_id]['time']) < timedelta(minutes=settings.SITH_BARMAN_TIMEOUT):
                Counter.barmen_session[counter_id]['time'] = timezone.now()
            else:
Skia's avatar
Skia committed
152
153
154
                for b in bl:
                    Counter.del_barman(counter_id, b.id)
                bl = []
155
156
157
                Counter.barmen_session[counter_id]['users'] = set()
        return bl

Skia's avatar
Skia committed
158
    def get_random_barman(counter_id):
Skia's avatar
Skia committed
159
        bl = Counter.get_barmen_list(counter_id)
Skia's avatar
Skia committed
160
        return bl[randrange(0, len(bl))]
Skia's avatar
Skia committed
161
162
163
164
165
166
167

class Refilling(models.Model):
    """
    Handle the refilling
    """
    counter = models.ForeignKey(Counter, related_name="refillings", blank=False)
    amount = CurrencyField(_('amount'))
168
169
    operator = models.ForeignKey(User, related_name="refillings_as_operator", blank=False)
    customer = models.ForeignKey(Customer, related_name="refillings", blank=False)
Skia's avatar
Skia committed
170
171
    date = models.DateTimeField(_('date'), auto_now=True)
    payment_method = models.CharField(_('payment method'), max_length=255,
172
173
174
            choices=settings.SITH_COUNTER_PAYMENT_METHOD, default='cash')
    bank = models.CharField(_('bank'), max_length=255,
            choices=settings.SITH_COUNTER_BANK, default='other')
Skia's avatar
Skia committed
175
176

    def __str__(self):
Skia's avatar
Skia committed
177
        return "Refilling: %.2f for %s" % (self.amount, self.customer.user.get_display_name())
Skia's avatar
Skia committed
178
179
180
181
182
183

    # def get_absolute_url(self):
    #     return reverse('counter:details', kwargs={'counter_id': self.id})

    def save(self, *args, **kwargs):
        self.full_clean()
Skia's avatar
Skia committed
184
        self.customer.amount += self.amount
Skia's avatar
Skia committed
185
        self.customer.save()
Skia's avatar
Skia committed
186
        super(Refilling, self).save(*args, **kwargs)
Skia's avatar
Skia committed
187
188
189
190
191
192
193
194
195

class Selling(models.Model):
    """
    Handle the sellings
    """
    product = models.ForeignKey(Product, related_name="sellings", blank=False)
    counter = models.ForeignKey(Counter, related_name="sellings", blank=False)
    unit_price = CurrencyField(_('unit price'))
    quantity = models.IntegerField(_('quantity'))
196
197
    seller = models.ForeignKey(User, related_name="sellings_as_operator", blank=False)
    customer = models.ForeignKey(Customer, related_name="buyings", blank=False)
Skia's avatar
Skia committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    date = models.DateTimeField(_('date'), auto_now=True)

    def __str__(self):
        return "Selling: %d x %s (%f) for %s" % (self.quantity, self.product.name,
                self.quantity*self.unit_price, self.customer.user.get_display_name())

    def save(self, *args, **kwargs):
        self.full_clean()
        self.customer.amount -= self.quantity * self.unit_price
        self.customer.save()
        super(Selling, self).save(*args, **kwargs)

    # def get_absolute_url(self):
    #     return reverse('counter:details', kwargs={'counter_id': self.id})

Skia's avatar
Skia committed
213
214
215
216
217
218
219
220
221
222
223
224
225
class Permanency(models.Model):
    """
    This class aims at storing a traceability of who was barman where and when
    """
    user = models.ForeignKey(User, related_name="permanencies")
    counter = models.ForeignKey(Counter, related_name="permanencies")
    start = models.DateTimeField(_('start date'))
    end = models.DateTimeField(_('end date'))

    def __str__(self):
        return "%s in %s from %s to %s" % (self.user, self.counter,
                self.start.strftime("%Y-%m-%d %H:%M:%S"), self.end.strftime("%Y-%m-%d %H:%M:%S"))

226
227
228
229
230
231

# TODO:
# une classe Vente
# foreign key vers comptoir, vendeur, client, produit, mais stocker le prix du produit, pour gerer les maj de prix
# une classe Rechargement
# foreign key vers comptoir, vendeur, client, plus montant
Skia's avatar
Skia committed
232