Skip to content

Commit

Permalink
Added support for Moldova.
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimirnani authored and benkonrath committed Aug 9, 2018
1 parent b5b0570 commit 2144cf4
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 1 deletion.
4 changes: 3 additions & 1 deletion docs/changelog.rst
Expand Up @@ -6,7 +6,9 @@ Changelog

New flavors:

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


New fields for existing flavors:

Expand Down
29 changes: 29 additions & 0 deletions docs/localflavor/md.rst
@@ -0,0 +1,29 @@
Moldova (``md``)
================

Forms
-----

.. automodule:: localflavor.md.forms
:members:

Models
------

.. automodule:: localflavor.md.models
:members:


Validators
----------

.. automodule:: localflavor.md.validators
:members:

Data
----

.. autodata:: localflavor.md.choices.COMPANY_TYPES_CHOICES
.. autodata:: localflavor.md.choices.LICENSE_PLATE_DIPLOMATIC
.. autodata:: localflavor.md.choices.LICENSE_PLATE_GOVERNMENT_TYPE
.. autodata:: localflavor.md.choices.LICENSE_PLATE_POLICE
Empty file added localflavor/md/__init__.py
Empty file.
84 changes: 84 additions & 0 deletions localflavor/md/choices.py
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.utils.translation import ugettext_lazy as _

COMPANY_TYPES_CHOICES = (
('II', _('Întreprindere Individuală')),
('SA', _('Societate pe acţiuni')),
('SNC', _('Societate în nume colectiv')),
('SC', _('Societatea în comandită')),
('CP', _('Cooperativa de producţie')),
('CI', _('Cooperativa de întreprinzători')),
('SRL', _('Societate cu răspundere limitată')),
('GT', _('Gospodăria ţărănească')),
)

LICENSE_PLATE_DIPLOMATIC = (
('CD', _('Diplomatic Corps')),
('TS', _('Service Staff')),
('TC', _('Consular Staff')),
('CA', _('Administrative body')),
)

LICENSE_PLATE_POLICE = (
('MAI', _('Ministry of Internal Affairs')),
('MIC', _('Carabinieri Subdivision')),
('FA', _('Military Forces')),
('DG', _('Border Control')),
)

LICENSE_PLATE_GOVERNMENT_TYPE = (
('P', _('Parliament')),
('G', _('Government')),
('A', _('Chancellery')),
)

REGION_CHOICES_2002_2015 = (
('AN', _('Anenii Noi')),
('BE', _('Tighina')),
('BL', _('Bălți')),
('BR', _('Briceni')),
('BS', _('Basarabeasca')),
('C', _('Chișinău')),
('CC', _('Camenca')),
('CG', _('Ceadîr-Lunga')),
('CH', _('Cahul')),
('CL', _('Călărași')),
('CM', _('Cimișlia')),
('CN', _('Căinari')),
('CO', _('Comrat')),
('CR', _('Criuleni')),
('CS', _('Căușeni')),
('CT', _('Cantemir')),
('DB', _('Dubăsari')),
('DN', _('Dondușeni')),
('DR', _('Drochia')),
('ED', _('Edineț')),
('FL', _('Fălești')),
('FR', _('Florești')),
('GE', _('Gagauzia')),
('GL', _('Glodeni')),
('GR', _('Grigoriopol')),
('HN', _('Hîncești')),
('IL', _('Ialoveni')),
('K', _('Chișinău')), # duplicate key for Chișinău (a.k.a. 'Kishinev')
('LV', _('Leova')),
('NS', _('Nisporeni')),
('OC', _('Ocnița')),
('OR', _('Orhei')),
('RB', _('Rîbnița')),
('RS', _('Rîșcani')),
('RZ', _('Rezina')),
('SD', _('Șoldănești')),
('SG', _('Sîngerei')),
('SL', _('Slobozia')),
('SR', _('Soroca')),
('ST', _('Strășeni')),
('SV', _('Ștefan Vodă')),
('TG', _('Tighina')),
('TR', _('Taraclia')),
('TL', _('Telenești')),
('UN', _('Ungheni')),
('VL', _('Vulcănești')),
)
57 changes: 57 additions & 0 deletions localflavor/md/forms.py
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django import forms

from .choices import COMPANY_TYPES_CHOICES, REGION_CHOICES_2002_2015
from .validators import MDIDNOFieldValidator, MDLicensePlateValidator


class MDIDNOField(forms.CharField):
"""
A form field for the Moldavian company identification number (IDNO).
.. versionadded:: 2.1
"""

default_validators = [MDIDNOFieldValidator()]

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


class MDLicensePlateField(forms.CharField):
"""
A form field for the Moldavian license plate number.
.. versionadded:: 2.1
"""

default_validators = [MDLicensePlateValidator()]

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


class MDCompanyTypesSelect(forms.Select):
"""
A Select widget that uses a list of Moldavian company types as its choices.
.. versionadded:: 2.1
"""

def __init__(self, attrs=None):
super(MDCompanyTypesSelect, self).__init__(attrs, choices=COMPANY_TYPES_CHOICES)


class MDRegionSelect(forms.Select):
"""
A Select widget that uses a list of Moldavian regions as its choices.
.. versionadded:: 2.1
"""

def __init__(self, attrs=None):
super(MDRegionSelect, self).__init__(attrs, choices=REGION_CHOICES_2002_2015)
57 changes: 57 additions & 0 deletions localflavor/md/models.py
@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

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

from .choices import COMPANY_TYPES_CHOICES
from .validators import MDIDNOFieldValidator, MDLicensePlateValidator


class MDIDNOField(CharField):
"""
A model field for the Moldavian company identification number (IDNO).
.. versionadded:: 2.1
"""
description = _("Moldavian identity number")
validators = [MDIDNOFieldValidator()]

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


class MDLicensePlateField(CharField):
"""
A model field for the Moldavian license plate number.
.. versionadded:: 2.1
"""

description = _("Moldavian license plate number")
validators = [MDLicensePlateValidator()]

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


class MDCompanyTypeField(CharField):
"""
A model field for the Moldavian company type abbreviation.
.. versionadded:: 2.1
"""

description = _("Moldavian company types")

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

def deconstruct(self):
name, path, args, kwargs = super(MDCompanyTypeField, self).deconstruct()
del kwargs['choices']
return name, path, args, kwargs
98 changes: 98 additions & 0 deletions localflavor/md/validators.py
@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import re

from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from django.utils.translation import ugettext_lazy as _

from .choices import (LICENSE_PLATE_DIPLOMATIC, LICENSE_PLATE_GOVERNMENT_TYPE, LICENSE_PLATE_POLICE,
REGION_CHOICES_2002_2015)


class MDIDNOFieldValidator(RegexValidator):
"""
Validation for Moldavian IDNO.
.. versionadded:: 2.1
"""

error_message = _('Enter a valid IDNO number.')
regex = '^\d{13}$'
message = error_message


class MDLicensePlateValidator(RegexValidator):
"""
Validation for `Moldavian License Plates`_.
.. _Moldavian License Plates: https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Moldova
.. versionadded:: 2.1
"""

error_message = _('Enter a valid license plate.')
regex = '^\d{13}$'
message = error_message

def __call__(self, value):
value = value.upper()
if not self._is_valid(value):
raise ValidationError(self.error_message)

def _is_valid(self, value):
return (
self._is_old_format(value) or
self._is_new_format(value) or
self._is_president_format(value) or
self._is_diplomatic_format(value) or
self._is_police_format(value) or
self._is_foreign_format(value) or
self._is_state_security_format(value) or
self._is_gov_format(value)
)

@staticmethod
def _is_old_format(value):
regions = "|".join([code for code, desc in REGION_CHOICES_2002_2015])
pattern = '({regions}) [A-Z]{{2}} \d{{1,3}}'.format(regions=regions)
return re.match(pattern, value) is not None

@staticmethod
def _is_new_format(value):
if not any(x in value for x, y in LICENSE_PLATE_POLICE):
pattern = '^[A-Z]{3} \d{1,3}$'
return re.match(pattern, value) is not None

@staticmethod
def _is_gov_format(value):
types = "|".join([code for code, desc in LICENSE_PLATE_GOVERNMENT_TYPE])
pattern = '^RM ({types}) \d{{3}}$'.format(types=types)
return re.match(pattern, value) is not None

@staticmethod
def _is_diplomatic_format(value):
types = "|".join([code for code, desc in LICENSE_PLATE_DIPLOMATIC])
pattern = '^({types}) \d{{3}} A{{1,2}}$'.format(types=types)
return re.match(pattern, value) is not None

@staticmethod
def _is_police_format(value):
types = "|".join([code for code, desc in LICENSE_PLATE_POLICE])
gov_format = '^({types}) \d{{4}}$'.format(types=types)
return re.match(gov_format, value) is not None

@staticmethod
def _is_president_format(value):
pattern = '^RM \d{4}$'
return re.match(pattern, value) is not None

@staticmethod
def _is_state_security_format(value):
pattern = '^SP \d{3}$'
return re.match(pattern, value) is not None

@staticmethod
def _is_foreign_format(value):
pattern = '^H \d{4}$'
return re.match(pattern, value) is not None
1 change: 1 addition & 0 deletions tests/settings.py
Expand Up @@ -11,6 +11,7 @@
'localflavor',
'tests.test_au',
'tests.test_ec',
'tests.test_md',
'tests.test_mk',
'tests.test_mx',
'tests.test_ua',
Expand Down
Empty file added tests/test_md/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions tests/test_md/forms.py
@@ -0,0 +1,9 @@
from django.forms import ModelForm

from .models import MDPlaceModel


class MDPlaceForm(ModelForm):
class Meta:
model = MDPlaceModel
fields = ('idno', 'company_type_1', 'company_type_2', 'license_plate')
13 changes: 13 additions & 0 deletions tests/test_md/models.py
@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models

from localflavor.md.models import MDCompanyTypeField, MDIDNOField, MDLicensePlateField


class MDPlaceModel(models.Model):
idno = MDIDNOField()
company_type_1 = MDCompanyTypeField()
company_type_2 = MDCompanyTypeField()
license_plate = MDLicensePlateField()

0 comments on commit 2144cf4

Please sign in to comment.