source: remit/finance_core/models.py @ 3f1e074

client
Last change on this file since 3f1e074 was 0e58ad0, checked in by Alex Dehnert <adehnert@…>, 15 years ago

Send email on submitted requests

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