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

Add BRCellPhoneField and BRLandLineField to standardize phone numbers #471

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions docs/authors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,4 @@ Authors
* Vishal Pandey
* Vladimir Nani
* Abhineet Tamrakar
* Leonardo Paz Estevam
2 changes: 2 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ New fields for existing flavors:
(`gh-457 <https://github.com/django/django-localflavor/pull/457>`_).
- Added the Canadian Models fields.
(`gh-465 <https://github.com/django/django-localflavor/pull/465>`_).
- Added Cellphone and Landline fields in Brazilian flavor.
(`gh-471 <https://github.com/django/django-localflavor/pull/471>`_)

Modifications to existing flavors:

Expand Down
35 changes: 33 additions & 2 deletions localflavor/br/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.utils.translation import gettext_lazy as _

from .br_states import STATE_CHOICES
from .validators import BRCNPJValidator, BRCPFValidator, BRPostalCodeValidator
from .validators import BRCNPJValidator, BRCPFValidator, BRLandLineValidator, BRPostalCodeValidator, BRCellPhoneValidator

process_digits_re = re.compile(
r'^(\d{7})-?(\d{2})\.?(\d{4})\.?(\d)\.?(\d{2})\.?(\d{4})$'
Expand Down Expand Up @@ -156,4 +156,35 @@ def clean(self, value):
if str(mod_97_base10(value_without_digits)).zfill(2) != orig_dv:
raise ValidationError(self.error_messages['invalid'], code='invalid')

return orig_value
return orig_value

class BRCellPhoneField(CharField):
"""
A form field that validates a Cell Phone number.

More information:
https://www.gov.br/anatel/pt-br/regulado/numeracao/tabela-servico-movel-celular
"""

default_error_messages = {
'invalid': _("Invalid Cell Phone, number needs to be in the format (XX)XXXXX-XXXX."),
}

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.validators.append(BRCellPhoneValidator())

class BRLandLineField(CharField):
"""
A form field that validates a Landline number.

More information:
https://www.gov.br/anatel/pt-br/regulado/numeracao/tabela-servico-telefonico-fixo-comutado
"""
default_error_messages = {
'invalid': _("Invalid Landline, number needs to be in the format (XX)XXXX-XXXX."),
}

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.validators.append(BRLandLineValidator())
24 changes: 24 additions & 0 deletions localflavor/br/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,27 @@ def __init__(self, *args, **kwargs):
kwargs['max_length'] = 9
super().__init__(*args, **kwargs)
self.validators.append(validators.BRPostalCodeValidator())

class BRLandLineField(CharField):
"""
A model field for brazilian LandLine number

"""
description = _("Landline Number")

def __init__(self, *args, **kwargs):
kwargs['max_length'] = 14
super().__init__(*args, **kwargs)
self.validators.append(validators.BRLandLineValidator())

class BRCellPhoneField(CharField):
"""
A model field for brazilian Cell Phone number

"""
description = _("Cell Phone Number")

def __init__(self, *args, **kwargs):
kwargs['max_length'] = 15
super().__init__(*args, **kwargs)
self.validators.append(validators.BRCellPhoneValidator())
27 changes: 26 additions & 1 deletion localflavor/br/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
postal_code_re = re.compile(r'^\d{5}-\d{3}$')
cnpj_digits_re = re.compile(r'^(\d{2})[.-]?(\d{3})[.-]?(\d{3})/(\d{4})-(\d{2})$')
cpf_digits_re = re.compile(r'^(\d{3})\.(\d{3})\.(\d{3})-(\d{2})$')
landline_number_re = re.compile(r'^[(][1-9][1-9][)][2-5]\d{3}-\d{4}$')
cell_phone_number_re = re.compile(r'^[(][1-9][1-9][)]9\d{4}-\d{4}$')


def dv_maker(v):
Expand Down Expand Up @@ -103,4 +105,27 @@ def __call__(self, value):
if value[-2:] != orig_dv:
raise ValidationError(self.message, code='invalid')
if value.count(value[0]) == 11:
raise ValidationError(self.message, code='invalid')
raise ValidationError(self.message, code='invalid')


class BRLandLineValidator(RegexValidator):
"""
Validator for brazilian LandLine number.

"""
def __init__(self, *args, **kwargs):
super().__init__(*args,
regex = landline_number_re,
message = _("Invalid Landline, number needs to be in the format (XX)XXXX-XXXX."),
**kwargs)

class BRCellPhoneValidator(RegexValidator):
"""
Validator for brazilian Cell Phone number.

"""
def __init__(self, *args, **kwargs):
super().__init__(*args,
regex = cell_phone_number_re,
message = _("Invalid Cell Phone, number needs to be in the format (XX)XXXXX-XXXX."),
**kwargs)
35 changes: 32 additions & 3 deletions tests/test_br/test_br.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from django.test import SimpleTestCase

from localflavor.br import models
from localflavor.br.forms import (BRCNPJField, BRCPFField, BRProcessoField, BRStateChoiceField, BRStateSelect,
BRZipCodeField)
from localflavor.br.forms import (BRCNPJField, BRCPFField, BRLandLineField, BRProcessoField, BRStateChoiceField, BRStateSelect,
BRZipCodeField, BRCellPhoneField)
from tests.test_br.forms import BRPersonProfileForm


Expand Down Expand Up @@ -222,7 +222,36 @@ def test_model_form_valid(self):

for case in data_to_test:
form = BRPersonProfileForm(case)
self.assertTrue(form.is_valid())
self.assertTrue(form.is_valid())

def test_CellPhoneField(self):
error_format = ["Invalid Cell Phone, number needs to be in the format (XX)XXXXX-XXXX."]
valid = {
'(11)99919-2696': '(11)99919-2696',
}
invalid = {
'(08)99919-2696': error_format,
'(11)89919-2696': error_format,
'(ab)cdefg-hijk': error_format,
'(11)99919 2696': error_format,
'(11) 99919-2696': error_format,
}
self.assertFieldOutput(BRCellPhoneField, valid, invalid)

def test_LandLineField(self):
error_format = ['Invalid Landline, number needs to be in the format (XX)XXXX-XXXX.']
valid = {
'(11)3223-3946': '(11)3223-3946',
}
invalid = {
'(08)99919-2696': error_format,
'(11)6919-2696': error_format,
'(ab)cdefg-hijk': error_format,
'(11)3919 2696': error_format,
'(11) 3919-2696': error_format,
}
self.assertFieldOutput(BRLandLineField, valid, invalid)



class BRLocalFlavorModelTests(SimpleTestCase):
Expand Down