From 3825bb2350d9547622a9d1201ced9743e21783ee Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Fri, 1 Jan 2010 21:31:47 +0000 Subject: [PATCH] Fixed #10736 - Added Uruguayan (uy) localflavor. Thanks to Gonzalo Saavedra for providing the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@12041 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- AUTHORS | 1 + django/contrib/localflavor/uy/__init__.py | 0 django/contrib/localflavor/uy/forms.py | 59 +++++++++++++++++++ django/contrib/localflavor/uy/util.py | 12 ++++ .../contrib/localflavor/uy/uy_departaments.py | 24 ++++++++ docs/ref/contrib/localflavor.txt | 14 +++++ tests/regressiontests/forms/localflavor/uy.py | 46 +++++++++++++++ tests/regressiontests/forms/tests.py | 2 + 8 files changed, 158 insertions(+) create mode 100644 django/contrib/localflavor/uy/__init__.py create mode 100644 django/contrib/localflavor/uy/forms.py create mode 100644 django/contrib/localflavor/uy/util.py create mode 100644 django/contrib/localflavor/uy/uy_departaments.py create mode 100644 tests/regressiontests/forms/localflavor/uy.py diff --git a/AUTHORS b/AUTHORS index 2788e4b22a..cc459fa4b4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -383,6 +383,7 @@ answer newbie questions, and generally made Django that much better: Rozza Oliver Rutherfurd ryankanno + Gonzalo Saavedra Manuel Saelices Ivan Sagalaev (Maniac) Vinay Sajip diff --git a/django/contrib/localflavor/uy/__init__.py b/django/contrib/localflavor/uy/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/localflavor/uy/forms.py b/django/contrib/localflavor/uy/forms.py new file mode 100644 index 0000000000..5b47ba1e24 --- /dev/null +++ b/django/contrib/localflavor/uy/forms.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +""" +UY-specific form helpers. +""" +import re + +from django.forms.fields import Select, RegexField, EMPTY_VALUES +from django.forms import ValidationError +from django.utils.translation import ugettext_lazy as _ +from django.contrib.localflavor.uy.util import get_validation_digit + + +class UYDepartamentSelect(Select): + """ + A Select widget that uses a list of Uruguayan departaments as its choices. + """ + def __init__(self, attrs=None): + from uy_departaments import DEPARTAMENT_CHOICES + super(UYDepartamentSelect, self).__init__(attrs, choices=DEPARTAMENT_CHOICES) + + +class UYCIField(RegexField): + """ + A field that validates Uruguayan 'Cedula de identidad' (CI) numbers. + """ + default_error_messages = { + 'invalid': _("Enter a valid CI number in X.XXX.XXX-X," + "XXXXXXX-X or XXXXXXXX format."), + 'invalid_validation_digit': _("Enter a valid CI number."), + } + + def __init__(self, *args, **kwargs): + super(UYCIField, self).__init__(r'(?P(\d{6,7}|(\d\.)?\d{3}\.\d{3}))-?(?P\d)', + *args, **kwargs) + + def clean(self, value): + """ + Validates format and validation digit. + + The official format is [X.]XXX.XXX-X but usually dots and/or slash are + omitted so, when validating, those characters are ignored if found in + the correct place. The three typically used formats are supported: + [X]XXXXXXX, [X]XXXXXX-X and [X.]XXX.XXX-X. + """ + + value = super(UYCIField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + match = self.regex.match(value) + if not match: + raise ValidationError(self.error_messages['invalid']) + + number = int(match.group('num').replace('.', '')) + validation_digit = int(match.group('val')) + + if not validation_digit == get_validation_digit(number): + raise ValidationError(self.error_messages['invalid_validation_digit']) + + return value diff --git a/django/contrib/localflavor/uy/util.py b/django/contrib/localflavor/uy/util.py new file mode 100644 index 0000000000..0c1a8f84be --- /dev/null +++ b/django/contrib/localflavor/uy/util.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +def get_validation_digit(number): + """ Calculates the validation digit for the given number. """ + sum = 0 + dvs = [4, 3, 6, 7, 8, 9, 2] + number = str(number) + + for i in range(0, len(number)): + sum = (int(number[-1 - i]) * dvs[i] + sum) % 10 + + return (10-sum) % 10 diff --git a/django/contrib/localflavor/uy/uy_departaments.py b/django/contrib/localflavor/uy/uy_departaments.py new file mode 100644 index 0000000000..97795f8e82 --- /dev/null +++ b/django/contrib/localflavor/uy/uy_departaments.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +"""A list of Urguayan departaments as `choices` in a formfield.""" + +DEPARTAMENT_CHOICES = ( + ('G', u'Artigas'), + ('A', u'Canelones'), + ('E', u'Cerro Largo'), + ('L', u'Colonia'), + ('Q', u'Durazno'), + ('N', u'Flores'), + ('O', u'Florida'), + ('P', u'Lavalleja'), + ('B', u'Maldonado'), + ('S', u'Montevideo'), + ('I', u'Paysandú'), + ('J', u'Río Negro'), + ('F', u'Rivera'), + ('C', u'Rocha'), + ('H', u'Salto'), + ('M', u'San José'), + ('K', u'Soriano'), + ('R', u'Tacuarembó'), + ('D', u'Treinta y Tres'), +) diff --git a/docs/ref/contrib/localflavor.txt b/docs/ref/contrib/localflavor.txt index 660b7c623b..1eafa9fac1 100644 --- a/docs/ref/contrib/localflavor.txt +++ b/docs/ref/contrib/localflavor.txt @@ -65,6 +65,7 @@ Countries currently supported by :mod:`~django.contrib.localflavor` are: * Switzerland_ * `United Kingdom`_ * `United States of America`_ + * Uruguay_ The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage, containing useful code that is not specific to one particular country or culture. @@ -106,6 +107,7 @@ Here's an example of how to use them:: .. _Switzerland: `Switzerland (ch)`_ .. _United Kingdom: `United Kingdom (uk)`_ .. _United States of America: `United States of America (us)`_ +.. _Uruguay: `Uruguay (uy)`_ Adding flavors ============== @@ -738,3 +740,15 @@ United States of America (``us``) A model field that forms represent as a ``forms.USStateField`` field and stores the two-letter U.S. state abbreviation in the database. + +Uruguay (``uy``) +================ + +.. class:: uy.forms.UYCIField + + A field that validates Uruguayan 'Cedula de identidad' (CI) numbers. + +.. class:: uy.forms.UYDepartamentSelect + + A ``Select`` widget that uses a list of Uruguayan departaments as its + choices. diff --git a/tests/regressiontests/forms/localflavor/uy.py b/tests/regressiontests/forms/localflavor/uy.py new file mode 100644 index 0000000000..057ab193f5 --- /dev/null +++ b/tests/regressiontests/forms/localflavor/uy.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# Tests for the contrib/localflavor/ UY form fields. + +tests = r""" +# UYDepartamentSelect ######################################################### + +>>> from django.contrib.localflavor.uy.forms import UYDepartamentSelect +>>> f = UYDepartamentSelect() +>>> f.render('departamentos', 'S') +u'' + +# UYCIField ################################################################### + +>>> from django.contrib.localflavor.uy.util import get_validation_digit +>>> get_validation_digit(409805) == 3 +True +>>> get_validation_digit(1005411) == 2 +True + +>>> from django.contrib.localflavor.uy.forms import UYCIField +>>> f = UYCIField() +>>> f.clean('4098053') +u'4098053' +>>> f.clean('409805-3') +u'409805-3' +>>> f.clean('409.805-3') +u'409.805-3' +>>> f.clean('10054112') +u'10054112' +>>> f.clean('1005411-2') +u'1005411-2' +>>> f.clean('1.005.411-2') +u'1.005.411-2' +>>> f.clean('foo') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid CI number in X.XXX.XXX-X,XXXXXXX-X or XXXXXXXX format.'] +>>> f.clean('409805-2') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid CI number.'] +>>> f.clean('1.005.411-5') +Traceback (most recent call last): +... +ValidationError: [u'Enter a valid CI number.'] +""" diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 18deb20242..0c70cf49aa 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -25,6 +25,7 @@ from localflavor.se import tests as localflavor_se_tests from localflavor.sk import tests as localflavor_sk_tests from localflavor.uk import tests as localflavor_uk_tests from localflavor.us import tests as localflavor_us_tests +from localflavor.uy import tests as localflavor_uy_tests from localflavor.za import tests as localflavor_za_tests from regressions import tests as regression_tests from util import tests as util_tests @@ -61,6 +62,7 @@ __test__ = { 'localflavor_sk_tests': localflavor_sk_tests, 'localflavor_uk_tests': localflavor_uk_tests, 'localflavor_us_tests': localflavor_us_tests, + 'localflavor_uy_tests': localflavor_uy_tests, 'localflavor_za_tests': localflavor_za_tests, 'regression_tests': regression_tests, 'formset_tests': formset_tests,