Changeset ad530b4
- Timestamp:
- Aug 26, 2010, 10:55:42 PM (15 years ago)
- Branches:
- master, client
- Children:
- 5cfd6f6
- Parents:
- 0df317c (diff), af48a00 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent. - git-author:
- Alex Dehnert <adehnert@…> (08/26/10 22:55:42)
- git-committer:
- Alex Dehnert <adehnert@…> (08/26/10 22:55:42)
- Location:
- remit
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
remit/media/style/style.css
re1086bd raf48a00 96 96 font-family: "Courier", monospace; 97 97 } 98 99 .select-modifiers li 100 { 101 display: inline; 102 } 103 .select-modifiers li a 104 { 105 border: 1px solid black; 106 padding: 0.25em; 107 } -
remit/remit_templates/base.html
r0671644 r5865e5f 7 7 <link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}style/style.css" /> 8 8 <link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}style/default.css" /> 9 <script type="text/javascript" 10 src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 11 9 12 10 13 </head> -
remit/remit_templates/vouchers/reimbursementrequest_list.html
r33cb144 raf48a00 13 13 {%endif%} 14 14 15 <form> 15 <form method='get' action=''> 16 <h3>Filter and Sort</h3> 17 16 18 <table class='pretty-table'> 17 19 <tr> … … 33 35 </tr> 34 36 <tr> 35 <th colspan='2'><input type='submit' name='submit' value='Submit' ></th>37 <th colspan='2'><input type='submit' name='submit' value='Submit' /></th> 36 38 </tr> 37 39 </table> … … 40 42 <p><br /></p> 41 43 42 <table class='pretty-table'> 44 <form method='post' action=''> 45 <h3>Request List</h3> 46 47 <table class='pretty-table' id='request-list'> 43 48 <tr> 44 49 <th>#</th> … … 49 54 <th>Approval state (date)</th> 50 55 </tr> 51 52 56 {% for object in object_list %} 53 57 <tr> 54 <td><a href='{% url review_request object.pk %}'>{{ object.pk }}</a></td> 58 <td> 59 <input type='checkbox' name='select' value='{{object.pk}}'{%ifin object.pk selected_ids %} checked='checked'{%endifin%}></input> 60 <a href='{% url review_request object.pk %}'>{{ object.pk }}</a> 61 </td> 55 62 <td> 56 63 <a href='{% url review_request object.pk %}'>{{ object.name }}</a> … … 77 84 </table> 78 85 86 <ul class='select-modifiers'> 87 <li><a id='select-all' href='#'>Select All</a></li> 88 <li><a id='select-none' href='#'>Select None</a></li> 89 <li><a id='select-other' href='#'>Invert Selection</a></li> 90 </ul> 91 92 <script type='text/javascript'> 93 $('#select-all').click(function(){ 94 $('#request-list input:checkbox').attr('checked', 'checked'); 95 return false; 96 }); 97 $('#select-none').click(function(){ 98 $('#request-list input:checkbox').removeAttr('checked'); 99 return false; 100 }); 101 $('#select-other').click(function(){ 102 $('#request-list input:checkbox').each(function(){ 103 this.checked = !this.checked; 104 }); 105 return false; 106 }); 107 </script> 108 109 <h3>Bulk Actions</h3> 110 111 <p> 112 <select name='action'> 113 <option value="none" selected="selected">-----------</option> 114 {% for action in actions %} 115 <option value='{{action.name}}'>{{action.label}}</option> 116 {%endfor%} 117 </select> 118 <input type='submit' name='apply-action' value='Apply' /> 119 </p> 120 121 {%if action_message%} 122 <p>{{action_message}}</p> 123 {% if action_errors %} 124 <p>Errors:</p> 125 <table class='pretty-table'> 126 <tr> 127 <th>ID</th> 128 <th>Message</th> 129 {% for err in action_errors %} 130 <tr><th>{{err.0.pk}}</th><td>{{err.1}}</td></tr> 131 {%endfor%} 132 </ul> 133 {%endif%} 134 {%endif%} 135 </form> 136 79 137 {% endblock %} -
remit/util/templatetags/misc.py
re1086bd rdd6edfb 1 1 from django import template 2 from django.template import Node, NodeList, Template, Context, Variable 2 3 import finance_core.models 3 4 … … 30 31 else: return 'zero' 31 32 33 class IfInNode(Node): 34 def __init__(self, member, container, nodelist_true, nodelist_false, negate): 35 self.member, self.container = member, container 36 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false 37 self.negate = negate 38 39 def __repr__(self): 40 return "<IfInNode>" 41 42 def render(self, context): 43 member_val = self.member.resolve(context, True) 44 container_val = self.container.resolve(context, True) 45 res = member_val in container_val 46 if (self.negate and not res) or (not self.negate and res): 47 return self.nodelist_true.render(context) 48 return self.nodelist_false.render(context) 49 50 def do_ifin(parser, token, negate): 51 bits = list(token.split_contents()) 52 if len(bits) != 3: 53 raise TemplateSyntaxError, "%r takes two arguments" % bits[0] 54 end_tag = 'end' + bits[0] 55 nodelist_true = parser.parse(('else', end_tag)) 56 token = parser.next_token() 57 if token.contents == 'else': 58 nodelist_false = parser.parse((end_tag,)) 59 parser.delete_first_token() 60 else: 61 nodelist_false = NodeList() 62 member = parser.compile_filter(bits[1]) 63 container = parser.compile_filter(bits[2]) 64 return IfInNode(member, container, nodelist_true, nodelist_false, negate) 65 register.tag("ifin", lambda x, y: do_ifin(x, y, False)) 66 67 32 68 register.filter('layer_num', finance_core.models.layer_num) 33 69 register.filter('layer_name', finance_core.models.layer_name) -
remit/vouchers/models.py
rf52f909 r3e372da 3 3 import finance_core 4 4 from finance_core.models import BudgetArea, BudgetTerm 5 6 from django.core.mail import send_mail, mail_admins 7 from django.template import Context, Template 8 from django.template.loader import get_template 5 9 6 10 import datetime … … 52 56 ) 53 57 54 def convert(self, signatory, signatory_email=settings.SIGNATORY_EMAIL): 58 def convert(self, signatory, signatory_email=None): 59 if signatory_email is None: 60 signatory_email = settings.SIGNATORY_EMAIL 55 61 voucher = Voucher() 56 62 voucher.group_name = settings.GROUP_NAME … … 82 88 self.save() 83 89 90 def approve(self, approver, signatory_name, signatory_email=None, ): 91 """Mark a request as approved. 92 93 approver: user object of the approving user 94 signatory_name: name of signatory 95 signatory_email: email address of signatory (provide None for default) 96 """ 97 voucher = self.convert(signatory_name, signatory_email,) 98 tmpl = get_template('vouchers/emails/request_approval_admin.txt') 99 ctx = Context({ 100 'approver': approver, 101 'request': self, 102 }) 103 body = tmpl.render(ctx) 104 mail_admins( 105 'Request approval: %s approved $%s' % ( 106 approver, 107 self.amount, 108 ), 109 body, 110 ) 111 84 112 def label(self, ): 85 113 return settings.GROUP_ABBR + unicode(self.pk) + 'RR' … … 222 250 ), 223 251 } 252 253 class BulkRequestAction: 254 def __init__(self, name, label, action, perm_predicate=None, ): 255 self.name = name 256 self.label = label 257 self.action = action 258 if perm_predicate is None: 259 perm_predicate = lambda user: True 260 elif perm_predicate == True: 261 perm_predicate = lambda user: True 262 self.perm_predicate = perm_predicate 263 def can(self, user): 264 return self.perm_predicate(user) 265 def do(self, http_request, rr, ): 266 if self.can(http_request.user): 267 return self.action(http_request, rr, ) 268 else: 269 return False, "permission denied" 270 def __str__(self): 271 return self.label 272 @classmethod 273 def filter_can_only(cls, actions, user): 274 return [ action for action in actions if action.can(user) ] 275 def bulk_action_approve(http_request, rr): 276 approver = http_request.user 277 signatory_name = http_request.user.get_full_name() 278 if rr.voucher: 279 return False, "already approved" 280 else: 281 rr.approve(approver, signatory_name) 282 return True, "request approved" 283 284 def bulk_action_email_factory(stock_email_obj): 285 assert stock_email_obj.context == 'request' 286 def inner(http_request, rr): 287 stock_email_obj.send_email_request(rr) 288 return True, "mail sent" 289 return inner 290 def perm_checker(perm): 291 def predicate(user): 292 return user.has_perm(perm) 293 return predicate 294 295 bulk_request_actions = [] 296 if settings.SIGNATORY_EMAIL: 297 bulk_request_actions.append(BulkRequestAction( 298 name='approve', 299 label='Approve Requests', 300 action=bulk_action_approve, 301 perm_predicate=perm_checker('vouchers.can_approve'), 302 )) 303 for name, stockemail in stock_emails.items(): 304 if stockemail.context == 'request': 305 bulk_request_actions.append(BulkRequestAction( 306 name='email/%s' % name, 307 label='Stock Email: %s' % stockemail.label, 308 action=bulk_action_email_factory(stockemail), 309 perm_predicate=perm_checker('vouchers.can_email'), 310 )) -
remit/vouchers/views.py
r71ca9e6 r3e372da 257 257 approve_form = VoucherizeForm(http_request.POST) 258 258 if approve_form.is_valid(): 259 voucher = request_obj.convert( 260 approve_form.cleaned_data['name'], 261 signatory_email=approve_form.cleaned_data['email'],) 262 tmpl = get_template('vouchers/emails/request_approval_admin.txt') 263 ctx = Context({ 264 'approver': http_request.user, 265 'request': request_obj, 266 }) 267 body = tmpl.render(ctx) 268 mail_admins( 269 'Request approval: %s approved $%s' % ( 270 http_request.user, 271 request_obj.amount, 272 ), 273 body, 259 request_obj.approve( 260 approver=http_request.user, 261 signatory_name=approve_form.cleaned_data['name'], 262 signatory_email=approve_form.cleaned_data['email'], 274 263 ) 275 264 approve_message = 'Created new voucher from request' … … 365 354 ) 366 355 356 def list_to_keys(lst): 357 dct = {} 358 for key in lst: 359 dct[key] = True 360 return dct 361 367 362 @login_required 368 def show_requests(request, ): 369 if request.user.has_perm('vouchers.can_list'): 363 def show_requests(http_request, ): 364 # BULK ACTIONS 365 actions = vouchers.models.BulkRequestAction.filter_can_only( 366 vouchers.models.bulk_request_actions, 367 http_request.user, 368 ) 369 apply_action_message = None 370 apply_action_errors = [] 371 if 'select' in http_request.REQUEST: 372 selected_rr_ids = [ int(item) for item in http_request.REQUEST.getlist('select') ] 373 else: 374 selected_rr_ids = [] 375 if "apply-action" in http_request.POST: 376 action_name = http_request.POST['action'] 377 if action_name == 'none': 378 apply_action_message = "No action selected." 379 else: 380 matching_actions = [ action for action in actions if action.name == action_name] 381 if(len(matching_actions) > 0): 382 action = matching_actions[0] 383 rrs = ReimbursementRequest.objects.filter(pk__in=selected_rr_ids) 384 for rr in rrs: 385 success, msg = action.do(http_request, rr) 386 if not success: 387 apply_action_errors.append((rr, msg)) 388 apply_action_message = '"%s" applied to %d request(s) (%d errors encountered)' % (action.label, len(rrs), len(apply_action_errors), ) 389 else: 390 apply_action_message = "Unknown or forbidden action requested." 391 392 # PERMISSION-BASED REQUEST FILTERING 393 if http_request.user.has_perm('vouchers.can_list'): 370 394 qs = ReimbursementRequest.objects.all() 371 395 useronly = False 372 396 else: 373 qs = ReimbursementRequest.objects.filter(get_related_requests_qobj( request.user))397 qs = ReimbursementRequest.objects.filter(get_related_requests_qobj(http_request.user)) 374 398 useronly = True 375 399 376 if 'order' in request.REQUEST: 377 order_row = [row for row in request_list_orders if row[0] == request.REQUEST['order']] 400 # SORTING 401 if 'order' in http_request.REQUEST: 402 order_row = [row for row in request_list_orders if row[0] == http_request.REQUEST['order']] 378 403 if order_row: 379 404 order, label, cols = order_row[0] … … 384 409 order = 'default' 385 410 386 if 'approval_status' in request.REQUEST: 387 approval_status = request.REQUEST['approval_status'] 411 # DISCRETIONARY REQUEST FILTERING 412 if 'approval_status' in http_request.REQUEST: 413 approval_status = http_request.REQUEST['approval_status'] 388 414 else: 389 415 approval_status = vouchers.models.APPROVAL_STATE_PENDING … … 401 427 raise Http404('approval_status not known') 402 428 429 # GENERATE THE REQUEST 403 430 return list_detail.object_list( 404 request,431 http_request, 405 432 queryset=qs, 406 433 extra_context={ 434 'actions' : actions, 435 'selected_ids' : list_to_keys(selected_rr_ids), 436 'action_message': apply_action_message, 437 'action_errors' : apply_action_errors, 407 438 'useronly': useronly, 408 439 'order' : order, -
remit/util/add_gl_accounts.py
r8132e8c r0df317c 1 #!/usr/bin/python 2 1 3 import sys 2 4 import os … … 25 27 ('Food.Meetings', 421000), 26 28 ('Food.Events', 421200), 27 ('Computer Supplies', 421900), 29 ('IT', None), 30 ('IT.Computer Supplies', 421900), 31 ('IT.On-line Services', 421920), 32 ('Promotional & Memorabilia', 420302), 28 33 ) 29 34
Note: See TracChangeset
for help on using the changeset viewer.