source: remit/finance_core/models.py @ 9102ac9

client
Last change on this file since 9102ac9 was 82211ea, checked in by Alex Dehnert <adehnert@…>, 15 years ago

Keep track of some more dates (Trac: #19)

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