From aa888083b5a2c867d41dec80c31fc544dbf8e3d5 Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Thu, 9 Mar 2017 22:34:17 +0330 Subject: [PATCH 1/7] init and provonce_choices --- localflavor/ir/__init__.py | 0 localflavor/ir/forms.py | 0 localflavor/ir/ir_provinces.py | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 localflavor/ir/__init__.py create mode 100644 localflavor/ir/forms.py create mode 100644 localflavor/ir/ir_provinces.py diff --git a/localflavor/ir/__init__.py b/localflavor/ir/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/localflavor/ir/forms.py b/localflavor/ir/forms.py new file mode 100644 index 000000000..e69de29bb diff --git a/localflavor/ir/ir_provinces.py b/localflavor/ir/ir_provinces.py new file mode 100644 index 000000000..1761ff291 --- /dev/null +++ b/localflavor/ir/ir_provinces.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.utils.translation import ugettext_lazy as _ + +#: A list of Iranian provinces according to https://en.wikipedia.org/wiki/Provinces_of_Iran +PROVINCE_CHOICES = ( + ('ALB', _('Alborz')), + ('ARD', _('Ardabil')), + ('AZE', _('Azerbaijan, East')), + ('AZW', _('Azerbaijan, West')), + ('BSH', _('Bushehr')), + ('CMB', _('Chahar Mahaal and Bakhtiari')), + ('FAR', _('Fars')), + ('GIL', _('Gilan')), + ('GOL', _('Golestan')), + ('HAM', _('Hamadan')), + ('HOR'), _('Hormozgān'), + ('ILA', _('Ilam')), + ('ISF', _('Isfahan')), + ('KES', _('Kerman')), + ('KER', _('Kermanshah')), + ('KHN', _('Khorasan, North')), + ('KHR', _('Khorasan, Razavi')), + ('KHS', _('Khorasan, South')), + ('KHU', _('Khuzestan')), + ('KBA', _('Kohgiluyeh and Boyer-Ahmad')), + ('KUR', _('Kurdistan')), + ('LOR', _('Lorestan')), + ('Mar', _('Markazi')), + ('MAZ', _('Mazandaran')), + ('QAZ', _('Qazvin')), + ('QOM', _('Qom')), + ('SEM', _('Semnan')), + ('SBA'), _('Sistan and Baluchestan'), + ('TEH', _('Tehran')), + ('YZD', _('Yazd')), + ('ZNJ', _('Zanjan')) +) From fe9066f000d9481503221a3acff6ced75ed03f5b Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Thu, 9 Mar 2017 22:54:54 +0330 Subject: [PATCH 2/7] IRProvinceSelect class and IRhoneNumberField class in Forms --- localflavor/ir/forms.py | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/localflavor/ir/forms.py b/localflavor/ir/forms.py index e69de29bb..3a3b37c2c 100644 --- a/localflavor/ir/forms.py +++ b/localflavor/ir/forms.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +"""IR-specific Form helpers.""" + +from __future__ import unicode_literals +import re + +from django.core.validators import EMPTY_VALUES +from django.forms import ValidationError +from django.forms.fields import CharField,Select +from django.utils.encoding import force_text + +from localflavor.generic.forms import DeprecatedPhoneNumberFormFieldMixin +from .ir_provinces import PROVINCE_CHOICES + +PHONE_DIGITS_RE = re.compile(r'^(\d{10})$') + + + + + + +class IRProvinceSelect(Select): + """A Select widget that uses a list of Iranian provinces/autonomous cities as its choices.""" + + def __init__(self, attrs=None): + super(IRProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES) + + + + +class IRhoneNumberField(CharField, DeprecatedPhoneNumberFormFieldMixin): + """ + A form field that validates input as an Iranian phone number. + + Valid numbers have ten digits. + """ + + default_error_messages = { + 'invalid': 'Phone numbers must contain 10 digits.', + } + + def clean(self, value): + """Validate a phone number. Strips parentheses, whitespace and hyphens.""" + super(IRhoneNumberField, self).clean(value) + if value in EMPTY_VALUES: + return '' + value = re.sub('(\(|\)|\s+|-)', '', force_text(value)) + phone_match = PHONE_DIGITS_RE.search(value) + if phone_match: + return '%s' % phone_match.group(1) + raise ValidationError(self.error_messages['invalid']) From 6ed8c14dbf9739dbd14a6fe8a83a42096049ad42 Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Thu, 9 Mar 2017 23:04:34 +0330 Subject: [PATCH 3/7] init and Updating ir.rst --- docs/localflavor/ir.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 docs/localflavor/ir.rst diff --git a/docs/localflavor/ir.rst b/docs/localflavor/ir.rst new file mode 100644 index 000000000..b21813f04 --- /dev/null +++ b/docs/localflavor/ir.rst @@ -0,0 +1,13 @@ +IRAN (``ir``) +=============== + +Forms +----- + +.. automodule:: localflavor.ir.forms + :members: + +Data +---- + +.. autodata:: localflavor.ir.ir_provinces.PROVINCE_CHOICES From a1defba0a7c7a5048eb8a56068c42ed9aab9d979 Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Thu, 9 Mar 2017 23:08:35 +0330 Subject: [PATCH 4/7] Add my name in author.rst --- docs/authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/authors.rst b/docs/authors.rst index ede3e6055..47538cffb 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -90,3 +90,4 @@ Authors * Tom Forbes * Venelin Stoykov * Vladimir Nani +* Sayed Mohammad Hossein Torabi From 9c7109bb137d55ba6c1ab1d2690a80b3f66db461 Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Fri, 10 Mar 2017 00:35:29 +0330 Subject: [PATCH 5/7] test --- tests/test_ir.py | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 tests/test_ir.py diff --git a/tests/test_ir.py b/tests/test_ir.py new file mode 100644 index 000000000..53f7125c7 --- /dev/null +++ b/tests/test_ir.py @@ -0,0 +1,132 @@ +from __future__ import unicode_literals + +from django.test import SimpleTestCase + +from localflavor.ar.forms import ARCBUField, ARCUITField, ARDNIField, ARPostalCodeField, ARProvinceSelect + + +class ARLocalFlavorTests(SimpleTestCase): + def test_ARProvinceSelect(self): + f = ARProvinceSelect() + out = '''''' + self.assertHTMLEqual(f.render('provincias', 'A'), out) + + def test_ARPostalCodeField(self): + error_format = ['Enter a postal code in the format NNNN or ANNNNAAA.'] + error_atmost = ['Ensure this value has at most 8 characters (it has 9).'] + error_atleast = ['Ensure this value has at least 4 characters (it has 3).'] + valid = { + '5000': '5000', + 'C1064AAB': 'C1064AAB', + 'c1064AAB': 'C1064AAB', + 'C1064aab': 'C1064AAB', + '4400': '4400', + 'C1064AAB': 'C1064AAB', + } + invalid = { + 'C1064AABB': error_atmost + error_format, + 'C1064AA': error_format, + 'C1064AB': error_format, + '106AAB': error_format, + '500': error_atleast + error_format, + '5PPP': error_format, + } + self.assertFieldOutput(ARPostalCodeField, valid, invalid) + + def test_ARDNIField(self): + error_length = ['This field requires 7 or 8 digits.'] + error_digitsonly = ['This field requires only numbers.'] + valid = { + '20123456': '20123456', + '20.123.456': '20123456', + '20123456': '20123456', + '20.123.456': '20123456', + '20.123456': '20123456', + '9123456': '9123456', + '9.123.456': '9123456', + } + invalid = { + '101234566': error_length, + 'W0123456': error_digitsonly, + '10,123,456': error_digitsonly, + } + self.assertFieldOutput(ARDNIField, valid, invalid) + + def test_ARCUITField(self): + error_format = ['Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'] + error_invalid = ['Invalid CUIT.'] + error_legal_type = ['Invalid legal type. Type must be 27, 20, 30, 23, 24 or 33.'] + valid = { + '20-10123456-9': '20-10123456-9', + '20-10123456-9': '20-10123456-9', + '27-10345678-4': '27-10345678-4', + '20101234569': '20-10123456-9', + '27103456784': '27-10345678-4', + '30011111110': '30-01111111-0', + '24117166062': '24-11716606-2', + '33500001599': '33-50000159-9', + '23000052264': '23-00005226-4', + } + invalid = { + '2-10123456-9': error_format, + '210123456-9': error_format, + '20-10123456': error_format, + '20-10123456-': error_format, + '20-10123456-5': error_invalid, + '27-10345678-1': error_invalid, + '27-10345678-1': error_invalid, + '11211111110': error_legal_type, + } + self.assertFieldOutput(ARCUITField, valid, invalid) + + def test_ARCBUField(self): + error_format = ['Enter a valid CBU in XXXXXXXXXXXXXXXXXXXXXX format.'] + error_length = ['CBU must be exactly 22 digits long.'] + error_checksum = ['Invalid CBU.'] + valid = { + '2237628810898098715378': '2237628810898098715378', + '5433758936130717465023': '5433758936130717465023', + '5729195067928761667584': '5729195067928761667584', + '9498175528566296510521': '9498175528566296510521', + '7362966507842824472644': '7362966507842824472644', + '8693513393883886497274': '8693513393883886497274', + '1542952861593836535608': '1542952861593836535608', + '5833008953419074707467': '5833008953419074707467', + '9687027721961737239525': '9687027721961737239525', + '8048819274216931992586': '8048819274216931992586' + } + + invalid = { + 'abc123def456-9024-2313': error_format, + '142512591859898123123': error_length, + '12312452521512526125566': error_length, + '1234567891234567891234': error_checksum, + '1234562374545894589234': error_checksum, + '0987653759257883891234': error_checksum, + } + self.assertFieldOutput(ARCBUField, valid, invalid) From b4e3ce53e01213825b9f856d9d2fcdae822f717b Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Sat, 11 Mar 2017 17:03:45 +0330 Subject: [PATCH 6/7] Updating forms --- localflavor/ir/forms.py | 45 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/localflavor/ir/forms.py b/localflavor/ir/forms.py index 3a3b37c2c..a211c8add 100644 --- a/localflavor/ir/forms.py +++ b/localflavor/ir/forms.py @@ -1,21 +1,15 @@ # -*- coding: utf-8 -*- -"""IR-specific Form helpers.""" +"""AR-specific Form helpers.""" from __future__ import unicode_literals -import re from django.core.validators import EMPTY_VALUES from django.forms import ValidationError -from django.forms.fields import CharField,Select -from django.utils.encoding import force_text +from django.forms.fields import CharField, RegexField, Select +from django.utils.translation import ugettext_lazy as _ -from localflavor.generic.forms import DeprecatedPhoneNumberFormFieldMixin from .ir_provinces import PROVINCE_CHOICES -PHONE_DIGITS_RE = re.compile(r'^(\d{10})$') - - - @@ -28,24 +22,33 @@ def __init__(self, attrs=None): -class IRhoneNumberField(CharField, DeprecatedPhoneNumberFormFieldMixin): +class IRPostlCodeField(RegexField): """ - A form field that validates input as an Iranian phone number. + A field that accepts a 'classic' XXXXXXXXXX Postal Code o. - Valid numbers have ten digits. - """ + See: + https://en.wikipedia.org/wiki/List_of_postal_codes + """ default_error_messages = { - 'invalid': 'Phone numbers must contain 10 digits.', + 'invlid': _("Enter a postal code in the format xxxxxxxxxx") } + def __init__(self, max_length=10, min_length=11, *args, **kwargs): + super(IRPostlCodeField,self).__init__(r'^\d{4}$|^[A-HJ-NP-Za-hj-np-z]\d{4}\D{3}$', + max_length, + min_length, + *args, + **kwargs + ) + def clean(self, value): - """Validate a phone number. Strips parentheses, whitespace and hyphens.""" - super(IRhoneNumberField, self).clean(value) + value = super(IRPostlCodeField,self).clean(value) if value in EMPTY_VALUES: return '' - value = re.sub('(\(|\)|\s+|-)', '', force_text(value)) - phone_match = PHONE_DIGITS_RE.search(value) - if phone_match: - return '%s' % phone_match.group(1) - raise ValidationError(self.error_messages['invalid']) + if len(value) != 10 : + raise ValidationError(self.error_messages['invalid']) + if len(value) == 10: + return '%s%s%s' % (value[0].upper(), value[1:5], value[5:].upper()) + return value + From 546a3c72a57706df780fe28ea0e202aa33248a2c Mon Sep 17 00:00:00 2001 From: hossein torabi Date: Sat, 11 Mar 2017 17:28:30 +0330 Subject: [PATCH 7/7] updating test --- localflavor/ir/ir_provinces.py | 2 +- tests/test_ir.py | 168 +++++++++------------------------ 2 files changed, 48 insertions(+), 122 deletions(-) diff --git a/localflavor/ir/ir_provinces.py b/localflavor/ir/ir_provinces.py index 1761ff291..fb7fcb138 100644 --- a/localflavor/ir/ir_provinces.py +++ b/localflavor/ir/ir_provinces.py @@ -27,7 +27,7 @@ ('KBA', _('Kohgiluyeh and Boyer-Ahmad')), ('KUR', _('Kurdistan')), ('LOR', _('Lorestan')), - ('Mar', _('Markazi')), + ('MAR', _('Markazi')), ('MAZ', _('Mazandaran')), ('QAZ', _('Qazvin')), ('QOM', _('Qom')), diff --git a/tests/test_ir.py b/tests/test_ir.py index 53f7125c7..53b0a1b57 100644 --- a/tests/test_ir.py +++ b/tests/test_ir.py @@ -2,131 +2,57 @@ from django.test import SimpleTestCase -from localflavor.ar.forms import ARCBUField, ARCUITField, ARDNIField, ARPostalCodeField, ARProvinceSelect - - -class ARLocalFlavorTests(SimpleTestCase): - def test_ARProvinceSelect(self): - f = ARProvinceSelect() - out = ''' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ''' - self.assertHTMLEqual(f.render('provincias', 'A'), out) - - def test_ARPostalCodeField(self): - error_format = ['Enter a postal code in the format NNNN or ANNNNAAA.'] - error_atmost = ['Ensure this value has at most 8 characters (it has 9).'] - error_atleast = ['Ensure this value has at least 4 characters (it has 3).'] - valid = { - '5000': '5000', - 'C1064AAB': 'C1064AAB', - 'c1064AAB': 'C1064AAB', - 'C1064aab': 'C1064AAB', - '4400': '4400', - 'C1064AAB': 'C1064AAB', - } - invalid = { - 'C1064AABB': error_atmost + error_format, - 'C1064AA': error_format, - 'C1064AB': error_format, - '106AAB': error_format, - '500': error_atleast + error_format, - '5PPP': error_format, - } - self.assertFieldOutput(ARPostalCodeField, valid, invalid) - - def test_ARDNIField(self): - error_length = ['This field requires 7 or 8 digits.'] - error_digitsonly = ['This field requires only numbers.'] - valid = { - '20123456': '20123456', - '20.123.456': '20123456', - '20123456': '20123456', - '20.123.456': '20123456', - '20.123456': '20123456', - '9123456': '9123456', - '9.123.456': '9123456', - } - invalid = { - '101234566': error_length, - 'W0123456': error_digitsonly, - '10,123,456': error_digitsonly, - } - self.assertFieldOutput(ARDNIField, valid, invalid) - - def test_ARCUITField(self): - error_format = ['Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.'] - error_invalid = ['Invalid CUIT.'] - error_legal_type = ['Invalid legal type. Type must be 27, 20, 30, 23, 24 or 33.'] - valid = { - '20-10123456-9': '20-10123456-9', - '20-10123456-9': '20-10123456-9', - '27-10345678-4': '27-10345678-4', - '20101234569': '20-10123456-9', - '27103456784': '27-10345678-4', - '30011111110': '30-01111111-0', - '24117166062': '24-11716606-2', - '33500001599': '33-50000159-9', - '23000052264': '23-00005226-4', - } - invalid = { - '2-10123456-9': error_format, - '210123456-9': error_format, - '20-10123456': error_format, - '20-10123456-': error_format, - '20-10123456-5': error_invalid, - '27-10345678-1': error_invalid, - '27-10345678-1': error_invalid, - '11211111110': error_legal_type, - } - self.assertFieldOutput(ARCUITField, valid, invalid) + self.assertHTMLEqual(f.render('provinces'),'ALB', out) + def test_IRPostalCodeField(self): + error_format = ['Enter a postal code in the format xxxxxxxxxx .'] + error_atmost = ['Ensure this value has at most 10 characters (it has 11).'] + error_atleast = ['Ensure this value has at least 10 characters (it has 9).'] - def test_ARCBUField(self): - error_format = ['Enter a valid CBU in XXXXXXXXXXXXXXXXXXXXXX format.'] - error_length = ['CBU must be exactly 22 digits long.'] - error_checksum = ['Invalid CBU.'] valid = { - '2237628810898098715378': '2237628810898098715378', - '5433758936130717465023': '5433758936130717465023', - '5729195067928761667584': '5729195067928761667584', - '9498175528566296510521': '9498175528566296510521', - '7362966507842824472644': '7362966507842824472644', - '8693513393883886497274': '8693513393883886497274', - '1542952861593836535608': '1542952861593836535608', - '5833008953419074707467': '5833008953419074707467', - '9687027721961737239525': '9687027721961737239525', - '8048819274216931992586': '8048819274216931992586' + '5987456987' : '9874698741', + '5987456321' : '4895785787', + 'c464646464' : '4848748487', } invalid = { - 'abc123def456-9024-2313': error_format, - '142512591859898123123': error_length, - '12312452521512526125566': error_length, - '1234567891234567891234': error_checksum, - '1234562374545894589234': error_checksum, - '0987653759257883891234': error_checksum, + '4545' : error_atmost+error_format, + '464676467676' : error_atleast+error_format, } - self.assertFieldOutput(ARCBUField, valid, invalid) + self.assertFieldOutput(IRPostlCodeField, valid, invalid)