lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 0.9-22-ge2948bb

[Date Prev][Date Next] [Thread Prev][Thread Next]

python-stdnum branch master updated. 0.9-22-ge2948bb



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".

The branch, master has been updated
       via  e2948bb6bd0ebf7b3828ac989a56d0e61982c545 (commit)
       via  e5250be45092363504ff61c868938439ec958985 (commit)
       via  10a044fe6efd05dcb9ead2d17c33f27dbd2b780c (commit)
       via  f61b855cf64bc1a91b196040b27dd176a3a50890 (commit)
       via  e8f1ca6022fa7e6e1fe309f4c1b141d85b73ed30 (commit)
      from  2700b7a064b0d0b7dcb71c91de33207826c15cea (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://arthurdejong.org/git/python-stdnum/commit/?id=e2948bb6bd0ebf7b3828ac989a56d0e61982c545

commit e2948bb6bd0ebf7b3828ac989a56d0e61982c545
Merge: 2700b7a e5250be
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Oct 17 21:54:28 2014 +0200

    Add Ecuadorian CI and RUC numbers
    
    Add modules for Ecuadorian Identification Card (CI - Cédula de
    identidad) and Fiscal Numbers (RUC - Registro Único de Contribuyentes)
    
    See: https://github.com/arthurdejong/python-stdnum/pull/12


http://arthurdejong.org/git/python-stdnum/commit/?id=e5250be45092363504ff61c868938439ec958985

commit e5250be45092363504ff61c868938439ec958985
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Oct 17 21:14:42 2014 +0200

    Validate parts of numbers
    
    This raises exceptions when the provice or establishment number part of
    the number contains invalid values.

diff --git a/stdnum/ec/ci.py b/stdnum/ec/ci.py
index a32c6e3..9343e47 100644
--- a/stdnum/ec/ci.py
+++ b/stdnum/ec/ci.py
@@ -60,6 +60,10 @@ def validate(number):
         raise InvalidLength()
     if not number.isdigit():
         raise InvalidFormat()
+    if number[:2] < '01' or number[:2] > '24':
+        raise InvalidComponent()  # invalid province code
+    if number[2] > '5':
+        raise InvalidComponent()  # third digit wrong
     if _checksum(number) != 0:
         raise InvalidChecksum()
     return number
diff --git a/stdnum/ec/ruc.py b/stdnum/ec/ruc.py
index 0bc62b5..8887467 100644
--- a/stdnum/ec/ruc.py
+++ b/stdnum/ec/ruc.py
@@ -60,15 +60,23 @@ def validate(number):
         raise InvalidLength()
     if not number.isdigit():
         raise InvalidFormat()
+    if number[:2] < '01' or number[:2] > '24':
+        raise InvalidComponent()  # invalid province code
     if number[2] < '6':
         # 0..5 = natural RUC: CI plus establishment number
+        if number[-3:] == '000':
+            raise InvalidComponent()  # establishment number wrong
         ci.validate(number[:10])
     elif number[2] == '6':
         # 6 = public RUC
+        if number[-4:] == '0000':
+            raise InvalidComponent()  # establishment number wrong
         if _checksum(number[:9], (3, 2, 7, 6, 5, 4, 3, 2, 1)) != 0:
             raise InvalidChecksum()
     elif number[2] == '9':
         # 9 = juridical RUC
+        if number[-3:] == '000':
+            raise InvalidComponent()  # establishment number wrong
         if _checksum(number[:10], (4, 3, 2, 7, 6, 5, 4, 3, 2, 1)) != 0:
             raise InvalidChecksum()
     else:
diff --git a/tests/test_ec_ci.doctest b/tests/test_ec_ci.doctest
index 2ab58fb..08efb8b 100644
--- a/tests/test_ec_ci.doctest
+++ b/tests/test_ec_ci.doctest
@@ -55,3 +55,11 @@ InvalidLength: ...
 Traceback (most recent call last):
     ...
 InvalidFormat: ...
+>>> ci.validate('1784307108')  # third digit wrong
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> ci.validate('8814307107')  # invalid province code
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
diff --git a/tests/test_ec_ruc.doctest b/tests/test_ec_ruc.doctest
index e64346b..2f1065f 100644
--- a/tests/test_ec_ruc.doctest
+++ b/tests/test_ec_ruc.doctest
@@ -136,3 +136,29 @@ InvalidChecksum: ...
 Traceback (most recent call last):
     ...
 InvalidChecksum: ...
+
+>>> ruc.validate('8810034069001')  # invalid province code in natural RUC
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> ruc.validate('8868152120001')  # invalid province code in public RUC
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> ruc.validate('8892397539001')  # invalid province code in juridical RUC
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+
+>>> ruc.validate('0926687856000')  # invalid establishment in natural RUC
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> ruc.validate('1760001550000')  # invalid establishment in public RUC
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> ruc.validate('0992397535000')  # invalid establishment in juridical RUC
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...

http://arthurdejong.org/git/python-stdnum/commit/?id=10a044fe6efd05dcb9ead2d17c33f27dbd2b780c

commit 10a044fe6efd05dcb9ead2d17c33f27dbd2b780c
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Oct 17 21:12:43 2014 +0200

    Refactor checksum functions
    
    Use the CI checks from within the RUC module for natural RUC numbers
    (thereby eliminating a bug in the RUC checksum calculation) and simplify
    the checksum functions.

diff --git a/stdnum/ec/ci.py b/stdnum/ec/ci.py
index bf4ad3e..a32c6e3 100644
--- a/stdnum/ec/ci.py
+++ b/stdnum/ec/ci.py
@@ -2,6 +2,7 @@
 # coding: utf-8
 #
 # Copyright (C) 2014 Jonathan Finlay
+# Copyright (C) 2014 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
@@ -44,13 +45,11 @@ def compact(number):
     return clean(number, ' -').upper().strip()
 
 
-def checksum(number):
+def _checksum(number):
     """Calculate a checksum over the number."""
-    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
+    fold = lambda x: x - 9 if x > 9 else x
+    return sum(fold((2 - (i % 2)) * int(n))
+               for i, n in enumerate(number)) % 10
 
 
 def validate(number):
@@ -61,7 +60,7 @@ def validate(number):
         raise InvalidLength()
     if not number.isdigit():
         raise InvalidFormat()
-    if not checksum(number):
+    if _checksum(number) != 0:
         raise InvalidChecksum()
     return number
 
diff --git a/stdnum/ec/ruc.py b/stdnum/ec/ruc.py
index 7a4a1c8..0bc62b5 100644
--- a/stdnum/ec/ruc.py
+++ b/stdnum/ec/ruc.py
@@ -2,6 +2,7 @@
 # coding: utf-8
 #
 # Copyright (C) 2014 Jonathan Finlay
+# Copyright (C) 2014 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
@@ -46,43 +47,9 @@ __all__ = ['compact', 'validate', 'is_valid']
 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 _checksum(number, weights):
+    """Calculate a checksum over the number given the weights."""
+    return sum(weights[i] * int(n) for i, n in enumerate(number)) % 11
 
 
 def validate(number):
@@ -93,9 +60,19 @@ def validate(number):
         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()
+    if number[2] < '6':
+        # 0..5 = natural RUC: CI plus establishment number
+        ci.validate(number[:10])
+    elif number[2] == '6':
+        # 6 = public RUC
+        if _checksum(number[:9], (3, 2, 7, 6, 5, 4, 3, 2, 1)) != 0:
+            raise InvalidChecksum()
+    elif number[2] == '9':
+        # 9 = juridical RUC
+        if _checksum(number[:10], (4, 3, 2, 7, 6, 5, 4, 3, 2, 1)) != 0:
+            raise InvalidChecksum()
+    else:
+        raise InvalidComponent()  # third digit wrong
     return number
 
 

http://arthurdejong.org/git/python-stdnum/commit/?id=f61b855cf64bc1a91b196040b27dd176a3a50890

commit f61b855cf64bc1a91b196040b27dd176a3a50890
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Fri Oct 17 18:33:02 2014 +0200

    Use dedicated doctests
    
    This moves a number of the existing test cases to dedicated doctest
    files and extend the tests with more numbers and corner cases.
    
    This also fixes a few docstrings.

diff --git a/stdnum/ec/ci.py b/stdnum/ec/ci.py
index 4834d58..bf4ad3e 100644
--- a/stdnum/ec/ci.py
+++ b/stdnum/ec/ci.py
@@ -1,4 +1,4 @@
-# dni.py - functions for handling Ecuadorian personal identity codes
+# ci.py - functions for handling Ecuadorian personal identity codes
 # coding: utf-8
 #
 # Copyright (C) 2014 Jonathan Finlay
@@ -18,15 +18,13 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 # 02110-1301 USA
 
-"""CI (Cédula de identidad, Ecuadorian personal identity codes).
+"""CI (Cédula de identidad, Ecuadorian personal identity code).
 
 The CI is a 10 digit number used to identify Ecuadorian citizens.
 
->>> validate('1714307103')
-'1714307103'
 >>> validate('171430710-3')
 '1714307103'
->>> validate('1714307104')  # invalid document
+>>> validate('1714307104')  # invalid check digit
 Traceback (most recent call last):
     ...
 InvalidChecksum: ...
@@ -47,7 +45,7 @@ def compact(number):
 
 
 def checksum(number):
-    """Calculate the check digit."""
+    """Calculate a checksum over the number."""
     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:])):
diff --git a/stdnum/ec/ruc.py b/stdnum/ec/ruc.py
index c39e73e..7a4a1c8 100644
--- a/stdnum/ec/ruc.py
+++ b/stdnum/ec/ruc.py
@@ -1,4 +1,4 @@
-# cif.py - functions for handling Ecuadorian fiscal numbers
+# ruc.py - functions for handling Ecuadorian fiscal numbers
 # coding: utf-8
 #
 # Copyright (C) 2014 Jonathan Finlay
@@ -21,17 +21,11 @@
 """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.
+where the third digit is a number 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
+>>> validate('1763154690001')  # invalid check digit
 Traceback (most recent call last):
     ...
 InvalidChecksum: ...
diff --git a/tests/test_ec_ci.doctest b/tests/test_ec_ci.doctest
new file mode 100644
index 0000000..2ab58fb
--- /dev/null
+++ b/tests/test_ec_ci.doctest
@@ -0,0 +1,57 @@
+test_ec_ci.doctest - more detailed doctests for stdnum.ec.ci module
+
+Copyright (C) 2014 Jonathan Finlay
+Copyright (C) 2014 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
+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
+
+
+This file contains more detailed doctests for the stdnum.ec.ci. It tries to
+cover more corner cases and detailed functionality that is not really useful
+as module documentation.
+
+>>> from stdnum.ec import ci
+>>> from stdnum.exceptions import *
+
+
+Normal values that should just work.
+
+>>> ci.validate('1714307103')
+'1714307103'
+>>> ci.validate('171430710-3')
+'1714307103'
+>>> ci.validate('0602910945')
+'0602910945'
+>>> ci.validate('0926687856')
+'0926687856'
+>>> ci.validate('0910005917')
+'0910005917'
+
+
+Some invalid numbers.
+
+>>> ci.validate('1714307104')  # invalid check digit
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> ci.validate('171430710')  # digit missing
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> ci.validate('123A567890')  # contains a letter
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
diff --git a/tests/test_ec_ruc.doctest b/tests/test_ec_ruc.doctest
new file mode 100644
index 0000000..e64346b
--- /dev/null
+++ b/tests/test_ec_ruc.doctest
@@ -0,0 +1,138 @@
+test_ec_ruc.doctest - more detailed doctests for stdnum.ec.ruc module
+
+Copyright (C) 2014 Jonathan Finlay
+Copyright (C) 2014 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
+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
+
+
+This file contains more detailed doctests for the stdnum.ec.ruc. It tries to
+cover more corner cases and detailed functionality that is not really useful
+as module documentation.
+
+>>> from stdnum.ec import ruc
+>>> from stdnum.exceptions import *
+
+
+Normal natural RUC values (third digit less than 6) that should just work.
+
+>>> numbers = '''
+... 0101016905001
+... 0602910945001
+... 0910005917001
+... 0926687856001
+... 1001152287001
+... 1102755442001
+... 1104552037001
+... 1311919078001
+... 1700672486001
+... 1702264233001
+... 1704159860001
+... 1710034065001
+... 1710585264001
+... 1710589373001
+... 1713238234001
+... 1714307103001
+... 1721788659001
+... 1803557964001
+... '''
+>>> [x for x in numbers.splitlines() if x and not ruc.is_valid(x)]
+[]
+
+
+Normal public RUC values (third digit is 6) that should just work.
+
+>>> numbers = '''
+... 0160001910001
+... 0260001060001
+... 0360001040001
+... 0560000540001
+... 0660000280001
+... 0660000600001
+... 0660000870001
+... 0968529830001
+... 1060000420001
+... 1060000690001
+... 1060008080001
+... 1060024600001
+... 1360000630001
+... 1560000780001
+... 1760001040001
+... 1760001550001
+... 1760009880001
+... 1768007390001
+... 1768152130001
+... 2160011760001
+... '''
+>>> [x for x in numbers.splitlines() if x and not ruc.is_valid(x)]
+[]
+
+
+Normal juridical RUC values (third digit is 9) that should just work.
+
+>>> numbers = '''
+... 0190155722001
+... 0490002669001
+... 0590041920001
+... 0790024656001
+... 0990138850001
+... 0992397535001
+... 1190015110001
+... 1390007791001
+... 1390089410001
+... 1390091474001
+... 1790011674001
+... 1790085783001
+... 1790325083001
+... 1791280172001
+... 1791714350001
+... 1792060346001
+... 1792141869001
+... 1792373255001
+... 1890001323001
+... 1890037646001
+... '''
+>>> [x for x in numbers.splitlines() if x and not ruc.is_valid(x)]
+[]
+
+
+Values that are invalid in one way or another:
+
+>>> ruc.validate('179206034601')  # too short
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> ruc.validate('17920603A6001')  # contains a character
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> ruc.validate('0170000610001')  # third digit invalid
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+
+>>> ruc.validate('1763154690001')  # invalid check digit in natural RUC
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> ruc.validate('0160000610001')  # invalid check digit in public RUC
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> ruc.validate('0190115799001')  # invalid check digit in juridical RUC
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...

http://arthurdejong.org/git/python-stdnum/commit/?id=e8f1ca6022fa7e6e1fe309f4c1b141d85b73ed30

commit e8f1ca6022fa7e6e1fe309f4c1b141d85b73ed30
Author: Jonathan Finlay <jfinlay@riseup.net>
Date:   Sun Oct 12 04:23:12 2014 +0200

    Add Ecuadorian CI and RUC numbers
    
    Add modules for Ecuadorian Identification Card (CI - Cédula de
    identidad) and Fiscal Numbers (RUC - Registro Único de Contribuyentes)

diff --git a/stdnum/ec/__init__.py b/stdnum/ec/__init__.py
new file mode 100644
index 0000000..18d02a8
--- /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 0000000..4834d58
--- /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 0000000..c39e73e
--- /dev/null
+++ b/stdnum/ec/ruc.py
@@ -0,0 +1,114 @@
+# 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

-----------------------------------------------------------------------

Summary of changes:
 stdnum/{cz => ec}/__init__.py  |    8 +-
 stdnum/{es/dni.py => ec/ci.py} |   46 +++++------
 stdnum/ec/ruc.py               |   93 +++++++++++++++++++++++
 tests/test_ec_ci.doctest       |   65 ++++++++++++++++
 tests/test_ec_ruc.doctest      |  164 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 350 insertions(+), 26 deletions(-)
 copy stdnum/{cz => ec}/__init__.py (82%)
 copy stdnum/{es/dni.py => ec/ci.py} (60%)
 create mode 100644 stdnum/ec/ruc.py
 create mode 100644 tests/test_ec_ci.doctest
 create mode 100644 tests/test_ec_ruc.doctest


hooks/post-receive
-- 
python-stdnum
-- 
To unsubscribe send an email to
python-stdnum-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/python-stdnum-commits/