Mercurial > hg > bnpparibas
comparison bnpparibas.py @ 14:0a3509a12762
Implement download of montly records and add command line options
author | Daniele Nicolodi <daniele@grinta.net> |
---|---|
date | Tue, 12 Jan 2016 02:22:59 +0100 |
parents | 37ce0dc68cad |
children | af2e222f2dad |
comparison
equal
deleted
inserted
replaced
13:37ce0dc68cad | 14:0a3509a12762 |
---|---|
2 import email | 2 import email |
3 import imp | 3 import imp |
4 import itertools | 4 import itertools |
5 import json | 5 import json |
6 import os.path | 6 import os.path |
7 import requests | |
8 import smtplib | 7 import smtplib |
9 import sqlite3 | 8 import sqlite3 |
10 import subprocess | 9 import subprocess |
11 import sys | 10 import sys |
12 import textwrap | 11 import textwrap |
17 from email.mime.text import MIMEText | 16 from email.mime.text import MIMEText |
18 from email.utils import format_datetime, localtime, parseaddr | 17 from email.utils import format_datetime, localtime, parseaddr |
19 from io import BytesIO | 18 from io import BytesIO |
20 from pprint import pprint | 19 from pprint import pprint |
21 from urllib.parse import urljoin | 20 from urllib.parse import urljoin |
21 | |
22 import requests | |
23 import click | |
22 | 24 |
23 from html2text import HTML2Text | 25 from html2text import HTML2Text |
24 from PIL import Image | 26 from PIL import Image |
25 | 27 |
26 | 28 |
62 exec(compile(fd.read(), filename, 'exec'), module.__dict__) | 64 exec(compile(fd.read(), filename, 'exec'), module.__dict__) |
63 conf = {} | 65 conf = {} |
64 for key in dir(module): | 66 for key in dir(module): |
65 if key.isupper(): | 67 if key.isupper(): |
66 conf[key] = getattr(module, key) | 68 conf[key] = getattr(module, key) |
69 | |
70 conf['DATADIR'] = os.path.dirname(filename) | |
71 for key in 'DATABASE', 'GNUPGHOME': | |
72 # if path is not absolute, it is interpreted as relative | |
73 # to the location of the configuration file | |
74 if not os.path.isabs(conf[key]): | |
75 conf[key] = os.path.join(conf['DATADIR'], conf[key]) | |
76 | |
67 return conf | 77 return conf |
68 | 78 |
69 | 79 |
70 def wrap(p, indent): | 80 def wrap(p, indent): |
71 return textwrap.fill(p, 72, initial_indent=indent, subsequent_indent=indent) | 81 return textwrap.fill(p, 72, initial_indent=indent, subsequent_indent=indent) |
312 url = urljoin(URL, 'bmm-wspl/recupMsg') | 322 url = urljoin(URL, 'bmm-wspl/recupMsg') |
313 r = self.session.get(url, params={'identifiant': mid}) | 323 r = self.session.get(url, params={'identifiant': mid}) |
314 v = self.validate(r) | 324 v = self.validate(r) |
315 return v['data'] | 325 return v['data'] |
316 | 326 |
317 | 327 def records(self): |
318 def main(): | 328 # required to set some cookies required by the next call |
319 conffile = sys.argv[1] | 329 url = urljoin(URL, 'fr/connexion/virements-services/releves-en-ligne') |
320 conf = loadconf(conffile) | 330 r = self.session.get(url) |
321 | 331 self.validate(r) |
322 datadir = os.path.dirname(conffile) | 332 |
323 for key in 'DATABASE', 'GNUPGHOME': | 333 url = urljoin(URL, 'demat-wspl/rest/initialisationDemat') |
324 # if path is not absolute, it is interpreted as relative | 334 r = self.session.get(url) |
325 # to the location of the configuration file | 335 v = self.validate(r) |
326 if not os.path.isabs(conf[key]): | 336 |
327 conf[key] = os.path.join(datadir, conf[key]) | 337 for branch in v['data']['initialisationDemat']['arbres']: |
328 | 338 for leave in branch.get('arbre', ( )): |
339 if leave['typeDoc'] == 'RELEV': | |
340 data = leave | |
341 break | |
342 | |
343 self.iban = data['ibans'][0]['ibanCrypte'] | |
344 query = {'famDoc': data['codeFamille'], | |
345 'idTypeDocument': data['idBranche'], | |
346 'listeIbanCrypte': [ self.iban, ], | |
347 'typeCpt': data['typeCompte'], | |
348 'typeDoc': data['typeDoc'], | |
349 'typeFamille': 'R001'} # ??? | |
350 | |
351 url = urljoin(URL, 'demat-wspl/rest/consultationDemat') | |
352 data = json.dumps(query) | |
353 headers = {'Content-Type': 'application/json'} | |
354 r = self.session.post(url, headers=headers, data=data) | |
355 v = self.validate(r) | |
356 | |
357 years = v['data']['consultationDemat']['listeCompte'][0]['listeAnnee'] | |
358 query['codeProduit'] = '' | |
359 documents = [] | |
360 | |
361 url = urljoin(URL, 'demat-wspl/rest/rechercheDemat') | |
362 for year in years: | |
363 query['anneeSelectionnee'] = year | |
364 data = json.dumps(query) | |
365 r = self.session.post(url, headers=headers, data=data) | |
366 v = self.validate(r) | |
367 documents += v['data']['consultationDemat']['listeCompte'][0]['listeDocument'] | |
368 | |
369 return documents | |
370 | |
371 def document(self, x): | |
372 url = urljoin(URL, 'demat-wspl/rest/consultationDocumentDemat') | |
373 params = {'consulted': x['consulted'], | |
374 'familleDoc': x['famDoc'], | |
375 'ibanCrypte': self.iban, | |
376 'idDocument': x['idDoc'], | |
377 'idLocalisation': 'undefined', | |
378 'typeCpt': x['typeCompte'], | |
379 'typeDoc': x['typeDoc'], | |
380 'viDocDocument': x['viDocDocument'], | |
381 'typeFamille': 'R001'} | |
382 r = self.session.get(url, params=params) | |
383 self.validate(r) | |
384 return r.content | |
385 | |
386 | |
387 def transactions(conf): | |
329 db = sqlite3.connect(conf['DATABASE']) | 388 db = sqlite3.connect(conf['DATABASE']) |
330 db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''') | |
331 db.execute('''CREATE TABLE IF NOT EXISTS transactions (id INTEGER PRIMARY KEY)''') | 389 db.execute('''CREATE TABLE IF NOT EXISTS transactions (id INTEGER PRIMARY KEY)''') |
332 | 390 |
333 sendmail = Mailer(host=conf['SMTPHOST'], | 391 sendmail = Mailer(host=conf['SMTPHOST'], |
334 port=conf['SMTPPORT'], | 392 port=conf['SMTPPORT'], |
335 starttls=conf['SMTPSTARTTLS'], | 393 starttls=conf['SMTPSTARTTLS'], |
339 encrypt = GPG(conf['GNUPGHOME']).encrypt | 397 encrypt = GPG(conf['GNUPGHOME']).encrypt |
340 | 398 |
341 remote = BNPParibas() | 399 remote = BNPParibas() |
342 remote.login(conf['USERNAME'], conf['PASSWORD']) | 400 remote.login(conf['USERNAME'], conf['PASSWORD']) |
343 | 401 |
344 ## transactions | |
345 recent = remote.recent() | 402 recent = remote.recent() |
346 data = recent['listerOperations']['compte'] | 403 data = recent['listerOperations']['compte'] |
347 transactions = [ Transaction.fromjson(x) for x in data['operationPassee'] ] | 404 transactions = [ Transaction.fromjson(x) for x in data['operationPassee'] ] |
348 balance = data['soldeDispo'] | 405 balance = data['soldeDispo'] |
349 | 406 |
376 sendmail(message) | 433 sendmail(message) |
377 | 434 |
378 curs.executemany('''INSERT INTO transactions (id) VALUES (?)''', ((x.id, ) for x in unseen)) | 435 curs.executemany('''INSERT INTO transactions (id) VALUES (?)''', ((x.id, ) for x in unseen)) |
379 db.commit() | 436 db.commit() |
380 | 437 |
381 ## messages | 438 |
439 def messages(conf): | |
440 db = sqlite3.connect(conf['DATABASE']) | |
441 db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''') | |
442 | |
443 sendmail = Mailer(host=conf['SMTPHOST'], | |
444 port=conf['SMTPPORT'], | |
445 starttls=conf['SMTPSTARTTLS'], | |
446 username=conf['SMTPUSER'], | |
447 password=conf['SMTPPASSWD']).send | |
448 | |
449 encrypt = GPG(conf['GNUPGHOME']).encrypt | |
450 | |
451 remote = BNPParibas() | |
452 remote.login(conf['USERNAME'], conf['PASSWORD']) | |
453 | |
382 data = remote.info() | 454 data = remote.info() |
383 info = data['abonnement'] | 455 info = data['abonnement'] |
384 nnew = info['nombreMessageBMMNonLus'] + info['nombreMessageBilatNonLus'] | 456 nnew = info['nombreMessageBMMNonLus'] + info['nombreMessageBilatNonLus'] |
385 | 457 |
386 data = remote.messages() | 458 data = remote.messages() |
405 | 477 |
406 curs.execute('''INSERT INTO messages (id) VALUES (?)''', (m['id'], )) | 478 curs.execute('''INSERT INTO messages (id) VALUES (?)''', (m['id'], )) |
407 db.commit() | 479 db.commit() |
408 | 480 |
409 | 481 |
482 def records(conf): | |
483 db = sqlite3.connect(conf['DATABASE']) | |
484 db.execute('''CREATE TABLE IF NOT EXISTS records (id TEXT PRIMARY KEY)''') | |
485 | |
486 remote = BNPParibas() | |
487 data = remote.login(conf['USERNAME'], conf['PASSWORD']) | |
488 | |
489 records = remote.records() | |
490 for r in records: | |
491 | |
492 curs = db.cursor() | |
493 curs.execute('''SELECT COUNT(*) FROM records WHERE id = ?''', (r['idDoc'], )) | |
494 if curs.fetchone()[0]: | |
495 # already handled | |
496 continue | |
497 | |
498 data = remote.document(r) | |
499 date = datetime.strptime(r['dateDoc'], '%d/%m/%Y').strftime('bnpparibas-%Y%m%d.pdf') | |
500 filename = os.path.join(conf['DATADIR'], 'data', date) | |
501 if conf.get('VERBOSE'): | |
502 print(r['idDoc'], filename) | |
503 with open(filename, 'wb') as fd: | |
504 fd.write(data) | |
505 | |
506 curs.execute('''INSERT INTO records (id) VALUES (?)''', (r['idDoc'], )) | |
507 db.commit() | |
508 | |
509 | |
510 @click.command() | |
511 @click.argument('conffile') | |
512 @click.option('--transactions', 'what', multiple=True, flag_value='transactions', help='Email new transactions.') | |
513 @click.option('--messages', 'what', multiple=True, flag_value='messages', help='Email new messages.') | |
514 @click.option('--records', 'what', multiple=True, flag_value='records', help='Download new montly records.') | |
515 @click.option('--verbose', is_flag=True, help='Verbose output.') | |
516 def main(conffile, what, verbose): | |
517 | |
518 actions = {'transactions': transactions, | |
519 'messages': messages, | |
520 'records': records} | |
521 | |
522 conf = loadconf(conffile) | |
523 if verbose: | |
524 conf['VERBOSE'] = True | |
525 | |
526 for x in what: | |
527 action = actions.get(x) | |
528 action(conf) | |
529 | |
530 | |
410 if __name__ == '__main__': | 531 if __name__ == '__main__': |
411 main() | 532 main() |