Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 18 additions & 16 deletions ofxclient/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,21 +90,22 @@ def long_description(self):
def _default_description(self):
return self.number_masked()

def download(self, days=60):
def download(self, days=60, end_date=datetime.datetime.now()):
"""Downloaded OFX response for the given time range

:param days: Number of days to look back at
:type days: integer
:rtype: :py:class:`StringIO`

"""
days_ago = datetime.datetime.now() - datetime.timedelta(days=days)
days_ago = end_date - datetime.timedelta(days=days)
as_of = time.strftime("%Y%m%d", days_ago.timetuple())
query = self._download_query(as_of=as_of)
until = time.strftime('%Y%m%d', end_date.timetuple())
query = self._download_query(as_of=as_of, until=until)
response = self.institution.client().post(query)
return StringIO(response)

def download_parsed(self, days=60):
def download_parsed(self, days=60, end_date=datetime.datetime.now()):
"""Downloaded OFX response parsed by :py:meth:`OfxParser.parse`

:param days: Number of days to look back at
Expand All @@ -113,31 +114,31 @@ def download_parsed(self, days=60):
"""
if IS_PYTHON_2:
return OfxParser.parse(
self.download(days=days)
self.download(days=days, end_date=datetime.datetime.now())
)
else:
return OfxParser.parse(
BytesIO(self.download(days=days).read().encode())
BytesIO(self.download(days=days, end_date=end_date).read().encode())
)

def statement(self, days=60):
def statement(self, days=60, end_date=datetime.datetime.now()):
"""Download the :py:class:`ofxparse.Statement` given the time range

:param days: Number of days to look back at
:type days: integer
:rtype: :py:class:`ofxparser.Statement`
"""
parsed = self.download_parsed(days=days)
parsed = self.download_parsed(days=days, end_date=end_date)
return parsed.account.statement

def transactions(self, days=60):
def transactions(self, days=60, end_date=datetime.datetime.now()):
"""Download a a list of :py:class:`ofxparse.Transaction` objects

:param days: Number of days to look back at
:type days: integer
:rtype: list of :py:class:`ofxparser.Transaction` objects
"""
return self.statement(days=days).transactions
return self.statement(days=days, end_date=end_date).transactions

def serialize(self):
"""Serialize predictably for use in configuration storage.
Expand Down Expand Up @@ -244,7 +245,7 @@ def __init__(self, broker_id, **kwargs):
super(BrokerageAccount, self).__init__(**kwargs)
self.broker_id = broker_id

def _download_query(self, as_of):
def _download_query(self, as_of, until):
"""Formulate the specific query needed for download

Not intended to be called by developers directly.
Expand All @@ -254,7 +255,7 @@ def _download_query(self, as_of):
"""
c = self.institution.client()
q = c.brokerage_account_query(
number=self.number, date=as_of, broker_id=self.broker_id)
number=self.number, date=as_of, date_end=until, broker_id=self.broker_id)
return q


Expand All @@ -278,7 +279,7 @@ def __init__(self, routing_number, account_type, **kwargs):
self.routing_number = routing_number
self.account_type = account_type

def _download_query(self, as_of):
def _download_query(self, as_of, until):
"""Formulate the specific query needed for download

Not intended to be called by developers directly.
Expand All @@ -289,7 +290,8 @@ def _download_query(self, as_of):
c = self.institution.client()
q = c.bank_account_query(
number=self.number,
date=as_of,
date_start=as_of,
date_end=until,
account_type=self.account_type,
bank_id=self.routing_number)
return q
Expand All @@ -307,7 +309,7 @@ class CreditCardAccount(Account):
def __init__(self, **kwargs):
super(CreditCardAccount, self).__init__(**kwargs)

def _download_query(self, as_of):
def _download_query(self, as_of, until):
"""Formulate the specific query needed for download

Not intended to be called by developers directly.
Expand All @@ -316,5 +318,5 @@ def _download_query(self, as_of):
:type as_of: string
"""
c = self.institution.client()
q = c.credit_card_account_query(number=self.number, date=as_of)
q = c.credit_card_account_query(number=self.number, date=as_of, date_end=until)
return q
7 changes: 4 additions & 3 deletions ofxclient/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ def authenticated_query(
contents.append(with_message)
return LINE_ENDING.join([self.header(), _tag(*contents)])

def bank_account_query(self, number, date, account_type, bank_id):
def bank_account_query(self, number, date_start, date_end, account_type, bank_id):
"""Bank account statement request"""
return self.authenticated_query(
self._bareq(number, date, account_type, bank_id)
self._bareq(number, date_start, date_end, account_type, bank_id)
)

def credit_card_account_query(self, number, date):
Expand Down Expand Up @@ -236,14 +236,15 @@ def _acctreq(self, dtstart):
return self._message("SIGNUP", "ACCTINFO", req)

# this is from _ccreq below and reading page 176 of the latest OFX doc.
def _bareq(self, acctid, dtstart, accttype, bankid):
def _bareq(self, acctid, dtstart, dtend, accttype, bankid):
req = _tag("STMTRQ",
_tag("BANKACCTFROM",
_field("BANKID", bankid),
_field("ACCTID", acctid),
_field("ACCTTYPE", accttype)),
_tag("INCTRAN",
_field("DTSTART", dtstart),
_field("DTEND", dtend),
_field("INCLUDE", "Y")))
return self._message("BANK", "STMT", req)

Expand Down