| | 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 value |
| | 72 | |