]> git.ipfire.org Git - thirdparty/python-fints.git/commitdiff
Add docs sepa-transfers 30/head
authorRaphael Michel <mail@raphaelmichel.de>
Thu, 26 Jul 2018 20:25:50 +0000 (22:25 +0200)
committerRaphael Michel <mail@raphaelmichel.de>
Thu, 26 Jul 2018 20:25:50 +0000 (22:25 +0200)
15 files changed:
README.md
docs/.gitignore [new file with mode: 0644]
docs/Makefile [new file with mode: 0644]
docs/conf.py [new file with mode: 0644]
docs/debits.rst [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/make.bat [new file with mode: 0644]
docs/quickstart.rst [new file with mode: 0644]
docs/reading.rst [new file with mode: 0644]
docs/tans.rst [new file with mode: 0644]
docs/tested.rst [new file with mode: 0644]
docs/transfers.rst [new file with mode: 0644]
fints/client.py
fints/hhd/flicker.py
fints/models.py

index 9b565f34fad9218365c381d95c53a8fc730d67de..0b2acdd67e4d1963977ed50d9b764d5837d1510f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -4,6 +4,9 @@ PyFinTS
 This is a pure-python implementation of FinTS (formerly known as HBCI), a
 online-banking protocol commonly supported by German banks.
 
+
+[Read our documentation for more info](https://python-fints.readthedocs.io)
+
 Limitations
 -----------
 
@@ -13,72 +16,14 @@ Limitations
   * Fetching bank statements
   * Fetching balances
   * Fetching holdings
-  * SEPA transfers (only with required TAN and with specific TAN methods)
+  * SEPA transfers and debits (only with required TAN and with specific TAN methods)
 * Supports Python 3.4+
 
-Banks tested:
-
-* GLS Bank eG (statements, transfers)
-* Triodos Bank (statements)
-* BBBank eG (statements)
-* Postbank (statements)
-* [1822direkt](https://www.1822direkt.de/service/zugang-zum-konto/softwarebanking-mit-hbci/)  (statements, holdings)
-* Sparkasse (statements)
-* Ing-Diba (statements)
-* CortalConsors (statements, holdings)
-* DKB (statements)
-* NIBC Direct (statements)
-* Wüstenrot (statements)
-* comdirect  (holdings)
-* Volksbank using Fiducia IT (statements)
-* netbank (statements)
-
-Usage
------
-
-```python
-import logging
-from datetime import date
-import getpass
-from fints.client import FinTS3PinTanClient
-
-logging.basicConfig(level=logging.DEBUG)
-f = FinTS3PinTanClient(
-    '123456789',  # Your bank's BLZ
-    'myusername',
-    getpass.getpass('PIN:'),
-    'https://mybank.com/…'  # endpoint, e.g.: https://hbci-pintan.gad.de/cgi-bin/hbciservlet
-                            # for German banks, see http://www.hbci-zka.de/institute/institut_auswahl.htm
-)
-
-accounts = f.get_sepa_accounts()
-print(accounts)
-# [SEPAAccount(iban='DE12345678901234567890', bic='ABCDEFGH1DEF', accountnumber='123456790', subaccount='',
-#              blz='123456789')]
-
-statement = f.get_statement(accounts[0], date(2016, 12, 1), date.today())
-print([t.data for t in statement])
-# The statement is a list of transaction objects as parsed by the mt940 parser, see
-# https://mt940.readthedocs.io/en/latest/mt940.html#mt940.models.Transaction
-# for documentation. Most information is contained in a dict accessible via their
-# ``data`` property
-
-# for retrieving the holdings of an account:
-holdings = f.get_holdings(accounts[0])
-# holdings contains a list of namedtuple values containing ISIN, name,
-# market_value, pieces, total_value and valuation_date as parsed from
-# the MT535 message.
-```
-
 Credits and License
 -------------------
 
 Maintainer: Raphael Michel <mail@raphaelmichel.de>
 
-Big thanks to Daniel Nowak for implementing outgoing transfers.
+Big thanks to: Daniel Nowak, Patrick Braune, Mathias Dalheimer, Christopher Grebs, Markus Schindler
 
 License: LGPL
-
-This is a quite close port of the [fints-hbci-php](https://github.com/mschindler83/fints-hbci-php)
-implementation that was released by Markus Schindler under the MIT license.
-Thanks for your work!
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644 (file)
index 0000000..69fa449
--- /dev/null
@@ -0,0 +1 @@
+_build/
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644 (file)
index 0000000..905f376
--- /dev/null
@@ -0,0 +1,223 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+       $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  applehelp  to make an Apple Help Book"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  epub3      to make an epub3"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  xml        to make Docutils-native XML files"
+       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+       @echo "  coverage   to run coverage check of the documentation (if enabled)"
+
+.PHONY: clean
+clean:
+       rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/django-i18nfield.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-i18nfield.qhc"
+
+.PHONY: applehelp
+applehelp:
+       $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+       @echo
+       @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+       @echo "N.B. You won't be able to view it unless you put it in" \
+             "~/Library/Documentation/Help or install it in your application" \
+             "bundle."
+
+.PHONY: devhelp
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/django-i18nfield"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/django-i18nfield"
+       @echo "# devhelp"
+
+.PHONY: epub
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: epub3
+epub3:
+       $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
+       @echo
+       @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
+
+.PHONY: latex
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through platex and dvipdfmx..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+       $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+       @echo "Testing of coverage in the sources finished, look at the " \
+             "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+       @echo
+       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+       @echo
+       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644 (file)
index 0000000..316782f
--- /dev/null
@@ -0,0 +1,387 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# python-fints documentation build configuration file, created by
+# sphinx-quickstart on Sun Apr  3 00:09:59 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import os
+import sys
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.insert(0, os.path.abspath('..'))
+
+try:
+    from fints import version
+except ImportError:
+    version = '?'
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.intersphinx',
+    'sphinx.ext.todo',
+    'sphinx.ext.doctest',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'python-fints'
+copyright = '2018, Raphael Michel'
+author = 'Raphael Michel'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '.'.join(version.split('.')[:2])
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+# today = ''
+# Else, today_fmt is used as the format for a strftime call.
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'alabaster'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {
+    'description': 'FinTS client library for Python',
+    'github_user': 'raphaelm',
+    'github_repo': 'python-fints',
+    'github_button': True,
+    'github_banner': False,
+    'travis_button': True,
+    'pre_bg': '#FFF6E5',
+    'note_bg': '#E5ECD1',
+    'note_border': '#BFCF8C',
+    'body_text': '#482C0A',
+    'sidebar_text': '#49443E',
+    'sidebar_header': '#4B4032',
+}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.
+# "<project> v<release> documentation" by default.
+# html_title = 'python-fints v0.0.1'
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+# html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+# html_extra_path = []
+
+# If not None, a 'Last updated on:' timestamp is inserted at every page
+# bottom, using the given strftime format.
+# The empty string is equivalent to '%b %d, %Y'.
+# html_last_updated_fmt = None
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+html_sidebars = {
+    '**': [
+        'about.html', 'navigation.html', 'searchbox.html',
+    ]
+}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+# html_domain_indices = True
+
+# If false, no index is generated.
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+#   'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
+#   'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
+# html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# 'ja' uses this config value.
+# 'zh' user can custom change `jieba` dictionary path.
+# html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+# html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'python-fintsdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+    # The paper size ('letterpaper' or 'a4paper').
+    # 'papersize': 'letterpaper',
+
+    # The font size ('10pt', '11pt' or '12pt').
+    # 'pointsize': '10pt',
+
+    # Additional stuff for the LaTeX preamble.
+    # 'preamble': '',
+
+    # Latex figure (float) alignment
+    # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'pythonfints.tex', 'python-fints Documentation',
+     'Raphael Michel', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+# latex_appendices = []
+
+# If false, no module index is generated.
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'python-fints', 'python-fints Documentation',
+     [author], 1)
+]
+
+# If true, show URL addresses after external links.
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'python-fints', 'python-fonts Documentation',
+     author, 'python-fints', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+# texinfo_no_detailmenu = False
+
+
+# -- Options for Epub output ----------------------------------------------
+
+# Bibliographic Dublin Core info.
+epub_title = project
+epub_author = author
+epub_publisher = author
+epub_copyright = copyright
+
+# The basename for the epub file. It defaults to the project name.
+# epub_basename = project
+
+# The HTML theme for the epub output. Since the default themes are not
+# optimized for small screen space, using the same theme for HTML and epub
+# output is usually not wise. This defaults to 'epub', a theme designed to save
+# visual space.
+# epub_theme = 'epub'
+
+# The language of the text. It defaults to the language option
+# or 'en' if the language is not set.
+# epub_language = ''
+
+# The scheme of the identifier. Typical schemes are ISBN or URL.
+# epub_scheme = ''
+
+# The unique identifier of the text. This can be a ISBN number
+# or the project homepage.
+# epub_identifier = ''
+
+# A unique identification for the text.
+# epub_uid = ''
+
+# A tuple containing the cover image and cover page html template filenames.
+# epub_cover = ()
+
+# A sequence of (type, uri, title) tuples for the guide element of content.opf.
+# epub_guide = ()
+
+# HTML files that should be inserted before the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+# epub_pre_files = []
+
+# HTML files that should be inserted after the pages created by sphinx.
+# The format is a list of tuples containing the path and title.
+# epub_post_files = []
+
+# A list of files that should not be packed into the epub file.
+epub_exclude_files = ['search.html']
+
+# The depth of the table of contents in toc.ncx.
+# epub_tocdepth = 3
+
+# Allow duplicate toc entries.
+# epub_tocdup = True
+
+# Choose between 'default' and 'includehidden'.
+# epub_tocscope = 'default'
+
+# Fix unsupported image types using the Pillow.
+# epub_fix_images = False
+
+# Scale large images.
+# epub_max_image_width = 0
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+# epub_show_urls = 'inline'
+
+# If false, no index is generated.
+# epub_use_index = True
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'https://docs.python.org/': None}
diff --git a/docs/debits.rst b/docs/debits.rst
new file mode 100644 (file)
index 0000000..acf2dbc
--- /dev/null
@@ -0,0 +1,41 @@
+Creating SEPA debits
+====================
+
+You can submit a SEPA debit XML file to the bank with the ``start_sepa_debit`` method:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: start_sepa_debit
+
+You should then enter a TAN, read our chapter :ref:`tans` to find out more.
+
+Example
+-------
+
+You can easily generate XML using the ``sepaxml`` python library:
+
+.. code-block:: python
+
+    from sepaxml import SepaDD
+
+    config = {
+        "name": "Test Company",
+        "IBAN": "DE12345",
+        "BIC": "BIC12345",
+        "batch": False,
+        "creditor_id": "TESTCORPID",
+        "currency": "EUR",
+    }
+
+    sepa = SepaDD(config, schema="pain.008.002.02")
+    sepa.add_payment({
+        "name": "Customer",
+        "IBAN": "DE12345",
+        "BIC": "BIC12345",
+        "amount": 100,
+        "type": "OOFF",  # FRST, RCUR, OOFF, FNAL
+        "collection_date": datetime.date.today() + datetime.timedelta(days=3),
+        "mandate_id": "FINTSTEST1",
+        "mandate_date": datetime.date(2018, 7, 26),
+        "description": "FinTS Test transaction",
+    })
+    pain_message = sepa.export().decode()
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..6fc5234
--- /dev/null
@@ -0,0 +1,21 @@
+FinTS client library
+====================
+
+.. image:: https://img.shields.io/pypi/v/python-fints.svg
+   :target: https://pypi.python.org/pypi/python-fints
+
+This is a pure-python implementation of FinTS (formerly known as HBCI), a
+online-banking protocol commonly supported by German banks.
+
+Documentation content
+---------------------
+
+.. toctree::
+   :maxdepth: 2
+
+   quickstart
+   reading
+   tans
+   transfers
+   debits
+   tested
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644 (file)
index 0000000..3cabb4e
--- /dev/null
@@ -0,0 +1,272 @@
+@ECHO OFF\r
+\r
+REM Command file for Sphinx documentation\r
+\r
+if "%SPHINXBUILD%" == "" (\r
+       set SPHINXBUILD=sphinx-build\r
+)\r
+set BUILDDIR=_build\r
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .\r
+set I18NSPHINXOPTS=%SPHINXOPTS% .\r
+if NOT "%PAPER%" == "" (\r
+       set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%\r
+       set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%\r
+)\r
+\r
+if "%1" == "" goto help\r
+\r
+if "%1" == "help" (\r
+       :help\r
+       echo.Please use `make ^<target^>` where ^<target^> is one of\r
+       echo.  html       to make standalone HTML files\r
+       echo.  dirhtml    to make HTML files named index.html in directories\r
+       echo.  singlehtml to make a single large HTML file\r
+       echo.  pickle     to make pickle files\r
+       echo.  json       to make JSON files\r
+       echo.  htmlhelp   to make HTML files and a HTML help project\r
+       echo.  qthelp     to make HTML files and a qthelp project\r
+       echo.  devhelp    to make HTML files and a Devhelp project\r
+       echo.  epub       to make an epub\r
+       echo.  epub3      to make an epub3\r
+       echo.  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter\r
+       echo.  text       to make text files\r
+       echo.  man        to make manual pages\r
+       echo.  texinfo    to make Texinfo files\r
+       echo.  gettext    to make PO message catalogs\r
+       echo.  changes    to make an overview over all changed/added/deprecated items\r
+       echo.  xml        to make Docutils-native XML files\r
+       echo.  pseudoxml  to make pseudoxml-XML files for display purposes\r
+       echo.  linkcheck  to check all external links for integrity\r
+       echo.  doctest    to run all doctests embedded in the documentation if enabled\r
+       echo.  coverage   to run coverage check of the documentation if enabled\r
+       goto end\r
+)\r
+\r
+if "%1" == "clean" (\r
+       for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i\r
+       del /q /s %BUILDDIR%\*\r
+       goto end\r
+)\r
+\r
+\r
+REM Check if sphinx-build is available and fallback to Python version if any\r
+%SPHINXBUILD% 1>NUL 2>NUL\r
+if errorlevel 9009 goto sphinx_python\r
+goto sphinx_ok\r
+\r
+:sphinx_python\r
+\r
+set SPHINXBUILD=python -m sphinx.__init__\r
+%SPHINXBUILD% 2> nul\r
+if errorlevel 9009 (\r
+       echo.\r
+       echo.The 'sphinx-build' command was not found. Make sure you have Sphinx\r
+       echo.installed, then set the SPHINXBUILD environment variable to point\r
+       echo.to the full path of the 'sphinx-build' executable. Alternatively you\r
+       echo.may add the Sphinx directory to PATH.\r
+       echo.\r
+       echo.If you don't have Sphinx installed, grab it from\r
+       echo.http://sphinx-doc.org/\r
+       exit /b 1\r
+)\r
+\r
+:sphinx_ok\r
+\r
+\r
+if "%1" == "html" (\r
+       %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The HTML pages are in %BUILDDIR%/html.\r
+       goto end\r
+)\r
+\r
+if "%1" == "dirhtml" (\r
+       %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.\r
+       goto end\r
+)\r
+\r
+if "%1" == "singlehtml" (\r
+       %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.\r
+       goto end\r
+)\r
+\r
+if "%1" == "pickle" (\r
+       %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can process the pickle files.\r
+       goto end\r
+)\r
+\r
+if "%1" == "json" (\r
+       %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can process the JSON files.\r
+       goto end\r
+)\r
+\r
+if "%1" == "htmlhelp" (\r
+       %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can run HTML Help Workshop with the ^\r
+.hhp project file in %BUILDDIR%/htmlhelp.\r
+       goto end\r
+)\r
+\r
+if "%1" == "qthelp" (\r
+       %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; now you can run "qcollectiongenerator" with the ^\r
+.qhcp project file in %BUILDDIR%/qthelp, like this:\r
+       echo.^> qcollectiongenerator %BUILDDIR%\qthelp\django-i18nfield.qhcp\r
+       echo.To view the help file:\r
+       echo.^> assistant -collectionFile %BUILDDIR%\qthelp\django-i18nfield.ghc\r
+       goto end\r
+)\r
+\r
+if "%1" == "devhelp" (\r
+       %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished.\r
+       goto end\r
+)\r
+\r
+if "%1" == "epub" (\r
+       %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The epub file is in %BUILDDIR%/epub.\r
+       goto end\r
+)\r
+\r
+if "%1" == "epub3" (\r
+       %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.\r
+       goto end\r
+)\r
+\r
+if "%1" == "latex" (\r
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.\r
+       goto end\r
+)\r
+\r
+if "%1" == "latexpdf" (\r
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r
+       cd %BUILDDIR%/latex\r
+       make all-pdf\r
+       cd %~dp0\r
+       echo.\r
+       echo.Build finished; the PDF files are in %BUILDDIR%/latex.\r
+       goto end\r
+)\r
+\r
+if "%1" == "latexpdfja" (\r
+       %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex\r
+       cd %BUILDDIR%/latex\r
+       make all-pdf-ja\r
+       cd %~dp0\r
+       echo.\r
+       echo.Build finished; the PDF files are in %BUILDDIR%/latex.\r
+       goto end\r
+)\r
+\r
+if "%1" == "text" (\r
+       %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The text files are in %BUILDDIR%/text.\r
+       goto end\r
+)\r
+\r
+if "%1" == "man" (\r
+       %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The manual pages are in %BUILDDIR%/man.\r
+       goto end\r
+)\r
+\r
+if "%1" == "texinfo" (\r
+       %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.\r
+       goto end\r
+)\r
+\r
+if "%1" == "gettext" (\r
+       %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The message catalogs are in %BUILDDIR%/locale.\r
+       goto end\r
+)\r
+\r
+if "%1" == "changes" (\r
+       %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.The overview file is in %BUILDDIR%/changes.\r
+       goto end\r
+)\r
+\r
+if "%1" == "linkcheck" (\r
+       %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Link check complete; look for any errors in the above output ^\r
+or in %BUILDDIR%/linkcheck/output.txt.\r
+       goto end\r
+)\r
+\r
+if "%1" == "doctest" (\r
+       %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Testing of doctests in the sources finished, look at the ^\r
+results in %BUILDDIR%/doctest/output.txt.\r
+       goto end\r
+)\r
+\r
+if "%1" == "coverage" (\r
+       %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Testing of coverage in the sources finished, look at the ^\r
+results in %BUILDDIR%/coverage/python.txt.\r
+       goto end\r
+)\r
+\r
+if "%1" == "xml" (\r
+       %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The XML files are in %BUILDDIR%/xml.\r
+       goto end\r
+)\r
+\r
+if "%1" == "pseudoxml" (\r
+       %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml\r
+       if errorlevel 1 exit /b 1\r
+       echo.\r
+       echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.\r
+       goto end\r
+)\r
+\r
+:end\r
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
new file mode 100644 (file)
index 0000000..513c56e
--- /dev/null
@@ -0,0 +1,33 @@
+Getting started
+===============
+
+First of all, you need to install the library::
+
+    $ pip3 install fints
+
+Then, you can initialize a FinTS client by providing your bank's BLZ, your username and PIN as well as the HBCI endpoint
+of your bank. Logging in with a signature file or chip card is currently not supported. For example:
+
+.. code-block:: python
+
+    import logging
+    from datetime import date
+    import getpass
+    from fints.client import FinTS3PinTanClient
+
+    logging.basicConfig(level=logging.DEBUG)
+    f = FinTS3PinTanClient(
+        '123456789',  # Your bank's BLZ
+        'myusername',  # Your login name
+        getpass.getpass('PIN:'),  # Your banking PIN
+        'https://hbci-pintan.gad.de/cgi-bin/hbciservlet'
+    )
+
+
+You can then execute commands using the client instance:
+
+.. code-block:: python
+
+    accounts = f.get_sepa_accounts()
+
+Go on to the next pages to find out what commands are supported!
\ No newline at end of file
diff --git a/docs/reading.rst b/docs/reading.rst
new file mode 100644 (file)
index 0000000..3355c5b
--- /dev/null
@@ -0,0 +1,58 @@
+Reading operations
+==================
+
+Fetching your bank accounts
+---------------------------
+
+The most simple method allows you to get all bank accounts that your user has access to:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: get_sepa_accounts
+
+This method will return a list of named tuples of the following type:
+
+.. autoclass:: fints.models.SEPAAccount
+
+You will need this account object for many further operations to show which account you want to operate on.
+
+
+Fetching account balances
+-------------------------
+
+You can fetch the current balance of an account with the ``get_balance`` operation.
+
+.. autoclass:: fints.client.FinTS3Client
+  :members: get_balance
+
+This method will return a list of ``Balance`` objects from the ``mt-940`` library. You can find more information
+in `balance <their documentation>`_.
+
+
+Reading account statements
+--------------------------
+
+You can fetch the banking statement of an account within a certain timeframe with the ``get_statement``
+operation.
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: get_statement
+
+This method will return a list of ``Transaction`` objects from the ``mt-940`` library. You can find more information
+in `their documentation`_.
+
+
+Fetching holdings
+-----------------
+
+You can fetch the holdings of an account with the ``get_holdings`` method:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: get_holdings
+
+This method will return a list of ``Holding`` objects:
+
+.. autoclass:: fints.models.Holding
+
+
+.. _their documentation: https://mt940.readthedocs.io/en/latest/mt940.html#mt940.models.Transaction
+.. _balance: https://mt940.readthedocs.io/en/latest/mt940.html#mt940.models.Balance
diff --git a/docs/tans.rst b/docs/tans.rst
new file mode 100644 (file)
index 0000000..729d794
--- /dev/null
@@ -0,0 +1,79 @@
+.. _tans:
+
+Working with TANs
+=================
+
+TAN methods
+-----------
+
+Before doing any operations involving TANs, you should get a list of supported TAN methods and select the TAN method
+you want to use:
+
+.. code-block:: python
+
+    methods = client.get_tan_methods()
+    method = methods[0]
+
+The returned values have a subtype ``fints.models.TANMethod``, with varying parameters depending on the version
+used by the bank:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: get_tan_methods
+
+.. autoclass:: fints.models.TANMethod5
+
+.. autoclass:: fints.models.TANMethod6
+
+.. warning:: If the ``description_required`` attribute is ``2``, you will need to get the description of the TAN medium
+             you want to use and pass it as ``tan_description`` to some operations. You can send a request for this
+             information with the ``client.get_tan_description()`` method call. Currently, this returns an unparsed
+             response from the bank. In the future, we will probably return a structured result here.
+
+TAN challenges
+--------------
+
+You should then pass the chosen ``TANMethod`` object to your operation, e.g. ``start_simple_sepa_transfer``.
+If a TAN is required, this operation will return a ``TANChallenge``, again depending on the version used by the bank.
+
+.. autoclass:: fints.models.TANChallenge3
+
+.. autoclass:: fints.models.TANChallenge4
+
+.. autoclass:: fints.models.TANChallenge5
+
+.. autoclass:: fints.models.TANChallenge6
+
+The ``challenge`` attribute will contain human-readable instructions on how to proceed.
+
+Flicker-Code / optiTAN
+----------------------
+
+If you want to use chipTAN with an optical TAN device, we provide utilities to print the flicker code on
+a unix terminal. Just pass the ``result.challenge_hhd_uc`` value to this method:
+
+.. autofunction:: fints.hhd.flicker.terminal_flicker_unix
+
+You should probably catch for ``KeyboardInterrupts`` to allow the user to abort the displaying and to continue
+with the TAN:
+
+.. code-block:: python
+
+    try:
+        terminal_flicker_unix(result.challenge_hhd_uc)
+    except KeyboardInterrupt:
+        pass
+
+Sending the TAN
+---------------
+
+Once obtained the TAN, you can send it with the ``send_tan`` client method:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: send_tan
+
+For example:
+
+.. code-block:: python
+
+    tan = input('Bitte die TAN eingeben.')
+    result = client.send_tan(result, tan)
diff --git a/docs/tested.rst b/docs/tested.rst
new file mode 100644 (file)
index 0000000..1b10370
--- /dev/null
@@ -0,0 +1,23 @@
+Tested banks
+============
+
+The following libraries have been tested with this library:
+
+======================================== ============  ======== ======== ======
+Bank                                     Statements    Holdings Transfer Debits
+======================================== ============  ======== ======== ======
+BBBank eG                                Yes                    Yes
+CortalConsors                            Yes           Yes
+comdirect                                              Yes
+GLS Bank eG                              Yes                    Yes      Yes
+DKB                                      Yes
+ING DiBa                                 Yes
+netbank                                  Xes
+NIBC Direct                              Yes
+Postbank                                 Yes
+Sparkasse                                Yes
+Triodos Bank                             Yes
+Volksbank (Fiducia)                      Yes
+Wüstenrot                                Yes
+1822direkt                               Yes           Yes
+======================================== ============  ======== ======== ======
diff --git a/docs/transfers.rst b/docs/transfers.rst
new file mode 100644 (file)
index 0000000..da28c5c
--- /dev/null
@@ -0,0 +1,57 @@
+Sending SEPA transfers
+======================
+
+Simple mode
+-----------
+
+You can create a simple SEPA transfer using this convenient client method:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: start_simple_sepa_transfer
+
+You should then enter a TAN, read our chapter :ref:`tans` to find out more.
+
+Advanced mode
+-------------
+
+If you want to use advanced methods, you can supply your own SEPA XML:
+
+.. autoclass:: fints.client.FinTS3Client
+   :members: start_sepa_transfer
+
+Example
+-------
+
+.. code-block:: python
+
+    client = FinTS3PinTanClient(…)
+
+    accounts = f.get_sepa_accounts()
+    account = accounts[0]
+
+    methods = f.get_tan_methods()
+    method = methods[0]
+    assert method.description_required != '2'
+
+    tan_desc = ''
+    res = f.start_simple_sepa_transfer(
+        account=accounts[0],
+        iban='DE12345',
+        bic='BIC12345',
+        amount=Decimal('7.00'),
+        recipient_name='Foo',
+        account_name='Test',
+        reason='Birthday gift',
+        endtoend_id='NOTPROVIDED',
+        tan_method=method
+    )
+    print(res.challenge)
+
+    if getattr(res, challenge_hhd_uc, None):
+        try:
+            terminal_flicker_unix(res.challenge_hhd_uc)
+        except KeyboardInterrupt:
+            pass
+
+    tan = input('Please enter TAN:')
+    res = f.send_tan(res, tan)
index 0fbad86eb3555f74108e9017bb2629a8ea7a7c9f..2f4fdcd64ad23bdc3404f50511ec19a73727b2f3 100644 (file)
@@ -10,7 +10,6 @@ from fints.segments.debit import HKDSE, HKDME
 from .connection import FinTSHTTPSConnection
 from .dialog import FinTSDialog
 from .message import FinTSMessage
-from .message import FinTSResponse
 from .models import SEPAAccount, TANMethod, TANChallenge6, TANChallenge5, TANChallenge3, TANChallenge4, TANChallenge
 from .segments.accounts import HKSPA
 from .segments.auth import HKTAN, HKTAB
@@ -36,6 +35,11 @@ class FinTS3Client:
         raise NotImplemented()
 
     def get_sepa_accounts(self):
+        """
+        Returns a list of SEPA accounts
+
+        :return: List of SEPAAccount objects.
+        """
         dialog = self._new_dialog()
         dialog.sync()
         dialog.init()
@@ -63,7 +67,15 @@ class FinTS3Client:
 
         return self.accounts
 
-    def get_statement(self, account, start_date, end_date):
+    def get_statement(self, account: SEPAAccount, start_date: datetime.datetime, end_date: datetime.date):
+        """
+        Fetches the statement of a bank account in a certain timeframe.
+
+        :param account: SEPA
+        :param start_date: First day to fetch
+        :param end_date: Last day to fetch
+        :return: A list of mt940.models.Transaction objects
+        """
         logger.info('Start fetching from {} to {}'.format(start_date, end_date))
 
         dialog = self._new_dialog()
@@ -138,7 +150,13 @@ class FinTS3Client:
             )
         ])
 
-    def get_balance(self, account):
+    def get_balance(self, account: SEPAAccount):
+        """
+        Fetches an accounts current balance.
+
+        :param account: SEPA account to fetch the balance
+        :return: A mt940.models.Balance object
+        """
         # init dialog
         dialog = self._new_dialog()
         dialog.sync()
@@ -189,7 +207,13 @@ class FinTS3Client:
             )
         ])
 
-    def get_holdings(self, account):
+    def get_holdings(self, account: SEPAAccount):
+        """
+        Retrieve holdings of an account.
+
+        :param account: SEPAAccount to retrieve holdings for.
+        :return: List of Holding objects
+        """
         # init dialog
         dialog = self._new_dialog()
         dialog.sync()
@@ -248,6 +272,13 @@ class FinTS3Client:
         ], tan)
 
     def send_tan(self, challenge: TANChallenge, tan: str):
+        """
+        Sends a TAN to confirm a pending operation.
+
+        :param challenge: TANChallenge to respond to
+        :param tan: TAN value
+        :return: Currently no response
+        """
         if challenge.tan_process != '4':
             raise NotImplementedError("TAN process {} currently not implemented".format(challenge.tan_process))
         with self.pin.protect():
@@ -265,6 +296,21 @@ class FinTS3Client:
     def start_simple_sepa_transfer(self, account: SEPAAccount, tan_method: TANMethod, iban: str, bic: str,
                                    recipient_name: str, amount: Decimal, account_name: str, reason: str,
                                    endtoend_id='NOTPROVIDED', tan_description=''):
+        """
+        Start a simple SEPA transfer.
+
+        :param account: SEPAAccount to start the transfer from.
+        :param tan_method: TANMethod object to use.
+        :param iban: Recipient's IBAN
+        :param bic: Recipient's BIC
+        :param recipient_name: Recipient name
+        :param amount: Amount as a ``Decimal``
+        :param account_name: Sender account name
+        :param reason: Transfer reason
+        :param endtoend_id: End-to-end-Id (defaults to ``NOTPROVIDED``)
+        :param tan_description: TAN medium description (if required)
+        :return: Returns a TANChallenge object
+        """
         config = {
             "name": account_name,
             "IBAN": account.iban,
@@ -302,6 +348,19 @@ class FinTS3Client:
 
     def start_sepa_transfer(self, account: SEPAAccount, pain_message: str, tan_method, tan_description='',
                             multiple=False, control_sum=None, currency='EUR', book_as_single=False):
+        """
+        Start a custom SEPA transfer.
+
+        :param account: SEPAAccount to send the transfer from.
+        :param pain_message: SEPA PAIN message containing the transfer details.
+        :param tan_method: TANMethod object to use.
+        :param tan_description: TAN medium description (if required)
+        :param multiple: Whether this message contains multiple transfers.
+        :param control_sum: Sum of all transfers (required if there are multiple)
+        :param currency: Transfer currency
+        :param book_as_single: Kindly ask the bank to put multiple transactions as separate lines on the bank statement (defaults to ``False``)
+        :return: Returns a TANChallenge object
+        """
         dialog = self._new_dialog()
         dialog.sync()
         dialog.tan_mechs = [tan_method]
@@ -336,6 +395,19 @@ class FinTS3Client:
 
     def start_sepa_debit(self, account: SEPAAccount, pain_message: str, tan_method, tan_description='',
                          multiple=False, control_sum=None, currency='EUR', book_as_single=False):
+        """
+        Start a custom SEPA debit.
+
+        :param account: SEPAAccount to send the debit from.
+        :param pain_message: SEPA PAIN message containing the debit details.
+        :param tan_method: TANMethod object to use.
+        :param tan_description: TAN medium description (if required)
+        :param multiple: Whether this message contains multiple debits.
+        :param control_sum: Sum of all debits (required if there are multiple)
+        :param currency: Debit currency
+        :param book_as_single: Kindly ask the bank to put multiple transactions as separate lines on the bank statement (defaults to ``False``)
+        :return: Returns a TANChallenge object
+        """
         dialog = self._new_dialog()
         dialog.sync()
         dialog.tan_mechs = [tan_method]
@@ -375,6 +447,11 @@ class FinTS3Client:
         return model(dialog, *s[1:1 + len(model.args)])
 
     def get_tan_methods(self):
+        """
+        Returns a list of TAN methods.
+
+        :return: List of TANMethod objects
+        """
         dialog = self._new_dialog()
         dialog.sync()
         dialog.init()
@@ -387,6 +464,11 @@ class FinTS3Client:
         ])
 
     def get_tan_description(self):
+        """
+        TAN method meta data, currently unparsed
+
+        :return: str
+        """
         dialog = self._new_dialog()
         dialog.sync()
         dialog.init()
index a72f17656e2a80dfdbd662e854aa0c2c30e4fd40..30ab5d2cf134f9bf5923a766bd549880260d703f 100644 (file)
@@ -31,6 +31,8 @@ def parse(code):
 
 
 def clean(code):
+    if code.startswith('@'):
+        code = code[res.challenge_hhd_uc.index('@', 2) + 1:]
     code = code.replace(" ", "").strip()
     if "CHLGUC" in code and "CHLGTEXT" in code:
         # Sometimes, HHD 1.3 codes are not transfered in the challenge field but in the free text,
@@ -233,9 +235,20 @@ class Startcode(DE):
 
 
 def terminal_flicker_unix(code, field_width=3, space_width=3, height=1, clear=False, wait=0.05):
+    """
+    Re-encodes a flicker code and prints it on a unix terminal.
+
+    :param code: Challenge value
+    :param field_width: Width of fields in characters (default: 3).
+    :param space_width: Width of spaces in characters (default: 3).
+    :param height: Height of fields in characters (default: 1).
+    :param clear: Clear terminal after every line (default: ``False``).
+    :param wait: Waiting interval between lines (default: 0.05).
+    """
     # Inspired by Andreas Schiermeier
     # https://git.ccc-ffm.de/?p=smartkram.git;a=blob_plain;f=chiptan/flicker/flicker.sh;h
     # =7066293b4e790c2c4c1f6cbdab703ed9976ffe1f;hb=refs/heads/master
+    code = parse(code).render()
     data = swap_bytes(code)
     high = '\033[48;05;15m'
     low = '\033[48;05;0m'
index 913172502383188cc888fe57bef156fe68c3288b..b53422ea0db9447f3338baac9007655a4baa7bf3 100644 (file)
@@ -28,6 +28,30 @@ class TANMethod(DataClass):
 
 
 class TANMethod5(TANMethod):
+    """
+    :param security_feature:
+    :param tan_process:
+    :param tech_id:
+    :param zka_id:
+    :param zka_version:
+    :param name:
+    :param max_length_input:
+    :param allowed_format:
+    :param text_returnvalue:
+    :param max_length_returnvalue:
+    :param number_of_supported_lists:
+    :param multiple_tans_allowed:
+    :param tan_time_dialog_association:
+    :param tan_list_number_required:
+    :param cancel_allowed:
+    :param sms_charge_account_required:
+    :param principal_account_required:
+    :param challenge_class_required:
+    :param challenge_value_required:
+    :param initialization_mode:
+    :param description_required:
+    :param supported_media_number:
+    """
     # Source: PIN/TAN docs – Verfahrensparameter Zwei-Schritt-Verfahren, Elementversion #5
     version = 5
     args = ['security_feature', 'tan_process', 'tech_id', 'zka_id', 'zka_version', 'name', 'max_length_input',
@@ -39,6 +63,30 @@ class TANMethod5(TANMethod):
 
 class TANMethod6(TANMethod):
     # Source: PIN/TAN docs – Verfahrensparameter Zwei-Schritt-Verfahren, Elementversion #6
+    """
+    :param security_feature:
+    :param tan_process:
+    :param tech_id:
+    :param zka_id:
+    :param zka_version:
+    :param name:
+    :param max_length_input:
+    :param allowed_format:
+    :param text_returnvalue:
+    :param max_length_returnvalue:
+    :param number_of_supported_lists:
+    :param multiple_tans_allowed:
+    :param tan_time_dialog_association:
+    :param cancel_allowed:
+    :param sms_charge_account_required:
+    :param principal_account_required:
+    :param challenge_class_required:
+    :param challenge_value_required:
+    :param initialization_mode:
+    :param description_required:
+    :param hhd_uc_required:
+    :param supported_media_number:
+    """
     version = 6
     args = ['security_feature', 'tan_process', 'tech_id', 'zka_id', 'zka_version', 'name', 'max_length_input',
             'allowed_format', 'text_returnvalue', 'max_length_returnvalue', 'multiple_tans_allowed',
@@ -55,24 +103,65 @@ class TANChallenge(DataClass):
 
 
 class TANChallenge3(TANChallenge):
+    """
+    :param tan_process:
+    :param request_hash:
+    :param reference:
+    :param challenge:
+    :param challenge_datetime:
+    :param tan_list_number:
+    :param ben:
+    :param medium_description:
+    """
     version = 3
     args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_datetime',
             'tan_list_number', 'ben', 'medium_description']
 
 
 class TANChallenge4(TANChallenge):
+    """
+    :param tan_process:
+    :param request_hash:
+    :param reference:
+    :param challenge:
+    :param challenge_hhd_uc:
+    :param challenge_datetime:
+    :param tan_list_number:
+    :param ben:
+    :param medium_description:
+    """
     version = 4
     args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_hhd_uc', 'challenge_datetime',
             'tan_list_number', 'ben', 'medium_description']
 
 
 class TANChallenge5(TANChallenge):
+    """
+    :param tan_process:
+    :param request_hash:
+    :param reference:
+    :param challenge:
+    :param challenge_hhd_uc:
+    :param challenge_datetime:
+    :param tan_list_number:
+    :param ben:
+    :param medium_description:
+    """
     version = 5
     args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_hhd_uc', 'challenge_datetime',
             'tan_list_number', 'ben', 'medium_description']
 
 
 class TANChallenge6(TANChallenge):
+    """
+    :param tan_process:
+    :param request_hash:
+    :param reference:
+    :param challenge:
+    :param challenge_hhd_uc:
+    :param challenge_datetime:
+    :param medium_description:
+    """
     version = 6
     args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_hhd_uc', 'challenge_datetime',
             'medium_description']
\ No newline at end of file