From 77f79485179f4a089733e9cafb5434858745b5f0 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Wed, 22 Apr 2026 12:47:39 +0200 Subject: [PATCH] Further event parsing improvements --- pytr/event.py | 58 ++++++++---------- tests/test_events.py | 22 +++++++ tests/zusammenschluss2.json | 119 ++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 31 deletions(-) create mode 100644 tests/zusammenschluss2.json diff --git a/pytr/event.py b/pytr/event.py index 3c82ed7..a923403 100644 --- a/pytr/event.py +++ b/pytr/event.py @@ -304,7 +304,8 @@ def from_dict(cls, event_dict: Dict[Any, Any]): ( fees_dict, taxes_dict, - ) = (None,) * 2 + wertpapier_dict, + ) = (None,) * 3 sections = event_dict.get("details", {}).get("sections", [{}]) @@ -325,6 +326,8 @@ def from_dict(cls, event_dict: Dict[Any, Any]): fees_dict = item elif ititle == "Steuer" and not taxes_dict: taxes_dict = item + elif ititle in ["Wertpapier", "Asset"] and not wertpapier_dict: + wertpapier_dict = item event_type: Optional[EventType] = None eventTypeStr = event_dict.get("eventType", "") @@ -509,7 +512,22 @@ def from_dict(cls, event_dict: Dict[Any, Any]): PPEventType.SWAP, PPEventType.TAXES, ]: - isin = cls._parse_isin(event_dict) + # Parse ISIN + for section in sections: + action = section.get("action", None) + if action and action.get("type", {}) == "instrumentDetail": + isin = section.get("action", {}).get("payload") + break + if section.get("type", {}) == "header": + isin = section.get("data", {}).get("icon") + if isinstance(isin, dict): + isin = isin.get("asset", "") + break + if isin is None: + isin = event_dict.get("icon", "") + isin = isin[isin.find("/") + 1 :] + isin = isin.split("/", 1)[0] + shares, shares2, value, note = cls._parse_shares_value_note(event_type, event_dict) else: value = v if (v := event_dict.get("amount", {}).get("value", None)) is not None and v != 0.0 else None @@ -539,36 +557,14 @@ def from_dict(cls, event_dict: Dict[Any, Any]): isin = "FR0011981968" note = None - return cls(event_type, date, title, isin, isin2, shares, shares2, value, fees, taxes, note) - - @staticmethod - def _parse_isin(event_dict: Dict[Any, Any]) -> str: - """Parses the isin - - Args: - event_dict (Dict[Any, Any]): _description_ + if ( + subtitle == "Zusammenschluss" + and title == "Deine Aktien waren von einer Kapitalmaßnahme betroffen" + and wertpapier_dict + ): + title = wertpapier_dict["detail"]["text"] - Returns: - str: isin - """ - sections = event_dict.get("details", {}).get("sections", [{}]) - isin = event_dict.get("icon", "") - isin = isin[isin.find("/") + 1 :] - isin = isin[: isin.find("/")] - isin2 = None - for section in sections: - action = section.get("action", None) - if action and action.get("type", {}) == "instrumentDetail": - isin2 = section.get("action", {}).get("payload") - break - if section.get("type", {}) == "header": - isin2 = section.get("data", {}).get("icon") - if isinstance(isin2, dict): - isin2 = isin2.get("asset", "") - isin2 = isin2[isin2.find("/") + 1 :] - isin2 = isin2[: isin2.find("/")] - break - return isin2 if isin2 else isin + return cls(event_type, date, title, isin, isin2, shares, shares2, value, fees, taxes, note) @classmethod def _parse_shares_value_note( diff --git a/tests/test_events.py b/tests/test_events.py index 48a09db..1bd47a8 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -1839,6 +1839,28 @@ def test_events(): }, ], }, + { + "filename": "zusammenschluss2.json", + "event_type": PPEventType.SWAP, + "title": "Rocket Lab USA", + "isin": "US7731221062", + "shares": 5.943100, + "shares2": 5.943100, + "value": 0, + "note": "ROCKET LAB CORP. O.N.", + "transactions": [ + { + "Datum": "2025-05-29T13:04:58", + "Typ": "Swap", + "Wert": 0, + "Notiz": "Rocket Lab USA", + "ISIN": "US7731221062", + "Stück": 5.9431, + "ISIN2": "US7731211089", + "Stück2": 5.9431, + }, + ], + }, { "filename": "zwischenpapiere.json", "event_type": PPEventType.SWAP, diff --git a/tests/zusammenschluss2.json b/tests/zusammenschluss2.json new file mode 100644 index 0000000..0d64365 --- /dev/null +++ b/tests/zusammenschluss2.json @@ -0,0 +1,119 @@ + { + "id": "1957e12e-a7f6-396c-97e4-5237b113c45a", + "timestamp": "2025-05-29T13:04:58.676+0000", + "title": "Deine Aktien waren von einer Kapitalmaßnahme betroffen", + "icon": "logos/US7731221062/v2", + "subtitle": "Zusammenschluss", + "action": { + "type": "timelineDetail", + "payload": "1957e12e-a7f6-396c-97e4-5237b113c45a" + }, + "trailing": null, + "eventType": "SSP_CORPORATE_ACTION_ACTIVITY", + "hidden": false, + "deleted": false, + "source": "timelineActivity", + "details": { + "id": "1957e12e-a7f6-396c-97e4-5237b113c45a", + "sections": [ + { + "title": "Deine Aktien waren von einer Kapitalmaßnahme betroffen", + "data": { + "icon": { + "asset": "logos/US7731221062/v2", + "badge": null + }, + "timestamp": "2025-05-29T13:04:58.676Z", + "status": "executed" + }, + "type": "header" + }, + { + "title": "Übersicht", + "data": [ + { + "title": "Status", + "detail": { + "text": "Ausgeführt", + "functionalStyle": "EXECUTED", + "type": "status" + }, + "style": "plain" + }, + { + "title": "Orderart", + "detail": { + "text": "Zusammenschluss", + "displayValue": { + "text": "Zusammenschluss" + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Wertpapier", + "detail": { + "text": "Rocket Lab USA", + "displayValue": { + "text": "Rocket Lab USA" + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Aktien entfernt", + "detail": { + "text": "5.943100", + "displayValue": { + "text": "5.943100" + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Wertpapier", + "detail": { + "text": "ROCKET LAB CORP. O.N.", + "displayValue": { + "text": "ROCKET LAB CORP. O.N." + }, + "type": "text" + }, + "style": "plain" + }, + { + "title": "Aktien hinzugefügt", + "detail": { + "text": "5.943100", + "displayValue": { + "text": "5.943100" + }, + "type": "text" + }, + "style": "plain" + } + ], + "type": "table" + }, + { + "title": "Dokumente", + "data": [ + { + "title": "Dokumente", + "detail": "29.05.2025", + "action": { + "payload": "", + "type": "browserModal" + }, + "id": "86a172b6-39e7-4d8f-9637-24b4feed62c6", + "postboxType": "CA_SECURITIES_INVOICE" + } + ], + "type": "documents" + } + ] + } +} \ No newline at end of file