payslip.forms: 129 total statements, 100.0% covered

Generated: Tue 2013-05-07 14:07 CEST

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

Stats: 121 executed, 0 missed, 8 excluded, 109 ignored

  1. """Forms for the ``payslip`` app."""
  2. import md5
  3. from django.contrib.auth.models import make_password, User
  4. from django.db.models import Q
  5. from django import forms
  6. from django.utils import timezone
  7. from django.utils.translation import ugettext_lazy as _
  8. from dateutil.relativedelta import relativedelta
  9. from payslip.models import (
  10. Company,
  11. Employee,
  12. ExtraField,
  13. ExtraFieldType,
  14. Payment,
  15. )
  16. def get_md5_hexdigest(email):
  17. """
  18. Returns an md5 hash for a given email.
  19. The length is 30 so that it fits into Django's ``User.username`` field.
  20. """
  21. return md5.new(email).hexdigest()[0:30]
  22. def generate_username(email):
  23. """
  24. Generates a unique username for the given email.
  25. The username will be an md5 hash of the given email. If the username exists
  26. we just append `a` to the email until we get a unique md5 hash.
  27. """
  28. username = get_md5_hexdigest(email)
  29. found_unique_username = False
  30. while not found_unique_username:
  31. try:
  32. User.objects.get(username=username)
  33. email = '{0}a'.format(email)
  34. username = get_md5_hexdigest(email)
  35. except User.DoesNotExist:
  36. found_unique_username = True
  37. return username
  38. class ExtraFieldFormMixin(object):
  39. """Mixin to handle extra field related functions."""
  40. def __init__(self, *args, **kwargs):
  41. self.extra_field_types = ExtraFieldType.objects.filter(
  42. Q(model=self.Meta.model.__name__) | Q(model__isnull=True))
  43. if kwargs.get('instance'):
  44. for extra_field_type in self.extra_field_types:
  45. try:
  46. field = kwargs.get('instance').extra_fields.get(
  47. field_type__name=extra_field_type.name)
  48. except ExtraField.DoesNotExist:
  49. pass
  50. else:
  51. kwargs['initial'].update({'{0}'.format(
  52. extra_field_type.name): field.value})
  53. super(ExtraFieldFormMixin, self).__init__(*args, **kwargs)
  54. for extra_field_type in self.extra_field_types:
  55. if extra_field_type.fixed_values:
  56. choices = [(x.value, x.value)
  57. for x in extra_field_type.extra_fields.all()]
  58. choices.append(('', '-----'))
  59. self.fields[extra_field_type.name] = forms.ChoiceField(
  60. required=False,
  61. choices=list(set(choices)),
  62. )
  63. else:
  64. self.fields[extra_field_type.name] = forms.CharField(
  65. required=False, max_length=200)
  66. def save(self, *args, **kwargs):
  67. resp = super(ExtraFieldFormMixin, self).save(*args, **kwargs)
  68. for extra_field_type in self.extra_field_types:
  69. try:
  70. field_to_save = self.instance.extra_fields.get(
  71. field_type__name=extra_field_type.name)
  72. except ExtraField.DoesNotExist:
  73. field_to_save = None
  74. if extra_field_type.fixed_values:
  75. if field_to_save:
  76. self.instance.extra_fields.remove(
  77. self.instance.extra_fields.get(
  78. field_type__name=extra_field_type.name))
  79. try:
  80. field_to_save = ExtraField.objects.get(
  81. field_type__name=extra_field_type.name,
  82. value=self.data.get(extra_field_type.name))
  83. except ExtraField.DoesNotExist:
  84. pass
  85. else:
  86. self.instance.extra_fields.add(field_to_save)
  87. else:
  88. if field_to_save:
  89. field_to_save.value = self.data.get(extra_field_type.name)
  90. field_to_save.save()
  91. elif self.data.get(extra_field_type.name):
  92. new_field = ExtraField(
  93. field_type=extra_field_type,
  94. value=self.data.get(extra_field_type.name),
  95. )
  96. new_field.save()
  97. self.instance.extra_fields.add(new_field)
  98. return resp
  99. class EmployeeForm(ExtraFieldFormMixin, forms.ModelForm):
  100. """Form to create a new Employee instance."""
  101. first_name = forms.CharField(max_length=30)
  102. last_name = forms.CharField(max_length=30)
  103. email = forms.EmailField()
  104. password = forms.CharField(widget=forms.PasswordInput(), max_length=128)
  105. retype_password = forms.CharField(widget=forms.PasswordInput(),
  106. max_length=128)
  107. def __init__(self, company, *args, **kwargs):
  108. self.company = company
  109. if kwargs.get('instance'):
  110. instance = kwargs.get('instance')
  111. user = instance.user
  112. kwargs['initial'] = {
  113. 'first_name': user.first_name,
  114. 'last_name': user.last_name,
  115. 'email': user.email,
  116. }
  117. super(EmployeeForm, self).__init__(*args, **kwargs)
  118. if self.instance.id:
  119. del self.fields['password']
  120. del self.fields['retype_password']
  121. if self.company and self.company.pk:
  122. del self.fields['company']
  123. def clean_email(self):
  124. """
  125. Validate that the username is alphanumeric and is not already
  126. in use.
  127. """
  128. email = self.cleaned_data['email']
  129. try:
  130. user = User.objects.get(email__iexact=email)
  131. except User.DoesNotExist:
  132. return email
  133. if self.instance.id and user == self.instance.user:
  134. return email
  135. raise forms.ValidationError(
  136. _('A user with that email already exists.'))
  137. def clean(self):
  138. """
  139. Verifiy that the values entered into the two password fields match.
  140. Note that an error here will end up in ``non_field_errors()`` because
  141. it doesn't apply to a single field.
  142. """
  143. data = self.cleaned_data
  144. if not 'email' in data:
  145. return data
  146. if ('password' in data and 'retype_password' in data):
  147. if data['password'] != data['retype_password']:
  148. raise forms.ValidationError(
  149. _("The two password fields didn't match."))
  150. self.cleaned_data['username'] = generate_username(data['email'])
  151. return self.cleaned_data
  152. def save(self, *args, **kwargs):
  153. if self.instance.id:
  154. User.objects.filter(pk=self.instance.user.pk).update(
  155. first_name=self.cleaned_data.get('first_name'),
  156. last_name=self.cleaned_data.get('last_name'),
  157. email=self.cleaned_data.get('email'),
  158. )
  159. else:
  160. user = User(
  161. username=self.cleaned_data.get('email'),
  162. first_name=self.cleaned_data.get('first_name'),
  163. last_name=self.cleaned_data.get('last_name'),
  164. email=self.cleaned_data.get('email'),
  165. password=make_password(self.cleaned_data.get('password')),
  166. )
  167. user.save()
  168. self.instance.user = user
  169. if self.company and self.company.pk:
  170. self.instance.company = Company.objects.get(pk=self.company.pk)
  171. return super(EmployeeForm, self).save(*args, **kwargs)
  172. class Meta:
  173. model = Employee
  174. exclude = ('user', 'extra_fields')
  175. class PaymentForm(ExtraFieldFormMixin, forms.ModelForm):
  176. """Form to create a new Payment instance."""
  177. class Meta:
  178. model = Payment
  179. exclude = ('extra_fields')
  180. class ExtraFieldForm(forms.ModelForm):
  181. """Form to create a new ExtraField instance."""
  182. def __init__(self, *args, **kwargs):
  183. super(ExtraFieldForm, self).__init__(*args, **kwargs)
  184. self.fields['field_type'].queryset = ExtraFieldType.objects.filter(
  185. fixed_values=True)
  186. class Meta:
  187. model = ExtraField
  188. class PayslipForm(forms.Form):
  189. """Form to create a custom payslip."""
  190. # First day of the last month
  191. date_start = forms.DateField(
  192. initial=timezone.now().replace(day=1) - relativedelta(months=1))
  193. # Last day of the last month
  194. date_end = forms.DateField(initial=timezone.now().replace(
  195. month=timezone.now().month, day=1) - timezone.timedelta(days=1))
  196. employee = forms.ChoiceField()
  197. def __init__(self, company, *args, **kwargs):
  198. super(PayslipForm, self).__init__(*args, **kwargs)
  199. self.company = company
  200. if self.company:
  201. self.fields['employee'].choices = [(
  202. x.id, x) for x in self.company.employees.all()]
  203. else:
  204. self.fields['employee'].choices = [(
  205. x.id, x) for x in Employee.objects.all()]