Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3957, #3945 -- Added CPF and CNPJ (some Brazilian identity num…

…bers)

fields to the Brazilian localflavor. Thanks, onaiort@gmail.com and
danielvaz@gmail.com.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@5089 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 6c02565e4fb92c4cc3bfb45bcc89eb9aa299efdc 1 parent b24c860
Malcolm Tredinnick authored April 26, 2007
1  AUTHORS
@@ -168,6 +168,7 @@ answer newbie questions, and generally made Django that much better:
168 168
     Sam Newman <http://www.magpiebrain.com/>
169 169
     Neal Norwitz <nnorwitz@google.com>
170 170
     oggie rob <oz.robharvey@gmail.com>
  171
+    onaiort@gmail.com
171 172
     Jay Parlar <parlar@gmail.com>
172 173
     pavithran s <pavithran.s@gmail.com>
173 174
     Barry Pederson <bp@barryp.org>
84  django/contrib/localflavor/br/forms.py
@@ -4,7 +4,7 @@
4 4
 """
5 5
 
6 6
 from django.newforms import ValidationError
7  
-from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
  7
+from django.newforms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES
8 8
 from django.utils.encoding import smart_unicode
9 9
 from django.utils.translation import gettext
10 10
 import re
@@ -15,7 +15,7 @@ class BRZipCodeField(RegexField):
15 15
     def __init__(self, *args, **kwargs):
16 16
         super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$',
17 17
             max_length=None, min_length=None,
18  
-            error_message=gettext(u'Enter a zip code in the format XXXXX-XXX.'),
  18
+            error_message=gettext('Enter a zip code in the format XXXXX-XXX.'),
19 19
             *args, **kwargs)
20 20
 
21 21
 class BRPhoneNumberField(Field):
@@ -37,3 +37,83 @@ class BRStateSelect(Select):
37 37
     def __init__(self, attrs=None):
38 38
         from br_states import STATE_CHOICES # relative import
39 39
         super(BRStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
  40
+
  41
+
  42
+def DV_maker(v):
  43
+    if v >= 2:
  44
+        return 11 - v
  45
+    return 0
  46
+
  47
+class BRCPFField(CharField):
  48
+    """
  49
+    This field validate a CPF number or a CPF string. A CPF number is
  50
+    compounded by XXX.XXX.XXX-VD, the two last digits are check digits.
  51
+
  52
+    More information:
  53
+    http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas
  54
+    """
  55
+    def __init__(self, *args, **kwargs):
  56
+        super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs)
  57
+
  58
+    def clean(self, value):
  59
+        """
  60
+        Value can be either a string in the format XXX.XXX.XXX-XX or an
  61
+        11-digit number.
  62
+        """
  63
+        value = super(BRCPFField, self).clean(value)
  64
+        if value in EMPTY_VALUES:
  65
+            return u''
  66
+        orig_value = value[:]
  67
+        if not value.isdigit():
  68
+            value = re.sub("[-\.]", "", value)
  69
+        try:
  70
+            int(value)
  71
+        except ValueError:
  72
+            raise ValidationError(gettext("This field requires only numbers"))
  73
+        if len(value) != 11:
  74
+            raise ValidationError(gettext("This field requires at most 11 digits or 14 characters."))
  75
+        orig_dv = value[-2:]
  76
+
  77
+        new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))])
  78
+        new_1dv = DV_maker(new_1dv % 11)
  79
+        value = value[:-2] + str(new_1dv) + value[-1]
  80
+        new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(range(11, 1, -1))])
  81
+        new_2dv = DV_maker(new_2dv % 11)
  82
+        value = value[:-1] + str(new_2dv)
  83
+        if value[-2:] != orig_dv:
  84
+            raise ValidationError(gettext("Invalid CPF number."))
  85
+
  86
+        return orig_value
  87
+
  88
+class BRCNPJField(Field):
  89
+    def clean(self, value):
  90
+        """
  91
+        Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a
  92
+        group of 14 characters.
  93
+        """
  94
+        value = super(BRCNPJField, self).clean(value)
  95
+        if value in EMPTY_VALUES:
  96
+            return u''
  97
+        orig_value = value[:]
  98
+        if not value.isdigit():
  99
+            value = re.sub("[-/\.]", "", value)
  100
+        try:
  101
+            int(value)
  102
+        except ValueError:
  103
+            raise ValidationError("This field requires only numbers")
  104
+        if len(value) != 14:
  105
+            raise ValidationError(
  106
+                gettext("This field requires at least 14 digits"))
  107
+        orig_dv = value[-2:]
  108
+
  109
+        new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))])
  110
+        new_1dv = DV_maker(new_1dv % 11)
  111
+        value = value[:-2] + str(new_1dv) + value[-1]
  112
+        new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(range(6, 1, -1) + range(9, 1, -1))])
  113
+        new_2dv = DV_maker(new_2dv % 11)
  114
+        value = value[:-1] + str(new_2dv)
  115
+        if value[-2:] != orig_dv:
  116
+            raise ValidationError(gettext("Invalid CNPJ number"))
  117
+
  118
+        return orig_value
  119
+
34  tests/regressiontests/forms/localflavor.py
@@ -840,6 +840,40 @@
840 840
 >>> f.clean('12345-123')
841 841
 u'12345-123'
842 842
 
  843
+# BRCNPJField ############################################################
  844
+
  845
+>>> from django.contrib.localflavor.br.forms import BRCNPJField
  846
+>>> f = BRCNPJField(required=True)
  847
+>>> f.clean('')
  848
+Traceback (most recent call last):
  849
+...
  850
+ValidationError: [u'This field is required.']
  851
+>>> f.clean('12-345-678/9012-10')
  852
+Traceback (most recent call last):
  853
+...
  854
+ValidationError: [u'Invalid CNPJ number']
  855
+>>> f.clean('12.345.678/9012-10')
  856
+Traceback (most recent call last):
  857
+...
  858
+ValidationError: [u'Invalid CNPJ number']
  859
+>>> f.clean('12345678/9012-10')
  860
+Traceback (most recent call last):
  861
+...
  862
+ValidationError: [u'Invalid CNPJ number']
  863
+>>> f.clean('64.132.916/0001-88')
  864
+'64.132.916/0001-88'
  865
+>>> f.clean('64-132-916/0001-88')
  866
+'64-132-916/0001-88'
  867
+>>> f.clean('64132916/0001-88')
  868
+'64132916/0001-88'
  869
+>>> f.clean('64.132.916/0001-XX')
  870
+Traceback (most recent call last):
  871
+...
  872
+ValidationError: [u'This field requires only numbers']
  873
+>>> f = BRCNPJField(required=False)
  874
+>>> f.clean('')
  875
+u''
  876
+
843 877
 # BRPhoneNumberField #########################################################
844 878
 
845 879
 >>> from django.contrib.localflavor.br.forms import BRPhoneNumberField

0 notes on commit 6c02565

Please sign in to comment.
Something went wrong with that request. Please try again.