7 from decimal import Decimal, InvalidOperation
9 from bluechips.lib.base import *
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
16 from formencode import validators, Schema
17 from formencode.foreach import ForEach
18 from formencode.variabledecode import NestedVariables
20 from mailer import Message
22 log = logging.getLogger(__name__)
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)
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)
43 class SpendController(BaseController):
47 def edit(self, id=None):
48 c.users = meta.Session.query(model.User.id, model.User)
50 c.title = 'Add a New Expenditure'
51 c.expenditure = model.Expenditure()
52 c.expenditure.spender_id = request.environ['user'].id
54 num_residents = meta.Session.query(model.User).\
55 filter_by(resident=True).count()
56 # Pre-populate split percentages for an even split.
58 for ii, user_row in enumerate(c.users):
59 user_id, user = user_row
61 val = Decimal(100) / Decimal(num_residents)
64 c.values['shares-%d.amount' % ii] = val
66 c.title = 'Edit an Expenditure'
67 c.expenditure = meta.Session.query(model.Expenditure).get(id)
68 if c.expenditure is None:
71 for ii, user_row in enumerate(c.users):
72 user_id, user = user_row
74 share = [s.share for s in c.expenditure.splits
76 if c.expenditure.amount == 0:
79 percent = (Decimal(100) * Decimal(int(share)) /
80 Decimal(int(c.expenditure.amount))).\
81 quantize(Decimal("0.001"))
84 c.values['shares-%d.amount' % ii] = percent
86 return render('/spend/index.mako')
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
93 e = model.Expenditure()
97 e = meta.Session.query(model.Expenditure).get(id)
102 # Set the fields that were submitted
103 shares = self.form_result.pop('shares')
104 update_sar(e, self.form_result)
106 users = dict(meta.Session.query(model.User.id, model.User).all())
108 for share_params in shares:
109 user = users[share_params['user_id']]
110 split_dict[user] = Decimal(str(share_params['amount']))
113 meta.Session.commit()
115 show = ("Expenditure of %s paid for by %s %s." %
116 (e.amount, e.spender, op))
119 # Send email notification to involved users if they have an email set.
120 involved_users = set(sp.user for sp in e.splits if sp.share != 0)
121 involved_users.add(e.spender)
122 body = render('/emails/expenditure.txt',
123 extra_vars={'expenditure': e,
125 g.handle_notification(involved_users, show, body)
127 return h.redirect_to('/')