diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2013-05-17 13:04:14 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2013-06-08 14:45:39 +0200 |
commit | 4753c09e81a0adb6b62d12ad60f5a5107d5033c2 (patch) | |
tree | 5b0eae70498fba8940793fac4bde1b37c6b74897 /stdnum | |
parent | 2259cbb09e419e56c355efdbd865f99127d559c5 (diff) |
Implement validate() for Finnish numbers
Diffstat (limited to 'stdnum')
-rw-r--r-- | stdnum/fi/alv.py | 31 | ||||
-rw-r--r-- | stdnum/fi/hetu.py | 54 |
2 files changed, 58 insertions, 27 deletions
diff --git a/stdnum/fi/alv.py b/stdnum/fi/alv.py index 509ad9c..ed9457c 100644 --- a/stdnum/fi/alv.py +++ b/stdnum/fi/alv.py @@ -1,7 +1,7 @@ # vat.py - functions for handling Finnish VAT numbers # coding: utf-8 # -# Copyright (C) 2012 Arthur de Jong +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -22,14 +22,15 @@ The number is an 8-digit code with a weighted checksum. ->>> compact('FI- 2077474-0') +>>> validate('FI 20774740') '20774740' ->>> is_valid('FI 20774740') -True ->>> is_valid('FI 20774741') # invalid check digit -False +>>> validate('FI 20774741') # invalid check digit +Traceback (most recent call last): + ... +InvalidChecksum: ... """ +from stdnum.exceptions import * from stdnum.util import clean @@ -48,11 +49,23 @@ def checksum(number): return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11 +def validate(number): + """Checks to see if the number provided is a valid VAT number. This + checks the length, formatting and check digit.""" + number = compact(number) + if not number.isdigit(): + raise InvalidFormat() + if len(number) != 8: + raise InvalidLength() + if checksum(number) != 0: + raise InvalidChecksum() + return number + + def is_valid(number): """Checks to see if the number provided is a valid VAT number. This checks the length, formatting and check digit.""" try: - number = compact(number) - except: + return bool(validate(number)) + except ValidationError: return False - return number.isdigit() and len(number) == 8 and checksum(number) == 0 diff --git a/stdnum/fi/hetu.py b/stdnum/fi/hetu.py index b22465d..69b543e 100644 --- a/stdnum/fi/hetu.py +++ b/stdnum/fi/hetu.py @@ -2,6 +2,7 @@ # coding: utf-8 # # Copyright (C) 2011 Jussi Judin +# Copyright (C) 2012, 2013 Arthur de Jong # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -25,12 +26,16 @@ See http://www.vaestorekisterikeskus.fi/default.aspx?id=45 for checksum calculation details and http://tarkistusmerkit.teppovuori.fi/tarkmerk.htm#hetu1 for historical details. ->>> is_valid('131052-308T') -True ->>> is_valid('131052-308U') -False ->>> is_valid('310252-308Y') -False +>>> validate('131052-308T') +'131052-308T' +>>> validate('131052-308U') +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('310252-308Y') +Traceback (most recent call last): + ... +InvalidComponent: ... >>> compact('131052a308t') '131052A308T' """ @@ -38,12 +43,15 @@ False import re import datetime +from stdnum.exceptions import * +from stdnum.util import clean + _century_codes = { '+': 1800, '-': 1900, 'A': 2000, - } +} # Finnish personal identity codes are composed of date part, century # indicating sign, individual number and control character. @@ -56,23 +64,21 @@ _hetu_re = re.compile(r'^(?P<day>[0123]\d)(?P<month>[01]\d)(?P<year>\d\d)' def compact(number): """Convert the HETU to the minimal representation. This strips surrounding whitespace and converts it to upper case.""" - return number.strip().upper() + return clean(number, '').upper().strip() def _calc_checksum(number): return '0123456789ABCDEFHJKLMNPRSTUVWXY'[int(number) % 31] -def is_valid(number): +def validate(number): """Checks to see if the number provided is a valid HETU. It checks the format, whether a valid date is given and whether the check digit is correct.""" - try: - match = _hetu_re.search(compact(number)) - if not match: - return False - except: - return False + number = compact(number) + match = _hetu_re.search(number) + if not match: + raise InvalidFormat() day = int(match.group('day')) month = int(match.group('month')) year = int(match.group('year')) @@ -82,12 +88,24 @@ def is_valid(number): try: datetime.date(century + year, month, day) except ValueError: - return False + raise InvalidComponent() # for historical reasons individual IDs start from 002 if individual < 2: - return False + raise InvalidComponent() checkable_number = '%02d%02d%02d%03d' % (day, month, year, individual) - return match.group('control') == _calc_checksum(checkable_number) + if match.group('control') != _calc_checksum(checkable_number): + raise InvalidChecksum() + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid HETU. It checks the + format, whether a valid date is given and whether the check digit is + correct.""" + try: + return bool(validate(number)) + except ValidationError: + return False # This is here just for completeness as there are no different length forms |