Test coverage report: payslip.views

# payslip.views: 149 total statements, 100.0% covered

Generated: Sun 2014-11-09 09:00 CET

Source file: /home/tobi/Projects/django-payslip/src/payslip/views.py

Stats: 135 executed, 0 missed, 14 excluded, 231 ignored

1. `"""Views for the ``online_docs`` app."""`
2. `import cStringIO as StringIO`
3. `import os`
4. `import pytz`
5. ``
6. `from django.contrib.auth.decorators import login_required`
7. `from django.core.urlresolvers import reverse`
8. `from django.db.models import Q, Sum`
9. `from django.http import Http404, HttpResponse`
10. `from django.utils.decorators import method_decorator`
11. `from django.views.generic import (`
12. `CreateView,`
13. `DeleteView,`
14. `FormView,`
15. `TemplateView,`
16. `UpdateView,`
17. `)`
18. ``
19. `from dateutil import parser, rrule`
20. `from xhtml2pdf import pisa`
21. ``
22. `from .app_settings import CURRENCY`
23. `from .forms import (`
24. `EmployeeForm,`
25. `ExtraFieldForm,`
26. `PaymentForm,`
27. `PayslipForm,`
28. `)`
29. `from .models import (`
30. `Company,`
31. `Employee,`
32. `ExtraField,`
33. `ExtraFieldType,`
34. `Payment,`
35. `PaymentType,`
36. `)`
37. ``
38. ``
39. `# -------------#`
40. `# Mixins #`
41. `# -------------#`
42. ``
43. `class PermissionMixin(object):`
44. `"""Mixin to handle security functions."""`
45. `@method_decorator(login_required)`
46. `def dispatch(self, request, *args, **kwargs):`
47. `"""`
48. `Makes sure that the user is logged in and has the right to display this`
49. `view.`
50. ``
51. `"""`
52. `if not request.user.is_staff:`
53. `raise Http404`
54. `return super(PermissionMixin, self).dispatch(request, *args, **kwargs)`
55. ``
56. `def get_success_url(self):`
57. `return reverse('payslip_dashboard')`
58. ``
59. ``
60. `class CompanyMixin(object):`
61. `"""Mixin to handle company related functions."""`
62. `@method_decorator(login_required)`
63. `def dispatch(self, request, *args, **kwargs):`
64. `"""`
65. `Makes sure that the user is logged in and has the right to display this`
66. `view.`
67. ``
68. `"""`
69. `self.kwargs = kwargs`
70. `self.object = self.get_object()`
71. `try:`
72. `Employee.objects.get(company=self.object, user=request.user,`
73. `is_manager=True)`
74. `except Employee.DoesNotExist:`
75. `if not request.user.is_staff:`
76. `raise Http404`
77. `return super(CompanyMixin, self).dispatch(request, *args, **kwargs)`
78. ``
79. `def get_success_url(self):`
80. `return reverse('payslip_dashboard')`
81. ``
82. ``
83. `class CompanyPermissionMixin(object):`
84. `"""Mixin to handle company-wide permissions functions."""`
85. ``
86. `@method_decorator(login_required)`
87. `def dispatch(self, request, *args, **kwargs):`
88. `"""`
89. `Makes sure that the user is logged in and has the right to display this`
90. `view.`
91. ``
92. `"""`
93. `try:`
94. `self.company = Employee.objects.get(`
95. `user=request.user, is_manager=True).company`
96. `except Employee.DoesNotExist:`
97. `if not request.user.is_staff:`
98. `raise Http404`
99. `self.company = None`
100. `return super(CompanyPermissionMixin, self).dispatch(request, *args,`
101. `**kwargs)`
102. ``
103. `def get_success_url(self):`
104. `return reverse('payslip_dashboard')`
105. ``
106. ``
107. `class EmployeeMixin(object):`
108. `"""Mixin to handle employee related functions."""`
109. `form_class = EmployeeForm`
110. ``
111. `def get_form_kwargs(self):`
112. `kwargs = super(EmployeeMixin, self).get_form_kwargs()`
113. `kwargs.update({'company': self.company})`
114. `return kwargs`
115. ``
116. ``
117. `class ExtraFieldMixin(object):`
118. `"""Mixin to handle extra field related functions."""`
119. `model = ExtraField`
120. `form_class = ExtraFieldForm`
121. ``
122. ``
123. `class ExtraFieldTypeMixin(object):`
124. `"""Mixin to handle extra field type related functions."""`
125. `model = ExtraFieldType`
126. ``
127. ``
128. `class PaymentMixin(object):`
129. `"""Mixin to handle payment related functions."""`
130. `model = Payment`
131. `form_class = PaymentForm`
132. ``
133. ``
134. `class PaymentTypeMixin(object):`
135. `"""Mixin to handle payment type related functions."""`
136. `model = PaymentType`
137. ``
138. ``
139. `# -------------#`
140. `# Views #`
141. `# -------------#`
142. ``
143. `class DashboardView(PermissionMixin, TemplateView):`
144. `"""Dashboard to navigate through the payslip app."""`
145. `template_name = 'payslip/dashboard.html'`
146. ``
147. `def get_context_data(self, **kwargs):`
148. `return {`
149. `'companies': Company.objects.all(),`
150. `'employees': Employee.objects.all(),`
151. `'extra_field_types': ExtraFieldType.objects.all(),`
152. `'fixed_value_extra_fields': ExtraField.objects.filter(`
153. `field_type__fixed_values=True),`
154. `'payments': Payment.objects.all(),`
155. `'payment_types': PaymentType.objects.all(),`
156. `}`
157. ``
158. ``
159. `class CompanyCreateView(PermissionMixin, CreateView):`
160. `"""Classic view to create a company."""`
161. `model = Company`
162. ``
163. `def get_success_url(self):`
164. `return reverse('payslip_dashboard')`
165. ``
166. ``
167. `class CompanyUpdateView(CompanyMixin, UpdateView):`
168. `"""Classic view to update a company."""`
169. `model = Company`
170. ``
171. ``
172. `class CompanyDeleteView(CompanyMixin, DeleteView):`
173. `"""Classic view to delete a company."""`
174. `model = Company`
175. ``
176. ``
177. `class EmployeeCreateView(CompanyPermissionMixin, EmployeeMixin, CreateView):`
178. `"""Classic view to create an employee."""`
179. `model = Employee`
180. ``
181. ``
182. `class EmployeeUpdateView(CompanyPermissionMixin, EmployeeMixin, UpdateView):`
183. `"""Classic view to update an employee."""`
184. `model = Employee`
185. ``
186. ``
187. `class EmployeeDeleteView(CompanyPermissionMixin, EmployeeMixin, DeleteView):`
188. `"""Classic view to delete an employee."""`
189. `model = Employee`
190. ``
191. ``
192. `class ExtraFieldTypeCreateView(PermissionMixin, ExtraFieldTypeMixin,`
193. `CreateView):`
194. `"""Classic view to create an extra field type."""`
195. `pass`
196. ``
197. ``
198. `class ExtraFieldTypeUpdateView(PermissionMixin, ExtraFieldTypeMixin,`
199. `UpdateView):`
200. `"""Classic view to update an extra field type."""`
201. `pass`
202. ``
203. ``
204. `class ExtraFieldTypeDeleteView(PermissionMixin, ExtraFieldTypeMixin,`
205. `DeleteView):`
206. `"""Classic view to delete an extra field type."""`
207. `pass`
208. ``
209. ``
210. `class ExtraFieldCreateView(PermissionMixin, ExtraFieldMixin, CreateView):`
211. `"""Classic view to create an extra field."""`
212. `pass`
213. ``
214. ``
215. `class ExtraFieldUpdateView(PermissionMixin, ExtraFieldMixin, UpdateView):`
216. `"""Classic view to update an extra field."""`
217. `pass`
218. ``
219. ``
220. `class ExtraFieldDeleteView(PermissionMixin, ExtraFieldMixin, DeleteView):`
221. `"""Classic view to delete an extra field."""`
222. `pass`
223. ``
224. ``
225. `class PaymentTypeCreateView(CompanyPermissionMixin, PaymentTypeMixin,`
226. `CreateView):`
227. `"""Classic view to create a payment type."""`
228. `pass`
229. ``
230. ``
231. `class PaymentTypeUpdateView(CompanyPermissionMixin, PaymentTypeMixin,`
232. `UpdateView):`
233. `"""Classic view to update a payment type."""`
234. `pass`
235. ``
236. ``
237. `class PaymentTypeDeleteView(CompanyPermissionMixin, PaymentTypeMixin,`
238. `DeleteView):`
239. `"""Classic view to delete a payment type."""`
240. `pass`
241. ``
242. ``
243. `class PaymentCreateView(CompanyPermissionMixin, PaymentMixin, CreateView):`
244. `"""Classic view to create a payment."""`
245. `pass`
246. ``
247. ``
248. `class PaymentUpdateView(CompanyPermissionMixin, PaymentMixin, UpdateView):`
249. `"""Classic view to update a payment."""`
250. `pass`
251. ``
252. ``
253. `class PaymentDeleteView(CompanyPermissionMixin, PaymentMixin, DeleteView):`
254. `"""Classic view to delete a payment."""`
255. `pass`
256. ``
257. ``
258. `class PayslipGeneratorView(CompanyPermissionMixin, FormView):`
259. `"""View to present a small form to generate a custom payslip."""`
260. `template_name = 'payslip/payslip_form.html'`
261. `form_class = PayslipForm`
262. ``
263. `def get_form_kwargs(self):`
264. `kwargs = super(PayslipGeneratorView, self).get_form_kwargs()`
265. `kwargs.update({'company': self.company})`
266. `return kwargs`
267. ``
268. `def get_template_names(self):`
269. `if hasattr(self, 'post_data'):`
270. `return ['payslip/payslip.html']`
271. `return super(PayslipGeneratorView, self).get_template_names()`
272. ``
273. `def get_context_data(self, **kwargs):`
274. `kwargs = super(PayslipGeneratorView, self).get_context_data(**kwargs)`
275. `if hasattr(self, 'post_data'):`
276. `# Get form data`
277. `employee = Employee.objects.get(pk=self.post_data.get('employee'))`
278. `date_start = parser.parse(`
279. `self.post_data.get('date_start')).replace(tzinfo=pytz.UTC)`
280. `date_end = parser.parse(`
281. `self.post_data.get('date_end')).replace(tzinfo=pytz.UTC)`
282. ``
283. `# Get payments for the selected year`
284. `payments_year = employee.payments.filter(`
285. `# Single payments in this year`
286. `Q(date__year=date_start.year, payment_type__rrule__exact='') |`
287. `# Recurring payments with past date and end_date in the`
288. `# selected year or later`
289. `Q(date__lte=date_end, end_date__gte=parser.parse(`
290. `'{0}0101T000000'.format(date_start.year)).replace(`
291. `tzinfo=pytz.UTC),`
292. `payment_type__rrule__isnull=False) |`
293. `# Recurring payments with past date in period and open end`
294. `Q(date__lte=date_end, end_date__isnull=True,`
295. `payment_type__rrule__isnull=False)`
296. `)`
297. `# Get payments for the selected period`
298. `payments = payments_year.filter(`
299. `# Single payments in the selected period`
300. `Q(date__gte=date_start, date__lte=date_end,`
301. `payment_type__rrule__exact='') |`
302. `# Recurring payments with past date and end_date in the period`
303. `Q(end_date__gte=date_end,`
304. `date__lte=date_end, payment_type__rrule__isnull=False) |`
305. `# Recurring payments with past date in period and open end`
306. `Q(date__lte=date_end, end_date__isnull=True,`
307. `payment_type__rrule__isnull=False)`
308. `)`
309. ``
310. `# Yearly positive summary`
311. `sum_year = payments_year.filter(`
312. `amount__gt=0, payment_type__rrule__exact='').aggregate(`
313. `Sum('amount')).get('amount__sum') or 0`
314. ``
315. `# Yearly negative summary`
316. `sum_year_neg = payments_year.filter(`
317. `amount__lt=0, payment_type__rrule__exact='').aggregate(`
318. `Sum('amount')).get('amount__sum') or 0`
319. ``
320. `# Yearly summary of recurring payments`
321. `for payment in payments_year.exclude(`
322. `payment_type__rrule__exact=''):`
323. `# If the recurring payment started in a year before, let's take`
324. `# January 1st as a start, otherwise take the original date`
325. `if payment.date.year < date_start.year:`
326. `start = parser.parse('{0}0101T000000'.format(`
327. `date_start.year)).replace(tzinfo=pytz.UTC)`
328. `else:`
329. `start = payment.date`
330. `# If the payments ends before the period's end date, let's take`
331. `# this date, otherwise we can take the period's end`
332. `if payment.end_date and payment.end_date < date_end:`
333. `end = payment.end_date`
334. `else:`
335. `end = date_end`
336. `recurrings = rrule.rrule(`
337. `rrule._rrulestr._freq_map.get(payment.payment_type.rrule),`
338. `dtstart=start, until=end,`
339. `)`
340. `# Multiply amount with recurrings`
341. `if payment.amount > 0:`
342. `sum_year += payment.amount * recurrings.count()`
343. `else:`
344. `sum_year_neg += payment.amount * recurrings.count()`
345. ``
346. `# Period summaries`
347. `sum = payments.filter(amount__gt=0).aggregate(`
348. `Sum('amount')).get('amount__sum') or 0`
349. `sum_neg = payments.filter(amount__lt=0).aggregate(`
350. `Sum('amount')).get('amount__sum') or 0`
351. ``
352. `kwargs.update({`
353. `'employee': employee,`
354. `'date_start': date_start,`
355. `'date_end': date_end,`
356. `'payments': payments,`
357. `'payment_extra_fields': ExtraFieldType.objects.filter(`
358. `model='Payment'),`
359. `'sum_year': sum_year,`
360. `'sum_year_neg': sum_year + sum_year_neg,`
361. `'sum': sum,`
362. `'sum_neg': sum_neg,`
363. `'currency': CURRENCY,`
364. `})`
365. `return kwargs`
366. ``
367. `def form_valid(self, form):`
368. `self.post_data = self.request.POST`
369. `if 'download' in self.post_data:`
370. `result = StringIO.StringIO()`
371. `html = self.render_to_response(self.get_context_data(form=form))`
372. `f = open(os.path.join(`
373. `os.path.dirname(__file__), './static/payslip/css/payslip.css'))`
374. `pdf = pisa.CreatePDF(html.render().content, result,`
375. `default_css=f.read())`
376. `f.close()`
377. `if not pdf.err:`
378. `return HttpResponse(result.getvalue(),`
379. `mimetype='application/pdf')`
380. `return self.render_to_response(self.get_context_data(form=form))`