Source code for ofxclient.institution

from __future__ import absolute_import
from __future__ import unicode_literals
import hashlib
try:
    # python 3
    from io import StringIO
except ImportError:
    # python 2
    from StringIO import StringIO

from bs4 import BeautifulSoup
from ofxparse import OfxParser

from ofxclient.client import Client


[docs]class Institution(object): """Represents an institution or bank :param id: FI Id :type id: string :param org: FI Org :type org: string :param url: FI Url :type url: string :param username: Customer username or member id :type username: string :param password: Customer password or PIN :type password: string :param broker_id: FI Broker ID (optional) :type broker_id: string :param description: Description of the bank (optional) :type description: string or None :param client_args: :py:class:`ofxclient.Client` kwargs (optional) :type client_args: dict Values for many of the parameters need to come from some sort of OFX registry which knows about each banks particular setup. For help obtaining this sort of information; please see the :py:mod:`ofxhome` python module and/or the `OFX Home <http://ofxhome.com>`_ website. Example:: from ofxclient import Institution inst = Institution( id = '3101', org = 'AMEX', url = 'https://online.americanexpress.com/myca\ /ofxdl/desktop/desktop Download.do?\ request_type=nl_ofxdownload', username = 'gene', password = 'wilder' ) for a in inst.accounts(): print(a.statement(days=5).balance) """
[docs] def __init__(self, id, org, url, username, password, broker_id='', description=None, client_args={}): self.id = id self.org = org self.url = url self.broker_id = broker_id self.username = username self.password = password self.description = description or self._default_description() self.client_args = client_args
def client(self): """Build a :py:class:`ofxclient.Client` for talking with the bank It implicitly passes in the ``client_args`` that were passed when instantiating this ``Institution``. :rtype: :py:class:`ofxclient.Client` """ return Client(institution=self, **self.client_args) def local_id(self): """Locally generated unique account identifier. :rtype: string """ return hashlib.sha256(("%s%s" % ( self.id, self.username)).encode()).hexdigest() def _default_description(self): return self.org def authenticate(self, username=None, password=None): """Test the authentication credentials Raises a ``ValueError`` if there is a problem authenticating with the human readable reason given by the institution. :param username: optional username (use self.username by default) :type username: string or None :param password: optional password (use self.password by default) :type password: string or None """ u = self.username p = self.password if username and password: u = username p = password client = self.client() query = client.authenticated_query(username=u, password=p) res = client.post(query) ofx = BeautifulSoup(res, 'xml') sonrs = ofx.find('sonrs') code = int(sonrs.find('code').contents[0].strip()) try: status = sonrs.find('message').contents[0].strip() except Exception: status = '' if code == 0: return 1 raise ValueError(status) def accounts(self): """Ask the bank for the known :py:class:`ofxclient.Account` list. :rtype: list of :py:class:`ofxclient.Account` objects """ from ofxclient.account import Account client = self.client() query = client.account_list_query() resp = client.post(query) resp_handle = StringIO(resp) parsed = OfxParser.parse(resp_handle) return [Account.from_ofxparse(a, institution=self) for a in parsed.accounts] def serialize(self): """Serialize predictably for use in configuration storage. Output looks like this:: { 'local_id': 'unique local identifier', 'id': 'FI Id', 'org': 'FI Org', 'url': 'FI OFX Endpoint Url', 'broker_id': 'FI Broker Id', 'username': 'Customer username', 'password': 'Customer password', 'description': 'descr', 'client_args': { 'id': 'random client id - see Client() for default', 'app_id': 'app name - see Client() for default', 'app_version': 'app version - see Client() for default', 'ofx_version': 'ofx version - see Client() for default', } } :rtype: nested dictionary """ client = self.client() client_args = { 'id': client.id, 'app_id': client.app_id, 'app_version': client.app_version, 'ofx_version': client.ofx_version, } return { 'id': self.id, 'org': self.org, 'url': self.url, 'broker_id': self.broker_id, 'username': self.username, 'password': self.password, 'description': self.description, 'client_args': client_args, 'local_id': self.local_id() } @staticmethod def deserialize(raw): """Instantiate :py:class:`ofxclient.Institution` from dictionary :param raw: serialized ``Institution`` :param type: dict per :py:method:`~Institution.serialize` :rtype: subclass of :py:class:`ofxclient.Institution` """ return Institution( id=raw['id'], org=raw['org'], url=raw['url'], broker_id=raw.get('broker_id', ''), username=raw['username'], password=raw['password'], description=raw.get('description', None), client_args=raw.get('client_args', {}) )