Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added local-flavor support for Cuba #292

Closed
wants to merge 16 commits into from
Closed
1 change: 1 addition & 0 deletions docs/authors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Authors
* Aaron Boman
* Adam Taylor
* Adnane Belmadiaf
* Adonys Alea Boffill
* Adrian Holovaty
* Agustín Scaramuzza
* Alex Butum
Expand Down
3 changes: 2 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Changelog

New flavors:

- None
- Added local flavor for Cuba
(`gh-292 <https://github.com/django/django-localflavor/pull/292>`_)

New fields for existing flavors:

Expand Down
Empty file added localflavor/cu/__init__.py
Empty file.
111 changes: 111 additions & 0 deletions localflavor/cu/choices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.utils.translation import ugettext_lazy as _

#: List of regions, from west to east
REGION_CHOICES = (
('OCC', _('Occidental')),
('CTL', _('Central')),
('OTL', _('Oriental')),
)

#: Normalized versions of regions
REGION_NORMALIZED = {
'occ': 'OCC',
'occidente': 'OCC',
'occidental': 'OCC',
'ctl': 'CTL',
'centro': 'CTL',
'central': 'CTL',
'otl': 'OTL',
'oriente': 'OTL',
'oriental': 'OTL',
}

#: List of provinces, from west to east
PROVINCE_CHOICES = (
('PRI', _('Pinar del Río')),
('ART', _('Artemisa')),
('MAY', _('Mayabeque')),
('HAB', _('La Habana')),
('MTZ', _('Matanzas')),
('CFG', _('Cienfuegos')),
('VCL', _('Villa Clara')),
('SSP', _('Sancti Spíritus')),
('CAV', _('Ciego de Ávila')),
('CMG', _('Camagüey')),
('LTU', _('Las Tunas')),
('HOL', _('Holguín')),
('GRA', _('Granma')),
('SCU', _('Santiago de Cuba')),
('GTM', _('Guantánamo')),
('IJV', _('Isla de la Juventud')),
)

#: Normalized versions of provinces
PROVINCE_NORMALIZED = {
'pr': 'PRI',
'pri': 'PRI',
'pinar': 'PRI',
'pinar del rio': 'PRI',
'pinar del río': 'PRI',
'ar': 'ART',
'art': 'ART',
'artemisa': 'ART',
'may': 'MAY',
'mayabeque': 'MAY',
'h': 'HAB',
'hab': 'HAB',
'lha': 'HAB',
'habana': 'HAB',
'la habana': 'HAB',
'ciudad de la habana': 'HAB',
'mt': 'MTZ',
'mtz': 'MTZ',
'matanzas': 'MTZ',
'cf': 'CFG',
'cfg': 'CFG',
'cienfuegos': 'CFG',
'vc': 'VCL',
'vcl': 'VCL',
'las villas': 'VCL',
'villa clara': 'VCL',
'ss': 'SSP',
'ssp': 'SSP',
's spiritus': 'SSP',
's. spiritus': 'SSP',
'sancti spiritus': 'SSP',
'sancti spíritus': 'SSP',
'ca': 'CAV',
'cav': 'CAV',
'ciego': 'CAV',
'ciego de avila': 'CAV',
'ciego de ávila': 'CAV',
'cmg': 'CMG',
'camaguey': 'CMG',
'camagüey': 'CMG',
'lt': 'LTU',
'ltu': 'LTU',
'tunas': 'LTU',
'las tunas': 'LTU',
'hol': 'HOL',
'holguin': 'HOL',
'holguín': 'HOL',
'gr': 'GRA',
'gra': 'GRA',
'grm': 'GRA',
'granma': 'GRA',
'sc': 'SCU',
'scu': 'SCU',
'santiago': 'SCU',
'santiago de cuba': 'SCU',
'GTM': 'GTM',
'guantanamo': 'GTM',
'guantánamo': 'GTM',
'ij': 'IJV',
'ijv': 'IJV',
'la isla': 'IJV',
'isla de la juventud': 'IJV',
'la isla de la juventud': 'IJV',
}
143 changes: 143 additions & 0 deletions localflavor/cu/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.core.exceptions import ValidationError
from django.forms import Field, RegexField, Select
from django.utils.translation import ugettext as _

from localflavor.compat import EmptyValueCompatMixin

from .choices import PROVINCE_CHOICES, PROVINCE_NORMALIZED, REGION_CHOICES, REGION_NORMALIZED
from .validators import CUIdentityCardNumberBirthdayValidator


class CURegionField(Field):
"""
A form field for a Cuban region.
The input is validated against a dictionary which includes names and abbreviations.

It normalizes the input to the standard abbreviation for the given region.

.. versionadded:: 1.6
"""

default_error_messages = {
'invalid': _('Enter a Cuban region.'),
}

def clean(self, value):
super(CURegionField, self).clean(value)
if value in self.empty_values:
return ''
try:
return REGION_NORMALIZED[value.strip().lower()]
except KeyError:
pass
raise ValidationError(self.error_messages['invalid'])


class CURegionSelect(Select):
"""
A Select widget that uses a list of Cuban regions as its choices.

.. versionadded:: 1.6
"""

def __init__(self, attrs=None):
super(CURegionSelect, self).__init__(attrs, choices=REGION_CHOICES)


class CUProvinceField(Field):
"""
A form field for a Cuban province.
The input is validated against a dictionary which includes names and abbreviations.

It normalizes the input to the standard abbreviation for the given province.

.. versionadded:: 1.6
"""

default_error_messages = {
'invalid': _('Enter a Cuban province.'),
}

def clean(self, value):
super(CUProvinceField, self).clean(value)
if value in self.empty_values:
return ''
try:
return PROVINCE_NORMALIZED[value.strip().lower()]
except KeyError:
pass
raise ValidationError(self.error_messages['invalid'])


class CUProvinceSelect(Select):
"""
A Select widget that uses a list of Cuban provinces as its choices.

.. versionadded:: 1.6
"""

def __init__(self, attrs=None):
super(CUProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)


class CUPostalCodeField(EmptyValueCompatMixin, RegexField):
"""
A form field for a Cuban postal Code.

Taken from : http://mapanet.eu/Postal_Codes/?C=CU

The Cuban postal code is a combination of 5 digits non begin with 0.

.. versionadded:: 1.6
"""

default_error_messages = {
'invalid': _('Enter a valid postal code in the format XXXXX.'),
}

def __init__(self, *args, **kwargs):
super(CUPostalCodeField, self).__init__(r'^[1-9]\d{4}$', *args, **kwargs)

def to_python(self, value):
value = super(CUPostalCodeField, self).to_python(value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to add localflavor.compat.EmptyValueCompatMixin to this class and add this python code:

if value in self.empty_values:
    return value

This comes from a recent change that was made to properly support Django >= 1.11 (#298). You can search through the other localflavor modules to see examples of how to set this up if you're not sure.

if value in self.empty_values:
return self.empty_value
return value.strip()


class CUIdentityCardNumberField(EmptyValueCompatMixin, RegexField):
"""
A form field for a Cuban identity card number.

Taken from : http://www.postdata.club/issues/201609/es-usted-unico-en-cuba.html

The Cuban identity card number is generated by a mathematical algorithm following those rules:
- Combination of 11 digits.
- The first 6 digits represents the birthday of the owner.
-> '%y%m%d' format, ex: `860619`
- 7th digit represent the century.
-> 9 for XIX
-> 0-5 for XX
-> 6, 7 and 8 for XXI
- 8th, 9th and 11th aleatory.
- 10th represent the sex of the owner. Male for the even numbers and Female for odd numbers.

.. versionadded:: 1.6
"""

default_error_messages = {
'invalid': _('Enter a valid identity card number in the format XXXXXXXXXXX.'),
}

def __init__(self, *args, **kwargs):
super(CUIdentityCardNumberField, self).__init__(r'^\d{11}$', *args, **kwargs)
self.validators.append(CUIdentityCardNumberBirthdayValidator())

def to_python(self, value):
value = super(CUIdentityCardNumberField, self).to_python(value)
if value in self.empty_values:
return self.empty_value
return value.strip()
95 changes: 95 additions & 0 deletions localflavor/cu/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db.models import CharField
from django.utils.translation import ugettext as _

from .choices import PROVINCE_CHOICES, REGION_CHOICES
from .forms import CUIdentityCardNumberField as CUIdentityCardNumberFormField
from .forms import CUPostalCodeField as CUPostalCodeFormField


class CURegionField(CharField):
"""
A model field for the three-letter of the Cuban region abbreviation.

Forms represent it as a ``forms.CURegionField``.

.. versionadded:: 1.6
"""

description = _("Cuban regions (three uppercase letters)")

def __init__(self, *args, **kwargs):
kwargs['choices'] = REGION_CHOICES
kwargs['max_length'] = 3
super(CURegionField, self).__init__(*args, **kwargs)

def deconstruct(self):
name, path, args, kwargs = super(CURegionField, self).deconstruct()
del kwargs['choices']
return name, path, args, kwargs


class CUProvinceField(CharField):
"""
A model field for the three-letter of the Cuban province abbreviation in the database.

Forms represent it as a ``forms.CUProvinceField``.

.. versionadded:: 1.6
"""

description = _("Cuban provinces (three uppercase letters)")

def __init__(self, *args, **kwargs):
kwargs['choices'] = PROVINCE_CHOICES
kwargs['max_length'] = 3
super(CUProvinceField, self).__init__(*args, **kwargs)

def deconstruct(self):
name, path, args, kwargs = super(CUProvinceField, self).deconstruct()
del kwargs['choices']
return name, path, args, kwargs


class CUPostalCodeField(CharField):
"""
A model field for the Cuban postal code.

Forms represent it as a ``forms.CUPostalCodeField``.

.. versionadded:: 1.6
"""

description = _("Cuban postal code")

def __init__(self, *args, **kwargs):
kwargs['max_length'] = 5
super(CUPostalCodeField, self).__init__(*args, **kwargs)

def formfield(self, **kwargs):
defaults = {'form_class': CUPostalCodeFormField}
defaults.update(kwargs)
return super(CUPostalCodeField, self).formfield(**defaults)


class CUIdentityCardNumberField(CharField):
"""
A model field for the Cuban identity card number.

Forms represent it as a ``forms.CUIdentityCardNumberField``.

.. versionadded:: 1.6
"""

description = _("Cuban identity card number")

def __init__(self, *args, **kwargs):
kwargs['max_length'] = 11
super(CUIdentityCardNumberField, self).__init__(*args, **kwargs)

def formfield(self, **kwargs):
defaults = {'form_class': CUIdentityCardNumberFormField}
defaults.update(kwargs)
return super(CUIdentityCardNumberField, self).formfield(**defaults)
Loading