Test coverage report: payslip.views

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

Generated: Mon 2014-11-10 12:51 CET

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

Stats: 136 executed, 0 missed, 14 excluded, 236 ignored

1. `"""Views for the ``online_docs`` app."""`
2. `import cStringIO as StringIO`
3. `from datetime import datetime`
4. `import os`
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 relativedelta, 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 = datetime.strptime(`
279. `'{}-{}-01'.format(`
280. `self.post_data.get('year'), self.post_data.get('month')),`
281. `'%Y-%m-%d',`
282. `)`
283. `january_1st = datetime.strptime(`
284. `'{}-01-01'.format(self.post_data.get('year')),`
285. `'%Y-%m-%d',`
286. `)`
287. `date_end = (date_start + relativedelta.relativedelta(months=1)`
288. `- relativedelta.relativedelta(days=1))`
289. ``
290. `# Get payments for the selected year`
291. `payments_year = employee.payments.filter(`
292. `# Single payments in this year`
293. `Q(date__year=date_start.year,`
294. `payment_type__rrule__isnull=True) |`
295. `# Recurring payments with past date and end_date in the`
296. `# selected year or later`
297. `Q(date__lte=date_end, end_date__gte=january_1st,`
298. `payment_type__rrule__isnull=False) |`
299. `# Recurring payments with past date in period and open end`
300. `Q(date__lte=date_end, end_date__isnull=True,`
301. `payment_type__rrule__isnull=False)`
302. `)`
303. `# Get payments for the selected period`
304. `payments = payments_year.exclude(`
305. `# Exclude single payments not transferred in the period`
306. `Q(date__lt=date_start) |`
307. `Q(date__gt=date_end),`
308. `Q(payment_type__rrule__exact=''),`
309. `).filter(`
310. `# Recurring payments with past date and end_date in the period`
311. `Q(end_date__gte=date_end, date__lte=date_end) |`
312. `# Recurring payments with past date in period and open end`
313. `Q(date__lte=date_end, end_date__isnull=True)`
314. `)`
315. ``
316. `# Yearly positive summary`
317. `sum_year = payments_year.filter(`
318. `amount__gt=0, payment_type__rrule__exact='').aggregate(`
319. `Sum('amount')).get('amount__sum') or 0`
320. ``
321. `# Yearly negative summary`
322. `sum_year_neg = payments_year.filter(`
323. `amount__lt=0, payment_type__rrule__exact='').aggregate(`
324. `Sum('amount')).get('amount__sum') or 0`
325. ``
326. `# Yearly summary of recurring payments`
327. `for payment in payments_year.exclude(`
328. `payment_type__rrule__exact=''):`
329. `# If the recurring payment started in a year before, let's take`
330. `# January 1st as a start, otherwise take the original date`
331. `if payment.get_date_without_tz().year < date_start.year:`
332. `start = january_1st`
333. `else:`
334. `start = payment.get_date_without_tz()`
335. `# If the payments ends before the period's end date, let's take`
336. `# this date, otherwise we can take the period's end`
337. `if (payment.end_date`
338. `and payment.get_end_date_without_tz() < date_end):`
339. `end = payment.get_end_date_without_tz()`
340. `else:`
341. `end = date_end`
342. `recurrings = rrule.rrule(`
343. `rrule._rrulestr._freq_map.get(payment.payment_type.rrule),`
344. `dtstart=start, until=end,`
345. `)`
346. `# Multiply amount with recurrings`
347. `if payment.amount > 0:`
348. `sum_year += payment.amount * recurrings.count()`
349. `else:`
350. `sum_year_neg += payment.amount * recurrings.count()`
351. ``
352. `# Period summaries`
353. `sum = payments.filter(amount__gt=0).aggregate(`
354. `Sum('amount')).get('amount__sum') or 0`
355. `sum_neg = payments.filter(amount__lt=0).aggregate(`
356. `Sum('amount')).get('amount__sum') or 0`
357. ``
358. `kwargs.update({`
359. `'employee': employee,`
360. `'date_start': date_start,`
361. `'date_end': date_end,`
362. `'payments': payments,`
363. `'payment_extra_fields': ExtraFieldType.objects.filter(`
364. `model='Payment'),`
365. `'sum_year': sum_year,`
366. `'sum_year_neg': sum_year + sum_year_neg,`
367. `'sum': sum,`
368. `'sum_neg': sum_neg,`
369. `'currency': CURRENCY,`
370. `})`
371. `return kwargs`
372. ``
373. `def form_valid(self, form):`
374. `self.post_data = self.request.POST`
375. `if 'download' in self.post_data:`
376. `result = StringIO.StringIO()`
377. `html = self.render_to_response(self.get_context_data(form=form))`
378. `f = open(os.path.join(`
379. `os.path.dirname(__file__), './static/payslip/css/payslip.css'))`
380. `pdf = pisa.CreatePDF(html.render().content, result,`
381. `default_css=f.read())`
382. `f.close()`
383. `if not pdf.err:`
384. `return HttpResponse(result.getvalue(),`
385. `mimetype='application/pdf')`
386. `return self.render_to_response(self.get_context_data(form=form))`