Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #3890 -- Added USSocialSecurityNumberField. Thanks James Bennet.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@4910 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit a5938f350ca65fdfbe22050c1a04ba8a99e87854 1 parent b6264d0
Malcolm Tredinnick authored
42  django/contrib/localflavor/usa/forms.py
@@ -9,6 +9,7 @@
9 9
 import re
10 10
 
11 11
 phone_digits_re = re.compile(r'^(?:1-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$')
  12
+ssn_re = re.compile(r"^(?P<area>\d{3})[-\ ]?(?P<group>\d{2})[-\ ]?(?P<serial>\d{4})$")
12 13
 
13 14
 class USZipCodeField(RegexField):
14 15
     def __init__(self, *args, **kwargs):
@@ -28,6 +29,47 @@ def clean(self, value):
28 29
             return u'%s-%s-%s' % (m.group(1), m.group(2), m.group(3))
29 30
         raise ValidationError(u'Phone numbers must be in XXX-XXX-XXXX format.')
30 31
 
  32
+class USSocialSecurityNumberField(Field):
  33
+    """
  34
+    A United States Social Security number.
  35
+    
  36
+    Checks the following rules to determine whether the number is valid:
  37
+    
  38
+        * Conforms to the XXX-XX-XXXX format.
  39
+        * No group consists entirely of zeroes.
  40
+        * The leading group is not "666" (block "666" will never be allocated).
  41
+        * The number is not in the promotional block 987-65-4320 through 987-65-4329,
  42
+          which are permanently invalid.
  43
+        * The number is not one known to be invalid due to otherwise widespread
  44
+          promotional use or distribution (e.g., the Woolworth's number or the 1962
  45
+          promotional number).
  46
+    
  47
+    """
  48
+    def clean(self, value):
  49
+        super(USSocialSecurityNumberField, self).clean(value)
  50
+        if value in EMPTY_VALUES:
  51
+            return u''
  52
+        msg = gettext(u'Enter a valid US Social Security number in XXX-XX-XXXX format')
  53
+        match = re.match(ssn_re, value)
  54
+        if not match:
  55
+            raise ValidationError(msg)
  56
+        area, group, serial = match.groupdict()['area'], match.groupdict()['group'], match.groupdict()['serial']
  57
+        
  58
+        # First pass: no blocks of all zeroes.
  59
+        if area == '000' or \
  60
+           group == '00' or \
  61
+           serial == '0000':
  62
+            raise ValidationError(msg)
  63
+        
  64
+        # Second pass: promotional and otherwise permanently invalid numbers.
  65
+        if area == '666' or \
  66
+           (area == '987' and group == '65' and \
  67
+            4320 <= int(serial) <= 4329) or \
  68
+           value == '078-05-1120' or \
  69
+           value == '219-09-9999':
  70
+            raise ValidationError(msg)
  71
+        return u'%s-%s-%s' % (area, group, serial)
  72
+
31 73
 class USStateField(Field):
32 74
     """
33 75
     A form field that validates its input is a U.S. state name or abbreviation.
12  tests/regressiontests/forms/localflavor.py
@@ -246,6 +246,18 @@
246 246
 <option value="WY">Wyoming</option>
247 247
 </select>
248 248
 
  249
+# USSocialSecurityNumberField #################################################
  250
+>>> from django.contrib.localflavor.usa.forms import USSocialSecurityNumberField
  251
+>>> f = USSocialSecurityNumberField()
  252
+>>> f.clean('987-65-4330')
  253
+u'987-65-4330'
  254
+>>> f.clean('987654330')
  255
+u'987-65-4330'
  256
+>>> f.clean('078-05-1120')
  257
+Traceback (most recent call last):
  258
+...
  259
+ValidationError: [u'Enter a valid US Social Security number in XXX-XX-XXXX format']
  260
+
249 261
 # UKPostcodeField #############################################################
250 262
 
251 263
 UKPostcodeField validates that the data is a valid UK postcode.

0 notes on commit a5938f3

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