Test coverage report: payslip.views

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

Generated: Sat 2014-11-08 19:42 CET

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

Stats: 135 executed, 0 missed, 13 excluded, 228 ignored

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