From 3e34ddf6242b2ade2c24213a9cebd9adb8e2f300 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 20 Jan 2026 18:57:40 +0100 Subject: [PATCH] Some changes --- pytr/alarms.py | 1 + pytr/dl.py | 10 +- pytr/event.py | 12 ++- pytr/transactions.py | 6 +- tests/aktiendividende_only_taxes.json | 136 ++++++++++++++++++++++++++ tests/test_events.py | 18 ++++ 6 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 tests/aktiendividende_only_taxes.json diff --git a/pytr/alarms.py b/pytr/alarms.py index edbd5350..5de1cbcf 100644 --- a/pytr/alarms.py +++ b/pytr/alarms.py @@ -135,6 +135,7 @@ def overview(self): writer.writerows( [alarms_dict_from_alarms_row(key, value, max_values) for key, value in alarms_per_ISIN.items()] ) + self.fp.close() def get(self): cur_isin = None diff --git a/pytr/dl.py b/pytr/dl.py index 60856b60..67fe7b09 100644 --- a/pytr/dl.py +++ b/pytr/dl.py @@ -67,6 +67,8 @@ "ORDER_REJECTED": "Trades", "TRADE_CORRECTED": "Trades", "TRADE_INVOICE": "Trades", + "TRADING_ORDER_CANCELLED": "Trades", + "TRADING_ORDER_CREATED": "Trades", "private_markets_order_created": "Trades", "trading_order_cancelled": "Trades", "trading_order_created": "Trades", @@ -241,8 +243,6 @@ def dl_callback(self, event): if section["type"] != "documents": continue - has_docs = True - subfolder = None eventType = event.get("eventType", None) title = event.get("title", "") @@ -283,6 +283,12 @@ def dl_callback(self, event): self.log.warning(f"no subfolder mapping for {eventdesc}") for doc in section["data"]: + if isinstance(doc["action"]["payload"], dict): + self.log.warning( + f'Download of document with new API-Path URL "{doc["action"]["payload"]["path"]}" is not possible. (yet?)' + ) + continue + has_docs = True timestamp_str = event["timestamp"] if timestamp_str[-3] != ":": timestamp_str = timestamp_str[:-2] + ":" + timestamp_str[-2:] diff --git a/pytr/event.py b/pytr/event.py index 487cf3ef..93177023 100644 --- a/pytr/event.py +++ b/pytr/event.py @@ -283,7 +283,9 @@ def from_dict(cls, event_dict: Dict[Any, Any]): Returns: Event: Event object """ - date: datetime = datetime.fromisoformat(event_dict["timestamp"][:19]) + ts = event_dict["timestamp"] + ts = ts[:-2] + ":" + ts[-2:] + date: datetime = datetime.fromisoformat(ts) title: str = event_dict["title"] isin2: Optional[str] = None subtitle = event_dict["subtitle"] @@ -373,9 +375,12 @@ def from_dict(cls, event_dict: Dict[Any, Any]): for item in uebersicht_dict.get("data", []): if item.get("title") == "Event" and item.get("detail", {}).get("text", "") == "Bonusaktien": event_type = PPEventType.TAXES - if event_type is PPEventType.SPINOFF and subtitle == "Spin-off" and uebersicht_dict: + if event_type is PPEventType.SPINOFF and subtitle in ["Aktiendividende", "Spin-off"] and uebersicht_dict: for item in uebersicht_dict.get("data", []): - if item.get("title") == "Event" and item.get("detail", {}).get("text", "") == "Spin-off": + if item.get("title") == "Event" and item.get("detail", {}).get("text", "") in [ + "Aktiendividende", + "Spin-off", + ]: event_type = PPEventType.TAXES ignoreEvent = False @@ -681,6 +686,7 @@ def _parse_shares_value_fees_taxes_note( and title not in ["Aktien-Bonus"] and subtitle not in [ + "Aktiendividende", "Aktiensplit", "Aufruf von Zwischenpapieren", "Bonusaktien", diff --git a/pytr/transactions.py b/pytr/transactions.py index b3eef473..1257f63c 100644 --- a/pytr/transactions.py +++ b/pytr/transactions.py @@ -123,7 +123,9 @@ def from_event(self, event: Event) -> Iterable[dict[str, Any]]: return kwargs: _SimpleTransaction = { - "date": event.date.isoformat() if self.date_with_time else event.date.date().isoformat(), + "date": event.date.replace(microsecond=0, tzinfo=None).isoformat() + if self.date_with_time + else event.date.date().isoformat(), "type": self._translate(event.event_type.value) if isinstance(event.event_type, PPEventType) else None, "value": self._decimal_format(event.value), "note": self._translate(event.note) + " - " + event.title if event.note is not None else event.title, @@ -166,6 +168,8 @@ def from_event(self, event: Event) -> Iterable[dict[str, Any]]: kwargs["isin"] = "CNE100000296" elif event.note == "Chipotle": kwargs["isin"] = "US1696561059" + elif event.note == "VERSANT MEDIA GRP A O.N.": + kwargs["isin"] = "US9252831030" elif event.note == "Eckert & Ziegler": kwargs["isin"] = "DE0005659700" elif event.note == "Enovix Corp. WTS 01.10.26": diff --git a/tests/aktiendividende_only_taxes.json b/tests/aktiendividende_only_taxes.json new file mode 100644 index 00000000..d643e052 --- /dev/null +++ b/tests/aktiendividende_only_taxes.json @@ -0,0 +1,136 @@ +{ + "id": "09fffef5-6022-32a6-a5b5-55fcd880cad6", + "timestamp": "2026-01-06T16:14:51.218+0000", + "title": "Enovix Corp. WTS 01.10.26", + "icon": "logos/US2935941078/v2", + "avatar": { + "asset": "logos/US2935941078/v2", + "badge": null + }, + "badge": null, + "subtitle": "Aktiendividende", + "amount": { + "currency": "EUR", + "value": -0.57, + "fractionDigits": 2 + }, + "subAmount": null, + "status": "EXECUTED", + "action": { + "type": "timelineDetail", + "payload": "09fffef5-6022-32a6-a5b5-55fcd880cad6" + }, + "cashAccountNumber": "123456789", + "hidden": false, + "deleted": false, + "source": "timelineTransaction", + "details": { + "id": "09fffef5-6022-32a6-a5b5-55fcd880cad6", + "sections": [ + { + "title": "Du hast -0,57 € bezahlt", + "data": { + "icon": { + "asset": "logos/US2935941318/v2", + "badge": null + }, + "timestamp": "2026-01-06T16:14:51.218Z", + "status": "executed" + }, + "type": "header" + }, + { + "title": "Übersicht", + "data": [ + { + "title": "Status", + "detail": { + "text": "Ausgeführt", + "functionalStyle": "EXECUTED", + "type": "status" + }, + "style": "plain" + }, + { + "title": "Event", + "detail": { + "text": "Aktiendividende", + "displayValue": { + "text": "Aktiendividende" + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Wertpapier", + "detail": { + "text": "Enovix Corp. WTS 01.10.26", + "displayValue": { + "text": "Enovix Corp. WTS 01.10.26" + }, + "type": "text" + }, + "style": "plain" + } + ], + "type": "table" + }, + { + "title": "Geschäft", + "data": [ + { + "title": "Bruttoertrag", + "detail": { + "text": "0,00 €", + "displayValue": { + "text": "0,00 €" + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Steuer", + "detail": { + "text": "-0,57 €", + "displayValue": { + "text": "-0,57 €" + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Gesamt", + "detail": { + "text": "-0,57 €", + "displayValue": { + "text": "-0,57 €" + }, + "type": "text" + }, + "style": "plain" + } + ], + "type": "table" + }, + { + "title": "Dokumente", + "data": [ + { + "title": "Dokumente", + "detail": "06.01.2026", + "action": { + "payload": "", + "type": "browserModal" + }, + "id": "6406bb21-18b9-41d6-9ec8-cecd3babbd82", + "postboxType": "CA_INCOME_INVOICE" + } + ], + "type": "documents" + } + ] + } +} diff --git a/tests/test_events.py b/tests/test_events.py index 4600020f..9dba310d 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -130,6 +130,24 @@ def test_events(): } ], }, + { + "filename": "aktiendividende_only_taxes.json", + "event_type": PPEventType.TAXES, + "title": "Enovix Corp. WTS 01.10.26", + "isin": "US2935941318", + "value": -0.57, + "taxes": -0.57, + "transactions": [ + { + "Datum": "2026-01-06T16:14:51", + "Typ": "Steuern", + "Wert": -0.57, + "Notiz": "Enovix Corp. WTS 01.10.26", + "ISIN": "US2935941318", + "Steuern": 0.57, + } + ], + }, { "filename": "aktienpraemiendividende.json", "event_type": PPEventType.DIVIDEND,