From bd07715e2a1bd1100063e4409e3760fa19c813b6 Mon Sep 17 00:00:00 2001 From: Abdellah EL YOUSSFI ALAOUI Date: Wed, 22 May 2024 11:19:56 +0100 Subject: [PATCH 1/3] Added MACinNumberField to MA flavor (#507) --- docs/authors.rst | 1 + docs/changelog.rst | 2 +- localflavor/ma/forms.py | 23 +++++++++++++++++++++++ tests/test_ma.py | 33 ++++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/docs/authors.rst b/docs/authors.rst index add25b974..026839e00 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -2,6 +2,7 @@ Authors ======= * Aaron Boman +* Abdellah El Youssfi Alaoui * Adam Taylor * Adnane Belmadiaf * Adonys Alea Boffill diff --git a/docs/changelog.rst b/docs/changelog.rst index e41dfb278..cb0c49375 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,7 +10,7 @@ New flavors: New fields for existing flavors: -- None +- Added CIN Number field in Morocco flavor (`gh-705 `_). Modifications to existing flavors: diff --git a/localflavor/ma/forms.py b/localflavor/ma/forms.py index 84bbd9e4c..8e11a0a19 100644 --- a/localflavor/ma/forms.py +++ b/localflavor/ma/forms.py @@ -74,3 +74,26 @@ class MARegionField(CharField): def __init__(self, **kwargs): kwargs.setdefault('label', _('Select Region')) super().__init__(**kwargs) + + +class MACinNumberField(RegexField): + """ + CIN number: (Numéro de la Carte D'Identité Nationale) The CIN represents the ID of a Moroccan citizen. + + - It is an 8-max-length string that starts with one or two Latin letters followed by digits, + with the first digit not being zero. + + - as implemented in the official government site "https://www.cnie.ma/" + .. versionadded:: 4.1 + """ + + default_error_messages = { + 'invalid': _('Enter a valid Moroccan CIN number.'), + } + cin_pattern = r'^[A-Za-z]{1,2}[1-9][0-9]{0,6}$' + + def __init__(self, **kwargs): + kwargs.setdefault('label', _('CIN Number')) + kwargs['max_length'] = 8 + kwargs['min_length'] = 2 + super().__init__(self.cin_pattern, **kwargs) diff --git a/tests/test_ma.py b/tests/test_ma.py index 2fdb75e5e..09e92ead6 100644 --- a/tests/test_ma.py +++ b/tests/test_ma.py @@ -1,6 +1,7 @@ from django.test import SimpleTestCase -from localflavor.ma.forms import MAPostalCodeField, MAProvinceField, MAProvinceSelect, MARegionField, MARegionSelect +from localflavor.ma.forms import MAPostalCodeField, MAProvinceField, MAProvinceSelect, MARegionField, MARegionSelect, \ + MACinNumberField PROVINCE_SELECT_OUTPUT = ''' ''' + class MALocalFlavorTests(SimpleTestCase): def test_MAPostalCodeField(self): error_format = ['Enter a postal code in the format XXXXX.'] @@ -128,3 +130,32 @@ def test_MAProvinceSelect(self): def test_MARegionSelect(self): f = MARegionSelect() self.assertHTMLEqual(f.render('region', '04'), REGION_SELECT_OUTPUT) + + def test_MACinNumberField(self): + error_format = ['Enter a valid Moroccan CIN number.'] + valid = { + 'D1': 'D1', + 'DZ1': 'DZ1', + 'D23': 'D23', + 'DR23': 'DR23', + 'D345': 'D345', + 'DR345': 'DR345', + 'D3454': 'D3454', + 'DT3454': 'DT3454', + 'D34546': 'D34546', + 'DG34546': 'DG34546', + 'D345467': 'D345467', + 'DH345467': 'DH345467', + 'D3454673': 'D3454673', + + } + invalid = { + '9': ['Ensure this value has at least 2 characters (it has 1).'] + error_format, + 'T': ['Ensure this value has at least 2 characters (it has 1).'] + error_format, + '903': error_format, + 'D034': error_format, + 'DR034': error_format, + 'RER45': error_format, + 'T23456786': ['Ensure this value has at most 8 characters (it has 9).'] + error_format, + } + self.assertFieldOutput(MACinNumberField, valid, invalid) From 1f13beb31bd4e477b326fbd5c88864adf8450290 Mon Sep 17 00:00:00 2001 From: Dmytro Litvinov Date: Sat, 8 Jun 2024 23:10:08 +0300 Subject: [PATCH 2/3] fix(ua): Kyiv - not Kiev --- docs/authors.rst | 1 + docs/changelog.rst | 1 + localflavor/ua/ua_regions.py | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/authors.rst b/docs/authors.rst index 026839e00..4e41ef554 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -43,6 +43,7 @@ Authors * Diederik van der Boor * d.merc * Dmitry Dygalo +* Dmytro Litvinov * Dominick Rivard * Douglas Miranda * Elliott Fawcett diff --git a/docs/changelog.rst b/docs/changelog.rst index cb0c49375..642acdd8a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -16,6 +16,7 @@ Modifications to existing flavors: - Fix Belarus passport field description punctuation (`gh-484 `_). +- Change `Kiev` to `Kyiv` 🇺🇦 according to ISO_3166-2:UA Other changes: diff --git a/localflavor/ua/ua_regions.py b/localflavor/ua/ua_regions.py index 3594f6f06..17c68137b 100644 --- a/localflavor/ua/ua_regions.py +++ b/localflavor/ua/ua_regions.py @@ -13,7 +13,7 @@ ('UA-65', _('Kherson Oblast')), ('UA-68', _('Khmelnytskyi Oblast')), ('UA-35', _('Kirovohrad Oblast')), - ('UA-32', _('Kiev Oblast')), + ('UA-32', _('Kyiv Oblast')), ('UA-09', _('Luhansk Oblast')), ('UA-46', _('Lviv Oblast')), ('UA-48', _('Mykolaiv Oblast')), @@ -28,6 +28,6 @@ ('UA-23', _('Zaporizhia Oblast')), ('UA-18', _('Zhytomyr Oblast')), ('UA-43', _('Autonomous Republic of Crimea')), - ('UA-30', _('Kiev')), + ('UA-30', _('Kyiv')), ('UA-40', _('Sevastopol')) ) From 085fb2be02cae1c95594c2a358b8df8d62fa5577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9lia?= Date: Fri, 23 Aug 2024 22:49:40 +0200 Subject: [PATCH 3/3] Accept French Postal Services identifiers in forms (#505) --- docs/authors.rst | 1 + docs/changelog.rst | 2 ++ localflavor/fr/forms.py | 31 ++++++++++++++----------------- tests/test_fr.py | 4 ++++ 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/authors.rst b/docs/authors.rst index 4e41ef554..8c0bb7c8d 100644 --- a/docs/authors.rst +++ b/docs/authors.rst @@ -33,6 +33,7 @@ Authors * Ben Konrath * Bruno M. Custódio * Burhan Khalid +* Célia Prat * Claude Paroz * Daniel Ampuero * Daniela Ponader diff --git a/docs/changelog.rst b/docs/changelog.rst index 642acdd8a..7227737b3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,8 @@ Modifications to existing flavors: - Fix Belarus passport field description punctuation (`gh-484 `_). - Change `Kiev` to `Kyiv` 🇺🇦 according to ISO_3166-2:UA +- Accept French Postal Services identifiers in forms + (`gh-505 `_). Other changes: diff --git a/localflavor/fr/forms.py b/localflavor/fr/forms.py index 5f642a235..0320e11cd 100644 --- a/localflavor/fr/forms.py +++ b/localflavor/fr/forms.py @@ -184,21 +184,7 @@ def _check_foreign_countries(self, commune_of_origin, current_year, department_o raise ValidationError(self.error_messages['invalid'], code='invalid') -class FRSIRENENumberMixin: - """Abstract class for SIREN and SIRET numbers, from the SIRENE register.""" - - def clean(self, value): - value = super().clean(value) - if value in self.empty_values: - return value - - value = value.replace(' ', '').replace('-', '') - if not self.r_valid.match(value) or not luhn.is_valid(value): - raise ValidationError(self.error_messages['invalid'], code='invalid') - return value - - -class FRSIRENField(FRSIRENENumberMixin, CharField): +class FRSIRENField(CharField): """ SIREN stands for "Système d'identification du répertoire des entreprises". @@ -220,8 +206,18 @@ def prepare_value(self, value): value = value.replace(' ', '').replace('-', '') return ' '.join((value[:3], value[3:6], value[6:])) + def clean(self, value): + value = super().clean(value) + if value in self.empty_values: + return value + + value = value.replace(' ', '').replace('-', '') + if not self.r_valid.match(value) or not luhn.is_valid(value): + raise ValidationError(self.error_messages['invalid'], code='invalid') + return value + -class FRSIRETField(FRSIRENENumberMixin, CharField): +class FRSIRETField(CharField): """ SIRET stands for "Système d'identification du répertoire des établissements". @@ -244,7 +240,8 @@ def clean(self, value): value = value.replace(' ', '').replace('-', '') - if not luhn.is_valid(value[:9]): + if not self.r_valid.match(value) or not luhn.is_valid(value[:9]) or \ + (value.startswith("356000000") and sum(int(x) for x in value) % 5 != 0): raise ValidationError(self.error_messages['invalid'], code='invalid') return value diff --git a/tests/test_fr.py b/tests/test_fr.py index b836a4b66..0bc6b0751 100644 --- a/tests/test_fr.py +++ b/tests/test_fr.py @@ -271,10 +271,12 @@ def test_FRSIRENNumber(self): '752932715': '752932715', '752 932 715': '752932715', '752-932-715': '752932715', + '356000000': '356000000' } invalid = { '1234': error_format, # wrong size '752932712': error_format, # Bad luhn on SIREN + '35600000014597' : error_format } self.assertFieldOutput(FRSIRENField, valid, invalid) @@ -294,11 +296,13 @@ def test_FRSIRETNumber(self): '75293271500010': '75293271500010', '752 932 715 00010': '75293271500010', '752-932-715-00010': '75293271500010', + '35600000014597' : '35600000014597', # Special case La Poste } invalid = { '1234': error_format, # wrong size '75293271200017': error_format, # Bad luhn on SIREN '75293271000010': error_format, # Bad luhn on whole + '35600000014596' : error_format # Special case La Poste } self.assertFieldOutput(FRSIRETField, valid, invalid)