From 88a6c114ad83798f3f737c257c36f83020dad7c3 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 14 Oct 2014 22:29:34 +0300 Subject: [PATCH 1/3] contrib/mageia: spec file for git-ified RPM builds --- contrib/python-stdnum.mageia.spec | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 contrib/python-stdnum.mageia.spec diff --git a/contrib/python-stdnum.mageia.spec b/contrib/python-stdnum.mageia.spec new file mode 100644 index 00000000..40b321ef --- /dev/null +++ b/contrib/python-stdnum.mageia.spec @@ -0,0 +1,42 @@ +%define git_repo python-stdnum +%define git_head HEAD + +Summary: Python module to handle standardized numbers and codes +Name: python-stdnum +Version: %git_get_ver +Release: %mkrel %git_get_rel2 +Source: %git_bs_source %{name}-%{version}.tar.gz +Source1: %{name}-gitrpm.version +Source2: %{name}-changelog.gitrpm.txt +License: LGPLv2.1 +Group: Development/Python +Url: http://arthurdejong.org/python-stdnum/ +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot +BuildArch: noarch +BuildRequires: python-devel python-setuptools + +%description +A Python module to parse, validate and reformat standard numbers and codes +in different formats. + + +%prep +%git_get_source +%setup -q + +%build +PYTHONDONTWRITEBYTECODE= %__python setup.py build + +%install +%__rm -rf %{buildroot} +PYTHONDONTWRITEBYTECODE= %__python setup.py install --root=%{buildroot} --record=FILE_LIST +%__rm -rf docs/_build/html/.buildinfo + +%clean +%__rm -rf %{buildroot} + +%files -f FILE_LIST +%defattr(-,root,root) +%doc README NEWS ChangeLog COPYING + +%changelog -f %{_sourcedir}/%{name}-changelog.gitrpm.txt From d14ba7a26c1ade30fa7feae0e572eec55315b217 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 14 Oct 2014 22:30:55 +0300 Subject: [PATCH 2/3] gr/vat: change doc wording of "FPA" number In Greece, our VAT number is used as a generic "tax registration" num. Update the docstring to reflect that name. --- stdnum/gr/vat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdnum/gr/vat.py b/stdnum/gr/vat.py index 0a28f43c..3510a35f 100644 --- a/stdnum/gr/vat.py +++ b/stdnum/gr/vat.py @@ -18,7 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301 USA -"""FPA, ΦΠΑ (Foros Prostithemenis Aksias, the Greek VAT number). +"""FPA, ΦΠΑ, ΑΦΜ (Αριθμός Φορολογικού Μητρώου, the Greek VAT number). The FPA is a 9-digit number with a simple checksum. From dc5816d9e44f144a91a7520f6e5ac09eb7627901 Mon Sep 17 00:00:00 2001 From: "P. Christeas" Date: Tue, 21 Oct 2014 09:44:38 +0300 Subject: [PATCH 3/3] gr/vat: web-service client for Greek VAT checker Since May 2014, the IT of Greek Ministry of Finance is offering a web-service for VAT-numbers lookup. It is a SOAP service, intended for individuals. The implementation is fairly trivial, but access to the service requires authentication and signup of the client using the web-page of "www.gsis.gr". Code originally drafted by Dimosthenes Fioretos --- stdnum/gr/check-vat.py | 32 ++++++++++++++++ stdnum/gr/vat.py | 86 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100755 stdnum/gr/check-vat.py diff --git a/stdnum/gr/check-vat.py b/stdnum/gr/check-vat.py new file mode 100755 index 00000000..d77558ed --- /dev/null +++ b/stdnum/gr/check-vat.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import logging +import sys +from vat import VATchecker + +sys.path.append('../..') + +logging.basicConfig(level=logging.DEBUG) + +# cancel some noisy loggers +logging.getLogger('suds.xsd').setLevel(logging.INFO) +logging.getLogger('suds.resolver').setLevel(logging.INFO) + +if __name__ == '__main__': + + vc = VATchecker('', '') + + ver = vc.getVersion() + print "version:", ver + + #vc._client.set_options(nosend=True) + + try: + res = vc.getAFMinfo('', '') + print res + except Exception, e: + logging.getLogger('main').exception("Failed: %s", e) + + +#eof diff --git a/stdnum/gr/vat.py b/stdnum/gr/vat.py index 3510a35f..9b2ba169 100644 --- a/stdnum/gr/vat.py +++ b/stdnum/gr/vat.py @@ -35,6 +35,18 @@ from stdnum.exceptions import * from stdnum.util import clean +class CheckException(Exception): + def __init__(self, code, descr): + self.args = (code, descr) + + def __str__(self): + return self.args[0] or '' + + def __unicode__(self): + return self.args[1] or '' + + def __repr__(self): + return u'' % self.args[0] def compact(number): """Convert the number to the minimal representation. This strips the @@ -76,3 +88,77 @@ def is_valid(number): return bool(validate(number)) except ValidationError: return False + +class VATchecker(object): + GSIS_HOST = 'https://www1.gsis.gr' + GSIS_WSDL = '/webtax2/wsgsis/RgWsPublic/RgWsPublicPort?wsdl' + + @classmethod + def _getClient(cls, **options): + """Establish a connection and get a `suds.Client` + + For internal purposes, only + """ + from suds.client import Client + try: + from urllib import getproxies + except ImportError: + from urllib.request import getproxies + return Client(cls.GSIS_HOST + cls.GSIS_WSDL, proxy=getproxies(), **options) + + def __init__(self, user_login, user_passwd): + """ Initialize a checker object, with authenticated access + """ + from suds.cache import ObjectCache + from suds.wsse import Security, UsernameToken + if not (user_login and user_passwd): + raise RuntimeError("You must specify user AFM and token for authentication") + security = Security() + security.tokens.append(UsernameToken(user_login, user_passwd)) + self._client = self._getClient(wsse=security) + + @classmethod + def getVersion(cls): + client = cls._getClient() + return unicode(client.service.rgWsPublicVersionInfo()) + + def getAFMinfo(self, called_for, called_by): + """Retrieve full VAT-number info + + @param called_for VAT number to look up in service + @param called_by VAT number of the user requesting information. It will + just be logged in the remote servers as a legal requirement + + @return ?? + """ + from suds import null + from suds.sudsobject import asdict + + def _reset(obj): + """ Resets all attributes of a suds.Object to null values + + The default pythonic `None` value would cause them to be + skipped, not sent. + """ + for k in obj.__keylist__: + obj[k] = null() + + qry = self._client.factory.create('RgWsPublicInputRtUser') + r2 = self._client.factory.create('RgWsPublicBasicRtUser') + #out1 = client.factory.create('RgWsPublicFirmActRtUserArray') + err = self._client.factory.create('GenWsErrorRtUser') + + qry.afmCalledBy = compact(called_by) + qry.afmCalledFor= compact(called_for) + + _reset(r2) + _reset(err) + + ret = self._client.service.rgWsPublicAfmMethod(qry,r2,'',0, err) + + if ret.pErrorRec_out and ret.pErrorRec_out.errorCode: + raise CheckException(ret.pErrorRec_out.errorCode, ret.pErrorRec_out.errorDescr) + else: + return asdict(ret) + +#eof