source: remit/vouchers/views.py @ dc17b01

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

WIP WIP WIP: Start of doc upload

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