@@ -308,12 +308,10 @@ def __init__(self, tr, max_age_timestamp):
308
308
self .log = get_logger (__name__ )
309
309
self .received_detail = 0
310
310
self .requested_detail = 0
311
- self .num_timeline_details = 0
312
311
self .events_without_docs = []
313
312
self .events_with_docs = []
314
313
self .num_timelines = 0
315
314
self .timeline_events = {}
316
- self .timeline_events_iter = None
317
315
self .max_age_timestamp = max_age_timestamp
318
316
319
317
async def get_next_timeline_transactions (self , response = None ):
@@ -329,24 +327,24 @@ async def get_next_timeline_transactions(self, response=None):
329
327
await self .tr .timeline_transactions ()
330
328
else :
331
329
self .num_timelines += 1
332
- # print(json.dumps(response))
333
- self .num_timeline_details += len (response ['items' ])
330
+ added_last_event = True
334
331
for event in response ['items' ]:
335
- event ['source' ] = "timelineTransaction"
336
- self .timeline_events [event ['id' ]] = event
332
+ if self .max_age_timestamp == 0 or datetime .fromisoformat (event ['timestamp' ][:19 ]).timestamp () >= self .max_age_timestamp :
333
+ event ['source' ] = "timelineTransaction"
334
+ self .timeline_events [event ['id' ]] = event
335
+ else :
336
+ added_last_event = False
337
+ break
337
338
338
- after = response ['cursors' ].get ('after' )
339
-
340
- last_transaction_time = response ['items' ][- 1 ]['timestamp' ][:19 ]
341
- timestamp = datetime .fromisoformat (last_transaction_time ).timestamp ()
342
339
self .log .info (
343
- f'Received #{ self .num_timelines :<2} timeline transactions until { last_transaction_time } '
340
+ f'Received #{ self .num_timelines :<2} timeline transactions'
344
341
)
345
- if (after is not None ) and ((self .max_age_timestamp == 0 ) or (timestamp >= self .max_age_timestamp )):
342
+ after = response ['cursors' ].get ('after' )
343
+ if (after is not None ) and added_last_event :
346
344
self .log .info (
347
345
f'Subscribing #{ self .num_timelines + 1 :<2} timeline transactions'
348
346
)
349
- await self .tr .timeline_transactions (after )
347
+ await self .tr .timeline_transactions (after )
350
348
else :
351
349
# last timeline is reached
352
350
self .log .info ('Received last relevant timeline transaction' )
@@ -365,19 +363,21 @@ async def get_next_timeline_activity_log(self, response=None):
365
363
self .num_timelines = 0
366
364
await self .tr .timeline_activity_log ()
367
365
else :
368
- last_transaction_time = response ['items' ][- 1 ]['timestamp' ][:19 ]
369
- timestamp = datetime .fromisoformat (last_transaction_time ).timestamp ()
370
366
self .num_timelines += 1
371
- # print(json.dumps(response))
372
- self .num_timeline_details += len (response ['items' ])
367
+ added_last_event = True
373
368
for event in response ['items' ]:
374
- if event ['id' ] not in self .timeline_events :
369
+ if self .max_age_timestamp == 0 or datetime .fromisoformat (event ['timestamp' ][:19 ]).timestamp () >= self .max_age_timestamp :
370
+ if event ['id' ] in self .timeline_events :
371
+ self .log .warning (f"Received duplicate event { event ['id' ] } " )
375
372
event ['source' ] = "timelineActivity"
376
373
self .timeline_events [event ['id' ]] = event
374
+ else :
375
+ added_last_event = False
376
+ break
377
377
378
+ self .log .info (f'Received #{ self .num_timelines :<2} timeline activity log' )
378
379
after = response ['cursors' ].get ('after' )
379
- self .log .info (f'Received #{ self .num_timelines :<2} timeline activity log unitl { last_transaction_time } ' )
380
- if (after is not None ) and ((self .max_age_timestamp == 0 ) or (timestamp >= self .max_age_timestamp )):
380
+ if (after is not None ) and added_last_event :
381
381
self .log .info (
382
382
f'Subscribing #{ self .num_timelines + 1 :<2} timeline activity log'
383
383
)
@@ -393,62 +393,55 @@ async def _get_timeline_details(self):
393
393
for event in self .timeline_events .values ():
394
394
action = event .get ('action' )
395
395
msg = ''
396
- timestamp_field = datetime .fromisoformat (event ['timestamp' ][:19 ]).timestamp ()
397
- if self .max_age_timestamp != 0 and (timestamp_field < self .max_age_timestamp ):
398
- msg += 'Skip: too old'
399
- elif action is None :
396
+ if action is None :
400
397
if event .get ('actionLabel' ) is None :
401
398
msg += 'Skip: no action'
402
399
elif action .get ('type' ) != 'timelineDetail' :
403
400
msg += f"Skip: action type unmatched ({ action ['type' ]} )"
404
401
elif action .get ('payload' ) != event ['id' ]:
405
402
msg += f"Skip: payload unmatched ({ action ['payload' ]} )"
406
403
407
- if msg == '' :
408
- self .events_with_docs .append (event )
409
- else :
404
+ if msg != '' :
410
405
self .events_without_docs .append (event )
411
- self .log .debug (f"{ msg } { event ['title' ]} : { event .get ('body' )} { json .dumps (event )} " )
412
- self .num_timeline_details -= 1
413
- continue
414
-
415
- self .requested_detail += 1
416
- await self .tr .timeline_detail_v2 (event ['id' ])
406
+ self .log .debug (f"{ msg } { event ['title' ]} : { event .get ('body' )} " )
407
+ else :
408
+ self .requested_detail += 1
409
+ await self .tr .timeline_detail_v2 (event ['id' ])
417
410
self .log .info ('All timeline details requested' )
418
411
return False
419
412
420
- async def timelineDetail (self , response , dl ):
413
+ async def process_timelineDetail (self , response , dl ):
421
414
'''
422
- process timeline response and request timelines
415
+ process timeline details response
416
+ download any associated docs
417
+ create other_events.json, events_with_documents.json and account_transactions.csv
423
418
'''
424
419
425
420
self .received_detail += 1
426
421
event = self .timeline_events [response ['id' ]]
427
422
event ['details' ] = response
428
423
429
- is_savings_plan = (event ["eventType" ] == "SAVINGS_PLAN_EXECUTED" )
430
-
431
- max_details_digits = len (str (self .num_timeline_details ))
424
+ max_details_digits = len (str (self .requested_detail ))
432
425
self .log .info (
433
- f"{ self .received_detail :>{max_details_digits }} /{ self .num_timeline_details } : "
434
- + f"{ event ['title' ]} -- { event ['subtitle' ]} "
426
+ f"{ self .received_detail :>{max_details_digits }} /{ self .requested_detail } : "
427
+ + f"{ event ['title' ]} -- { event ['subtitle' ]} - { event [ 'timestamp' ][: 19 ] } "
435
428
)
436
429
437
- if is_savings_plan :
438
- subfolder = 'Sparplan'
439
- else :
440
- subfolder = {
430
+ subfolder = {
441
431
'benefits_saveback_execution' : 'Saveback' ,
442
432
'benefits_spare_change_execution' : 'RoundUp' ,
443
433
'ssp_corporate_action_invoice_cash' : 'Dividende' ,
444
434
'CREDIT' : 'Dividende' ,
445
435
'INTEREST_PAYOUT_CREATED' : 'Zinsen' ,
436
+ "SAVINGS_PLAN_EXECUTED" :'Sparplan'
446
437
}.get (event ["eventType" ])
447
438
439
+ event ['has_docs' ] = False
448
440
for section in response ['sections' ]:
449
441
if section ['type' ] != 'documents' :
450
442
continue
451
443
for doc in section ['data' ]:
444
+ event ['has_docs' ] = True
452
445
try :
453
446
timestamp = datetime .strptime (doc ['detail' ], '%d.%m.%Y' ).timestamp ()
454
447
except (ValueError , KeyError ):
@@ -459,7 +452,12 @@ async def timelineDetail(self, response, dl):
459
452
title += f" - { event ['subtitle' ]} "
460
453
dl .dl_doc (doc , title , doc .get ('detail' ), subfolder )
461
454
462
- if self .received_detail == self .num_timeline_details :
455
+ if event ['has_docs' ]:
456
+ self .events_with_docs .append (event )
457
+ else :
458
+ self .events_without_docs .append (event )
459
+
460
+ if self .received_detail == self .requested_detail :
463
461
self .log .info ('Received all details' )
464
462
dl .output_path .mkdir (parents = True , exist_ok = True )
465
463
with open (dl .output_path / 'other_events.json' , 'w' , encoding = 'utf-8' ) as f :
0 commit comments