models.py 6.73 KB
Newer Older
Skia's avatar
Skia committed
1
from django.core.urlresolvers import reverse
Skia's avatar
Skia committed
2
from django.db import models
3
from django.conf import settings
Skia's avatar
Skia committed
4
5
6
7
from django.utils.translation import ugettext_lazy as _

from decimal import Decimal
from core.models import User
8
from club.models import Club
Skia's avatar
Skia committed
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

class CurrencyField(models.DecimalField):
    """
    This is a custom database field used for currency
    """
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        kwargs['max_digits'] = 12
        kwargs['decimal_places'] = 2
        super(CurrencyField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        try:
           return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
        except AttributeError:
           return None


Skia's avatar
Skia committed
28
class BankAccount(models.Model):
29
    name = models.CharField(_('name'), max_length=30)
30
    iban = models.CharField(_('iban'), max_length=255, blank=True)
31
    number = models.CharField(_('account number'), max_length=255, blank=True)
Skia's avatar
Skia committed
32
33
34
35
36
37
38
39
40
41
42
43
    club = models.ForeignKey(Club, related_name="bank_accounts")

    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
        m = self.club.get_membership_for(user)
        if m is not None and m.role >= 7:
            return True
        return False
44

Skia's avatar
Skia committed
45
46
47
    def get_absolute_url(self):
        return reverse('accounting:bank_details', kwargs={'b_account_id': self.id})

48
49
50
    def __str__(self):
        return self.name

Skia's avatar
Skia committed
51
class ClubAccount(models.Model):
52
    name = models.CharField(_('name'), max_length=30)
Skia's avatar
Skia committed
53
    club = models.OneToOneField(Club, related_name="club_account")
54
55
    bank_account = models.ForeignKey(BankAccount, related_name="club_accounts")

Skia's avatar
Skia committed
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
    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 can_be_edited_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
        m = self.club.get_membership_for(user)
        if m is not None and m.role >= 7:
            return True
        return False

Skia's avatar
Skia committed
73
74
75
76
77
78
    def has_open_journal(self):
        for j in self.journals.all():
            if not j.closed:
                return True
        return False

Skia's avatar
Skia committed
79
80
81
    def get_absolute_url(self):
        return reverse('accounting:club_details', kwargs={'c_account_id': self.id})

82
83
84
    def __str__(self):
        return self.name

Skia's avatar
Skia committed
85
class GeneralJournal(models.Model):
Skia's avatar
Skia committed
86
    """
87
    Class storing all the operations for a period of time
Skia's avatar
Skia committed
88
89
90
91
92
    """
    start_date = models.DateField(_('start date'))
    end_date = models.DateField(_('end date'), null=True, blank=True, default=None)
    name = models.CharField(_('name'), max_length=30)
    closed = models.BooleanField(_('is closed'), default=False)
93
    club_account = models.ForeignKey(ClubAccount, related_name="journals", null=False)
94
    amount = CurrencyField(_('amount'), default=0)
Skia's avatar
Skia committed
95
    effective_amount = CurrencyField(_('effective_amount'), default=0)
96

Skia's avatar
Skia committed
97
98
99
100
101
102
103
104
105
106
    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
        if self.club_account.can_be_edited_by(user):
            return True
        return False

Skia's avatar
Skia committed
107
108
109
    def get_absolute_url(self):
        return reverse('accounting:journal_details', kwargs={'j_id': self.id})

Skia's avatar
Skia committed
110
111
112
    def __str__(self):
        return self.name

Skia's avatar
Skia committed
113
114
115
116
    def update_amounts(self):
        self.amount = 0
        self.effective_amount = 0
        for o in self.operations.all():
Skia's avatar
Skia committed
117
            if o.accounting_type.movement_type == "credit":
Skia's avatar
Skia committed
118
119
120
121
122
123
124
125
                if o.done:
                    self.effective_amount += o.amount
                self.amount += o.amount
            else:
                if o.done:
                    self.effective_amount -= o.amount
                self.amount -= o.amount
        self.save()
Skia's avatar
Skia committed
126

Skia's avatar
Skia committed
127
class Operation(models.Model):
128
129
    """
    An operation is a line in the journal, a debit or a credit
Skia's avatar
Skia committed
130
    """
Skia's avatar
Skia committed
131
    journal = models.ForeignKey(GeneralJournal, related_name="operations", null=False)
132
    amount = CurrencyField(_('amount'))
133
    date = models.DateField(_('date'))
Skia's avatar
Skia committed
134
    label = models.CharField(_('label'), max_length=50)
135
136
    remark = models.TextField(_('remark'), max_length=255)
    mode = models.CharField(_('payment method'), max_length=255, choices=settings.SITH_ACCOUNTING_PAYMENT_METHOD)
Skia's avatar
Skia committed
137
    cheque_number = models.IntegerField(_('cheque number'), default=-1)
138
139
    invoice = models.FileField(upload_to='invoices', null=True, blank=True)
    done = models.BooleanField(_('is done'), default=False)
Skia's avatar
Skia committed
140
141
142
143
144
    accounting_type = models.ForeignKey('AccountingType', related_name="operations")

    def save(self):
        super(Operation, self).save()
        self.journal.update_amounts()
Skia's avatar
Skia committed
145

Skia's avatar
Skia committed
146
147
148
149
150
151
    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
Skia's avatar
Skia committed
152
153
        if self.journal.closed:
            return False
154
        m = self.journal.club_account.club.get_membership_for(user)
Skia's avatar
Skia committed
155
156
157
158
159
160
161
162
        if m is not None and m.role >= 7:
            return True
        return False

    def can_be_edited_by(self, user):
        """
        Method to see if that object can be edited by the given user
        """
Skia's avatar
Skia committed
163
        if self.is_owned_by(user):
Skia's avatar
Skia committed
164
165
166
            return True
        return False

Skia's avatar
Skia committed
167
168
169
    def get_absolute_url(self):
        return reverse('accounting:journal_details', kwargs={'j_id': self.journal.id})

Skia's avatar
Skia committed
170
    def __str__(self):
171
172
        return "%d € | %s | %s | %s" % (
                self.amount, self.date, self.accounting_type, self.done,
Skia's avatar
Skia committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
                )

class AccountingType(models.Model):
    """
    Class describing the accounting types.

    Thoses are numbers used in accounting to classify operations
    """
    code = models.CharField(_('code'), max_length=16) # TODO: add number validator
    label = models.CharField(_('label'), max_length=60)
    movement_type = models.CharField(_('movement type'), choices=[('credit', 'Credit'), ('debit', 'Debit'), ('neutral', 'Neutral')], max_length=12)

    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 get_absolute_url(self):
        return reverse('accounting:type_list')

    def __str__(self):
        return self.movement_type+" - "+self.code+" - "+self.label
Skia's avatar
Skia committed
198