source: remit/finance_core/models.py @ ce973f1

client
Last change on this file since ce973f1 was 485673a, checked in by Alex Dehnert <adehnert@…>, 15 years ago

Add list page

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