Coverage for lino/utils/ssin.py : 73%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: UTF-8 -*- # Copyright 2008-2015 Luc Saffre # License: BSD (see file COPYING for details)
numbers*.
Belgians call their national identification number **INSZ** ("identificatienummer van de sociale zekerheid) in Dutch, **NISS** ("No. d'identification de Sécurité Sociale") in French or **INSS** ("Identifizierungsnummer der Sozialen Sicherheit") in German. We use the English abbreviation **SSIN** ("Social Security Identification Number"), though some sources also speak about **INSS** ("Identification Number Social Security").
See also
- the Wikipedia articles about `Belgian national identification numbers <http://en.wikipedia.org/wiki/National_identification_number#Belgium>`__, `Numéro de registre national <http://fr.wikipedia.org/wiki/Num%C3%A9ro_de_registre_national>`_ and `Rijksregisternummer <http://nl.wikipedia.org/wiki/Rijksregisternummer>`_
- http://www.ibz.rrn.fgov.be/fileadmin/user_upload/Registre/Acces_RN/RRNS003_F_IV.pdf - http://www.simplification.fgov.be/doc/1206617650-4990.pdf
Formatting Belgian National Numbers -----------------------------------
This module defines the functions :func:`format_ssin` and :func:`new_format_ssin`.
An officialy obsolete but still used format for printing a Belgian SSIN is ``YYMMDDx123-97``, where ``YYMMDD`` is the birth date, ``x`` indicates the century (``*`` for the 19th, a *space* for the 20th and a ``=`` for the 21st century), ``123`` is a sequential number for persons born the same day (odd numbers for men and even numbers for women), and ``97`` is a check digit (remainder of previous digits divided by 97).
Validation ----------
There are two validator functions, :func:`is_valid_ssin` and :func:`ssin_validator`. the difference between them is that one returns True or False while the other raises a ValidationError to be used in Django forms. The message of this ValidationError depends on the user language.
>>> import lino >>> lino.startup('lino.projects.min1.settings')
>>> ssin_validator('123') Traceback (most recent call last): ... ValidationError: [u'Invalid SSIN 123 : A formatted SSIN must have 13 positions']
>>> is_valid_ssin('123') False
Here is the SSIN of a person with incomplete birth date:
>>> from lino.utils import IncompleteDate >>> n = generate_ssin(IncompleteDate(1995, 0, 0), Genders.male, 153) >>> print n 950000 153-96 >>> ssin_validator(n)
No need for special characters? -------------------------------
In 1983 Belgians discovered that the formatting with a special character to indicate the century is not absolutely required since the national register no longer cared about people born before 1900, and now the century can be deduced by trying the check digits.
>>> format_ssin('68060105329') '680601 053-29'
In order to say whether the person is born in 19xx or 20xx, we need to look at the check digits.
For example, the 25th boy born on June 1st in **1912** will get another check-digit than a similar boy exactly 100 years later (in **2012**):
>>> format_ssin('12060105317') '120601 053-17'
>>> format_ssin('12060105346') '120601 053=46'
Question to mathematicians: is it sure that there is no combination of birth date and sequence number for which the check digits are the same?
Functions ---------
"""
"""Generate an SSIN from a given birth date, gender and optional sequence number.
And a function :func:`generate_ssin` is mainly used to generate fictive demo data. For example, here is the national number of the 25th boy born in Belgium on June 1st, 1968:
Examples:
>>> import datetime
>>> n = generate_ssin(datetime.date(1968, 6, 1), Genders.male, 53) >>> print n 680601 053-29 >>> ssin_validator(n)
The sequence number is optional and the default value depends on the gender. For boys it is 1, for girls 2.
>>> n = generate_ssin(datetime.date(2002, 4, 5),Genders.female) >>> print n 020405 002=44 >>> ssin_validator(n)
""" else: raise Exception("Born before 1900")
seq = 1 else: checksum = 97
""" Returns True if this is a valid SSIN. """ return True
"""Formats a raw SSIN as they are printed on the back of Belgian eid cards, for example "68.06.01-053.09"
""" s = s.strip() if not s: return '' if len(s) != 11: raise Exception( force_text(_('Invalid SSIN %s : ') % s) + force_text(_('A raw SSIN must have 11 positions'))) return s[:2] + '.' + s[2:4] + '.' + s[4:6] + '-' + s[6:9] + '.' + s[9:]
"""Remove formatting characters from given SSIN.""" ssin = ssin.replace(YEAR2000, '') ssin = ssin.replace(YEAR1900, '') ssin = ssin.replace(YEAR1800, '') ssin = ssin.replace('.', '') ssin = ssin.replace(' ', '') return ssin
return format_ssin(unformat_ssin(ssin))
""" Add formatting chars to a given raw SSIN. """ return '' raise ValidationError( force_text(_('Invalid SSIN %s : ') % raw_ssin) + force_text(_('A raw SSIN must have 11 positions')))
xtest = 97
raise ValidationError( force_text(_('Invalid SSIN %s : ') % raw_ssin) + force_text(_('Could not recognize checkdigit')))
"""Checks whether the specified SSIN is valid. If not, raises a ValidationError.
""" return '' force_text(_('Invalid SSIN %s : ') % ssin) + force_text(_('A formatted SSIN must have 13 positions')) ) #~ print 'yes' except ValueError as e: raise ValidationError(_('Invalid SSIN %s : ') % ssin + str(e)) xtest = 97 raise ValidationError( force_text(_("Invalid SSIN %s :") % ssin) + _("Check digit is %(found)d but should be %(expected)d") % dict( expected=xtest, found=found) )
|