lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 1.16-18-g424e408

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

python-stdnum branch master updated. 1.16-18-g424e408



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  424e408707a66fa97e95d3fd109c4a2ff44af08f (commit)
      from  36d723ce54dc0a9e2404e24b55311321367786af (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 -----------------------------------------------------------------
https://arthurdejong.org/git/python-stdnum/commit/?id=424e408707a66fa97e95d3fd109c4a2ff44af08f

commit 424e408707a66fa97e95d3fd109c4a2ff44af08f
Author: Piruin Panichphol <piruin.p@gmail.com>
Date:   Sun Feb 21 20:40:02 2021 +0700

    Add support for Thai Numbers
    
    - TIN Taxpayer Identification Number
    - PIN Personal Identification Number
    - MOA Memorandum of Association Number
    
    Closes https://github.com/arthurdejong/python-stdnum/issues/118
    Closes https://github.com/arthurdejong/python-stdnum/pull/255

diff --git a/stdnum/th/__init__.py b/stdnum/th/__init__.py
new file mode 100644
index 0000000..7e47a0c
--- /dev/null
+++ b/stdnum/th/__init__.py
@@ -0,0 +1,21 @@
+# __init__.py - collection of Thai numbers
+# coding: utf-8
+#
+# Copyright (C) 2021 Piruin Panichphol
+#
+# 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 Thai numbers."""
diff --git a/stdnum/th/moa.py b/stdnum/th/moa.py
new file mode 100644
index 0000000..9538021
--- /dev/null
+++ b/stdnum/th/moa.py
@@ -0,0 +1,94 @@
+# moa.py - functions for handling Memorandum of Association Number
+#
+# Copyright (C) 2021 Piruin Panichphol
+#
+# 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
+
+"""MOA (Thailand Memorandum of Association Number).
+
+Memorandum of Association Number (aka Company's Taxpayer Identification
+Number) are numbers issued by the Department of Business Development.
+
+The number consists of 13 digits of which the last is a check digit following
+the same algorithm as in the Personal Identity Number (PIN). It uses a
+different grouping format and always starts with zero to indicate that the
+number issued by DBD.
+
+More information:
+
+* https://www.dbd.go.th/download/pdf_kc/s09/busin_2542-48.pdf
+
+>>> compact('0 10 5 536 11201 4')
+'0105536112014'
+>>> validate('0994000617721')
+'0994000617721'
+>>> validate('0-99-4-000-61772-1')
+'0994000617721'
+>>> validate('0-99-4-000-61772-3')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> format('0993000133978')
+'0-99-3-000-13397-8'
+"""
+
+from stdnum.exceptions import *
+from stdnum.th import pin
+from stdnum.util import clean, isdigits
+
+
+__all__ = ['compact', 'calc_check_digit', 'validate', 'is_valid', 'format']
+
+
+# use the same calc_check_digit function as PIN
+calc_check_digit = pin.calc_check_digit
+
+
+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, ' -').strip()
+
+
+def validate(number):
+    """Check if the number is a valid MOA Number. This checks the length,
+    formatting, component and check digit."""
+    number = compact(number)
+    if len(number) != 13:
+        raise InvalidLength()
+    if not isdigits(number):
+        raise InvalidFormat()
+    if number[0] != '0':
+        raise InvalidComponent()
+    if number[-1] != calc_check_digit(number):
+        raise InvalidChecksum()
+    return number
+
+
+def is_valid(number):
+    """Check whether the number is valid."""
+    try:
+        return bool(validate(number))
+    except ValidationError:
+        return False
+
+
+def format(number):
+    """Reformat the number to the standard presentation format."""
+    number = compact(number)
+    return '-'.join((
+        number[:1], number[1:3], number[3:4], number[4:7], number[7:12],
+        number[12:]))
diff --git a/stdnum/th/pin.py b/stdnum/th/pin.py
new file mode 100644
index 0000000..77afe40
--- /dev/null
+++ b/stdnum/th/pin.py
@@ -0,0 +1,90 @@
+# pin.py - functions for handling Thailand PINs
+#
+# Copyright (C) 2021 Piruin Panichphol
+#
+# 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
+
+"""PIN (Thailand Personal Identification Number).
+
+The Thailand Personal Identification Number is a unique personal identifier
+assigned at birth or upon receiving Thai citizenship issue by the Ministry of
+Interior.
+
+This number consists of 13 digits which the last is a check digit. Usually
+separated into five groups using hyphens to make it easier to read.
+
+More information:
+
+* https://en.wikipedia.org/wiki/Thai_identity_card
+
+>>> compact('1-2345-45678-78-1')
+'1234545678781'
+>>> validate('3100600445635')
+'3100600445635'
+>>> validate('1-2345-45678-78-1')
+'1234545678781'
+>>> validate('1-2345-45678-78-9')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> format('7100600445635')
+'7-1006-00445-63-5'
+"""
+
+from stdnum.exceptions import *
+from stdnum.util import clean, isdigits
+
+
+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, ' -').strip()
+
+
+def calc_check_digit(number):
+    """Calculate the check digit."""
+    s = sum((2 - i) * int(n) for i, n in enumerate(number[:12])) % 11
+    return str((1 - s) % 10)
+
+
+def validate(number):
+    """Check if the number is a valid PIN. This checks the length,
+    formatting and check digit."""
+    number = compact(number)
+    if len(number) != 13:
+        raise InvalidLength()
+    if not isdigits(number):
+        raise InvalidFormat()
+    if number[0] in ('0', '9'):
+        raise InvalidComponent()
+    if number[-1] != calc_check_digit(number):
+        raise InvalidChecksum()
+    return number
+
+
+def is_valid(number):
+    """Check whether the number is valid."""
+    try:
+        return bool(validate(number))
+    except ValidationError:
+        return False
+
+
+def format(number):
+    """Reformat the number to the standard presentation format."""
+    number = compact(number)
+    return '-'.join((
+        number[:1], number[1:5], number[5:10], number[10:12], number[12:]))
diff --git a/stdnum/th/tin.py b/stdnum/th/tin.py
new file mode 100644
index 0000000..cc51387
--- /dev/null
+++ b/stdnum/th/tin.py
@@ -0,0 +1,95 @@
+# tin.py - functions for handling Thailand TINs
+#
+# Copyright (C) 2021 Piruin Panichphol
+#
+# 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
+
+"""TIN (Thailand Taxpayer Identification Number).
+
+The Taxpayer Identification Number is used for tax purposes in the Thailand.
+This number consists of 13 digits which the last is a check digit.
+
+Personal income taxpayers use Personal Identification Number (PIN) while
+companies use Memorandum of Association (MOA).
+
+>>> validate('1-2345-45678-78-1')
+'1234545678781'
+>>> validate('0-99-4-000-61772-1')
+'0994000617721'
+>>> validate('1234545678789')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> tin_type('1-2345-45678-78-1')
+'pin'
+>>> tin_type('0-99-4-000-61772-1')
+'moa'
+>>> format('3100600445635')
+'3-1006-00445-63-5'
+>>> format('0993000133978')
+'0-99-3-000-13397-8'
+"""
+
+from stdnum.exceptions import *
+from stdnum.th import moa, pin
+from stdnum.util import clean
+
+
+_tin_modules = (moa, pin)
+
+
+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, ' -').strip()
+
+
+def tin_type(number):
+    """Return a TIN type which this number is valid."""
+    number = compact(number)
+    for mod in _tin_modules:
+        if mod.is_valid(number):
+            return mod.__name__.rsplit('.', 1)[-1]
+    # fallback
+    return None
+
+
+def validate(number):
+    """Check if the number is a valid TIN. This searches for the proper
+    sub-type and validates using that."""
+    for mod in _tin_modules:
+        try:
+            return mod.validate(number)
+        except ValidationError:
+            pass  # try next module
+    # fallback
+    raise InvalidFormat()
+
+
+def is_valid(number):
+    """Check whether the number is valid."""
+    try:
+        return bool(validate(number))
+    except ValidationError:
+        return False
+
+
+def format(number):
+    """Reformat the number to the standard presentation format."""
+    for mod in _tin_modules:
+        if mod.is_valid(number):
+            return mod.format(number)
+    return number
diff --git a/tests/test_th_moa.doctest b/tests/test_th_moa.doctest
new file mode 100644
index 0000000..47c0f08
--- /dev/null
+++ b/tests/test_th_moa.doctest
@@ -0,0 +1,83 @@
+test_th_mod.doctest - more detailed doctests for stdnum.th.moa module
+
+Copyright (C) 2021 Piruin Panichphol
+
+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.th.moa module.
+
+>>> from stdnum.th import moa
+
+
+>>> moa.validate('0-99-4-000')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> moa.validate('0-99-4-00A-61772-X')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> moa.validate('3-99-4-000-61772-1')
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> moa.validate('0-99-4-000-61772-8')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+
+
+These have been found online and should all be valid numbers.
+https://vsreg.rd.go.th/VATINFOWSWeb/jsp/VATInfoWSServlet?
+
+>>> numbers = '''
+...
+... 0 10 5 544 04660 2
+... 0 10 5 559 13643 2
+... 0 10 5 560 07360 1
+... 0 1055 43000 15 3
+... 0 12 5 551 01213 1
+... 0 19 5 554 00071 1
+... 0 22 5 550 00051 1
+... 0-10-3-541-01737-5
+... 0-10-5-518-00189-3
+... 0-10-5-539-13697-6
+... 0-10-5-554-04636-2
+... 0-7035-36000-78-2
+... 0-99-2-002-50289-9
+... 01055  6302 15 4 7
+... 0105530041751
+... 0105542067556
+... 0105543014758
+... 0105549020393
+... 0105554084159
+... 0105556000751
+... 0105556142792
+... 0115555008901
+... 0115556023301
+... 0245541000066
+... 05  0  55440 03519
+... 0655554000295
+... 0713551000259
+... 0745554003056
+... 0992001001446
+... 0992001158728
+... 0992001526719
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not moa.is_valid(x)]
+[]
diff --git a/tests/test_th_pin.doctest b/tests/test_th_pin.doctest
new file mode 100644
index 0000000..eee130b
--- /dev/null
+++ b/tests/test_th_pin.doctest
@@ -0,0 +1,96 @@
+test_th_pin.doctest - more detailed doctests for stdnum.th.pin module
+
+Copyright (C) 2021 Piruin Panichphol
+
+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.th.pin module.
+
+>>> from stdnum.th import pin
+
+
+>>> pin.validate('1-2345-45678-78-11')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> pin.validate('1-2345-45678-78-X')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> pin.validate('0-2345-45678-78-1')
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> pin.validate('9-2345-45678-78-1')
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+
+
+These have been found online and should all be valid numbers.
+
+>>> numbers = '''
+...
+... 1 1101 00152 64 1
+... 1 1996 00076 67 4
+... 1 6299 00299 92 5
+... 1 7399 00504 82 0
+... 1-1002-00439-84-4
+... 1100900359657
+... 1311100161266
+... 1350500075722
+... 1459900065632
+... 1670800079267
+... 2 3107 00002 24 7
+... 3   451  000  50     5414
+... 3  3415  01 082 5 68
+... 3  91 05 00  3    92 03 6
+... 3 5099 00736 90 7
+... 3 6710 00129 65 8
+... 3 7401 00523 48 8
+... 3-1001-00818-95-5
+... 3-1103-00283-26-5
+... 3-1898-00009-58-6
+... 3-3207-00476-55-7
+... 3-5207-00211-03-9
+... 3-6599-00381-54-7
+... 3-7005-00702-40-1
+... 3-9099-00588-10-6
+... 3100400648338
+... 3101900254691
+... 3102400746269
+... 33508 0030 2577
+... 3400100399577
+... 3540200423193
+... 3569900168313
+... 3600500113229
+... 3629900162691
+... 3709800221741
+... 3810100438722
+... 4 6205000  0482 7
+... 4-6607-00003-53-1
+... 4220100005137
+... 5 3013 00038 01 1
+... 5 5805 90000 01 9
+... 5100200233319
+... 5260399000878
+... 5671000003006
+... 5900599008311
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not pin.is_valid(x)]
+[]
diff --git a/tests/test_th_tin.doctest b/tests/test_th_tin.doctest
new file mode 100644
index 0000000..52e5e1d
--- /dev/null
+++ b/tests/test_th_tin.doctest
@@ -0,0 +1,93 @@
+test_th_tin.doctest - more detailed doctests for stdnum.th.tin module
+
+Copyright (C) 2021 Piruin Panichphol
+
+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.th.tin module.
+
+>>> from stdnum.th import tin
+
+
+>>> tin.validate('1-2345-45678-78-11') # InvalidLength
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> tin.validate('1-2345-45678-78-X') # InvalidFormat
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> tin.validate('0-2345-45678-78-1') # InvalidChecksum
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> tin.validate('9-2345-45678-78-1') # InvalidComponent
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> tin.format('0234545678783')
+'0-23-4-545-67878-3'
+>>> tin.format('0234545678781') # Not format invalid number
+'0234545678781'
+>>> tin.tin_type('0234545678783')
+'moa'
+>>> tin.tin_type('0234545678780')  # Invalid number return None
+
+
+These have been found online and should all be valid numbers.
+
+>>> numbers = '''
+...
+... 0 13 5 559 01262 8
+... 0 20 5 560 00584 1
+... 0 55 3 561 00041 5
+... 0 74 5 561 00276 1
+... 0-11-5-561-01623-6
+... 0-2055-61011-25-0
+... 0-2155-51001-61-8
+... 0-3035-50001-80-8
+... 0-33-3-558-00060-6
+... 0-47-5-562-00062-4
+... 0-58-3-558-00012-4
+... 0-73-5-561-00588-3
+... 0-7355-56003-30-4
+... 0105552029681
+... 0105559074461
+... 0343559002742
+... 0403552000484
+... 0835561014091
+... 1 1020 01865 33 1
+... 1 3501 00018 05 5
+... 1-40-9-900-07433-0
+... 1-4701-00062-82-7
+... 1-56-0-300-01581-3
+... 1-6707-00016-13-1
+... 1-8399-00112-47-5
+... 1129900166199
+... 1509900258294
+... 1939990003289
+... 2-30-9-900-00391-1
+... 3 2001 00052 57 9
+... 3 5099 01429 67 6
+... 3-10-1-201-21325-1
+... 3-1907-00075-74-1
+... 5-49-0-200-01960-8
+... 8 4799 88011 44 1
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not tin.is_valid(x)]
+[]

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

Summary of changes:
 stdnum/{cu => th}/__init__.py    |  6 +--
 stdnum/{ar/cuit.py => th/moa.py} | 74 +++++++++++++++----------------
 stdnum/{ar/cbu.py => th/pin.py}  | 55 ++++++++++++-----------
 stdnum/{us => th}/tin.py         | 73 +++++++++++++++---------------
 tests/test_th_moa.doctest        | 83 ++++++++++++++++++++++++++++++++++
 tests/test_th_pin.doctest        | 96 ++++++++++++++++++++++++++++++++++++++++
 tests/test_th_tin.doctest        | 93 ++++++++++++++++++++++++++++++++++++++
 7 files changed, 377 insertions(+), 103 deletions(-)
 copy stdnum/{cu => th}/__init__.py (86%)
 copy stdnum/{ar/cuit.py => th/moa.py} (52%)
 copy stdnum/{ar/cbu.py => th/pin.py} (57%)
 copy stdnum/{us => th}/tin.py (56%)
 create mode 100644 tests/test_th_moa.doctest
 create mode 100644 tests/test_th_pin.doctest
 create mode 100644 tests/test_th_tin.doctest


hooks/post-receive
-- 
python-stdnum