changeset 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 453c9fe6f7f9
files bnpparibas.py
diffstat 1 files changed, 134 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/bnpparibas.py	Mon Jan 11 21:39:40 2016 +0100
+++ b/bnpparibas.py	Tue Jan 12 02:22:59 2016 +0100
@@ -4,7 +4,6 @@
 import itertools
 import json
 import os.path
-import requests
 import smtplib
 import sqlite3
 import subprocess
@@ -20,6 +19,9 @@
 from pprint import pprint
 from urllib.parse import urljoin
 
+import requests
+import click
+
 from html2text import HTML2Text
 from PIL import Image
 
@@ -64,6 +66,14 @@
     for key in dir(module):
         if key.isupper():
             conf[key] = getattr(module, key)
+
+    conf['DATADIR'] = os.path.dirname(filename)
+    for key in 'DATABASE', 'GNUPGHOME':
+        # if path is not absolute, it is interpreted as relative
+        # to the location of the configuration file
+        if not os.path.isabs(conf[key]):
+            conf[key] = os.path.join(conf['DATADIR'], conf[key])
+
     return conf
 
 
@@ -314,20 +324,68 @@
         v = self.validate(r)
         return v['data']
 
+    def records(self):
+        # required to set some cookies required by the next call
+        url = urljoin(URL, 'fr/connexion/virements-services/releves-en-ligne')
+        r = self.session.get(url)
+        self.validate(r)
 
-def main():
-    conffile = sys.argv[1]
-    conf = loadconf(conffile)
+        url = urljoin(URL, 'demat-wspl/rest/initialisationDemat')
+        r = self.session.get(url)
+        v = self.validate(r)
+
+        for branch in v['data']['initialisationDemat']['arbres']:
+            for leave in branch.get('arbre', ( )):
+                if leave['typeDoc'] == 'RELEV':
+                    data = leave
+                    break
+
+        self.iban = data['ibans'][0]['ibanCrypte']
+        query = {'famDoc': data['codeFamille'],
+                 'idTypeDocument': data['idBranche'],
+                 'listeIbanCrypte': [ self.iban, ],
+                 'typeCpt': data['typeCompte'],
+                 'typeDoc': data['typeDoc'],
+                 'typeFamille': 'R001'} # ???
+
+        url = urljoin(URL, 'demat-wspl/rest/consultationDemat')
+        data = json.dumps(query)
+        headers = {'Content-Type': 'application/json'}
+        r = self.session.post(url, headers=headers, data=data)
+        v = self.validate(r)
 
-    datadir = os.path.dirname(conffile)
-    for key in 'DATABASE', 'GNUPGHOME':
-        # if path is not absolute, it is interpreted as relative
-        # to the location of the configuration file
-        if not os.path.isabs(conf[key]):
-            conf[key] = os.path.join(datadir, conf[key])
+        years = v['data']['consultationDemat']['listeCompte'][0]['listeAnnee']
+        query['codeProduit'] = ''
+        documents = []
+
+        url = urljoin(URL, 'demat-wspl/rest/rechercheDemat')
+        for year in years:
+            query['anneeSelectionnee'] = year
+            data = json.dumps(query)
+            r = self.session.post(url, headers=headers, data=data)
+            v = self.validate(r)
+            documents += v['data']['consultationDemat']['listeCompte'][0]['listeDocument']
+
+        return documents
 
+    def document(self, x):
+        url = urljoin(URL, 'demat-wspl/rest/consultationDocumentDemat')
+        params = {'consulted': x['consulted'],
+                  'familleDoc': x['famDoc'],
+                  'ibanCrypte': self.iban,
+                  'idDocument': x['idDoc'],
+                  'idLocalisation': 'undefined',
+                  'typeCpt': x['typeCompte'],
+                  'typeDoc': x['typeDoc'],
+                  'viDocDocument': x['viDocDocument'],
+                  'typeFamille': 'R001'}
+        r = self.session.get(url, params=params)
+        self.validate(r)
+        return r.content
+
+
+def transactions(conf):
     db = sqlite3.connect(conf['DATABASE'])
-    db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''')
     db.execute('''CREATE TABLE IF NOT EXISTS transactions (id INTEGER PRIMARY KEY)''')
 
     sendmail = Mailer(host=conf['SMTPHOST'],
@@ -341,7 +399,6 @@
     remote = BNPParibas()
     remote.login(conf['USERNAME'], conf['PASSWORD'])
 
-    ## transactions
     recent = remote.recent()
     data = recent['listerOperations']['compte']
     transactions = [ Transaction.fromjson(x) for x in data['operationPassee'] ]
@@ -378,7 +435,22 @@
     curs.executemany('''INSERT INTO transactions (id) VALUES (?)''', ((x.id, ) for x in unseen))
     db.commit()
 
-    ## messages
+
+def messages(conf):
+    db = sqlite3.connect(conf['DATABASE'])
+    db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''')
+
+    sendmail = Mailer(host=conf['SMTPHOST'],
+                      port=conf['SMTPPORT'],
+                      starttls=conf['SMTPSTARTTLS'],
+                      username=conf['SMTPUSER'],
+                      password=conf['SMTPPASSWD']).send
+
+    encrypt = GPG(conf['GNUPGHOME']).encrypt
+
+    remote = BNPParibas()
+    remote.login(conf['USERNAME'], conf['PASSWORD'])
+
     data = remote.info()
     info = data['abonnement']
     nnew = info['nombreMessageBMMNonLus'] + info['nombreMessageBilatNonLus']
@@ -407,5 +479,54 @@
         db.commit()
 
 
+def records(conf):
+    db = sqlite3.connect(conf['DATABASE'])
+    db.execute('''CREATE TABLE IF NOT EXISTS records (id TEXT PRIMARY KEY)''')
+
+    remote = BNPParibas()
+    data = remote.login(conf['USERNAME'], conf['PASSWORD'])
+
+    records = remote.records()
+    for r in records:
+
+        curs = db.cursor()
+        curs.execute('''SELECT COUNT(*) FROM records WHERE id = ?''', (r['idDoc'], ))
+        if curs.fetchone()[0]:
+            # already handled
+            continue
+
+        data = remote.document(r)
+        date = datetime.strptime(r['dateDoc'], '%d/%m/%Y').strftime('bnpparibas-%Y%m%d.pdf')
+        filename = os.path.join(conf['DATADIR'], 'data', date)
+        if conf.get('VERBOSE'):
+            print(r['idDoc'], filename)
+        with open(filename, 'wb') as fd:
+            fd.write(data)
+
+        curs.execute('''INSERT INTO records (id) VALUES (?)''', (r['idDoc'], ))
+        db.commit()
+
+
+@click.command()
+@click.argument('conffile')
+@click.option('--transactions', 'what', multiple=True, flag_value='transactions', help='Email new transactions.')
+@click.option('--messages', 'what', multiple=True, flag_value='messages', help='Email new messages.')
+@click.option('--records', 'what', multiple=True, flag_value='records', help='Download new montly records.')
+@click.option('--verbose', is_flag=True, help='Verbose output.')
+def main(conffile, what, verbose):
+
+    actions = {'transactions': transactions,
+               'messages': messages,
+               'records': records}
+
+    conf = loadconf(conffile)
+    if verbose:
+        conf['VERBOSE'] = True
+
+    for x in what:
+        action = actions.get(x)
+        action(conf)
+
+
 if __name__ == '__main__':
     main()