source: remit/vouchers/views.py @ 37c15c4

client
Last change on this file since 37c15c4 was 37c15c4, checked in by Alex Dehnert <adehnert@…>, 15 years ago

Pull defaults from user object not certificate

In order to make Remit work better on a Django
test server or possibly with non-MIT group
members, pull data like name and email from the
user object instead of certificate, since as
of Trac #7 getting resolved we have that data.

Closes #11

  • Property mode set to 100644
File size: 10.8 KB
Line 
1import vouchers.models
2from vouchers.models import ReimbursementRequest
3from finance_core.models import BudgetTerm, BudgetArea
4
5from django.contrib.auth.decorators import user_passes_test
6from django.shortcuts import render_to_response, get_object_or_404
7from django.template import RequestContext
8from django.http import Http404, HttpResponseRedirect
9import django.forms
10from django.forms import Form
11from django.forms import ModelForm
12from django.forms import ModelChoiceField
13from django.core.urlresolvers import reverse
14from django.core.mail import send_mail, mail_admins
15from django.template import Context, Template
16from django.template.loader import get_template
17
18import settings
19
20class RequestForm(ModelForm):
21    class Meta:
22        model = ReimbursementRequest
23        fields = (
24            'name',
25            'description',
26            'amount',
27            'budget_area',
28            'expense_area',
29            'check_to_first_name',
30            'check_to_last_name',
31            'check_to_email',
32            'check_to_addr',
33        )
34
35class CommitteesField(ModelChoiceField):
36    def __init__(self, *args, **kargs):
37        base_area = BudgetArea.get_by_path(['Accounts', 'Assets', 'Budget', ])
38        self.strip_levels = base_area.depth
39        areas = (base_area.get_descendants()
40            .filter(depth__lte=base_area.depth+2)
41            .exclude(name='Holding')
42        )
43        ModelChoiceField.__init__(self, queryset=areas,
44            help_text='Select the appropriate committe or other budget area',
45            *args, **kargs)
46
47    def label_from_instance(self, obj,):
48        return obj.indented_name(strip_levels=self.strip_levels)
49
50class SelectRequestBasicsForm(Form):
51    area = CommitteesField()
52    term = ModelChoiceField(queryset = BudgetTerm.objects.all())
53
54@user_passes_test(lambda u: u.is_authenticated())
55def select_request_basics(http_request, ):
56    if http_request.method == 'POST': # If the form has been submitted...
57        form = SelectRequestBasicsForm(http_request.POST) # A form bound to the POST data
58        if form.is_valid(): # All validation rules pass
59            term = form.cleaned_data['term'].slug
60            area = form.cleaned_data['area'].id
61            return HttpResponseRedirect(reverse(submit_request, args=[term, area],)) # Redirect after POST
62    else:
63        form = SelectRequestBasicsForm() # An unbound form
64
65    context = {
66        'form':form,
67        'pagename':'request_reimbursement',
68    }
69    return render_to_response('vouchers/select.html', context, context_instance=RequestContext(http_request), )
70
71class CommitteeBudgetAreasField(ModelChoiceField):
72    def __init__(self, base_area, *args, **kargs):
73        self.strip_levels = base_area.depth
74        areas = base_area.get_descendants()
75        ModelChoiceField.__init__(self, queryset=areas,
76            help_text='In general, this should be a fully indented budget area, not one with children',
77            *args, **kargs)
78
79    def label_from_instance(self, obj,):
80        return obj.indented_name(strip_levels=self.strip_levels)
81
82class ExpenseAreasField(ModelChoiceField):
83    def __init__(self, *args, **kargs):
84        base_area = vouchers.models.BudgetArea.get_by_path(['Accounts', 'Expenses'])
85        self.strip_levels = base_area.depth
86        areas = base_area.get_descendants()
87        ModelChoiceField.__init__(self, queryset=areas,
88            help_text='In general, this should be a fully indented budget area, not one with children',
89            *args, **kargs)
90
91    def label_from_instance(self, obj,):
92        return obj.indented_name(strip_levels=self.strip_levels)
93
94@user_passes_test(lambda u: u.is_authenticated())
95def submit_request(http_request, term, committee):
96    term_obj = get_object_or_404(BudgetTerm, slug=term)
97    comm_obj = get_object_or_404(BudgetArea, pk=committee)
98
99    new_request = ReimbursementRequest()
100    new_request.submitter = http_request.user.username
101    new_request.budget_term = term_obj
102
103    # Prefill from user information (itself prefilled from LDAP now)
104    initial = {}
105    initial['check_to_first_name'] = http_request.user.first_name
106    initial['check_to_last_name']  = http_request.user.last_name
107    initial['check_to_email']      = http_request.user.email
108
109    if http_request.method == 'POST': # If the form has been submitted...
110        form = RequestForm(http_request.POST, instance=new_request) # A form bound to the POST data
111        form.fields['budget_area'] = CommitteeBudgetAreasField(comm_obj)
112        form.fields['expense_area'] = ExpenseAreasField()
113        if form.is_valid(): # All validation rules pass
114            request_obj = form.save()
115
116            # Send email
117            tmpl = get_template('vouchers/emails/request_submit_admin.txt')
118            ctx = Context({
119                'submitter': http_request.user,
120                'request': request_obj,
121            })
122            body = tmpl.render(ctx)
123            recipients = []
124            for name, addr in settings.ADMINS:
125                recipients.append(addr)
126            recipients.append(request_obj.budget_area.owner_address())
127            send_mail(
128                '%sRequest submittal: %s requested $%s' % (
129                    settings.EMAIL_SUBJECT_PREFIX,
130                    http_request.user,
131                    request_obj.amount,
132                ),
133                body,
134                settings.SERVER_EMAIL,
135                recipients,
136            )
137
138            return HttpResponseRedirect(reverse(review_request, args=[new_request.pk],) + '?new=true') # Redirect after POST
139    else:
140        form = RequestForm(instance=new_request, initial=initial, ) # An unbound form
141        form.fields['budget_area'] = CommitteeBudgetAreasField(comm_obj)
142        form.fields['expense_area'] = ExpenseAreasField()
143
144    context = {
145        'term':term_obj,
146        'comm':comm_obj,
147        'form':form,
148        'pagename':'request_reimbursement',
149    }
150    return render_to_response('vouchers/submit.html', context, context_instance=RequestContext(http_request), )
151
152class VoucherizeForm(Form):
153    name = django.forms.CharField(max_length=100, help_text='Signatory name for voucher',)
154    email = django.forms.EmailField(max_length=100, help_text='Signatory email for voucher')
155
156
157@user_passes_test(lambda u: u.is_authenticated())
158def review_request(http_request, object_id):
159    request_obj = get_object_or_404(ReimbursementRequest, pk=object_id)
160    new = False
161    if 'new' in http_request.REQUEST:
162        if http_request.REQUEST['new'].upper() == 'TRUE':
163            new = True
164        else:
165            new = False
166
167    show_email = http_request.user.has_perm('vouchers.can_email')
168    if show_email:
169        email_message = ''
170        if http_request.method == 'POST' and 'send_email' in http_request.REQUEST:
171            mail = vouchers.models.stock_emails[http_request.REQUEST['email_name']]
172            assert mail.context == 'request'
173            mail.send_email_request(request_obj)
174            email_message = 'Sent email "%s".' % (mail.label, )
175        email_options = []
176        for mail in vouchers.models.stock_emails.values():
177            if mail.context == 'request':
178                email_options.append({
179                    'label': mail.label,
180                    'name' : mail.name,
181                })
182
183    show_approve = (http_request.user.has_perm('vouchers.can_approve')
184        and request_obj.approval_status == vouchers.models.APPROVAL_STATE_PENDING)
185    if show_approve:
186        # Voucherize form
187        # Prefill from certs / config
188        initial = {}
189        initial['name'] = '%s %s' % (http_request.user.first_name, http_request.user.last_name, )
190        if settings.SIGNATORY_EMAIL:
191            initial['email'] = settings.SIGNATORY_EMAIL
192        else:
193            initial['email'] = http_request.user.email
194
195        approve_message = ''
196        if http_request.method == 'POST' and 'approve' in http_request.REQUEST:
197            approve_form = VoucherizeForm(http_request.POST)
198            if approve_form.is_valid():
199                voucher = request_obj.convert(
200                    approve_form.cleaned_data['name'],
201                    signatory_email=approve_form.cleaned_data['email'],)
202                tmpl = get_template('vouchers/emails/request_approval_admin.txt')
203                ctx = Context({
204                    'approver': http_request.user,
205                    'request': request_obj,
206                })
207                body = tmpl.render(ctx)
208                mail_admins(
209                    'Request approval: %s approved $%s' % (
210                        http_request.user,
211                        request_obj.amount,
212                    ),
213                    body,
214                )
215                approve_message = 'Created new voucher from request'
216        else:
217            approve_form = VoucherizeForm(initial=initial)
218
219    # Display the content
220    if not (http_request.user.has_perm('vouchers.view_requests')
221        or http_request.user.username == request_obj.submitter):
222        # I'd probably use a 403, but that requires like writing
223        # a new template and stuff
224        # So I'm going to call this "don't leak information"
225        # and let it be
226        raise Http404
227    context = {
228        'rr':request_obj,
229        'pagename':'request_reimbursement',
230        'new': new,
231    }
232    if show_approve:
233        context['approve_form'] = approve_form
234        context['approve_message'] = approve_message
235    if show_email:
236        context['email_options'] = email_options
237        context['email_message'] = email_message
238    return render_to_response('vouchers/ReimbursementRequest_review.html', context, context_instance=RequestContext(http_request), )
239
240@user_passes_test(lambda u: u.has_perm('vouchers.generate_vouchers'))
241def generate_vouchers(http_request, *args):
242    unprocessed = True
243    if 'unprocessed' in http_request.REQUEST:
244        if http_request.REQUEST['unprocessed'].upper() == 'TRUE':
245            unprocessed = True
246        else:
247            unprocessed = False
248    mark = True
249    if 'mark' in http_request.REQUEST:
250        if http_request.REQUEST['mark'].upper() == 'TRUE':
251            mark = True
252        else:
253            mark = False
254
255    lst = vouchers.models.Voucher.objects.all()
256    if unprocessed:
257        lst = lst.filter(processed=False)
258
259    context = {'vouchers': lst }
260    response = render_to_response('vouchers/vouchers.tex', context, context_instance=RequestContext(http_request), )
261
262    # Send mail
263    tmpl = get_template('vouchers/emails/vouchers_tex.txt')
264    ctx = Context({
265        'converter': http_request.user,
266        'vouchers': lst,
267        'mark': mark,
268        'unprocessed': unprocessed,
269    })
270    body = tmpl.render(ctx)
271    mail_admins(
272        'Voucher rendering: %d by %s' % (
273            len(lst),
274            http_request.user,
275        ),
276        body,
277    )
278
279    if mark:
280        for voucher in lst:
281            voucher.processed = True
282            voucher.save()
283
284    return response
Note: See TracBrowser for help on using the repository browser.