diff --git a/docs/stdnum.ec.ci.rst b/docs/stdnum.ec.ci.rst new file mode 100644 index 00000000..d28b9d1f --- /dev/null +++ b/docs/stdnum.ec.ci.rst @@ -0,0 +1,5 @@ +stdnum.ec.ci +============ + +.. automodule:: stdnum.ec.ci + :members: diff --git a/docs/stdnum.ec.ruc.rst b/docs/stdnum.ec.ruc.rst new file mode 100644 index 00000000..8b9442c7 --- /dev/null +++ b/docs/stdnum.ec.ruc.rst @@ -0,0 +1,5 @@ +stdnum.ec.ruc +============= + +.. automodule:: stdnum.ec.ruc + :members: diff --git a/stdnum/ec/__init__.py b/stdnum/ec/__init__.py new file mode 100644 index 00000000..18d02a88 --- /dev/null +++ b/stdnum/ec/__init__.py @@ -0,0 +1,24 @@ +# __init__.py - collection of Ecuadorian numbers +# coding: utf-8 +# +# Copyright (C) 2014 Jonathan Finlay +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +"""Collection of Ecuadorian numbers.""" + +# provide vat as an alias +from stdnum.ec import ruc as vat diff --git a/stdnum/ec/ci.py b/stdnum/ec/ci.py new file mode 100644 index 00000000..4834d587 --- /dev/null +++ b/stdnum/ec/ci.py @@ -0,0 +1,77 @@ +# dni.py - functions for handling Ecuadorian personal identity codes +# coding: utf-8 +# +# Copyright (C) 2014 Jonathan Finlay +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +"""CI (Cédula de identidad, Ecuadorian personal identity codes). + +The CI is a 10 digit number used to identify Ecuadorian citizens. + +>>> validate('1714307103') +'1714307103' +>>> validate('171430710-3') +'1714307103' +>>> validate('1714307104') # invalid document +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('171430710') # digit missing +Traceback (most recent call last): + ... +InvalidLength: ... +""" + +from stdnum.exceptions import * +from stdnum.util import clean + + +def compact(number): + """Convert the number to the minimal representation. This strips the + number of any valid separators and removes surrounding whitespace.""" + return clean(number, ' -').upper().strip() + + +def checksum(number): + """Calculate the check digit.""" + value = [int(number[x]) * (2 - x % 2) for x in range(9)] + total = sum(map(lambda x: x > 9 and x - 9 or x, value)) + if int(int(number[9] if int(number[9]) != 0 else 10)) != (10 - int(str(total)[-1:])): + return False + return True + + +def validate(number): + """Checks to see if the number provided is a valid CI number. This + checks the length, formatting and check digit.""" + number = compact(number) + if len(number) != 10: + raise InvalidLength() + if not number.isdigit(): + raise InvalidFormat() + if not checksum(number): + raise InvalidChecksum() + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid CI number. This + checks the length, formatting and check digit.""" + try: + return bool(validate(number)) + except ValidationError: + return False diff --git a/stdnum/ec/ruc.py b/stdnum/ec/ruc.py new file mode 100644 index 00000000..f0114bc4 --- /dev/null +++ b/stdnum/ec/ruc.py @@ -0,0 +1,113 @@ +# cif.py - functions for handling Ecuadorian fiscal numbers +# coding: utf-8 +# +# Copyright (C) 2014 Jonathan Finlay +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +"""RUC (Registro Único de Contribuyentes, Ecuadorian company tax number). + +The RUC is a tax identification number for legal entities. It has 13 digits +where the third digit is a number who denoting the type of entity. + +>>> validate('1714307103001') # Natural entity +'1714307103001' +>>> validate('1768152130001') # Public entity +'1768152130001' +>>> validate('1792060346001') # Juridical entity +'1792060346001' +>>> validate('1792060346-001') +'1792060346001' +>>> validate('1763154690001') # Invalid +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> validate('179206034601') # too short +Traceback (most recent call last): + ... +InvalidLength: ... +""" + +from stdnum.ec import ci +from stdnum.exceptions import * + + +__all__ = ['compact', 'validate', 'is_valid'] + + +# use the same compact function as CI +compact = ci.compact + +def calc_check_sum(number): + result = 0 + if int(number[2]) == 6: + # 6 = Public RUC + coefficient = "32765432" + result = sum(int(number[i]) * int(coefficient[i]) for i in range(8)) + residue = result % 11 + if residue == 0: + result = residue + else: + result = 11 - residue + elif int(number[2]) == 9: + # 9 = Juridical RUC + coefficient = "432765432" + result = sum(int(number[i]) * int(coefficient[i]) for i in range(9)) + residue = result % 11 + if residue == 0: + result = residue + else: + result = 11 - residue + elif int(number[2]) < 6: + # less than 6 = Natural RUC + coefficient = "212121212" + for i in range(9): + suma = int(number[i]) * int(coefficient[i]) + if suma > 10: + str_sum = str(suma) + suma = int(str_sum[0]) + int(str_sum[1]) + result += suma + residue = result % 10 + if residue == 0: + result = residue + else: + result = 10 - residue + else: + raise InvalidFormat() + return result + + +def validate(number): + """Checks to see if the number provided is a valid RUC number. This + checks the length, formatting, check digit and check sum.""" + number = compact(number) + if len(number) != 13: + raise InvalidLength() + if not number.isdigit(): + raise InvalidFormat() + checker = int(number[8]) if int(number[2]) == 6 else int(number[9]) + if calc_check_sum(number) != checker: + raise InvalidChecksum() + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid RUC number. This + checks the length, formatting and check digit.""" + try: + return bool(validate(number)) + except ValidationError: + return False