Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add parsing support for gift transactions (Schwab Equity Awards JSON). #539

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
4 changes: 4 additions & 0 deletions cgt_calc/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ def convert_to_hmrc_transactions(
self.add_disposal(transaction)
if self.date_in_tax_year(transaction.date):
total_sells += self.converter.to_gbp_for(amount, transaction)
elif transaction.action is ActionType.GIFT:
raise NotImplementedError(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of adding it if it errors here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought NotImplementedError was a more appropriate error message than the InvalidTransactionError that IIRC it otherwise produces (as the transaction itself is valid), so it would be easier for users to understand why the tool isn't producing calculations.

f"{transaction.action} is not currently supported ({transaction})"
)
elif transaction.action is ActionType.FEE:
amount = get_amount_or_fail(transaction)
new_balance += amount
Expand Down
1 change: 1 addition & 0 deletions cgt_calc/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class ActionType(Enum):
WIRE_FUNDS_RECEIVED = 14
STOCK_SPLIT = 15
CASH_MERGER = 16
GIFT = 17


@dataclass
Expand Down
14 changes: 14 additions & 0 deletions cgt_calc/parsers/schwab_equity_award_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ def action_from_str(label: str) -> ActionType:
if label == "Wire Funds Received":
return ActionType.WIRE_FUNDS_RECEIVED

if label == "Gift":
return ActionType.GIFT

raise ParsingError("schwab transactions", f"Unknown action: {label}")


Expand Down Expand Up @@ -222,6 +225,17 @@ def __init__(self, row: JsonRowType, file: str, field_names: FieldNames) -> None
f"{details[names.award_date]} "
f"(ID {details[names.award_id]})"
)
elif row[names.action] == "Gift":
if OPTIONAL_DETAILS_NAME in row[names.transac_details][0]:
details = row[names.transac_details][0]["Details"]
else:
details = row[names.transac_details][0]
date = datetime.datetime.strptime(row[names.date], "%m/%d/%Y").date()
if any((row[names.amount], row[names.fees])):
raise ParsingError(file, "Unexpected fees or amount for gifted shares.")
price = None
# Note that currently the default currency is used, because the model does
# not support a None currency.
elif row[names.action] == "Sale":
# Schwab's data export shows the settlement date,
# whereas HMRC wants the trade date:
Expand Down
38 changes: 38 additions & 0 deletions tests/test_data/schwab_equity_award_v1.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
{
"transactions": [
{
"typeName": "DisbursementViewModel",
"eventDateSortValue": "2022-11-20T00:00:00",
"eventDate": "11/20/2022",
"action": "Gift",
"symbol": "GOOG",
"quantitySortValue": 2.0,
"quantity": "2",
"description": "Share Transfer",
"totalCommissionsAndFeesSortValue": null,
"totalCommissionsAndFees": null,
"disbursementElection": null,
"amountSortValue": null,
"amount": null,
"transactionDetails": [
{
"shareLotType": "RS",
"quantity": "2",
"vestDate": "03/25/2021",
"vestFMV": "$2,045.06",
"grantId": "C111111",
"typeName": "DisbursementDetail",
"fieldNameToDisplayValueLookup": {
"Type": "RS",
"Shares": "53",
"PurchaseDate": null,
"PurchasePrice": null,
"PurchaseFairMarketValue": null,
"SubscriptionDate": null,
"SubscriptionFairMarketValue": null,
"DispositionType": null,
"VestDate": "03/25/2021",
"VestFairMarketValue": "$2,045.06",
"GrantId": "C111111"
}
}
]
},
{
"typeName": "ShareSaleViewModel",
"eventDateSortValue": "2022-11-16:00:00",
Expand Down
27 changes: 27 additions & 0 deletions tests/test_data/schwab_equity_award_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@
"FromDate": "01/01/2020",
"ToDate": "12/23/2023",
"Transactions": [
{
"Date": "09/29/2023",
"Action": "Gift",
"Symbol": "GOOG",
"Quantity": "2",
"Description": "Share Transfer",
"FeesAndCommissions": null,
"DisbursementElection": null,
"Amount": null,
"TransactionDetails": [
{
"Details": {
"Type": "RS",
"Shares": "2",
"PurchaseDate": null,
"PurchasePrice": null,
"PurchaseFairMarketValue": null,
"SubscriptionDate": null,
"SubscriptionFairMarketValue": null,
"DispositionType": null,
"VestDate": "09/25/2023",
"VestFairMarketValue": "$131.25",
"GrantId": "C987654"
}
}
]
},
{
"Date": "09/27/2023",
"Action": "Deposit",
Expand Down
18 changes: 18 additions & 0 deletions tests/test_schwab_equity_award_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ def test_schwab_transaction_v1() -> None:
assert transactions[3].amount == Decimal("25745")
assert transactions[3].fees == Decimal("0.50")

assert transactions[4].date == datetime.date(2022, 11, 20)
assert transactions[4].action == ActionType.GIFT
assert transactions[4].symbol == "GOOG"
assert transactions[4].quantity == Decimal("2")
assert transactions[4].price is None
assert transactions[4].fees == Decimal("0")
assert transactions[4].currency == "USD"
assert transactions[4].broker == "Charles Schwab"


def test_schwab_transaction_v2() -> None:
"""Test read_schwab_equity_award_json_transactions() on v2 data."""
Expand Down Expand Up @@ -137,3 +146,12 @@ def test_schwab_transaction_v2() -> None:
assert transactions[4].fees == Decimal("0")
assert transactions[4].currency == "USD"
assert transactions[4].broker == "Charles Schwab"

assert transactions[5].date == datetime.date(2023, 9, 29)
assert transactions[5].action == ActionType.GIFT
assert transactions[5].symbol == "GOOG"
assert transactions[5].quantity == Decimal("2")
assert transactions[5].price is None
assert transactions[5].fees == Decimal("0")
assert transactions[5].currency == "USD"
assert transactions[5].broker == "Charles Schwab"