diff options
author | Andrew Shadura <andrewsh@debian.org> | 2016-10-19 18:02:05 +0200 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2016-10-19 18:02:05 +0200 |
commit | d8216aeb9c12ea81d9941edc6eff39be32c24aca (patch) | |
tree | 1ad1a1dd693ba915dcda076adf037964c9d6132f /tests | |
parent | bdbd753fe4ab2de979939bae4caf93b16f6b5efc (diff) |
Imported Upstream version 0.15
Diffstat (limited to 'tests')
-rw-r--r-- | tests/fixtures/investment_401k.ofx | 180 | ||||
-rw-r--r-- | tests/fixtures/suncorp.ofx | 56 | ||||
-rw-r--r-- | tests/fixtures/vanguard401k.ofx | 11 | ||||
-rw-r--r-- | tests/test_parse.py | 207 | ||||
-rw-r--r-- | tests/test_write.py | 1 |
5 files changed, 444 insertions, 11 deletions
diff --git a/tests/fixtures/investment_401k.ofx b/tests/fixtures/investment_401k.ofx new file mode 100644 index 0000000..1fc0898 --- /dev/null +++ b/tests/fixtures/investment_401k.ofx @@ -0,0 +1,180 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + +<OFX> + <SIGNONMSGSRSV1> + <SONRS> + <STATUS> + <CODE>0</CODE> + <SEVERITY>INFO</SEVERITY> + <MESSAGE>SUCCESS</MESSAGE> + </STATUS> + <DTSERVER>20150909084609.717[-6:MDT]</DTSERVER> + <LANGUAGE>ENG</LANGUAGE> + <FI> + <ORG>EXAMPLE</ORG> + <FID>1234</FID> + </FI> + <INTU.BID>1234</INTU.BID> + </SONRS> + </SIGNONMSGSRSV1> + <INVSTMTMSGSRSV1> + <INVSTMTTRNRS> + <TRNUID>0</TRNUID> + <STATUS> + <CODE>0</CODE> + <SEVERITY>INFO</SEVERITY> + <MESSAGE>SUCCESS</MESSAGE> + </STATUS> + <INVSTMTRS> + <DTASOF>20140630000000.000[-6:MDT]</DTASOF> + <CURDEF>USD</CURDEF> + <INVACCTFROM> + <BROKERID>example.org</BROKERID> + <ACCTID>12345678.123456-01</ACCTID> + </INVACCTFROM> + <INVTRANLIST> + <DTSTART>20140401000000.000[-6:MDT]</DTSTART> + <DTEND>20140630000000.000[-6:MDT]</DTEND> + <BUYMF> + <INVBUY> + <INVTRAN> + <FITID>1</FITID> + <DTTRADE>20140617000000.000[-6:MDT]</DTTRADE> + </INVTRAN> + <SECID> + <UNIQUEID>FOO</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <UNITS>8.846699</UNITS> + <UNITPRICE>22.2908</UNITPRICE> + <TOTAL>-197.2</TOTAL> + <SUBACCTSEC>OTHER</SUBACCTSEC> + <SUBACCTFUND>OTHER</SUBACCTFUND> + </INVBUY> + <BUYTYPE>BUY</BUYTYPE> + </BUYMF> + <TRANSFER> + <INVTRAN> + <FITID>2</FITID> + <DTTRADE>20140630000000.000[-6:MDT]</DTTRADE> + </INVTRAN> + <SECID> + <UNIQUEID>BAR</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <SUBACCTSEC>OTHER</SUBACCTSEC> + <UNITS>6.800992</UNITS> + <TFERACTION>IN</TFERACTION> + <POSTYPE>LONG</POSTYPE> + <UNITPRICE>29.214856</UNITPRICE> + </TRANSFER> + <TRANSFER> + <INVTRAN> + <FITID>3</FITID> + <DTTRADE>20140630000000.000[-6:MDT]</DTTRADE> + </INVTRAN> + <SECID> + <UNIQUEID>BAZ</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <SUBACCTSEC>OTHER</SUBACCTSEC> + <UNITS>-9.060702</UNITS> + <TFERACTION>OUT</TFERACTION> + <POSTYPE>LONG</POSTYPE> + <UNITPRICE>21.928764</UNITPRICE> + </TRANSFER> + </INVTRANLIST> + <INVPOSLIST> + <POSMF> + <INVPOS> + <SECID> + <UNIQUEID>FOO</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <HELDINACCT>CASH</HELDINACCT> + <POSTYPE>LONG</POSTYPE> + <UNITS>17.604312</UNITS> + <UNITPRICE>22.517211</UNITPRICE> + <MKTVAL>396.4</MKTVAL> + <DTPRICEASOF>20140630000000.000[-6:MDT]</DTPRICEASOF> + </INVPOS> + </POSMF> + <POSMF> + <INVPOS> + <SECID> + <UNIQUEID>BAR</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <HELDINACCT>CASH</HELDINACCT> + <POSTYPE>LONG</POSTYPE> + <UNITS>13.550983</UNITS> + <UNITPRICE>29.214855</UNITPRICE> + <MKTVAL>395.89</MKTVAL> + <DTPRICEASOF>20140630000000.000[-6:MDT]</DTPRICEASOF> + </INVPOS> + </POSMF> + <POSMF> + <INVPOS> + <SECID> + <UNIQUEID>BAZ</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <HELDINACCT>CASH</HELDINACCT> + <POSTYPE>LONG</POSTYPE> + <UNITS>0.0</UNITS> + <UNITPRICE>0.0</UNITPRICE> + <MKTVAL>0.0</MKTVAL> + <DTPRICEASOF>20140630000000.000[-6:MDT]</DTPRICEASOF> + </INVPOS> + </POSMF> + </INVPOSLIST> + <INV401KBAL> + <TOTAL>1000.00</TOTAL> + </INV401KBAL> + </INVSTMTRS> + </INVSTMTTRNRS> + </INVSTMTMSGSRSV1> + <SECLISTMSGSRSV1> + <SECLIST> + <MFINFO> + <SECINFO> + <SECID> + <UNIQUEID>BAR</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <SECNAME>BAR Index Fund</SECNAME> + <TICKER>BAR</TICKER> + </SECINFO> + </MFINFO> + <MFINFO> + <SECINFO> + <SECID> + <UNIQUEID>FOO</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <SECNAME>Foo Index Fund</SECNAME> + <TICKER>FOO</TICKER> + </SECINFO> + </MFINFO> + <MFINFO> + <SECINFO> + <SECID> + <UNIQUEID>BAZ</UNIQUEID> + <UNIQUEIDTYPE>PRIVATE</UNIQUEIDTYPE> + </SECID> + <SECNAME>Baz Fund</SECNAME> + <TICKER>BAZ</TICKER> + </SECINFO> + </MFINFO> + </SECLIST> + </SECLISTMSGSRSV1> +</OFX> + diff --git a/tests/fixtures/suncorp.ofx b/tests/fixtures/suncorp.ofx new file mode 100644 index 0000000..4a0558d --- /dev/null +++ b/tests/fixtures/suncorp.ofx @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="us-ascii"?>
+<?OFX OFXHEADER="200" VERSION="200" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>
+<OFX>
+ <SIGNONMSGSRSV1>
+ <SONRS>
+ <STATUS>
+ <CODE>0</CODE>
+ <SEVERITY>INFO</SEVERITY>
+ </STATUS>
+ <DTSERVER>20131215</DTSERVER>
+ <LANGUAGE>ENG</LANGUAGE>
+ <FI>
+ <ORG>SUNCORP</ORG>
+ <FID>484-799</FID>
+ </FI>
+ </SONRS>
+ </SIGNONMSGSRSV1>
+ <BANKMSGSRSV1>
+ <STMTTRNRS>
+ <TRNUID>1</TRNUID>
+ <STATUS>
+ <CODE>0</CODE>
+ <SEVERITY>INFO</SEVERITY>
+ </STATUS>
+ <STMTRS>
+ <CURDEF>AUD</CURDEF>
+ <BANKACCTFROM>
+ <BANKID>SUNCORP</BANKID>
+ <ACCTID>123456789</ACCTID>
+ <ACCTTYPE>CHECKING</ACCTTYPE>
+ </BANKACCTFROM>
+ <BANKTRANLIST>
+ <DTSTART>20130618</DTSTART>
+ <DTEND>20131215</DTEND>
+ <STMTTRN>
+ <TRNTYPE>DEBIT</TRNTYPE>
+ <DTPOSTED>20131215</DTPOSTED>
+ <TRNAMT>-16.85</TRNAMT>
+ <FITID>1</FITID>
+ <CHECKNUM>0</CHECKNUM>
+ <NAME><![CDATA[EFTPOS WDL HANDYWAY ALDI STORE ]]></NAME>
+ <MEMO><![CDATA[EFTPOS WDL HANDYWAY ALDI STORE GEELONG WEST VICAU]]></MEMO>
+ </STMTTRN>
+ </BANKTRANLIST>
+ <LEDGERBAL>
+ <BALAMT>1234.12</BALAMT>
+ <DTASOF>20131215</DTASOF>
+ </LEDGERBAL>
+ <AVAILBAL>
+ <BALAMT>1234.12</BALAMT>
+ <DTASOF>20131215</DTASOF>
+ </AVAILBAL>
+ </STMTRS>
+ </STMTTRNRS>
+ </BANKMSGSRSV1>
+</OFX>
\ No newline at end of file diff --git a/tests/fixtures/vanguard401k.ofx b/tests/fixtures/vanguard401k.ofx new file mode 100644 index 0000000..0443ca1 --- /dev/null +++ b/tests/fixtures/vanguard401k.ofx @@ -0,0 +1,11 @@ +OFXHEADER:100 +DATA:OFXSGML +VERSION:102 +SECURITY:NONE +ENCODING:USASCII +CHARSET:1252 +COMPRESSION:NONE +OLDFILEUID:NONE +NEWFILEUID:NONE + +<OFX><SIGNONMSGSRSV1><SONRS><STATUS><CODE>0<SEVERITY>INFO<MESSAGE>Successful Sign On</STATUS><DTSERVER>20141018150740[-5:EST]<LANGUAGE>ENG<DTPROFUP>20140605083000<FI><ORG>Vanguard<FID>84022</FI><SESSCOOKIE>foo<INTU.BID>84022<INTU.USERID>USER345</SONRS></SIGNONMSGSRSV1><INVSTMTMSGSRSV1><INVSTMTTRNRS><TRNUID>0<STATUS><CODE>0<SEVERITY>INFO</STATUS><INVSTMTRS><DTASOF>20141017160000.000[-5:EST]<CURDEF>USD<INVACCTFROM><BROKERID>vanguard.com<ACCTID>0123456</INVACCTFROM><INVTRANLIST><DTSTART>20140916160000.000[-5:EST]<DTEND>20141018150740.000[-5:EST]<BUYMF><INVBUY><INVTRAN><FITID>1234567890123456790AAA<DTTRADE>20140926160000.000[-5:EST]<DTSETTLE>20140926160000.000[-5:EST]<MEMO>Price as of date based on closing price</INVTRAN><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><UNITS>14.61137<UNITPRICE>46.06<TOTAL>-673.0<SUBACCTSEC>CASH<SUBACCTFUND>OTHER<INV401KSOURCE>PRETAX</INVBUY><BUYTYPE>BUY</BUYMF><BUYMF><INVBUY><INVTRAN><FITID>1234567890123456791AAA<DTTRADE>20140926160000.000[-5:EST]<DTSETTLE>20140926160000.000[-5:EST]<MEMO>Price as of date based on closing price</INVTRAN><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><UNITS>7.30568<UNITPRICE>46.06<TOTAL>-336.5<SUBACCTSEC>CASH<SUBACCTFUND>OTHER<INV401KSOURCE>MATCH</INVBUY><BUYTYPE>BUY</BUYMF><BUYMF><INVBUY><INVTRAN><FITID>1234567890123456793AAA<DTTRADE>20141010160000.000[-5:EST]<DTSETTLE>20141010160000.000[-5:EST]<MEMO>Price as of date based on closing price</INVTRAN><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><UNITS>15.25039<UNITPRICE>44.13<TOTAL>-673.0<SUBACCTSEC>CASH<SUBACCTFUND>OTHER<INV401KSOURCE>PRETAX</INVBUY><BUYTYPE>BUY</BUYMF><BUYMF><INVBUY><INVTRAN><FITID>1234567890123456794AAA<DTTRADE>20141010160000.000[-5:EST]<DTSETTLE>20141010160000.000[-5:EST]<MEMO>Price as of date based on closing price</INVTRAN><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><UNITS>7.62519<UNITPRICE>44.13<TOTAL>-336.5<SUBACCTSEC>CASH<SUBACCTFUND>OTHER<INV401KSOURCE>MATCH</INVBUY><BUYTYPE>BUY</BUYMF><TRANSFER><INVTRAN><FITID>1234567890123456795AAA<DTTRADE>20130905160000.000[-5:EST]<DTSETTLE>20130906160000.000[-5:EST]<MEMO>Investment Expense</INVTRAN><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><SUBACCTSEC>CASH<UNITS>-0.04241<TFERACTION>OUT<POSTYPE>LONG<UNITPRICE>39.37<INV401KSOURCE>MATCH</TRANSFER></INVTRANLIST><INVPOSLIST><POSMF><INVPOS><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><HELDINACCT>OTHER<POSTYPE>LONG<UNITS>117.506<UNITPRICE>44.01<MKTVAL>5171.44<DTPRICEASOF>20141017160000.000[-5:EST]<MEMO>Price as of date based on closing price<INV401KSOURCE>OTHERNONVEST</INVPOS><REINVDIV>Y<REINVCG>Y</POSMF></INVPOSLIST><INV401K><EMPLOYERNAME>GOOGLE INC. 401(K) SAVINGS PLAN<CURRENTVESTPCT>100.0</INV401K><INV401KBAL><CASHBAL>0.0<PRETAX>0.0<AFTERTAX>0.0<MATCH>0.0<PROFITSHARING>0.0<ROLLOVER>0.0<OTHERVEST>0.0<OTHERNONVEST>0.0<TOTAL>0.0</INV401KBAL></INVSTMTRS></INVSTMTTRNRS></INVSTMTMSGSRSV1><SECLISTMSGSRSV1><SECLIST><MFINFO><SECINFO><SECID><UNIQUEID>92202V351<UNIQUEIDTYPE>CUSIP</SECID><SECNAME>Target Retirement 2050 Trust Plus<FIID>1659<UNITPRICE>44.01<DTASOF>20141017160000.000[-5:EST]<MEMO>Price as of date based on closing price</SECINFO></MFINFO></SECLIST></SECLISTMSGSRSV1></OFX> diff --git a/tests/test_parse.py b/tests/test_parse.py index 35260ce..476b28e 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -1,17 +1,18 @@ from __future__ import absolute_import -from ofxparse.ofxparse import soup_maker +import os from datetime import datetime, timedelta from decimal import Decimal from unittest import TestCase import sys -sys.path.append('..') +sys.path.insert(0, os.path.abspath('..')) import six from .support import open_file from ofxparse import OfxParser, AccountType, Account, Statement, Transaction -from ofxparse.ofxparse import OfxFile, OfxPreprocessedFile, OfxParserException +from ofxparse.ofxparse import OfxFile, OfxPreprocessedFile, OfxParserException, soup_maker + class TestOfxPreprocessedFile(TestCase): @@ -41,8 +42,8 @@ NEWFILEUID:NONE <OFX><DTASOF><![CDATA[></tricky]]><LEAVE ALONE></DTASOF><VAL.UE>a</VAL.UE><VAL_UE>b</VAL_UE><TE_ST></TE_ST><TE.ST></TE.ST><INVBAL><BALLIST><BAL><NAME>Net</NAME><DTASOF>2222</DTASOF></BAL><BAL><NAME>Gross</NAME><DTASOF>3333</DTASOF></BAL></BALLIST></INVBAL></OFX> """ ofx_file = OfxPreprocessedFile(fh) - data = ofx_file.fh.read() - self.assertEqual(data,expect) + data = ofx_file.fh.read() + self.assertEqual(data, expect) def testHeaders(self): expect = {"OFXHEADER": six.u("100"), @@ -124,7 +125,6 @@ NEWFILEUID:NONE self.assertEquals(len(ofx_file.headers.keys()), 2) - class TestOfxFile(TestCase): def testHeaders(self): expect = {"OFXHEADER": six.u("100"), @@ -219,7 +219,7 @@ class TestParse(TestCase): def testThatParseFailsIfAPathIsPassedIn(self): # A file handle should be passed in, not the path. - self.assertRaises(RuntimeError, OfxParser.parse, '/foo/bar') + self.assertRaises(TypeError, OfxParser.parse, '/foo/bar') def testThatParseReturnsAResultWithABankAccount(self): ofx = OfxParser.parse(open_file('bank_medium.ofx')) @@ -232,11 +232,15 @@ class TestParse(TestCase): self.assertEquals('00', ofx.account.branch_id) self.assertEquals('CHECKING', ofx.account.account_type) self.assertEquals(Decimal('382.34'), ofx.account.statement.balance) + self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), + ofx.account.statement.balance_date) # Todo: support values in decimal or int form. # self.assertEquals('15', # ofx.bank_account.statement.balance_in_pennies) self.assertEquals( Decimal('682.34'), ofx.account.statement.available_balance) + self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), + ofx.account.statement.available_balance_date) self.assertEquals( datetime(2009, 4, 1), ofx.account.statement.start_date) self.assertEquals( @@ -271,10 +275,13 @@ class TestStringToDate(TestCase): self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string) bad_but_close_string = '881103' - self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string) + self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_but_close_string) no_month_string = '19881301' - self.assertRaises(ValueError, OfxParser.parseOfxDateTime, bad_string) + self.assertRaises(ValueError, OfxParser.parseOfxDateTime, no_month_string) + + def test_returns_none(self): + self.assertIsNone(OfxParser.parseOfxDateTime('00000000')) def test_parses_correct_time(self): '''Test whether it can parse correct time for some valid time fields''' @@ -387,8 +394,58 @@ class TestParseStatement(TestCase): datetime(2009, 5, 23, 12, 20, 17), statement.end_date) self.assertEquals(1, len(statement.transactions)) self.assertEquals(Decimal('382.34'), statement.balance) + self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.balance_date) self.assertEquals(Decimal('682.34'), statement.available_balance) + self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.available_balance_date) + def testThatParseStatementWithBlankDatesReturnsAStatement(self): + input = ''' +<STMTTRNRS> + <TRNUID>20090523122017 + <STATUS> + <CODE>0 + <SEVERITY>INFO + <MESSAGE>OK + </STATUS> + <STMTRS> + <CURDEF>CAD + <BANKACCTFROM> + <BANKID>160000100 + <ACCTID>12300 000012345678 + <ACCTTYPE>CHECKING + </BANKACCTFROM> + <BANKTRANLIST> + <DTSTART>00000000 + <DTEND>00000000 + <STMTTRN> + <TRNTYPE>POS + <DTPOSTED>20090401122017.000[-5:EST] + <TRNAMT>-6.60 + <FITID>0000123456782009040100001 + <NAME>MCDONALD'S #112 + <MEMO>POS MERCHANDISE;MCDONALD'S #112 + </STMTTRN> + </BANKTRANLIST> + <LEDGERBAL> + <BALAMT>382.34 + <DTASOF>20090523122017 + </LEDGERBAL> + <AVAILBAL> + <BALAMT>682.34 + <DTASOF>20090523122017 + </AVAILBAL> + </STMTRS> +</STMTTRNRS> + ''' + txn = soup_maker(input) + statement = OfxParser.parseStatement(txn.find('stmttrnrs')) + self.assertEquals(None, statement.start_date) + self.assertEquals(None, statement.end_date) + self.assertEquals(1, len(statement.transactions)) + self.assertEquals(Decimal('382.34'), statement.balance) + self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.balance_date) + self.assertEquals(Decimal('682.34'), statement.available_balance) + self.assertEquals(datetime(2009, 5, 23, 12, 20, 17), statement.available_balance_date) class TestStatement(TestCase): def testThatANewStatementIsValid(self): @@ -420,7 +477,6 @@ class TestParseTransaction(TestCase): self.assertEquals("MCDONALD'S #112", transaction.payee) self.assertEquals("POS MERCHANDISE;MCDONALD'S #112", transaction.memo) - def testThatParseTransactionWithFieldCheckNum(self): input = ''' <STMTTRN> @@ -436,6 +492,61 @@ class TestParseTransaction(TestCase): transaction = OfxParser.parseTransaction(txn.find('stmttrn')) self.assertEquals('700', transaction.checknum) + def testThatParseTransactionWithCommaAsDecimalPoint(self): + input = ''' +<STMTTRN> + <TRNTYPE>POS + <DTPOSTED>20090401122017.000[-5:EST] + <TRNAMT>-1006,60 + <FITID>0000123456782009040100001 + <NAME>MCDONALD'S #112 + <MEMO>POS MERCHANDISE;MCDONALD'S #112 +</STMTTRN> +''' + txn = soup_maker(input) + transaction = OfxParser.parseTransaction(txn.find('stmttrn')) + self.assertEquals(Decimal('-1006.60'), transaction.amount) + + def testThatParseTransactionWithCommaAsDecimalPointAndDotAsSeparator(self): + input = ''' +<STMTTRN> + <TRNTYPE>POS + <DTPOSTED>20090401122017.000[-5:EST] + <TRNAMT>-1.006,60 + <FITID>0000123456782009040100001 + <NAME>MCDONALD'S #112 + <MEMO>POS MERCHANDISE;MCDONALD'S #112 +</STMTTRN> +''' + txn = soup_maker(input) + with self.assertRaises(OfxParserException): + transaction = OfxParser.parseTransaction(txn.find('stmttrn')) + + def testThatParseTransactionWithNullAmountIgnored(self): + """A null transaction value is converted to 0. + + Some banks use a null transaction to include interest + rate changes on statements. + """ + input_template = ''' +<STMTTRN> + <TRNTYPE>DEP + <DTPOSTED>20130306 + <TRNAMT>{amount} + <FITID>2013030601009100 + <CHECKNUM>700 + <MEMO>DEPOSITO ONLINE +</STMTTRN> +''' + for amount in ("null", "-null"): + input = input_template.format(amount=amount) + txn = soup_maker(input) + + transaction = OfxParser.parseTransaction(txn.find('stmttrn')) + + self.assertEquals(0, transaction.amount) + + class TestTransaction(TestCase): def testThatAnEmptyTransactionIsValid(self): t = Transaction() @@ -473,7 +584,6 @@ class TestInvestmentAccount(TestCase): # Success! - class TestVanguardInvestmentStatement(TestCase): def testForUnclosedTags(self): ofx = OfxParser.parse(open_file('vanguard.ofx')) @@ -497,6 +607,20 @@ class TestVanguardInvestmentStatement(TestCase): self.assertEquals(len(ofx.security_list), 2) +class TestVanguard401kStatement(TestCase): + def testReadTransfer(self): + ofx = OfxParser.parse(open_file('vanguard401k.ofx')) + self.assertTrue(hasattr(ofx, 'account')) + self.assertTrue(hasattr(ofx.account, 'statement')) + self.assertTrue(hasattr(ofx.account.statement, 'transactions')) + self.assertEquals(len(ofx.account.statement.transactions), 5) + self.assertEquals(ofx.account.statement.transactions[-1].id, + '1234567890123456795AAA') + self.assertEquals('transfer', ofx.account.statement.transactions[-1].type) + self.assertEquals(ofx.account.statement.transactions[-1].inv401ksource, + 'MATCH') + + class TestFidelityInvestmentStatement(TestCase): def testForUnclosedTags(self): ofx = OfxParser.parse(open_file('fidelity.ofx')) @@ -510,6 +634,66 @@ class TestFidelityInvestmentStatement(TestCase): self.assertEquals(len(ofx.security_list), 7) +class Test401InvestmentStatement(TestCase): + def testTransferAggregate(self): + ofx = OfxParser.parse(open_file('investment_401k.ofx')) + expected_txns = [{'id': '1', + 'type': 'buymf', + 'units': Decimal('8.846699'), + 'unit_price': Decimal('22.2908'), + 'total': Decimal('-197.2'), + 'security': 'FOO'}, + {'id': '2', + 'type': 'transfer', + 'units': Decimal('6.800992'), + 'unit_price': Decimal('29.214856'), + 'total': Decimal('0.0'), + 'security': 'BAR'}, + {'id': '3', + 'type': 'transfer', + 'units': Decimal('-9.060702'), + 'unit_price': Decimal('21.928764'), + 'total': Decimal('0.0'), + 'security': 'BAZ'}] + for txn, expected_txn in zip(ofx.account.statement.transactions, expected_txns): + self.assertEquals(txn.id, expected_txn['id']) + self.assertEquals(txn.type, expected_txn['type']) + self.assertEquals(txn.units, expected_txn['units']) + self.assertEquals(txn.unit_price, expected_txn['unit_price']) + self.assertEquals(txn.total, expected_txn['total']) + self.assertEquals(txn.security, expected_txn['security']) + + expected_positions = [{'security': 'FOO', + 'units': Decimal('17.604312'), + 'unit_price': Decimal('22.517211')}, + {'security': 'BAR', + 'units': Decimal('13.550983'), + 'unit_price': Decimal('29.214855')}, + {'security': 'BAZ', + 'units': Decimal('0.0'), + 'unit_price': Decimal('0.0')}] + for pos, expected_pos in zip(ofx.account.statement.positions, expected_positions): + self.assertEquals(pos.security, expected_pos['security']) + self.assertEquals(pos.units, expected_pos['units']) + self.assertEquals(pos.unit_price, expected_pos['unit_price']) + + +class TestSuncorpBankStatement(TestCase): + def testCDATATransactions(self): + ofx = OfxParser.parse(open_file('suncorp.ofx')) + accounts = ofx.accounts + self.assertEquals(len(accounts), 1) + account = accounts[0] + transactions = account.statement.transactions + self.assertEquals(len(transactions), 1) + transaction = transactions[0] + self.assertEquals(transaction.payee, "EFTPOS WDL HANDYWAY ALDI STORE") + self.assertEquals( + transaction.memo, + "EFTPOS WDL HANDYWAY ALDI STORE GEELONG WEST VICAU") + self.assertEquals(transaction.amount, Decimal("-16.85")) + + class TestAccountInfoAggregation(TestCase): def testForFourAccounts(self): ofx = OfxParser.parse(open_file('account_listing_aggregation.ofx')) @@ -596,6 +780,7 @@ class TestGracefulFailures(TestCase): self.assertRaises(OfxParserException, OfxParser.parse, open_file('fail_nice/empty_balance.ofx')) + class TestParseSonrs(TestCase): def testSuccess(self): diff --git a/tests/test_write.py b/tests/test_write.py index 3366217..28361b0 100644 --- a/tests/test_write.py +++ b/tests/test_write.py @@ -6,6 +6,7 @@ import sys sys.path.append('..') from .support import open_file + class TestOfxWrite(TestCase): def test_write(self): test_file = open_file('fidelity.ofx') |