diff --git a/Sources/Importers/ChuckHistory.swift b/Sources/Importers/ChuckHistory.swift index 4874e89..211bc68 100644 --- a/Sources/Importers/ChuckHistory.swift +++ b/Sources/Importers/ChuckHistory.swift @@ -116,8 +116,11 @@ class ChuckHistory: FINporter { delimitedRows.reduce(into: []) { decodedRows, delimitedRow in + // ignore totals row + let rawDate = delimitedRow["Date"] + guard rawDate != "Transactions Total" else { return } + guard let rawAction = MTransaction.parseString(delimitedRow["Action"]), - let rawDate = delimitedRow["Date"], let transactedAt = parseChuckMMDDYYYY(rawDate, defTimeOfDay: defTimeOfDay, timeZone: timeZone) else { rejectedRows.append(delimitedRow) @@ -176,6 +179,7 @@ class ChuckHistory: FINporter { switch netAction { case .buysell: guard let symbol = rawSymbol, + symbol.count > 0, let sharePrice = rawSharePrice, let quantity = rawQuantity else { @@ -198,7 +202,7 @@ class ChuckHistory: FINporter { } if rawSymbol == "NO NUMBER" { - // assume that it's a cash transfer, where amount is required + // assume that it's a cash transfer (where amount is required) guard let amount = rawAmount else { return nil } decodedRow[MTransaction.CodingKeys.shareCount.rawValue] = amount decodedRow[MTransaction.CodingKeys.sharePrice.rawValue] = 1.0 @@ -217,20 +221,15 @@ class ChuckHistory: FINporter { } } - case .income: + default: guard let amount = rawAmount else { return nil } decodedRow[MTransaction.CodingKeys.shareCount.rawValue] = amount decodedRow[MTransaction.CodingKeys.sharePrice.rawValue] = 1.0 - // accept the income even if no symbol specified + // accept the income/miscflow even if no symbol specified if let symbol = rawSymbol { decodedRow[MTransaction.CodingKeys.securityID.rawValue] = symbol } - - default: - guard let amount = rawAmount else { return nil } - decodedRow[MTransaction.CodingKeys.shareCount.rawValue] = amount - decodedRow[MTransaction.CodingKeys.sharePrice.rawValue] = 1.0 } return decodedRow diff --git a/Sources/Importers/FidoHistory.swift b/Sources/Importers/FidoHistory.swift index 9fa37c5..457be41 100644 --- a/Sources/Importers/FidoHistory.swift +++ b/Sources/Importers/FidoHistory.swift @@ -173,17 +173,17 @@ class FidoHistory: FINporter { case .transfer: if let symbol = rawSymbol { - guard let quantity = rawShareCount, - let sharePrice = rawSharePrice - else { - return nil - } + guard let quantity = rawShareCount else { return nil } decodedRow[MTransaction.CodingKeys.shareCount.rawValue] = quantity - decodedRow[MTransaction.CodingKeys.sharePrice.rawValue] = sharePrice decodedRow[MTransaction.CodingKeys.securityID.rawValue] = symbol + + // if transfer of a stock/etf, there may be no share price + if let sharePrice = rawSharePrice { + decodedRow[MTransaction.CodingKeys.sharePrice.rawValue] = sharePrice + } } else { - // no symbol, so it's probably cash + // no symbol, so it's probably cash (where amount is required) guard let amount = rawAmount else { return nil } decodedRow[MTransaction.CodingKeys.shareCount.rawValue] = amount diff --git a/Tests/Importers/ChuckHistoryTests.swift b/Tests/Importers/ChuckHistoryTests.swift index 7b1f6b6..3b225d4 100644 --- a/Tests/Importers/ChuckHistoryTests.swift +++ b/Tests/Importers/ChuckHistoryTests.swift @@ -114,22 +114,15 @@ final class ChuckHistoryTests: XCTestCase { timeZone: tzNewYork) let expected: [AllocRowed.DecodedRow] = [ - ["txnAccountID": "XXXX-1234", "txnShareCount": 100.0, "txnSharePrice": 1.0, "txnTransactedAt": timestamp3, "txnAction": MTransaction.Action.miscflow], - ["txnAction": MTransaction.Action.buysell, "txnShareCount": 961.0, "txnSharePrice": 105.0736, "txnAccountID": "XXXX-1234", "txnTransactedAt": timestamp1, "txnSecurityID": "SCHB"], - ["txnTransactedAt": timestamp4, "txnSharePrice": 1.0, "txnAccountID": "XXXX-1234", "txnAction": MTransaction.Action.transfer, "txnShareCount": 101000.0], - ["txnTransactedAt": timestamp2, "txnAccountID": "XXXX-5678", "txnSecurityID": "VOO", "txnAction": MTransaction.Action.buysell, "txnShareCount": -10.0, "txnSharePrice": 137.1222], - ["txnAccountID": "XXXX-5678", "txnShareCount": 0.55, "txnSharePrice": 1.0, "txnAction": MTransaction.Action.income, "txnTransactedAt": timestamp4], + ["txnAction": MTransaction.Action.miscflow, "txnTransactedAt": timestamp3, "txnAccountID": "XXXX-1234", "txnShareCount": 100.0, "txnSharePrice": 1.0], + ["txnAction": MTransaction.Action.buysell, "txnTransactedAt": timestamp1, "txnAccountID": "XXXX-1234", "txnShareCount": 961.0, "txnSharePrice": 105.0736, "txnSecurityID": "SCHB"], + ["txnAction": MTransaction.Action.transfer, "txnTransactedAt": timestamp4, "txnAccountID": "XXXX-1234", "txnShareCount": 101000.0, "txnSharePrice": 1.0], + ["txnAction": MTransaction.Action.buysell, "txnTransactedAt": timestamp2, "txnAccountID": "XXXX-5678", "txnShareCount": -10.0, "txnSharePrice": 137.1222, "txnSecurityID": "VOO"], + ["txnAction": MTransaction.Action.income, "txnTransactedAt": timestamp4, "txnAccountID": "XXXX-5678", "txnShareCount": 0.55, "txnSharePrice": 1.0], ] - XCTAssertEqual(expected, actual) - - let rejected: [AllocRowed.RawRow] = [ - ["Action": "", "Quantity": "", "Symbol": "", "Date": "Transactions Total", "Amount": "$524.82", "Price": "", "Fees & Comm": "", "Description": "", "": ""], - ["Description": "", "Action": "", "Fees & Comm": "", "Quantity": "", "Date": "Transactions Total", "Price": "", "Amount": "$524.82", "": "", "Symbol": ""] - ] - XCTAssertEqual(rejected, rr) - - XCTAssertEqual(2, rr.count) + XCTAssertEqual(expected, actual) + XCTAssertEqual(0, rr.count) } func testParseAccountTitleID() throws { diff --git a/Tests/Importers/FidoHistoryActionTests.swift b/Tests/Importers/FidoHistoryActionTests.swift index 9800137..d78aa27 100644 --- a/Tests/Importers/FidoHistoryActionTests.swift +++ b/Tests/Importers/FidoHistoryActionTests.swift @@ -176,10 +176,10 @@ final class FidoHistoryActionTests: XCTestCase { ("03/01/2021,PASSIVE X0000000A, YOU BOUGHT VANGUARD INDEX FDS VANGUARD VALUE ETF F (VTV) (Cash), VTV, VANGUARD INDEX FDS VANGUARD VALUE ETF F,Cash,7.0,100.0,,,,-700.0,03/05/2021", [["txnTransactedAt": YYYYMMDDts, "txnSharePrice": 100.0, "txnShareCount": 7.0, "txnAction": buysell, "txnAccountID": accountID, "txnSecurityID": "VTV"]]), - + ("03/01/2021,PASSIVE X0000000A, REDEMPTION FROM CORE ACCOUNT FIDELITY GOVERNMENT MONEY MARKET (SPAXX) MORNING TRADE (Cash), SPAXX, FIDELITY GOVERNMENT MONEY MARKET,Cash,-17.00,1,,,,17.00,", [["txnTransactedAt": YYYYMMDDts, "txnSharePrice": 1.0, "txnShareCount": -17.0, "txnAction": buysell, "txnAccountID": accountID, "txnSecurityID": "SPAXX"]]), - + ("03/01/2021,PASSIVE X0000000A, REINVESTMENT FIDELITY GOVERNMENT MONEY MARKET (SPAXX) (Cash), SPAXX, FIDELITY GOVERNMENT MONEY MARKET,Cash,-17.00,1,,,,-17.00,", [["txnTransactedAt": YYYYMMDDts, "txnSharePrice": 1.0, "txnShareCount": -17.0, "txnAction": buysell, "txnAccountID": accountID, "txnSecurityID": "SPAXX"]]), @@ -193,6 +193,10 @@ final class FidoHistoryActionTests: XCTestCase { ("03/01/2021,BROKERAGE X0000000A, TRANSFER OF ASSETS ACAT DELIVER, TLT, ISHARES TR 20 YR TR BD ETF,Cash,-86,144.41,,0.07,,12418.76,08/02/2021", [["txnTransactedAt": YYYYMMDDts, "txnSharePrice": 144.41, "txnShareCount": -86.0, "txnAction": transfer, "txnAccountID": accountID, "txnSecurityID":"TLT"]]), + + // no share price on this stock transfer + ("03/01/2021,BROKERAGE X0000000A, TRANSFER OF ASSETS EST SETTLE 02-04-21 ALPHABET INC (ABCD) (Cash), ABCD, ALPHA INC,Cash,-200,,,,,,", + [["txnTransactedAt": YYYYMMDDts, "txnShareCount": -200.0, "txnAction": transfer, "txnAccountID": accountID, "txnSecurityID":"ABCD"]]), // income