diff --git a/cgt_calc/main.py b/cgt_calc/main.py index de74a67c..9ba52c8c 100755 --- a/cgt_calc/main.py +++ b/cgt_calc/main.py @@ -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( + f"{transaction.action} is not currently supported ({transaction})" + ) elif transaction.action is ActionType.FEE: amount = get_amount_or_fail(transaction) new_balance += amount diff --git a/cgt_calc/model.py b/cgt_calc/model.py index 07c9dd1b..32b13fb5 100644 --- a/cgt_calc/model.py +++ b/cgt_calc/model.py @@ -66,6 +66,7 @@ class ActionType(Enum): WIRE_FUNDS_RECEIVED = 14 STOCK_SPLIT = 15 CASH_MERGER = 16 + GIFT = 17 @dataclass diff --git a/cgt_calc/parsers/schwab_equity_award_json.py b/cgt_calc/parsers/schwab_equity_award_json.py index f4aad66c..5818f6d5 100644 --- a/cgt_calc/parsers/schwab_equity_award_json.py +++ b/cgt_calc/parsers/schwab_equity_award_json.py @@ -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}") @@ -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: diff --git a/tests/test_data/schwab_equity_award_v1.json b/tests/test_data/schwab_equity_award_v1.json index e390f505..e66bd2a7 100644 --- a/tests/test_data/schwab_equity_award_v1.json +++ b/tests/test_data/schwab_equity_award_v1.json @@ -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", diff --git a/tests/test_data/schwab_equity_award_v2.json b/tests/test_data/schwab_equity_award_v2.json index 096acab4..be7670ab 100644 --- a/tests/test_data/schwab_equity_award_v2.json +++ b/tests/test_data/schwab_equity_award_v2.json @@ -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", diff --git a/tests/test_schwab_equity_award_json.py b/tests/test_schwab_equity_award_json.py index 9b42737e..cfca3f35 100644 --- a/tests/test_schwab_equity_award_json.py +++ b/tests/test_schwab_equity_award_json.py @@ -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.""" @@ -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"