Author: mtredinnick
Date: 2007-04-30 22:10:10 -0500 (Mon, 30 Apr 2007)
New Revision: 5132

Added:
   django/trunk/django/contrib/localflavor/ch/
   django/trunk/django/contrib/localflavor/ch/__init__.py
   django/trunk/django/contrib/localflavor/ch/ch_states.py
   django/trunk/django/contrib/localflavor/ch/forms.py
Modified:
   django/trunk/AUTHORS
   django/trunk/tests/regressiontests/forms/localflavor.py
Log:
Fixed #3946 -- Added Swiss localflavor. Thanks, [EMAIL PROTECTED]


Modified: django/trunk/AUTHORS
===================================================================
--- django/trunk/AUTHORS        2007-05-01 02:44:24 UTC (rev 5131)
+++ django/trunk/AUTHORS        2007-05-01 03:10:10 UTC (rev 5132)
@@ -225,6 +225,7 @@
     [EMAIL PROTECTED]
     Dan Watson <http://theidioteque.net/>
     Chris Wesseling <[EMAIL PROTECTED]>
+    [EMAIL PROTECTED]
     Rachel Willmer <http://www.willmer.com/kb/>
     Gary Wilson <[EMAIL PROTECTED]>
     wojtek

Added: django/trunk/django/contrib/localflavor/ch/__init__.py
===================================================================

Added: django/trunk/django/contrib/localflavor/ch/ch_states.py
===================================================================
--- django/trunk/django/contrib/localflavor/ch/ch_states.py                     
        (rev 0)
+++ django/trunk/django/contrib/localflavor/ch/ch_states.py     2007-05-01 
03:10:10 UTC (rev 5132)
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*
+from django.utils.translation import gettext_lazy as _
+
+STATE_CHOICES = (
+    ('AG', _('Aargau')),
+    ('AI', _('Appenzell Innerrhoden')),
+    ('AR', _('Appenzell Ausserrhoden')),
+    ('BS', _('Basel-Stadt')),
+    ('BL', _('Basel-Land')),
+    ('BE', _('Berne')),
+    ('FR', _('Fribourg')),
+    ('GE', _('Geneva')),
+    ('GL', _('Glarus')),
+    ('GR', _('Graubuenden')),
+    ('JU', _('Jura')),
+    ('LU', _('Lucerne')),
+    ('NE', _('Neuchatel')),
+    ('NW', _('Nidwalden')),
+    ('OW', _('Obwalden')),
+    ('SH', _('Schaffhausen')),
+    ('SZ', _('Schwyz')),
+    ('SO', _('Solothurn')),
+    ('SG', _('St. Gallen')),
+    ('TG', _('Thurgau')),
+    ('TI', _('Ticino')),
+    ('UR', _('Uri')),
+    ('VS', _('Valais')),
+    ('VD', _('Vaud')),
+    ('ZG', _('Zug')),
+    ('ZH', _('Zurich'))
+)

Added: django/trunk/django/contrib/localflavor/ch/forms.py
===================================================================
--- django/trunk/django/contrib/localflavor/ch/forms.py                         
(rev 0)
+++ django/trunk/django/contrib/localflavor/ch/forms.py 2007-05-01 03:10:10 UTC 
(rev 5132)
@@ -0,0 +1,109 @@
+"""
+Swiss-specific Form helpers
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES
+from django.utils.encoding import smart_unicode
+from django.utils.translation import gettext
+import re
+
+id_re = 
re.compile(r"^(?P<idnumber>\w{8})(?P<pos9>(\d{1}|<))(?P<checksum>\d{1})$")
+phone_digits_re = re.compile(r'^0([1-9]{1})\d{8}$')
+
+class CHZipCodeField(RegexField):
+    def __init__(self, *args, **kwargs):
+        super(CHZipCodeField, self).__init__(r'^\d{4}$',
+        max_length=None, min_length=None,
+        error_message=gettext('Enter a zip code in the format XXXX.'),
+        *args, **kwargs)
+
+class CHPhoneNumberField(Field):
+    """
+    Validate local Swiss phone number (not international ones)
+    The correct format is '0XX XXX XX XX'.
+    '0XX.XXX.XX.XX' and '0XXXXXXXXX' validate but are corrected to
+    '0XX XXX XX XX'.
+    """
+    def clean(self, value):
+        super(CHPhoneNumberField, self).clean(value)
+        if value in EMPTY_VALUES:
+            return u''
+        value = re.sub('(\.|\s|/|-)', '', smart_unicode(value))
+        m = phone_digits_re.search(value)
+        if m:
+            return u'%s %s %s %s' % (value[0:3], value[3:6], value[6:8], 
value[8:10])
+        raise ValidationError('Phone numbers must be in 0XX XXX XX XX format.')
+
+class CHStateSelect(Select):
+    """
+    A Select widget that uses a list of CH states as its choices.
+    """
+    def __init__(self, attrs=None):
+        from ch_states import STATE_CHOICES # relative import
+        super(CHStateSelect, self).__init__(attrs, choices=STATE_CHOICES)
+
+class CHIdentityCardNumberField(Field):
+    """
+    A Swiss identity card number.
+
+    Checks the following rules to determine whether the number is valid:
+
+        * Conforms to the X1234567<0 or 1234567890 format.
+        * Included checksums match calculated checksums
+
+    Algorithm is documented at http://adi.kousz.ch/artikel/IDCHE.htm
+    """
+    def has_valid_checksum(self, number):
+        given_number, given_checksum = number[:-1], number[-1]
+        new_number = given_number
+        calculated_checksum = 0
+        fragment = ""
+        parameter = 7
+
+        first = str(number[:1])
+        if first.isalpha():
+            num = ord(first.upper()) - 65
+            if num < 0 or num > 8:
+                return False
+            new_number = str(num) + new_number[1:]
+            new_number = new_number[:8] + '0'
+
+        if not new_number.isdigit():
+            return False
+
+        for i in range(len(new_number)):
+          fragment = int(new_number[i])*parameter
+          calculated_checksum += fragment
+
+          if parameter == 1:
+            parameter = 7
+          elif parameter == 3:
+            parameter = 1
+          elif parameter ==7:
+            parameter = 3
+
+        return str(calculated_checksum)[-1] == given_checksum
+
+    def clean(self, value):
+        super(CHIdentityCardNumberField, self).clean(value)
+        error_msg = gettext('Enter a valid Swiss identity or passport card 
number in X1234567<0 or 1234567890 format.')
+        if value in EMPTY_VALUES:
+            return u''
+
+        match = re.match(id_re, value)
+        if not match:
+            raise ValidationError(error_msg)
+
+        idnumber, pos9, checksum = match.groupdict()['idnumber'], 
match.groupdict()['pos9'], match.groupdict()['checksum']
+
+        if idnumber == '00000000' or \
+           idnumber == 'A0000000':
+            raise ValidationError(error_msg)
+
+        all_digits = "%s%s%s" % (idnumber, pos9, checksum)
+        if not self.has_valid_checksum(all_digits):
+            raise ValidationError(error_msg)
+
+        return u'%s%s%s' % (idnumber, pos9, checksum)
+

Modified: django/trunk/tests/regressiontests/forms/localflavor.py
===================================================================
--- django/trunk/tests/regressiontests/forms/localflavor.py     2007-05-01 
02:44:24 UTC (rev 5131)
+++ django/trunk/tests/regressiontests/forms/localflavor.py     2007-05-01 
03:10:10 UTC (rev 5132)
@@ -1011,6 +1011,60 @@
 ...
 ValidationError: [u'Enter a valid German identity card number in 
XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.']
 
+# CHZipCodeField ############################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHZipCodeField
+>>> f = CHZipCodeField()
+>>> f.clean('800x')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXX.']
+>>> f.clean('80 00')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXX.']
+>>> f.clean('8000')
+u'8000'
+
+# CHPhoneNumberField ########################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHPhoneNumberField
+>>> f = CHPhoneNumberField()
+>>> f.clean('01234567890')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
+>>> f.clean('1234567890')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
+>>> f.clean('0123456789')
+u'012 345 67 89'
+
+# CHIdentityCardNumberField #################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHIdentityCardNumberField
+>>> f = CHIdentityCardNumberField()
+>>> f.clean('C1234567<0')
+u'C1234567<0'
+>>> f.clean('C1234567<1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Swiss identity or passport card number in 
X1234567<0 or 1234567890 format.']
+>>> f.clean('2123456700')
+u'2123456700'
+>>> f.clean('2123456701')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Swiss identity or passport card number in 
X1234567<0 or 1234567890 format.']
+
+# CHStateSelect #############################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHStateSelect
+>>> w = CHStateSelect()
+>>> w.render('state', 'AG')
+u'<select name="state">\n<option value="AG" 
selected="selected">Aargau</option>\n<option value="AI">Appenzell 
Innerrhoden</option>\n<option value="AR">Appenzell 
Ausserrhoden</option>\n<option value="BS">Basel-Stadt</option>\n<option 
value="BL">Basel-Land</option>\n<option value="BE">Berne</option>\n<option 
value="FR">Fribourg</option>\n<option value="GE">Geneva</option>\n<option 
value="GL">Glarus</option>\n<option value="GR">Graubuenden</option>\n<option 
value="JU">Jura</option>\n<option value="LU">Lucerne</option>\n<option 
value="NE">Neuchatel</option>\n<option value="NW">Nidwalden</option>\n<option 
value="OW">Obwalden</option>\n<option value="SH">Schaffhausen</option>\n<option 
value="SZ">Schwyz</option>\n<option value="SO">Solothurn</option>\n<option 
value="SG">St. Gallen</option>\n<option value="TG">Thurgau</option>\n<option 
value="TI">Ticino</option>\n<option value="UR">Uri</option>\n<option 
value="VS">Valais</option>\n<option value="VD">Vaud</option>\n<option value="ZG!
 ">Zug</option>\n<option value="ZH">Zurich</option>\n</select>'
+
 ## AUPostCodeField ##########################################################
 
 A field that accepts a four digit Australian post code.


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to