lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 1.11-18-g817c177

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

python-stdnum branch master updated. 1.11-18-g817c177



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  817c177dc2699856289821e74abcc1836a02ef7f (commit)
      from  51e00da36a647589921d1ea1bf8356f467964ea1 (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=817c177dc2699856289821e74abcc1836a02ef7f

commit 817c177dc2699856289821e74abcc1836a02ef7f
Author: Leandro Regueiro <leandro.regueiro@gmail.com>
Date:   Thu Jun 6 20:52:11 2019 +0200

    Add Uruguay RUT number
    
    Closes https://github.com/arthurdejong/python-stdnum/pull/121
    Closes https://github.com/arthurdejong/python-stdnum/issues/110

diff --git a/stdnum/uy/__init__.py b/stdnum/uy/__init__.py
new file mode 100644
index 0000000..3cfea91
--- /dev/null
+++ b/stdnum/uy/__init__.py
@@ -0,0 +1,24 @@
+# __init__.py - collection of Uruguayan numbers
+# coding: utf-8
+#
+# Copyright (C) 2019 Leandro Regueiro
+#
+# 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 Uruguayan numbers."""
+
+# provide aliases
+from stdnum.uy import rut as vat  # noqa: F401
diff --git a/stdnum/uy/rut.py b/stdnum/uy/rut.py
new file mode 100644
index 0000000..baf6322
--- /dev/null
+++ b/stdnum/uy/rut.py
@@ -0,0 +1,112 @@
+# rut.py - functions for handling Uruguay RUT numbers
+# coding: utf-8
+#
+# Copyright (C) 2019 Leandro Regueiro
+#
+# 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
+
+"""RUT (Registro Único Tributario, Uruguay tax number).
+
+The Registro Único Tributario (RUT) is an identifier of legal entities for
+tax purposes.
+
+This number consists of 12 digits, the first two indicate the registration
+number, followed by a 6 digit sequence number, followed by 001 and a check
+digit.
+
+More information:
+
+* https://www.agesic.gub.uy/innovaportal/file/1634/1/modelo_de_datos.pdf (page 
71)
+* 
https://servicios.dgi.gub.uy/ServiciosEnLinea/dgi--servicios-en-linea--consulta-de-certifcado-unico
+
+>>> validate('21-100342-001-7')
+'211003420017'
+>>> validate('UY 21 140634 001 1')
+'211406340011'
+>>> validate('210303670014')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+>>> validate('12345678')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> format('211003420017')
+'21-100342-001-7'
+"""
+
+from stdnum.exceptions import *
+from stdnum.util import clean, isdigits
+
+
+# There are various online validation services available but they require
+# registration and WS-Securety signatures.
+# 
https://www.agesic.gub.uy/innovaportal/v/1600/9/agesic/consulta-de-entidad-por-rut.html
+# https://servicios.dgi.gub.uy/ServiciosEnLinea/ampliar/servicios-automatizados
+
+
+def compact(number):
+    """Convert the number to the minimal representation.
+
+    This strips the number of any valid separators and removes surrounding
+    whitespace.
+    """
+    number = clean(number, ' -').upper().strip()
+    if number.startswith('UY'):
+        return number[2:]
+    return number
+
+
+def calc_check_digit(number):
+    """Calculate the check digit."""
+    weights = (4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
+    total = sum(int(n) * w for w, n in zip(weights, number))
+    return str(-total % 11)
+
+
+def validate(number):
+    """Check if the number is a valid Uruguay RUT number.
+
+    This checks the length, formatting and check digit.
+    """
+    number = compact(number)
+    if len(number) != 12:
+        raise InvalidLength()
+    if not isdigits(number):
+        raise InvalidFormat()
+    if number[:2] < '01' or number[:2] > '21':
+        raise InvalidComponent()
+    if number[2:8] == '000000':
+        raise InvalidComponent()
+    if number[8:11] != '001':
+        raise InvalidComponent()
+    if number[-1] != calc_check_digit(number):
+        raise InvalidChecksum()
+    return number
+
+
+def is_valid(number):
+    """Check if the number is a valid Uruguay RUT number."""
+    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[:2], number[2:-4], number[-4:-1], number[-1]])
diff --git a/tests/test_uy_rut.doctest b/tests/test_uy_rut.doctest
new file mode 100644
index 0000000..0458389
--- /dev/null
+++ b/tests/test_uy_rut.doctest
@@ -0,0 +1,275 @@
+test_uy_rut.doctest - more detailed doctests for stdnum.uy.rut module
+
+Copyright (C) 2019 Leandro Regueiro
+
+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.uy.rut module. It
+tries to test more corner cases and detailed functionality that is not really
+useful as module documentation.
+
+>>> from stdnum.uy import rut
+
+
+Tests for some corner cases.
+
+>>> rut.validate('211003420017')
+'211003420017'
+>>> rut.validate('21-100342-001-7')
+'211003420017'
+>>> rut.validate('UY 21 140634 001 1')
+'211406340011'
+>>> rut.format('211003420017')
+'21-100342-001-7'
+>>> rut.validate('2142184200106')
+Traceback (most recent call last):
+    ...
+InvalidLength: ...
+>>> rut.validate('FF1599340019')
+Traceback (most recent call last):
+    ...
+InvalidFormat: ...
+>>> rut.validate('001599340019')  # invalid first two digits
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> rut.validate('221599340019')  # invalid first two digits
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> rut.validate('210000000019')  # all-zero serial number
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> rut.validate('211599345519')  # does not end with 001x
+Traceback (most recent call last):
+    ...
+InvalidComponent: ...
+>>> rut.validate('211599340010')
+Traceback (most recent call last):
+    ...
+InvalidChecksum: ...
+
+
+These have been found online and should all be valid numbers.
+
+>>> numbers = '''
+...
+... 020164180014
+... 020334150013
+... 040003080012
+... 040005970015
+... 040016670018
+... 040418690013
+... 080001340016
+... 080022140016
+... 080139130010
+... 080213100019
+... 100073350016
+... 100318040014
+... 100500830017
+... 110064620011
+... 120003950019
+... 140099980016
+... 140157860014
+... 140181240012
+... 140215500011
+... 160144250012
+... 170006780013
+... 170027590019
+... 180224740010
+... 210001550012
+... 210002620014
+... 210058770011
+... 210073150010
+... 210115100016
+... 210139110011
+... 210145870014
+... 210150270011
+... 210158640012
+... 210166180017
+... 210179150014
+... 210180920014
+... 210182980014
+... 210201150018
+... 210222900016
+... 210258830018
+... 210276780019
+... 210297670018
+... 210312110014
+... 210327080019
+... 210353720011
+... 210356860019
+... 210387110011
+... 210458060011
+... 210732000017
+... 210745160018
+... 210911810013
+... 210963830015
+... 210973860014
+... 211004160019
+... 211049510019
+... 211073320011
+... 211261790011
+... 211322010010
+... 211436660014
+... 211469540018
+... 211490580015
+... 211522640018
+... 211549020010
+... 211561010011
+... 211599370015
+... 211614400013
+... 211615780014
+... 211801770015
+... 211996800016
+... 212045470010
+... 212070680015
+... 212153160019
+... 212240850013
+... 212413240017
+... 212429590012
+... 212440120019
+... 212454430015
+... 212491250017
+... 212496500011
+... 212501340013
+... 212517220012
+... 212532040011
+... 212543290014
+... 212597820011
+... 212623570013
+... 212659640011
+... 212673700018
+... 212678980019
+... 212740500011
+... 212801630017
+... 213056780014
+... 213090120013
+... 213096710017
+... 213103770016
+... 213158420017
+... 213212900018
+... 213342900018
+... 213382280010
+... 213397140015
+... 213424230016
+... 213470310019
+... 213522890010
+... 213580520018
+... 213634090016
+... 213646230012
+... 213691440012
+... 213809790011
+... 213879900010
+... 213928210019
+... 213945140015
+... 213953600011
+... 213998850017
+... 214004730014
+... 214047130019
+... 214058380011
+... 214074720018
+... 214102340016
+... 214133790013
+... 214146600013
+... 214147150011
+... 214193940011
+... 214198770017
+... 214216810011
+... 214375810016
+... 214426070014
+... 214528610018
+... 214592480014
+... 214603870018
+... 214610610018
+... 214614190013
+... 214615280016
+... 214633640010
+... 214655630018
+... 214662920018
+... 214736710011
+... 214737600015
+... 214766080016
+... 214809150010
+... 214884800019
+... 214943860019
+... 214962680012
+... 214986830014
+... 215009140019
+... 215023680017
+... 215062370015
+... 215099710014
+... 215118080017
+... 215162380012
+... 215171410018
+... 215203500017
+... 215281420018
+... 215304750019
+... 215351000012
+... 215396520015
+... 215438030010
+... 215445310015
+... 215449070019
+... 215488970017
+... 215953280013
+... 215963430018
+... 215964960010
+... 215967140014
+... 215987660013
+... 216003500011
+... 216016210017
+... 216047790015
+... 216059620012
+... 216110670018
+... 216129770018
+... 216157100013
+... 216168420014
+... 216195870017
+... 216201780010
+... 216230690016
+... 216245990010
+... 216361860012
+... 216366570012
+... 216397780019
+... 216465750019
+... 216474980013
+... 216502710011
+... 216515360014
+... 216517220015
+... 216533380013
+... 216547290011
+... 216551320019
+... 216556470019
+... 216640300013
+... 216704520019
+... 216747520010
+... 216752600019
+... 216758850017
+... 216825090015
+... 216861310011
+... 216862000016
+... 216893210012
+... 216924940017
+... 217055850011
+... 217132510011
+... 217142440016
+... 217149110011
+...
+... '''
+>>> [x for x in numbers.splitlines() if x and not rut.is_valid(x)]
+[]

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

Summary of changes:
 stdnum/{ve => uy}/__init__.py |   8 +-
 stdnum/uy/rut.py              | 112 +++++++++++++++++
 tests/test_uy_rut.doctest     | 275 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 391 insertions(+), 4 deletions(-)
 copy stdnum/{ve => uy}/__init__.py (81%)
 create mode 100644 stdnum/uy/rut.py
 create mode 100644 tests/test_uy_rut.doctest


hooks/post-receive
-- 
python-stdnum