-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathadvance_form.py
89 lines (75 loc) · 2.94 KB
/
advance_form.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import io
from datetime import date
from decimal import Decimal
import attr
from mailmerge import MailMerge
WORD_TEMPLATE = 'template.travel-advance.docx'
# Per PCO guidelines
PERCENTAGE_TO_CLAIM = Decimal('0.8')
# https://www.njc-cnm.gc.ca/directive/d10/v238/s659/en
# Effective Date: April 1, 2018
PD_BREAKFAST = Decimal("19.45")
PD_LUNCH = Decimal("19.20")
PD_DINNER = Decimal("48.15")
PD_INCIDENTAL = Decimal("17.30")
def to_decimal(inp):
return round_decimal(Decimal(inp))
def round_decimal(number):
return number.quantize(Decimal('0.01'))
@attr.s
class AdvanceForm(object):
full_name = attr.ib()
phone_number = attr.ib()
trip_purpose = attr.ib()
departure_date = attr.ib(validator=attr.validators.instance_of(date))
return_date = attr.ib(validator=attr.validators.instance_of(date))
travel_city = attr.ib()
accom_amt = attr.ib(default=0, converter=to_decimal)
rental_amt = attr.ib(default=0, converter=to_decimal)
num_breakfast = attr.ib(default=0, converter=int)
num_lunch = attr.ib(default=0, converter=int)
num_dinner = attr.ib(default=0, converter=int)
num_incidental = attr.ib(default=0, converter=int)
transport_amt = attr.ib(default=Decimal(0), converter=to_decimal)
date_submitted = attr.ib(default=attr.Factory(lambda: date.today()), validator=attr.validators.instance_of(date))
@property
def total_amt(self):
return sum(map(round_decimal, (
self.accom_amt,
self.rental_amt,
self.meals_amt,
self.transport_amt
)))
@property
def claimed_amt(self):
return round_decimal(PERCENTAGE_TO_CLAIM * self.total_amt)
@property
def meals_amt(self):
return sum(map(round_decimal, (
self.num_breakfast * PD_BREAKFAST,
self.num_lunch * PD_LUNCH,
self.num_dinner * PD_DINNER,
self.num_incidental * PD_INCIDENTAL
)))
def render(self):
template_vals = {
'full_name': self.full_name,
'phone_number': self.phone_number,
'purpose': self.trip_purpose,
'dep_date': self.departure_date.strftime("%-d-%b"),
'ret_date': self.return_date.strftime("%-d-%b"),
'travel_city': self.travel_city,
'amt_accom': str(self.accom_amt),
'amt_transport': str(self.transport_amt),
'amt_rental': str(self.rental_amt),
'amt_meals': str(self.meals_amt),
'amt_total': str(self.total_amt),
'amt_claimed': str(self.claimed_amt),
'date_submitted': self.date_submitted.strftime("%Y-%m-%d")
}
output_buffer = io.BytesIO()
with MailMerge(WORD_TEMPLATE) as template:
template.merge(**template_vals)
template.write(output_buffer)
output_buffer.seek(0)
return output_buffer