Repository: identique/idnumbers (language: python)

Issue:
[NationalID] Denmark TIN
## basic data
* Country ISO-3166 code: DNK
* Links to National IDs
    * TIN: check file at #239  


Discussion / hints:

Fix patch:
diff --git a/idnumbers/nationalid/DNK.py b/idnumbers/nationalid/DNK.py
index d73a6029..956109ab 100644
--- a/idnumbers/nationalid/DNK.py
+++ b/idnumbers/nationalid/DNK.py
@@ -1,7 +1,14 @@
+from types import SimpleNamespace
 from .dnk.personal_id import PersonalIdentityNumber
+from .dnk.entity_vat import EntityVAT
 from .util import alias_of
 
 NationalID = alias_of(PersonalIdentityNumber)
 """alias of PersonalIdentityNumber"""
 CPR = alias_of(PersonalIdentityNumber)
 """alias of PersonalIdentityNumber"""
+
+TIN = SimpleNamespace(**{
+    'individual': PersonalIdentityNumber,
+    'entity': EntityVAT
+})
diff --git a/idnumbers/nationalid/dnk/entity_vat.py b/idnumbers/nationalid/dnk/entity_vat.py
new file mode 100644
index 00000000..6ff56196
--- /dev/null
+++ b/idnumbers/nationalid/dnk/entity_vat.py
@@ -0,0 +1,48 @@
+import re
+from types import SimpleNamespace
+from ..util import validate_regexp, weighted_modulus_digit
+
+
+class EntityVAT:
+    """
+    Entity VAT Number is called Momsregistreringsnummer or CVR nummer.
+    https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/tax-identification-numbers/Denmark-TIN.pdf
+    https://wiki.scn.sap.com/wiki/display/CRM/Denmark
+    CPR numbers issued after 1 October 2007 can have a different format meaning that the last digit is not a check digit
+    and can therefore not be verified on the TIN on Europa web portal.
+    """
+    METADATA = SimpleNamespace(**{
+        'iso3166_alpha2': 'DK',
+        'min_length': 8,
+        'max_length': 8,
+        'parsable': False,
+        'checksum': True,
+        'regexp': re.compile(r'^\d{8}$'),
+        'alias_of': None,
+        'names': ['Entity VAT',
+                  'CVR',
+                  'SE',
+                  'Momsregistreringsnummer'],
+        'links': ['https://wiki.scn.sap.com/wiki/display/CRM/Denmark',
+                  'https://www.oecd.org/tax/automatic-exchange/crs-implementation-and-assistance/'
+                  'tax-identification-numbers/Denmark-TIN.pdf'],
+        'deprecated': False
+    })
+
+    MULTIPLIER = [2, 7, 6, 5, 4, 3, 2, 1]
+
+    @staticmethod
+    def validate(id_number: str) -> bool:
+        """
+        Validate the id number
+        """
+        return EntityVAT.checksum(id_number)
+
+    @staticmethod
+    def checksum(id_number: str) -> bool:
+        """ validate the CVR id"""
+        if not validate_regexp(id_number, EntityVAT.METADATA.regexp):
+            return False
+
+        numbers = [int(char) for char in id_number]
+        return weighted_modulus_digit(numbers, EntityVAT.MULTIPLIER, 11, True) == 0
diff --git a/idnumbers/nationalid/dnk/personal_id.py b/idnumbers/nationalid/dnk/personal_id.py
index 86581e89..cd86f8db 100644
--- a/idnumbers/nationalid/dnk/personal_id.py
+++ b/idnumbers/nationalid/dnk/personal_id.py
@@ -17,6 +17,8 @@ class PersonalIdentityNumber:
     """
     Denmark personal identity number, CPR, Det Centrale Personregister
     https://en.wikipedia.org/wiki/National_identification_number#Denmark
+    CPR numbers issued after 1 October 2007 can have a different format meaning that the last digit is not a check digit
+    and can therefore not be verified on the TIN on Europa web portal.
     """
     METADATA = SimpleNamespace(**{
         'iso3166_alpha2': 'DK',


Test patch:
diff --git a/tests/nationalid/test_DNK.py b/tests/nationalid/test_DNK.py
index 35c0190f..b4d32976 100644
--- a/tests/nationalid/test_DNK.py
+++ b/tests/nationalid/test_DNK.py
@@ -1,7 +1,6 @@
 from unittest import TestCase
 
 from idnumbers.nationalid import DNK
-from idnumbers.nationalid.constant import Gender
 
 
 class TestDNKValidation(TestCase):
@@ -17,3 +16,8 @@ def test_parse(self):
         self.assertEqual(10, result['yyyymmdd'].month)
         self.assertEqual(6, result['yyyymmdd'].day)
         self.assertEqual('1178', result['sn'])
+
+    def test_tin(self):
+        self.assertTrue(DNK.TIN.individual.validate('0101801234'))
+        self.assertTrue(DNK.TIN.entity.validate('88146328'))
+        self.assertFalse(DNK.TIN.entity.validate('88146327'))