source: remit/vouchers/models.py @ c020a3b

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

Make admin list pages useful (Closes: #6)

  • Property mode set to 100644
File size: 7.2 KB
Line 
1from django.db import models
2import settings
3import finance_core
4from finance_core.models import BudgetArea, BudgetTerm
5
6import datetime
7
8APPROVAL_STATE_PENDING = 0
9APPROVAL_STATE_APPROVED = 1
10APPROVAL_STATE_REJECTED = -1
11APPROVAL_STATES = (
12    (APPROVAL_STATE_PENDING,  'Pending'),
13    (APPROVAL_STATE_APPROVED, 'Approved'),
14    (APPROVAL_STATE_REJECTED, 'Rejected'),
15)
16
17class ReimbursementRequest(models.Model):
18    submitter = models.CharField(max_length=10) # MIT username of submitter
19    check_to_first_name = models.CharField(max_length=50, verbose_name="check recipient's first name")
20    check_to_last_name = models.CharField(max_length=50, verbose_name="check recipient's last name")
21    check_to_email = models.EmailField(verbose_name="email address for check pickup")
22    check_to_addr = models.TextField(blank=True, verbose_name="address for check mailing", help_text="For most requests, this should be blank for pickup in SAO (W20-549)")
23    amount = models.DecimalField(max_digits=7, decimal_places=2, help_text='Do not include "$"')
24    budget_area = models.ForeignKey(BudgetArea, related_name='as_budget_area')
25    budget_term = models.ForeignKey(BudgetTerm)
26    expense_area = models.ForeignKey(BudgetArea, related_name='as_expense_area') # ~GL
27    request_time = models.DateTimeField(default=datetime.datetime.now)
28    approval_time = models.DateTimeField(blank=True, null=True,)
29    approval_status = models.IntegerField(default=0, choices=APPROVAL_STATES)
30    printing_time = models.DateTimeField(blank=True, null=True,)
31    name = models.CharField(max_length=50, verbose_name='short description', )
32    description = models.TextField(blank=True, verbose_name='long description', )
33
34    class Meta:
35        permissions = (
36            ('can_list', 'Can list requests',),
37            ('can_approve', 'Can approve requests',),
38            ('can_email', 'Can send mail about requests',),
39        )
40
41    def __unicode__(self, ):
42        return "%s: %s %s (%s) (by %s) for $%s" % (
43            self.name,
44            self.check_to_first_name,
45            self.check_to_last_name,
46            self.check_to_email,
47            self.submitter,
48            self.amount,
49        )
50
51    def convert(self, signatory, signatory_email=settings.SIGNATORY_EMAIL):
52        voucher = Voucher()
53        voucher.group_name = settings.GROUP_NAME
54        voucher.account = self.budget_area.get_account_number()
55        voucher.signatory = signatory
56        voucher.signatory_email = signatory_email
57        voucher.first_name = self.check_to_first_name
58        voucher.last_name = self.check_to_last_name
59        voucher.email_address = self.check_to_email
60        voucher.mailing_address = self.check_to_addr
61        voucher.amount = self.amount
62        voucher.description = self.label() + ': ' + self.name
63        voucher.gl = self.expense_area.get_account_number()
64        voucher.save()
65        finance_core.models.make_transfer(
66            self.name,
67            self.amount,
68            finance_core.models.LAYER_EXPENDITURE,
69            self.budget_term,
70            self.budget_area,
71            self.expense_area,
72            self.description,
73        )
74        self.approval_status = 1
75        self.approval_time = datetime.datetime.now()
76        self.save()
77
78    def label(self, ):
79        return settings.GROUP_ABBR + unicode(self.pk) + 'RR'
80
81class Voucher(models.Model):
82    group_name = models.CharField(max_length=10)
83    account = models.IntegerField()
84    signatory = models.CharField(max_length=50)
85    signatory_email = models.EmailField()
86    first_name = models.CharField(max_length=20)
87    last_name = models.CharField(max_length=20)
88    email_address = models.EmailField(max_length=50)
89    mailing_address = models.TextField()
90    amount = models.DecimalField(max_digits=7, decimal_places=2,)
91    description = models.TextField()
92    gl = models.IntegerField()
93    processed = models.BooleanField()
94
95    def mailing_addr_lines(self):
96        import re
97        if self.mailing_address:
98            lst = re.split(re.compile('[\n\r]*'), self.mailing_address)
99            lst = filter(lambda elem: len(elem)>0, lst)
100        else:
101            lst = []
102        lst = lst + ['']*(3-len(lst))
103        return lst
104
105    def __unicode__(self, ):
106        return "%s: %s %s (%s) for $%s" % (
107            self.description,
108            self.first_name,
109            self.last_name,
110            self.email_address,
111            self.amount,
112        )
113
114    class Meta:
115        permissions = (
116            ('generate_vouchers', 'Can generate vouchers',),
117        )
118
119
120class StockEmail:
121    def __init__(self, name, label, recipients, template, subject_template, context, ):
122        """
123        Initialize a stock email object.
124       
125        Each argument is required.
126       
127        name:       Short name. Letters, numbers, and hyphens only.
128        label:      User-readable label. Briefly describe what the email says
129        recipients: Who receives the email. List of "recipient" (check recipient), "area" (area owner), "admins" (site admins)
130        template:   Django template filename with the actual text
131        subject_template: Django template string with the subject
132        context:    Type of context the email needs. Must be 'request' currently.
133        """
134
135        self.name       = name
136        self.label      = label
137        self.recipients = recipients
138        self.template   = template
139        self.subject_template = subject_template
140        self.context    = context
141
142    def send_email_request(self, request,):
143        """
144        Send an email that requires context "request".
145        """
146
147        assert self.context == 'request'
148
149        # Generate text
150        from django.template import Context, Template
151        from django.template.loader import get_template
152        ctx = Context({
153            'prefix': settings.EMAIL_SUBJECT_PREFIX,
154            'request': request,
155            'sender': settings.USER_EMAIL_SIGNATURE,
156        })
157        tmpl = get_template(self.template)
158        body = tmpl.render(ctx)
159        subject_tmpl = Template(self.subject_template)
160        subject = subject_tmpl.render(ctx)
161
162        # Generate recipients
163        recipients = []
164        for rt in self.recipients:
165            if rt == 'recipient':
166                recipients.append(request.check_to_email)
167            elif rt == 'area':
168                recipients.append(request.budget_area.owner_address())
169            elif rt == 'admins':
170                pass # you don't *actually* have a choice...
171        for name, addr in settings.ADMINS:
172            recipients.append(addr)
173
174        # Send mail!
175        from django.core.mail import send_mail
176        send_mail(
177            subject,
178            body,
179            settings.SERVER_EMAIL,
180            recipients,
181        )
182
183stock_emails = {
184    'nodoc': StockEmail(
185        name='nodoc',
186        label='No documentation',
187        recipients=['recipient', 'area',],
188        template='vouchers/emails/no_docs_user.txt',
189        subject_template='{{prefix}}Missing documentation for reimbursement',
190        context = 'request',
191    ),
192    'voucher-sao': StockEmail(
193        name='voucher-sao',
194        label='Voucher submitted to SAO',
195        recipients=['recipient', ],
196        template='vouchers/emails/voucher_sao_user.txt',
197        subject_template='{{prefix}}Reimbursement sent to SAO for processing',
198        context = 'request',
199    ),
200}
Note: See TracBrowser for help on using the repository browser.