瀏覽代碼

initial version

Radu Boncea 6 年之前
父節點
當前提交
3bce90c87b
共有 7 個文件被更改,包括 270 次插入52 次删除
  1. 102 4
      README.md
  2. 0 0
      examples/__init__.py
  3. 0 11
      examples/example_syncron.py
  4. 70 36
      pyAnaf/api.py
  5. 60 0
      pyAnaf/console.py
  6. 16 0
      pyAnaf/models.py
  7. 22 1
      setup.py

+ 102 - 4
README.md

@@ -1,5 +1,103 @@
-# Example Package
+# A wrapper API of ANAF web services
 
-This is a simple example package. You can use
-[Github-flavored Markdown](https://guides.github.com/features/mastering-markdown/)
-to write your content.
+
+## Compatibility
+>=Python 2.6
+Tested on python 2.6, 3.4, 3.5 and 3.6
+
+## Installation
+
+    $ pip install pyAnaf
+
+
+## Usage
+
+##### From Python:
+
+```python
+import datetime
+from pyAnaf.api import Anaf
+
+anaf = Anaf()
+anaf.setLimit(500) #optional
+
+# adding a list of CUIs and an optional query date
+anaf.setCUIList( [36804251, 2785503], date =  datetime.date.today())
+
+# adding a CUI one by one
+anaf.addCUI(36804251)
+anaf.addCUI(2785503)
+
+# submit the request to ANAF and hope for the best
+anaf.Request()
+
+# printing the json returned from ANAF
+print (anaf.result)
+
+# or doing more programmatic stuff
+first_cui = anaf.getCUIData(36804251)
+print (first_cui.cui)
+print (first_cui.name)
+print (first_cui.address)
+print (first_cui.is_active)
+print (first_cui.vat_eligible)
+print (first_cui.vat_split_eligible)
+print (first_cui.vat_collection_eligible)
+
+```
+
+##### From the console:
+
+	$ pyanaf <list_of_CUIs> <max_limit>
+
+For python3 you might have to set python encoding for your environment (e.g. export PYTHONIOENCODING=utf-8)
+
+E.g.:
+
+    $ pyanaf 36804251,2785503 500
+    $ {   'adresa': '',
+    'cui': 34434,
+    'data': '2018-12-12',
+    'dataActualizareTvaInc': '',
+    'dataAnulareSplitTVA': '',
+    'dataInactivare': ' ',
+    'dataInceputSplitTVA': '',
+    'dataInceputTvaInc': '',
+    'dataPublicare': ' ',
+    'dataPublicareTvaInc': '',
+    'dataRadiere': ' ',
+    'dataReactivare': ' ',
+    'dataSfarsitTvaInc': '',
+    'data_anul_imp_ScpTVA': '',
+    'data_inceput_ScpTVA': '',
+    'data_sfarsit_ScpTVA': '',
+    'denumire': '',
+    'mesaj_ScpTVA': '',
+    'scpTVA': False,
+    'statusInactivi': False,
+    'statusSplitTVA': False,
+    'statusTvaIncasare': False,
+    'tipActTvaInc': ''}
+	{   'adresa': '',
+    'cui': 2,
+    'data': '2018-12-12',
+    'dataActualizareTvaInc': '',
+    'dataAnulareSplitTVA': '',
+    'dataInactivare': ' ',
+    'dataInceputSplitTVA': '',
+    'dataInceputTvaInc': '',
+    'dataPublicare': ' ',
+    'dataPublicareTvaInc': '',
+    'dataRadiere': ' ',
+    'dataReactivare': ' ',
+    'dataSfarsitTvaInc': '',
+    'data_anul_imp_ScpTVA': '',
+    'data_inceput_ScpTVA': '',
+    'data_sfarsit_ScpTVA': '',
+    'denumire': '',
+    'mesaj_ScpTVA': '',
+    'scpTVA': False,
+    'statusInactivi': False,
+    'statusSplitTVA': False,
+    'statusTvaIncasare': False,
+    'tipActTvaInc': ''}

+ 0 - 0
examples/__init__.py


+ 0 - 11
examples/example_syncron.py

@@ -1,11 +0,0 @@
-from __future__ import unicode_literals
-
-import os
-import sys
-sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
-from pyAnaf.api import Anaf
-
-anaf = Anaf()
-
-anaf.addCUI('dddd')

+ 70 - 36
pyAnaf/api.py

@@ -1,7 +1,9 @@
-# encoding: utf-8
 from __future__ import unicode_literals, print_function
 
 import datetime
+import sys
+
+PY_3_OR_HIGHER = sys.version_info >= (3, 0)
 
 try:
     import urllib.request as urllib_request
@@ -25,6 +27,8 @@ try:
 except ImportError:
     import simplejson as json
 
+from .models import AnafResultEntry
+
 
 class AnafError(Exception):
     """
@@ -34,6 +38,22 @@ class AnafError(Exception):
     pass
 
 
+class AnafHTTPError(Exception):
+    """
+    Exception thrown by the Anaf object when there is an
+    HTTP error interacting with anaf.ro.
+    """
+    pass
+
+
+class AnafResponseError(Exception):
+    """
+    Exception thrown by the Anaf object when there is an
+    error the response returned from ANAF.
+    """
+    pass
+
+
 class Anaf(object):
     WS_ENDPOINTS = {
         'sync': 'https://webservicesp.anaf.ro/PlatitorTvaRest/api/v3/ws/tva',
@@ -43,15 +63,26 @@ class Anaf(object):
 
     def __init__(self):
         self.cuis = {}
+        self.result = None
+        self.entries = {}
 
-    def __validate_cui(self, cui):
+    @staticmethod
+    def _validate_cui(cui):
         if not isinstance(cui, int):
             raise AnafError('CUI should be integer')
 
-    def __validate_date(self, date):
+    @staticmethod
+    def _validate_date(date):
         if not isinstance(date, datetime.date):
             raise AnafError('Date should be of type datetime.date')
 
+    @staticmethod
+    def _prepare_data(data):
+        if PY_3_OR_HIGHER:
+            return bytes(data, 'utf-8')
+        else:
+            return data
+
     def addEndpoint(self, url, target='sync'):
         if target not in ['sync', 'async']:
             raise AnafError('Invalid target for endpoint. Must be one of \'sync\' or \'async\'')
@@ -65,56 +96,29 @@ class Anaf(object):
             raise AnafError('Limit should be an integer')
 
     def setCUIList(self, cui_list=[], date=None):
-        """Sets the CUI list
-
-        :param cui_list: A list of unique fiscal code numbers
-        :param date: A single date
-
-        :type cui_list: list
-        :type date: datetime.date type
-
-        :return:
-        """
-
         if date is None:
             date = datetime.date.today()
 
         if len(cui_list) > self.LIMIT:
             raise AnafError('Too many CUIs to be queried. Should limit to %d' % self.LIMIT)
 
-        self.__validate_date(date)
+        self._validate_date(date)
         for cui in cui_list:
-            self.__validate_cui(cui)
+            self._validate_cui(cui)
             self.cuis[cui] = date
 
     def addCUI(self, cui, date=None):
-        """ Adds CUI entry to the list of CUIs
-
-        :param cui: A unique fiscal code number in the form of an integer  (e.g. 273663)
-        :param date: A datetime.date object
-
-        :type cui: int
-        :type date: datetime.date type
-
-        :raise AnafError: If invalid cui and date are provided, or CUI limit is exceeded
-        """
-
         if date is None:
             date = datetime.date.today()
 
-        self.__validate_cui(cui)
-        self.__validate_date(date)
+        self._validate_cui(cui)
+        self._validate_date(date)
 
         self.cuis[cui] = date
         if len(self.cuis.items()) > self.LIMIT:
             raise AnafError('Too many CUIs to be queried. Should limit to %d' % self.LIMIT)
 
-    def Query(self):
-        """
-
-        :return:
-        """
-
+    def Request(self):
         # translate cuis entries to ANAF json format
         cui_list = []
         for entry in self.cuis.items():
@@ -124,4 +128,34 @@ class Anaf(object):
                     'data': entry[1].isoformat()
                 }
             )
-        print (cui_list)
+
+        request = urllib_request.Request(self.WS_ENDPOINTS['sync'])
+        request.add_header('Content-Type', 'application/json')
+
+        try:
+            response = urllib_request.urlopen(request, self._prepare_data(json.dumps(cui_list)))
+        except urllib_error.HTTPError as e:
+            raise AnafHTTPError('Error connecting to ANAF. Got a %d HTTP code.' % e.code)
+
+        data = response.read()
+        if isinstance(data, bytes):
+            data = data.decode('utf-8')
+        try:
+            result = json.loads(data)
+        except:
+            raise AnafResponseError('Error parsing json response from ANAF.')
+
+        if result['cod'] != 200:
+            raise AnafResponseError('%s' % result['message'])
+
+        result = result['found']
+        self.result = result
+
+        for entry in result:
+            self.entries[entry['cui']] = AnafResultEntry(entry)
+
+    def getCUIData(self, cui):
+        if cui not in self.entries.keys():
+            return None
+
+        return self.entries[cui]

+ 60 - 0
pyAnaf/console.py

@@ -0,0 +1,60 @@
+# coding: utf-8
+
+from __future__ import print_function
+import sys
+import os
+import datetime
+import pprint
+
+
+try:
+    from pyAnaf.api import Anaf
+except:
+    sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+    from pyAnaf.api import Anaf
+
+
+class MyPrettyPrinter(pprint.PrettyPrinter):
+    def format(self, object, context, maxlevels, level):
+        #print (type(object))
+        #print (object)
+        # if isinstance(object, str):
+        #     return (object.encode('utf8'), True, False)
+        return pprint.PrettyPrinter.format(self, object, context, maxlevels, level)
+
+def print_err(*args, **kwargs):
+    print(*args, file=sys.stderr, **kwargs)
+
+def main():
+    if len(sys.argv) < 2:
+        print_err("usage: %s <cuis_separated_by_comma> <limit>\n" % sys.argv[0])
+        sys.exit(-255)
+
+    limit = 5
+
+    cuis = sys.argv[1].split(',')
+
+
+    try:
+        limit = int(sys.argv[2])
+    except:
+        pass
+
+    today = datetime.date.today()
+
+    anaf = Anaf()
+    anaf.setLimit(limit)
+    for cui in cuis:
+        try:
+            anaf.addCUI(int(cui), date=today)
+        except Exception as e:
+            print_err(e)
+
+    anaf.Request()
+
+    pp = MyPrettyPrinter(indent=4)
+    for entry in anaf.result:
+        pp.pprint(entry)
+
+if __name__ == '__main__':
+    main()

+ 16 - 0
pyAnaf/models.py

@@ -0,0 +1,16 @@
+
+class AnafResultEntry(object):
+
+    def __init__(self, result):
+        self.cui = result['cui']
+        self.date = result['data']
+        self.is_active = not result['statusInactivi']
+        self.name = result['denumire']
+        self.address = result['adresa']
+        self.vat_eligible = result['scpTVA']
+        self.vat_split_eligible = result['statusSplitTVA']
+        self.vat_collection_eligible = result['statusTvaIncasare']
+
+
+    def __str__(self):
+        return "CUI: %s, Name: %s" % (self.cui,self.name)

+ 22 - 1
setup.py

@@ -13,9 +13,30 @@ setuptools.setup(
     long_description_content_type="text/markdown",
     url="https://github.com/pypa/sampleproject",
     packages=setuptools.find_packages(),
+    entry_points={
+        "console_scripts": [
+            "pyanaf = console:main",
+        ]
+    },
     classifiers=[
-        "Programming Language :: Python :: 3",
         "License :: OSI Approved :: MIT License",
         "Operating System :: OS Independent",
+        "Development Status :: 4 - Beta",
+        "Intended Audience :: Developers",
+        "Intended Audience :: Financial and Insurance Industry",
+        "License :: OSI Approved :: MIT License",
+        "Programming Language :: Python :: 2.6",
+        "Programming Language :: Python :: 2.7",
+        "Programming Language :: Python :: 3.0",
+        "Programming Language :: Python :: 3.1",
+        "Programming Language :: Python :: 3.2",
+        "Programming Language :: Python :: 3.3",
+        "Programming Language :: Python :: 3.4",
+        "Programming Language :: Python :: 3.5",
+        "Programming Language :: Python :: 3.6",
+        "Topic :: Database :: Front-Ends",
+        "Topic :: Office/Business :: Financial :: Accounting",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+        "Topic :: Utilities",
     ],
 )