source: remit/finance_core/models.py @ 36d2293

client
Last change on this file since 36d2293 was dfcab53, checked in by Alex Dehnert <adehnert@…>, 14 years ago

Use the finance_core.use_reporting permission

  • Property mode set to 100644
File size: 6.5 KB
Line 
1from django.db import models, connection
2import settings
3import treebeard.mp_tree
4
5
6class BudgetArea(treebeard.mp_tree.MP_Node):
7    indent_str = u"\u00A0\u00A0"
8
9    name = models.CharField(max_length=50)
10    comment = models.TextField(blank=True)
11
12    # Applicable to every term?
13    always = models.BooleanField(blank=True, default=False)
14    budget_term = models.ManyToManyField('BudgetTerm', through='BudgetAreaTerm')
15
16    # Contact / ACL information
17    # If not specified, inherit from parent
18    owner = models.EmailField(help_text = 'Email address of the officer responsible for the area', blank=True) # owner of the budget area
19    interested = models.EmailField(help_text='Email address of parties interested in the area', blank=True) # interested parties (ie, whole committee)
20    use_owner = models.BooleanField(default=False, blank=True)
21    account_number = models.IntegerField(help_text='Account number: for example, cost object or GL', blank=True, null=True)
22
23    def contact_address(self,):
24        address = ''
25        if self.use_owner:
26            address = self.owner or self.interested
27        else:
28            address = self.interested or self.owner
29
30    def owner_address(self,):
31        address = self.owner
32        return address or self.get_parent().owner_address()
33
34    def get_account_number(self):
35        """Retrieve the account number for this account.
36
37        This properly recurses through the hierarchy until reaching the root
38        or an account with the account number set."""
39
40        print self.account_number
41        if self.account_number:
42            return self.account_number
43        else:
44            parent = self.get_parent()
45            if parent:
46                return parent.get_account_number()
47            else:
48                return 0
49
50    def mark_used(self, term, comment=""):
51        BudgetAreaTerm.objects.get_or_create(
52            budget_area=self,
53            budget_term=term,
54            defaults={'comment':comment}
55        )
56
57    @classmethod
58    def get_by_path(cls, path):
59        try:
60            root = BudgetArea.objects.get(name=path[0], depth=1)
61        except IndexError, e:
62            raise KeyError(e)
63        node = root
64        for name in path[1:]:
65            try:
66                node = node.get_children().filter(name=name)[0]
67            except IndexError, e:
68                raise KeyError(e)
69        return node
70
71    @classmethod
72    def get_by_pathstr(cls, path):
73        path = path.split('.')
74        return cls.get_by_path(path)
75
76    def pathstr(self, skip=0):
77        if self.depth-1 > skip:
78            parent = self.get_parent()
79            prefix = parent.pathstr(skip=skip) + '.'
80        else:
81            prefix = ''
82        return prefix + self.name
83
84    def dump_to_html(self):
85        struct = self.dump_bulk()
86        return self.struct_to_html(struct, depth=0)
87
88    def struct_to_html(self, struct, depth=0):
89        def format_data(data):
90            return "<em>"+data['name']+"</em> "+unicode(data)
91        prefix = "\t"*depth
92        html = prefix+"<ul>\n"
93        html = html + "\n".join(
94            [("%(prefix)s\t<li>%(data)s\n%(children)s\t%(prefix)s</li>\n" % {
95                'prefix':prefix,
96                'data':format_data(elem['data']),
97                'children':('children' in elem and self.struct_to_html(elem['children'], depth+1) or '')
98            }) for elem in struct])
99        html = html + prefix + "</ul>\n"
100        return html
101
102    def indented_name(self, strip_levels=0):
103        return self.indent_str*(self.depth-strip_levels) + unicode(self)
104
105    def __unicode__(self,):
106        return u"%s [%s] (%s)" % (self.name, self.contact_address(), self.always, )
107
108    class Meta:
109        permissions = (
110            ('use_reporting', 'Can use basic reporting functionality',),
111        )
112
113
114class BudgetTerm(models.Model):
115    name = models.CharField(max_length=20)
116    slug = models.SlugField(max_length=20)
117    start_date = models.DateField()
118    end_date = models.DateField()
119    submit_deadline = models.DateField()
120
121    def __unicode__(self,):
122        return "%s (%s to %s [due %s])" % (self.name, self.start_date, self.end_date, self.submit_deadline, )
123
124
125class BudgetAreaTerm(models.Model):
126    budget_area = models.ForeignKey(BudgetArea)
127    budget_term = models.ForeignKey(BudgetTerm)
128    comment = models.TextField(blank=True, )
129
130    def __unicode__(self,):
131        return "%s during %s" % (self.budget_area, self.budget_term, )
132
133
134class Transaction(models.Model):
135    name = models.CharField(max_length=40)
136    desc = models.TextField(blank=True)
137
138    def __unicode__(self,):
139        return self.name
140
141def make_transfer(name, amount,
142    layer, budget_term, from_area, to_area, desc, ):
143    tx = Transaction(
144        name=name,
145        desc=desc,
146    )
147    tx.save()
148
149    from_li = LineItem(
150        label='Send: %s' % (name, ),
151        amount=-amount,
152        budget_area=from_area,
153        budget_term=budget_term,
154        layer=layer,
155        tx=tx,
156    )
157    from_li.save()
158
159    to_li = LineItem(
160        label='Receive: %s' % (name, ),
161        amount=amount,
162        budget_area=to_area,
163        budget_term=budget_term,
164        layer=layer,
165        tx=tx,
166    )
167    to_li.save()
168
169    return tx
170
171
172class LineItem(models.Model):
173    tx = models.ForeignKey(Transaction)
174    amount = models.DecimalField(max_digits=7, decimal_places=2, help_text='Do not include "$"')
175    label = models.CharField(max_length=60)
176    budget_area = models.ForeignKey(BudgetArea)
177    budget_term = models.ForeignKey(BudgetTerm)
178    layer = models.IntegerField() # this might actually be a Transaction property...
179
180    def layer_string(self,):
181        layer = self.layer
182        return layer_name(get_layer_by_num(layer))
183
184    def __unicode__(self, ):
185        return "%s: %s: $%s (%s) in %s during %s" % (
186            self.tx, self.label, self.amount, self.layer,
187            self.budget_area, self.budget_term, )
188
189
190LAYER_BUDGET      = 10
191LAYER_ALLOCATION  = 20
192LAYER_EXPENDITURE = 30
193LAYER_CLOSEOUT    = 40
194layers=(
195    (LAYER_BUDGET,      'budget'),
196    (LAYER_ALLOCATION,  'allocation'),
197    (LAYER_EXPENDITURE, 'expenditure'),
198    (LAYER_CLOSEOUT,    'closeout'),
199)
200def get_layer_by_name(name):
201    for layer in layers:
202        if name == layer[1]:
203            return layer
204    raise KeyError, "layer %s not found" % (name, )
205def get_layer_by_num(num):
206    for layer in layers:
207        if num == layer[0]:
208            return layer
209    raise KeyError, "layer %d not found" % (num, )
210def layer_name(layer): return layer[1]
211def layer_num(layer):  return layer[0]
212
213
214def coerce_full_email(email):
215    if '@' in email: return email
216    else: return email + '@' + settings.DEFAULT_DOMAIN
Note: See TracBrowser for help on using the repository browser.