]> asedeno.scripts.mit.edu Git - bluechips.git/blob - bluechips/controllers/spend.py
fix error with zero-value expenditure
[bluechips.git] / bluechips / controllers / spend.py
1 """
2 Handle expenditures
3 """
4
5 import logging
6
7 from decimal import Decimal, InvalidOperation
8
9 from bluechips.lib.base import *
10
11 from pylons import request, app_globals as g
12 from pylons.decorators.rest import dispatch_on
13 from pylons.decorators import validate
14 from pylons.controllers.util import abort
15
16 from formencode import validators, Schema
17 from formencode.foreach import ForEach
18 from formencode.variabledecode import NestedVariables
19
20 from mailer import Message
21
22 log = logging.getLogger(__name__)
23
24
25 class ShareSchema(Schema):
26     "Validate individual user shares."
27     allow_extra_fields = False
28     user_id = validators.Int(not_empty=True)
29     amount = validators.Number(not_empty=True)
30
31
32 class ExpenditureSchema(Schema):
33     "Validate an expenditure."
34     allow_extra_fields = False
35     pre_validators = [NestedVariables()]
36     spender_id = validators.Int(not_empty=True)
37     amount = model.types.CurrencyValidator(not_empty=True)
38     description = validators.UnicodeString()
39     date = validators.DateConverter()
40     shares = ForEach(ShareSchema)
41     
42
43 class SpendController(BaseController):
44     def index(self):
45         return self.edit()
46     
47     def edit(self, id=None):
48         c.users = meta.Session.query(model.User.id, model.User)
49         if id is None:
50             c.title = 'Add a New Expenditure'
51             c.expenditure = model.Expenditure()
52             c.expenditure.spender_id = request.environ['user'].id
53
54             num_residents = meta.Session.query(model.User).\
55                     filter_by(resident=True).count()
56             # Pre-populate split percentages for an even split.
57             c.values = {}
58             for ii, user_row in enumerate(c.users):
59                 user_id, user = user_row
60                 if user.resident:
61                     val = Decimal(100) / Decimal(num_residents)
62                 else:
63                     val = 0
64                 c.values['shares-%d.amount' % ii] = val
65         else:
66             c.title = 'Edit an Expenditure'
67             c.expenditure = meta.Session.query(model.Expenditure).get(id)
68             if c.expenditure is None:
69                 abort(404)
70             c.values = {}
71             for ii, user_row in enumerate(c.users):
72                 user_id, user = user_row
73                 try:
74                     share = [s.share for s in c.expenditure.splits
75                              if s.user == user][0]
76                     if c.expenditure.amount == 0:
77                         percent = 0
78                     else:
79                         percent = (Decimal(100) * Decimal(int(share)) /
80                                    Decimal(int(c.expenditure.amount))).\
81                                 quantize(Decimal("0.001"))
82                 except IndexError:
83                     percent = 0
84                 c.values['shares-%d.amount' % ii] = percent
85
86         return render('/spend/index.mako')
87
88     @validate(schema=ExpenditureSchema(), form='edit', variable_decode=True)
89     def update(self, id=None):
90         # Either create a new object, or, if we're editing, get the
91         # old one
92         if id is None:
93             e = model.Expenditure()
94             meta.Session.add(e)
95             op = 'created'
96         else:
97             e = meta.Session.query(model.Expenditure).get(id)
98             if e is None:
99                 abort(404)
100             op = 'updated'
101         
102         # Set the fields that were submitted
103         shares = self.form_result.pop('shares')
104         update_sar(e, self.form_result)
105         if e.id is not None:
106             e.update_split()
107
108         users = dict(meta.Session.query(model.User.id, model.User).all())
109         split_dict = {}
110         for share_params in shares:
111             user = users[share_params['user_id']]
112             split_dict[user] = Decimal(str(share_params['amount']))
113         e.split(split_dict)
114         
115         meta.Session.commit()
116        
117         show = ("Expenditure of %s paid for by %s %s." %
118                 (e.amount, e.spender, op))
119         h.flash(show)
120
121         # Send email notification to involved users if they have an email set.
122         involved_users = set(sp.user for sp in e.splits if sp.share != 0)
123         involved_users.add(e.spender)
124         body = render('/emails/expenditure.txt',
125                       extra_vars={'expenditure': e,
126                                   'op': op})
127         g.handle_notification(involved_users, show, body)
128
129         return h.redirect_to('/')