Source code for localflavor.ae.forms

"""UAE-specific Form helpers."""

import re

from django.core.exceptions import ValidationError
from django.forms.fields import CharField, Select, ChoiceField
from django.utils.translation import gettext_lazy as _

from .ae_emirates import EMIRATE_CHOICES, EMIRATES_NORMALIZED
from .validators import (
    PO_BOX_PREFIX_RE, UAEEmiratesIDValidator, UAEPostalCodeValidator, UAEPOBoxValidator,
    UAETaxRegistrationNumberValidator,
)


[docs] class UAEEmiratesIDField(CharField): """ A field for validating UAE Emirates ID numbers. UAE Emirates ID format: 784-YYYY-NNNNNNN-N Where: - 784 is the UAE country code - YYYY is an identification block assigned by ICP - NNNNNNN is a 7-digit sequence number - N is a single check digit .. versionadded:: 5.1 """ default_error_messages = { 'invalid': _('Enter a valid UAE Emirates ID number in format 784-YYYY-NNNNNNN-N.'), } def __init__(self, **kwargs): super().__init__(**kwargs) self.validators.append(UAEEmiratesIDValidator())
[docs] def clean(self, value): value = super().clean(value) if value in self.empty_values: return value # Remove any dashes or spaces and return clean 15-digit format clean_value = re.sub(r'[\s\-]', '', str(value)) # Format as 784-YYYY-NNNNNNN-N for consistency if len(clean_value) == 15: formatted = f"{clean_value[:3]}-{clean_value[3:7]}-{clean_value[7:14]}-{clean_value[14]}" return formatted return clean_value
[docs] class UAEEmirateField(ChoiceField): """ A choice field that uses a list of UAE Emirates as its choices. .. versionadded:: 5.1 """ def __init__(self, **kwargs): kwargs.setdefault('choices', EMIRATE_CHOICES) super().__init__(**kwargs)
[docs] def clean(self, value): value = self.to_python(value) if value in self.empty_values: return super().clean(value) try: normalized_value = EMIRATES_NORMALIZED[value.lower()] except KeyError: raise ValidationError( self.error_messages['invalid_choice'], code='invalid_choice', params={'value': value}, ) return super().clean(normalized_value)
[docs] class UAEEmirateSelect(Select): """ A Select widget that uses a list of UAE Emirates as its choices. .. versionadded:: 5.1 """ def __init__(self, attrs=None): super().__init__(attrs, choices=EMIRATE_CHOICES)
[docs] class UAEPostalCodeField(CharField): """ A field for validating UAE postal codes. UAE doesn't use postal codes, but some systems require "00000". This field accepts "00000" or empty values. .. versionadded:: 5.1 """ default_error_messages = { 'invalid': _('Enter a valid UAE postal code. Use 00000 if postal code is required.'), } def __init__(self, **kwargs): kwargs.setdefault('required', False) super().__init__(**kwargs) self.validators.append(UAEPostalCodeValidator())
[docs] def clean(self, value): value = super().clean(value) if value in self.empty_values: return self.empty_value # Normalize to 00000 if needed clean_value = str(value).strip() if clean_value in ('00000', ''): return clean_value return value
[docs] class UAEPOBoxField(CharField): """ A field for validating UAE P.O. Box numbers. Accepts formats: "P.O. Box XXXXX", "PO Box XXXXX", "POB XXXXX", or just "XXXXX" .. versionadded:: 5.1 """ default_error_messages = { 'invalid': _('Enter a valid P.O. Box number.'), } def __init__(self, **kwargs): super().__init__(**kwargs) self.validators.append(UAEPOBoxValidator())
[docs] def clean(self, value): value = super().clean(value) if value in self.empty_values: return value # Clean up the value clean_value = str(value).strip().upper() # Remove "P.O. BOX", "PO BOX", or "POB" prefix if present clean_value = re.sub(PO_BOX_PREFIX_RE, '', clean_value) # Return just the number part if re.match(r'^\d{1,10}$', clean_value): return clean_value return value
[docs] class UAETaxRegistrationNumberField(CharField): """ A field for validating UAE Tax Registration Numbers (TRN). UAE TRN is a 15-digit number used for VAT registration. .. versionadded:: 5.1 """ default_error_messages = { 'invalid': _('Enter a valid UAE Tax Registration Number (15 digits).'), } def __init__(self, **kwargs): super().__init__(**kwargs) self.validators.append(UAETaxRegistrationNumberValidator())
[docs] def clean(self, value): value = super().clean(value) if value in self.empty_values: return value # Remove any spaces or formatting clean_value = re.sub(r'\s', '', str(value)) return clean_value