From 08a7d2b584e8af9952b98872c7201615a71ab3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Rucin=CC=81ski?= Date: Mon, 23 Mar 2026 09:23:12 +0100 Subject: [PATCH 1/3] Improve Revolut stock parsing --- src/plugins/stock/revolut/row_parser.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/plugins/stock/revolut/row_parser.py b/src/plugins/stock/revolut/row_parser.py index 27e15d4..030c523 100644 --- a/src/plugins/stock/revolut/row_parser.py +++ b/src/plugins/stock/revolut/row_parser.py @@ -9,10 +9,8 @@ class RowParser: OPERATIONS = { - "BUY - MARKET": OperationType.BUY, - "BUY - LIMIT": OperationType.BUY, - "SELL - MARKET": OperationType.SELL, - "SELL - LIMIT": OperationType.SELL, + "BUY": OperationType.BUY, + "SELL": OperationType.SELL, "DIVIDEND": OperationType.DIVIDEND, "CUSTODY FEE": OperationType.SERVICE_FEE, "STOCK SPLIT": OperationType.STOCK_SPLIT, @@ -27,6 +25,7 @@ def _fiat_value(cls, row: Dict) -> FiatValue: currency = CurrencyBuilder.build(row['Currency']) # e.g."-$1,003.01" amount_row = row['Total Amount'] + amount_row = amount_row.strip(str(currency)) if amount_row.startswith("-"): amount_row = amount_row[1:] amount_row = amount_row[1:].replace(",", "") @@ -43,4 +42,10 @@ def _date(cls, row: dict) -> pendulum.DateTime: @classmethod def _operation_type(cls, row: dict) -> OperationType: - return cls.OPERATIONS.get(row['Type']) + operation_type = cls.OPERATIONS.get(row['Type']) + if operation_type: + return operation_type + for operation_name, operation_type in cls.OPERATIONS.items(): + if operation_name in row['Type']: + return operation_type + return None From ccab627669eaa7e23bd4c0a626e89d615f182caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Rucin=CC=81ski?= Date: Mon, 23 Mar 2026 09:23:22 +0100 Subject: [PATCH 2/3] Improve error message for unmatched sell transaction in PerStockProfitCalculator --- src/domain/stock/profit/per_stock_calculator.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/domain/stock/profit/per_stock_calculator.py b/src/domain/stock/profit/per_stock_calculator.py index 488e6ba..604a154 100644 --- a/src/domain/stock/profit/per_stock_calculator.py +++ b/src/domain/stock/profit/per_stock_calculator.py @@ -54,7 +54,10 @@ def _calculate_cost_for_sell(self, buy_queue: Queue, transaction: Transaction) - try: oldest_buy = buy_queue.head() except IndexError: - raise ValueError("No buy transaction to match sell transaction. Try exporting whole history.") + raise ValueError( + f"No buy transaction to match sell transaction: {transaction}. " + "Try exporting whole history." + ) oldest_buy_stock_amount = oldest_buy.asset.amount if oldest_buy_stock_amount <= stock_amount_to_account + self.EPSILON: From 39ab5afb5b4bad23894a665e788ef11184c39ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Rucin=CC=81ski?= Date: Mon, 23 Mar 2026 09:45:28 +0100 Subject: [PATCH 3/3] Enhance date parsing in RowParser to handle unicode spaces and update month abbreviation --- src/plugins/crypto/revolut/row_parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/crypto/revolut/row_parser.py b/src/plugins/crypto/revolut/row_parser.py index 260c933..5adbd58 100644 --- a/src/plugins/crypto/revolut/row_parser.py +++ b/src/plugins/crypto/revolut/row_parser.py @@ -62,10 +62,12 @@ def _action(cls, row: dict) -> Action: @classmethod def _datetime(cls, row: dict) -> pendulum.DateTime: - date_str = row["Date"].replace("Sept", "Sep") # revolut uses Sept instead of Sep + date_str = re.sub(r"\s+", " ", row["Date"], flags=re.UNICODE) # Revolut sometimes uses unicode thin/non-breaking spaces in timestamps. + date_str = date_str.replace("Sept", "Sep").strip() # Revolut uses Sept instead of Sep supported_formats = ( "DD MMM YYYY, HH:mm:ss", "MMM DD, YYYY, hh:mm:ss A", + "MMM DD, YYYY, h:mm:ss A", ) for fmt in supported_formats: