source: treasury/finance_core/models.py @ 064683a

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

Store account numbers

  • Property mode set to 100644
File size: 5.6 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        root = BudgetArea.objects.get(name=path[0], depth=1)
56        node = root
57        for name in path[1:]:
58            node = node.get_children().filter(name=name)[0]
59        return node
60
61    def dump_to_html(self):
62        struct = self.dump_bulk()
63        return self.struct_to_html(struct, depth=0)
64
65    def struct_to_html(self, struct, depth=0):
66        def format_data(data):
67            return "<em>"+data['name']+"</em> "+unicode(data)
68        prefix = "\t"*depth
69        html = prefix+"<ul>\n"
70        html = html + "\n".join(
71            [("%(prefix)s\t<li>%(data)s\n%(children)s\t%(prefix)s</li>\n" % {
72                'prefix':prefix,
73                'data':format_data(elem['data']),
74                'children':('children' in elem and self.struct_to_html(elem['children'], depth+1) or '')
75            }) for elem in struct])
76        html = html + prefix + "</ul>\n"
77        return html
78
79    def indented_name(self, strip_levels=0):
80        return self.indent_str*(self.depth-strip_levels) + unicode(self)
81
82    def __unicode__(self,):
83        return u"%s [%s] (%s)" % (self.name, self.contact_address(), self.always, )
84
85
86class BudgetTerm(models.Model):
87    name = models.CharField(max_length=20)
88    slug = models.SlugField(max_length=20)
89    start_date = models.DateField()
90    end_date = models.DateField()
91    submit_deadline = models.DateField()
92
93    def __unicode__(self,):
94        return "%s (%s to %s [due %s])" % (self.name, self.start_date, self.end_date, self.submit_deadline, )
95
96
97class BudgetAreaTerm(models.Model):
98    budget_area = models.ForeignKey(BudgetArea)
99    budget_term = models.ForeignKey(BudgetTerm)
100    comment = models.TextField(blank=True, )
101
102    def __unicode__(self,):
103        return "%s during %s" % (self.budget_area, self.budget_term, )
104
105
106class Transaction(models.Model):
107    name = models.CharField(max_length=40)
108    desc = models.TextField(blank=True)
109
110    def __unicode__(self,):
111        return self.name
112
113def make_transfer(name, amount,
114    layer, budget_term, from_area, to_area, desc, ):
115    tx = Transaction(
116        name=name,
117        desc=desc,
118    )
119    tx.save()
120
121    from_li = LineItem(
122        label='Send: %s' % (name, ),
123        amount=-amount,
124        budget_area=from_area,
125        budget_term=budget_term,
126        layer=layer,
127        tx=tx,
128    )
129    from_li.save()
130
131    to_li = LineItem(
132        label='Receive: %s' % (name, ),
133        amount=amount,
134        budget_area=to_area,
135        budget_term=budget_term,
136        layer=layer,
137        tx=tx,
138    )
139    to_li.save()
140
141    return tx
142
143
144class LineItem(models.Model):
145    tx = models.ForeignKey(Transaction)
146    amount = models.DecimalField(max_digits=7, decimal_places=2, help_text='Do not include "$"')
147    label = models.CharField(max_length=40)
148    budget_area = models.ForeignKey(BudgetArea)
149    budget_term = models.ForeignKey(BudgetTerm)
150    layer = models.IntegerField() # this might actually be a Transaction property...
151
152    def layer_string(self,):
153        layer = self.layer
154        return layer_name(get_layer_by_num(layer))
155
156    def __unicode__(self, ):
157        return "%s: %s: $%s (%s) in %s during %s" % (
158            self.tx, self.label, self.amount, self.layer,
159            self.budget_area, self.budget_term, )
160
161
162layers=(
163    (10, 'budget'),
164    (20, 'allocation'),
165    (30, 'expenditure'),
166    (40, 'closeout'),
167)
168def get_layer_by_name(name):
169    for layer in layers:
170        if name == layer[1]:
171            return layer
172    raise KeyError, "layer %s not found" % (name, )
173def get_layer_by_num(num):
174    for layer in layers:
175        if num == layer[0]:
176            return layer
177    raise KeyError, "layer %d not found" % (num, )
178def layer_name(layer): return layer[1]
179def layer_num(layer):  return layer[0]
180
181
182def coerce_full_email(email):
183    if '@' in email: return email
184    else: return email + '@' + settings.DEFAULT_DOMAIN
Note: See TracBrowser for help on using the repository browser.