Repository: identique/idnumbers (language: python)

Issue:
id number for Colombia
https://en.wikipedia.org/wiki/National_identification_number#Colombia


Discussion / hints:
Any idea about when the Colombia id number will be available? Great project btw!
Any idea about when the Colombia id number will be available? Great project btw!
@marcilioLemos let me try to finish it before this release. 😄 
@marcilioLemos May you provide some information about the ID number, NUIP? I just googled the result:
* It contains 10 digits, from https://validatetin.com/colombia/#
* The last digit is the checksum. It is a weighted value. I could only find the checksum algorithm from there: https://github.com/anghelvalentin/CountryValidator/blob/master/CountryValidator/CountriesValidators/ColombiaValidator.cs#L61

I cannot make sure if there is any sources about the NUIP checksum algorithm. It would be great if you could provide some.

Fix patch:
diff --git a/idnumbers/nationalid/COL.py b/idnumbers/nationalid/COL.py
new file mode 100644
index 00000000..1cfca16a
--- /dev/null
+++ b/idnumbers/nationalid/COL.py
@@ -0,0 +1,65 @@
+import re
+from types import SimpleNamespace
+from .util import CHECK_DIGIT, validate_regexp, weighted_modulus_digit
+
+
+def normalize(id_number):
+    """strip out useless characters/whitespaces"""
+    return re.sub(r'[-. ]', '', id_number)
+
+
+def colombia_checksum(id_number: str) -> CHECK_DIGIT:
+    """
+    Python version of
+    https://github.com/anghelvalentin/CountryValidator/blob/master/CountryValidator/CountriesValidators/ColombiaValidator.cs
+    """
+    numbers = [int(char) for char in list(normalize(id_number[:-1]))]
+    numbers.reverse()
+    modulus = weighted_modulus_digit(numbers, UniquePersonalID.WEIGHTS[0:len(numbers)], 11)
+    if modulus == 11:
+        return 0
+    elif modulus == 10:
+        return 1
+    else:
+        return modulus
+
+
+class UniquePersonalID:
+    """
+    UniquePersonalID, NUIP, Número único de identidad personal
+    https://en.wikipedia.org/wiki/Colombian_identity_card
+    https://validatetin.com/colombia/#
+    """
+    METADATA = SimpleNamespace(**{
+        'iso3166_alpha2': 'CO',
+        # length without insignificant chars
+        'min_length': 9,
+        'max_length': 10,
+        # has parse function
+        'parsable': False,
+        # has checksum function
+        'checksum': True,
+        # regular expression to validate the id
+        'regexp': re.compile(r'^(\d{2,3}\.?\d{3}\.?\d{3}-?\d)$')
+    })
+
+    WEIGHTS = [3, 7, 13, 17, 19, 23, 29, 37, 41, 43, 47, 53, 59, 67, 71]
+
+    @staticmethod
+    def validate(id_number: str) -> bool:
+        """
+        Validate id number
+        """
+        if not validate_regexp(id_number, UniquePersonalID.METADATA.regexp):
+            return False
+        return UniquePersonalID.checksum(id_number) == int(id_number[-1])
+
+    @staticmethod
+    def checksum(id_number: str) -> CHECK_DIGIT:
+        if not validate_regexp(id_number, UniquePersonalID.METADATA.regexp):
+            return False
+        return colombia_checksum(id_number)
+
+
+NUIP = UniquePersonalID
+"""alias of UniquePersonalID"""


Test patch:
diff --git a/tests/nationalid/test_COL.py b/tests/nationalid/test_COL.py
new file mode 100644
index 00000000..5101931b
--- /dev/null
+++ b/tests/nationalid/test_COL.py
@@ -0,0 +1,15 @@
+from unittest import TestCase
+
+from idnumbers.nationalid import COL
+
+
+class TestCOLNationalIDValidation(TestCase):
+    def test_normal_case(self):
+        self.assertTrue(COL.NUIP.validate('901.458.652-7'))
+        self.assertTrue(COL.NUIP.validate('800.134.536-3'))
+        self.assertTrue(COL.NUIP.validate('900701704-1'))
+        self.assertTrue(COL.NUIP.validate('52.238.803-1'))
+
+    def test_error_case(self):
+        self.assertFalse(COL.NUIP.validate('901.458.652-6'))
+        self.assertFalse(COL.NUIP.validate('800.134.536-2'))