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
15 from formencode import validators, Schema
16 from formencode.foreach import ForEach
17 from formencode.variabledecode import NestedVariables
19 from mailer import Message
21 log = logging.getLogger(__name__)
24 class ShareSchema(Schema):
25 "Validate individual user shares."
26 allow_extra_fields = False
27 user_id = validators.Int(not_empty=True)
28 amount = validators.Number(not_empty=True)
31 class ExpenditureSchema(Schema):
32 "Validate an expenditure."
33 allow_extra_fields = False
34 pre_validators = [NestedVariables()]
35 spender_id = validators.Int(not_empty=True)
36 amount = model.types.CurrencyValidator(not_empty=True)
37 description = validators.UnicodeString()
38 date = validators.DateConverter()
39 shares = ForEach(ShareSchema)
42 class SpendController(BaseController):
46 def edit(self, id=None):
47 c.users = meta.Session.query(model.User.id, model.User)
49 c.title = 'Add a New Expenditure'
50 c.expenditure = model.Expenditure()
51 c.expenditure.spender_id = request.environ['user'].id
53 num_residents = meta.Session.query(model.User).\
54 filter_by(resident=True).count()
55 # Pre-populate split percentages for an even split.
57 for ii, user_row in enumerate(c.users):
58 user_id, user = user_row
60 val = Decimal(100) / Decimal(num_residents)
63 c.values['shares-%d.amount' % ii] = val
65 c.title = 'Edit an Expenditure'
66 c.expenditure = meta.Session.query(model.Expenditure).get(id)
67 return render('/spend/index.mako')
69 @validate(schema=ExpenditureSchema(), form='edit', variable_decode=True)
70 def update(self, id=None):
71 # Either create a new object, or, if we're editing, get the
74 e = model.Expenditure()
78 e = meta.Session.query(model.Expenditure).get(id)
81 # Set the fields that were submitted
82 shares = self.form_result.pop('shares')
83 update_sar(e, self.form_result)
87 users = dict(meta.Session.query(model.User.id, model.User).all())
89 for share_params in shares:
90 user = users[share_params['user_id']]
91 split_dict[user] = Decimal(share_params['amount'])
96 show = ("Expenditure of %s paid for by %s %s." %
97 (e.amount, e.spender, op))
100 # Send email notification to involved users if they have an email set.
101 involved_users = set(sp.user for sp in e.splits if sp.share != 0)
102 involved_users.add(e.spender)
103 body = render('/emails/expenditure.txt',
104 extra_vars={'expenditure': e,
106 g.handle_notification(involved_users, show, body)
108 return h.redirect_to('/')