PageRenderTime 23ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/django/contrib/localflavor/ro/forms.py

https://code.google.com/p/mango-py/
Python | 206 lines | 189 code | 5 blank | 12 comment | 2 complexity | ea25f01e5308599bb2fa80036d08cfd4 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. # -*- coding: utf-8 -*-
  2. """
  3. Romanian specific form helpers.
  4. """
  5. import re
  6. from django.core.validators import EMPTY_VALUES
  7. from django.forms import ValidationError, Field, RegexField, Select
  8. from django.utils.translation import ugettext_lazy as _
  9. class ROCIFField(RegexField):
  10. """
  11. A Romanian fiscal identity code (CIF) field
  12. For CIF validation algorithm see http://www.validari.ro/cui.html
  13. """
  14. default_error_messages = {
  15. 'invalid': _("Enter a valid CIF."),
  16. }
  17. def __init__(self, *args, **kwargs):
  18. super(ROCIFField, self).__init__(r'^(RO)?[0-9]{2,10}', max_length=10,
  19. min_length=2, *args, **kwargs)
  20. def clean(self, value):
  21. """
  22. CIF validation
  23. """
  24. value = super(ROCIFField, self).clean(value)
  25. if value in EMPTY_VALUES:
  26. return u''
  27. # strip RO part
  28. if value[0:2] == 'RO':
  29. value = value[2:]
  30. key = '753217532'[::-1]
  31. value = value[::-1]
  32. key_iter = iter(key)
  33. checksum = 0
  34. for digit in value[1:]:
  35. checksum += int(digit) * int(key_iter.next())
  36. checksum = checksum * 10 % 11
  37. if checksum == 10:
  38. checksum = 0
  39. if checksum != int(value[0]):
  40. raise ValidationError(self.error_messages['invalid'])
  41. return value[::-1]
  42. class ROCNPField(RegexField):
  43. """
  44. A Romanian personal identity code (CNP) field
  45. For CNP validation algorithm see http://www.validari.ro/cnp.html
  46. """
  47. default_error_messages = {
  48. 'invalid': _("Enter a valid CNP."),
  49. }
  50. def __init__(self, *args, **kwargs):
  51. super(ROCNPField, self).__init__(r'^[1-9][0-9]{12}', max_length=13,
  52. min_length=13, *args, **kwargs)
  53. def clean(self, value):
  54. """
  55. CNP validations
  56. """
  57. value = super(ROCNPField, self).clean(value)
  58. if value in EMPTY_VALUES:
  59. return u''
  60. # check birthdate digits
  61. import datetime
  62. try:
  63. datetime.date(int(value[1:3]),int(value[3:5]),int(value[5:7]))
  64. except:
  65. raise ValidationError(self.error_messages['invalid'])
  66. # checksum
  67. key = '279146358279'
  68. checksum = 0
  69. value_iter = iter(value)
  70. for digit in key:
  71. checksum += int(digit) * int(value_iter.next())
  72. checksum %= 11
  73. if checksum == 10:
  74. checksum = 1
  75. if checksum != int(value[12]):
  76. raise ValidationError(self.error_messages['invalid'])
  77. return value
  78. class ROCountyField(Field):
  79. """
  80. A form field that validates its input is a Romanian county name or
  81. abbreviation. It normalizes the input to the standard vehicle registration
  82. abbreviation for the given county
  83. WARNING: This field will only accept names written with diacritics; consider
  84. using ROCountySelect if this behavior is unnaceptable for you
  85. Example:
  86. Arge?&#x; => valid
  87. Arges => invalid
  88. """
  89. default_error_messages = {
  90. 'invalid': u'Enter a Romanian county code or name.',
  91. }
  92. def clean(self, value):
  93. from ro_counties import COUNTIES_CHOICES
  94. super(ROCountyField, self).clean(value)
  95. if value in EMPTY_VALUES:
  96. return u''
  97. try:
  98. value = value.strip().upper()
  99. except AttributeError:
  100. pass
  101. # search for county code
  102. for entry in COUNTIES_CHOICES:
  103. if value in entry:
  104. return value
  105. # search for county name
  106. normalized_CC = []
  107. for entry in COUNTIES_CHOICES:
  108. normalized_CC.append((entry[0],entry[1].upper()))
  109. for entry in normalized_CC:
  110. if entry[1] == value:
  111. return entry[0]
  112. raise ValidationError(self.error_messages['invalid'])
  113. class ROCountySelect(Select):
  114. """
  115. A Select widget that uses a list of Romanian counties (judete) as its
  116. choices.
  117. """
  118. def __init__(self, attrs=None):
  119. from ro_counties import COUNTIES_CHOICES
  120. super(ROCountySelect, self).__init__(attrs, choices=COUNTIES_CHOICES)
  121. class ROIBANField(RegexField):
  122. """
  123. Romanian International Bank Account Number (IBAN) field
  124. For Romanian IBAN validation algorithm see http://validari.ro/iban.html
  125. """
  126. default_error_messages = {
  127. 'invalid': _('Enter a valid IBAN in ROXX-XXXX-XXXX-XXXX-XXXX-XXXX format'),
  128. }
  129. def __init__(self, *args, **kwargs):
  130. super(ROIBANField, self).__init__(r'^[0-9A-Za-z\-\s]{24,40}$',
  131. max_length=40, min_length=24, *args, **kwargs)
  132. def clean(self, value):
  133. """
  134. Strips - and spaces, performs country code and checksum validation
  135. """
  136. value = super(ROIBANField, self).clean(value)
  137. if value in EMPTY_VALUES:
  138. return u''
  139. value = value.replace('-','')
  140. value = value.replace(' ','')
  141. value = value.upper()
  142. if value[0:2] != 'RO':
  143. raise ValidationError(self.error_messages['invalid'])
  144. numeric_format = ''
  145. for char in value[4:] + value[0:4]:
  146. if char.isalpha():
  147. numeric_format += str(ord(char) - 55)
  148. else:
  149. numeric_format += char
  150. if int(numeric_format) % 97 != 1:
  151. raise ValidationError(self.error_messages['invalid'])
  152. return value
  153. class ROPhoneNumberField(RegexField):
  154. """Romanian phone number field"""
  155. default_error_messages = {
  156. 'invalid': _('Phone numbers must be in XXXX-XXXXXX format.'),
  157. }
  158. def __init__(self, *args, **kwargs):
  159. super(ROPhoneNumberField, self).__init__(r'^[0-9\-\(\)\s]{10,20}$',
  160. max_length=20, min_length=10, *args, **kwargs)
  161. def clean(self, value):
  162. """
  163. Strips -, (, ) and spaces. Checks the final length.
  164. """
  165. value = super(ROPhoneNumberField, self).clean(value)
  166. if value in EMPTY_VALUES:
  167. return u''
  168. value = value.replace('-','')
  169. value = value.replace('(','')
  170. value = value.replace(')','')
  171. value = value.replace(' ','')
  172. if len(value) != 10:
  173. raise ValidationError(self.error_messages['invalid'])
  174. return value
  175. class ROPostalCodeField(RegexField):
  176. """Romanian postal code field."""
  177. default_error_messages = {
  178. 'invalid': _('Enter a valid postal code in the format XXXXXX'),
  179. }
  180. def __init__(self, *args, **kwargs):
  181. super(ROPostalCodeField, self).__init__(r'^[0-9][0-8][0-9]{4}$',
  182. max_length=6, min_length=6, *args, **kwargs)