Skip to content

Commit

Permalink
Handle TRANSFER type
Browse files Browse the repository at this point in the history
For share transfers, TRANSFER is the appropriate type with no
trntype_detailed, no amount and an optional unit_price.
  • Loading branch information
edwagner committed Mar 4, 2024
1 parent ce8604f commit 6ff1d3a
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 12 deletions.
16 changes: 8 additions & 8 deletions src/ofxstatement/ofx.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ def buildInvestTransactionList(self) -> None:
tb.end("INVSTMTMSGSRSV1")

def buildInvestTransaction(self, line: InvestStatementLine) -> None:
# invest transactions must always have trntype and trntype_detailed
if line.trntype is None or line.trntype_detailed is None:
# invest transactions must always have trntype
if line.trntype is None:
return

tb = self.tb
Expand All @@ -224,14 +224,18 @@ def buildInvestTransaction(self, line: InvestStatementLine) -> None:
elif line.trntype.startswith("SELL"):
tran_type_detailed_tag_name = "SELLTYPE"
inner_tran_type_tag_name = "INVSELL"
elif line.trntype == "TRANSFER":
# Transfer transactions don't have details or an envelope
tran_type_detailed_tag_name = None
inner_tran_type_tag_name = None
else:
tran_type_detailed_tag_name = "INCOMETYPE"
inner_tran_type_tag_name = (
None # income transactions don't have an envelope element
)

tb.start(line.trntype, {})
self.buildText(tran_type_detailed_tag_name, line.trntype_detailed, False)
self.buildText(tran_type_detailed_tag_name, line.trntype_detailed)

if inner_tran_type_tag_name:
tb.start(inner_tran_type_tag_name, {})
Expand Down Expand Up @@ -277,11 +281,7 @@ def buildInvestTransaction(self, line: InvestStatementLine) -> None:
precision=self.invest_transactions_float_precision,
)

self.buildAmount(
"TOTAL",
line.amount,
False,
)
self.buildAmount("TOTAL", line.amount)

if inner_tran_type_tag_name:
tb.end(inner_tran_type_tag_name)
Expand Down
12 changes: 8 additions & 4 deletions src/ofxstatement/statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@
INVEST_TRANSACTION_TYPES = [
"BUYSTOCK",
"BUYDEBT",
"SELLSTOCK",
"SELLDEBT",
"INCOME",
"INVBANKTRAN",
"SELLSTOCK",
"SELLDEBT",
"TRANSFER",
]

INVEST_TRANSACTION_TYPES_DETAILED = [
Expand Down Expand Up @@ -294,6 +295,9 @@ def assert_valid(self) -> None:
self.trntype_detailed,
INVBANKTRAN_TYPES_DETAILED,
)
elif self.trntype == "TRANSFER":
assert (self.trntype_detailed is None
), f"trntype_detailed '{self.trntype_detailed}' should be empty for TRANSFERS"
else:
assert (
self.trntype_detailed in INVEST_TRANSACTION_TYPES_DETAILED
Expand All @@ -304,7 +308,7 @@ def assert_valid(self) -> None:

assert self.id
assert self.date
assert self.amount
assert self.trntype == "TRANSFER" or self.amount
assert self.trntype == "INVBANKTRAN" or self.security_id

if self.trntype == "INVBANKTRAN":
Expand All @@ -314,7 +318,7 @@ def assert_valid(self) -> None:
else:
assert self.security_id
assert self.units
assert self.unit_price
assert self.trntype == "TRANSFER" or self.unit_price


class BankAccount(Printable):
Expand Down
27 changes: 27 additions & 0 deletions src/ofxstatement/tests/test_ofx_invest.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@
</STMTTRN>
<SUBACCTFUND>OTHER</SUBACCTFUND>
</INVBANKTRAN>
<TRANSFER>
<INVTRAN>
<FITID>7</FITID>
<DTTRADE>20210103</DTTRADE>
<MEMO>Journaled Shares</MEMO>
</INVTRAN>
<SECID>
<UNIQUEID>MSFT</UNIQUEID>
<UNIQUEIDTYPE>TICKER</UNIQUEIDTYPE>
</SECID>
<SUBACCTSEC>OTHER</SUBACCTSEC>
<SUBACCTFUND>OTHER</SUBACCTFUND>
<UNITPRICE>225.63000</UNITPRICE>
<UNITS>4.00000</UNITS>
</TRANSFER>
</INVTRANLIST>
</INVSTMTRS>
</INVSTMTTRNRS>
Expand Down Expand Up @@ -211,6 +226,18 @@ def test_ofxWriter(self) -> None:
invest_line.assert_valid()
statement.invest_lines.append(invest_line)

invest_line = InvestStatementLine(
"7",
datetime(2021, 1, 3),
"Journaled Shares",
"TRANSFER"
)
invest_line.security_id = "MSFT"
invest_line.units = Decimal("4")
invest_line.unit_price = Decimal("225.63")
invest_line.assert_valid()
statement.invest_lines.append(invest_line)

# Create writer:
writer = ofx.OfxWriter(statement)

Expand Down
18 changes: 18 additions & 0 deletions src/ofxstatement/tests/test_statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ def test_generate_unique_transaction_id(self) -> None:
self.assertTrue(tid2.endswith("-1"))
self.assertEqual(len(txnids), 2)

def test_transfer_line_validation(self) -> None:
line = statement.InvestStatementLine("id", datetime(2020, 3, 25))
line.trntype = "TRANSFER"
line.security_id = "ABC"
line.units = Decimal(2)
line.assert_valid()
with self.assertRaises(AssertionError):
line.security_id = None
line.assert_valid()
line.security_id = "ABC"
with self.assertRaises(AssertionError):
line.units = None
line.assert_valid()
line.units = Decimal(2)
with self.assertRaises(AssertionError):
line.trntype_detailed = "DETAIL"
line.assert_valid()

def test_invbank_line_validation(self) -> None:
line = statement.InvestStatementLine("id", datetime(2020, 3, 25))
line.trntype = "INVBANKTRAN"
Expand Down

0 comments on commit 6ff1d3a

Please sign in to comment.