Skip to content

Commit

Permalink
Add support for stock dividend (#232)
Browse files Browse the repository at this point in the history
  • Loading branch information
Nef10 committed Nov 11, 2023
1 parent 95a97c4 commit 16ba4be
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ extension Wealthsimple.Transaction {
var marketPrice: Amount {
Amount(for: marketPriceAmount, in: marketPriceCurrency)
}
var negatedMarketValue: Amount {
Amount(for: marketValueAmount, in: marketValueCurrency, negate: true)
}
var netCash: Amount {
Amount(for: netCashAmount, in: netCashCurrency)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ public struct WealthsimpleLedgerMapper {
result = try mapTransfer(transaction, in: account, accountTypes: [.expense])
case .fee, .reimbursement, .interest:
result = try mapTransfer(transaction, in: account, accountTypes: [.expense, .income], payee: Self.payee)
case .stockDividend:
(price, result) = try mapStockDividend(transaction, in: account)
default:
throw WealthsimpleConversionError.unsupportedTransactionType(transaction.transactionType.rawValue)
}
Expand Down Expand Up @@ -263,6 +265,16 @@ public struct WealthsimpleLedgerMapper {
return STransaction(metaData: TransactionMetaData(date: transaction.processDate, metaData: metaDataDict), postings: [posting1, posting2])
}

private func mapStockDividend(_ transaction: WTransaction, in account: WAccount) throws -> (Price, STransaction) {
let result = STransaction(metaData: TransactionMetaData(date: transaction.processDate, metaData: [MetaDataKeys.id: transaction.id]), postings: [
Posting(accountName: try lookup.ledgerAccountName(for: .dividend(transaction.symbol), in: account, ofType: [.income]), amount: transaction.negatedMarketValue),
Posting(accountName: try lookup.ledgerAccountName(of: account, symbol: transaction.symbol),
amount: Amount(for: transaction.quantity, in: try lookup.commoditySymbol(for: transaction.symbol)),
cost: try Cost(amount: transaction.marketPrice, date: nil, label: nil))
])
return (try Price(date: transaction.processDate, commoditySymbol: lookup.commoditySymbol(for: transaction.symbol), amount: transaction.marketPrice), result)
}

private func mapNonResidentWithholdingTax(_ transaction: WTransaction, in account: WAccount) throws -> STransaction {
let amount = try parseNRWTDescription(transaction.description)
let price = Amount(number: transaction.fxAmount.number, commoditySymbol: amount.commoditySymbol, decimalDigits: transaction.fxAmount.decimalDigits)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ final class TransactionHelperTests: XCTestCase {
XCTAssertEqual(transaction.netCash, Amount(number: Decimal(15.10), commoditySymbol: "CAD", decimalDigits: 2))
XCTAssertEqual(transaction.negatedNetCash, Amount(number: Decimal(-15.10), commoditySymbol: "CAD", decimalDigits: 2))

transaction.marketValueAmount = "10.0110"
transaction.marketValueCurrency = "EUR"
XCTAssertEqual(transaction.negatedMarketValue, Amount(number: Decimal(-10.011_0), commoditySymbol: "EUR", decimalDigits: 4))

transaction.marketValueCurrency = "CAD"
XCTAssertFalse(transaction.useFx)
transaction.marketValueCurrency = "EUR"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ final class WealthsimpleLedgerMapperTests: XCTestCase {
quantity: "5.25",
marketPriceAmount: "2.24",
marketPriceCurrency: "CAD",
marketValueAmount: "11.76",
marketValueCurrency: "CAD",
netCashAmount: "-11.76",
netCashCurrency: "CAD",
Expand Down Expand Up @@ -305,6 +306,25 @@ final class WealthsimpleLedgerMapperTests: XCTestCase {
XCTAssert(prices.isEmpty)
}

func testMapTransactionsStockDividend() throws {
var transaction = testTransaction
transaction.transactionType = .stockDividend

let accountName = try AccountName("Income:Dividend:ETF")
try ledger.add(SAccount(name: accountName, metaData: ["\(MetaDataKeys.dividendPrefix)ETF": accountNumber]))

let (prices, transactions) = try mapper.mapTransactionsToPriceAndTransactions([transaction])
let postings = [
Posting(accountName: accountName, amount: Amount(number: -Decimal(string: transaction.marketValueAmount)!, commoditySymbol: "CAD", decimalDigits: 2)),
Posting(accountName: try AccountName("Assets:W:ETF"),
amount: Amount(number: Decimal(string: transaction.quantity)!, commoditySymbol: "ETF", decimalDigits: 2),
cost: try Cost(amount: testTransactionPrice.amount, date: nil, label: nil))
]
let resultTransaction = Transaction(metaData: TransactionMetaData(date: transaction.processDate, metaData: [MetaDataKeys.id: transactionId]), postings: postings)
XCTAssertEqual(prices, [testTransactionPrice])
XCTAssertEqual(transactions, [resultTransaction])
}

func testMapTransactionsTransfers() throws {
var count = 1
let types: [SwiftBeanCountModel.AccountType: [Wealthsimple.TransactionType]] = [
Expand Down Expand Up @@ -395,3 +415,4 @@ final class WealthsimpleLedgerMapperTests: XCTestCase {
}

}
// swiftlint:disable:this file_length

0 comments on commit 16ba4be

Please sign in to comment.