pax_global_header 0000666 0000000 0000000 00000000064 13436457030 0014517 g ustar 00root root 0000000 0000000 52 comment=3863a14eedf17551743a8bbccf0237874d7f4a16
woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/ 0000775 0000000 0000000 00000000000 13436457030 0022412 5 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/modules/ 0000775 0000000 0000000 00000000000 13436457030 0024062 5 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/modules/edf/ 0000775 0000000 0000000 00000000000 13436457030 0024620 5 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/modules/edf/pro/ 0000775 0000000 0000000 00000000000 13436457030 0025420 5 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/modules/edf/pro/__init__.py 0000664 0000000 0000000 00000000000 13436457030 0027517 0 ustar 00root root 0000000 0000000 woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/modules/edf/pro/browser.py 0000664 0000000 0000000 00000012166 13436457030 0027463 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Jean Walrave
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from __future__ import unicode_literals
from datetime import datetime, timedelta
from weboob.browser import LoginBrowser, URL, need_login
from weboob.capabilities.base import NotAvailable
from weboob.exceptions import BrowserIncorrectPassword, ActionNeeded, BrowserUnavailable
from weboob.browser.exceptions import ServerError, ClientError
from .pages import (
LoginPage, HomePage, AuthPage, ErrorPage, LireSitePage,
SubscriptionsPage, SubscriptionsAccountPage, BillsPage, DocumentsPage, ProfilePage,
)
class EdfproBrowser(LoginBrowser):
BASEURL = 'https://www.edfentreprises.fr'
login = URL('/openam/json/authenticate', LoginPage)
auth = URL('/openam/UI/Login.*',
'/ice/rest/aiguillagemp/redirect', AuthPage)
error = URL(r'/page_erreur/', ErrorPage)
home = URL('/ice/content/ice-pmse/homepage.html', HomePage)
liresite = URL(r'/rest/homepagemp/liresite', LireSitePage)
subscriptions = URL('/rest/homepagemp/lireprofilsfacturation', SubscriptionsPage)
contracts = URL('/rest/contratmp/consultercontrats', SubscriptionsAccountPage)
bills = URL('/rest/facturemp/getnomtelechargerfacture', BillsPage)
documents = URL('/rest/facturemp/recherchefacture', DocumentsPage)
profile = URL('/rest/servicemp/consulterinterlocuteur', ProfilePage)
def __init__(self, config, *args, **kwargs):
self.config = config
kwargs['username'] = self.config['login'].get()
kwargs['password'] = self.config['password'].get()
super(EdfproBrowser, self).__init__(*args, **kwargs)
def do_login(self):
self.login.go('/openam/json/authenticate', method='POST')
login_data = self.page.get_data(self.username, self.password)
try:
self.login.go(json=login_data)
except ClientError as e:
raise BrowserIncorrectPassword(e.response.json()['message'])
self.session.cookies['ICESSOsession'] = self.page.doc['tokenId']
self.location(self.absurl('/rest/aiguillagemp/redirect'), allow_redirects=True)
if self.auth.is_here() and self.page.response.status_code != 303:
raise BrowserIncorrectPassword()
if self.error.is_here():
raise BrowserUnavailable(self.page.get_message())
self.session.headers['Content-Type'] = 'application/json;charset=UTF-8'
self.session.headers['X-XSRF-TOKEN'] = self.session.cookies['XSRF-TOKEN']
@need_login
def get_subscription_list(self):
self.liresite.go(json={"numPremierSitePage": 0, "pageSize": 100000, "idTdg": None,
"critereFiltre": [], "critereTri": []})
id_site_list = self.page.get_id_site_list()
if not id_site_list:
raise ActionNeeded("Vous ne disposez d'aucun contrat actif relatif à vos sites")
data = {
'critereFiltre': [],
'critereTri': [],
'idTdg': None,
'pageSize': 100000,
'startRowNum': 0
}
sub_page = self.subscriptions.go(json=data)
self.contracts.go(json={'refDevisOMList': [], 'refDevisOHList': id_site_list})
for sub in sub_page.get_subscriptions():
self.page.update_subscription(sub)
yield sub
@need_login
def iter_documents(self, subscription):
try:
self.documents.go(json={
'dateDebut': (datetime.now() - timedelta(weeks=156)).strftime('%d/%m/%Y'),
'dateFin': datetime.now().strftime('%d/%m/%Y'),
'element': subscription._account_id,
'typeElementListe': 'ID_FELIX'
})
return self.page.get_documents()
except ServerError:
return []
@need_login
def download_document(self, document):
if document.url is not NotAvailable:
try:
self.bills.go(json={'date': int(document.date.strftime('%s')),
'iDFelix': document._account_billing,
'numFacture': document._bill_number})
return self.open('%s/rest/facturemp/telechargerfichier?fname=%s' % (
self.BASEURL, self.page.get_bill_name())).content
except ServerError:
return NotAvailable
@need_login
def get_profile(self):
self.profile.go(json={'idSpcInterlocuteur': ''})
return self.page.get_profile()
woob-3863a14eedf17551743a8bbccf0237874d7f4a16-modules-edf-pro/modules/edf/pro/pages.py 0000664 0000000 0000000 00000012365 13436457030 0027100 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2016 Jean Walrave
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob module is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this weboob module. If not, see .
from __future__ import unicode_literals
from datetime import date
from weboob.browser.pages import JsonPage, HTMLPage, RawPage, LoggedPage
from weboob.browser.elements import DictElement, ItemElement, method
from weboob.browser.filters.standard import CleanDecimal, CleanText
from weboob.browser.filters.json import Dict
from weboob.capabilities.bill import DocumentTypes, Subscription, Bill
from weboob.exceptions import ActionNeeded
from weboob.capabilities.profile import Profile
class LoginPage(JsonPage):
def get_data(self, login, password):
login_data = self.doc
login_data['callbacks'][0]['input'][0]['value'] = login
login_data['callbacks'][1]['input'][0]['value'] = password
return login_data
class AuthPage(RawPage):
pass
class ErrorPage(HTMLPage):
def get_message(self):
return CleanText('//div[@id="div_text"]/h1 | //div[@id="div_text"]/p')(self.doc)
class HomePage(LoggedPage, HTMLPage):
pass
class JsonCguPage(JsonPage):
def build_doc(self, text):
if text == 'REDIRECT_CGU': # JSON can always be decoded in UTF-8 so testing text is fine
raise ActionNeeded("Vous devez accepter les conditions générales d'utilisation.")
return super(JsonCguPage, self).build_doc(text)
class LireSitePage(LoggedPage, JsonCguPage):
# id site is not about website but geographical site
def get_id_site_list(self):
return [site['idSite'] for site in self.doc['site']]
class SubscriptionsPage(LoggedPage, JsonPage):
@method
class get_subscriptions(DictElement):
item_xpath = 'profilFacturation'
class item(ItemElement):
klass = Subscription
obj_id = CleanText(Dict('idPFLabel'))
obj__account_id = CleanText(Dict('idCompteDeFacturation'))
class SubscriptionsAccountPage(LoggedPage, JsonCguPage):
@classmethod
def _get_similarity_among_id(cls, sub_id, account_id):
"""
sometimes there are several sub_id and several account_id
sub_id looks like 1-UD8Z6FPO
and account_id 1-UD8Z6F7S
when a sub_id and an account_id are related their id are not completely identical but close
this function count numbers of char that are identical from the beginning until one char is different
more the count value is high more there is a chance that both id are from related objects (subscription and account)
"""
_, sub_id_value = sub_id.split('-', 1)
_, account_id_value = account_id.split('-', 1)
count = 0
for idx, c in enumerate(sub_id_value):
if idx >= len(account_id_value):
return count
if account_id_value[idx] != c:
return count
count += 1
return count
def update_subscription(self, subscription):
good_con = None
best_matching = 0
for con in self.doc['listeContrat']:
matching = self._get_similarity_among_id(subscription.id, con['refDevisLabel'])
if matching > best_matching:
best_matching = matching
good_con = con
if good_con:
subscription.label = good_con['nomOffreModele']
subscription.subscriber = (good_con['prenomIntPrinc'] + ' ' + good_con['nomIntPrinc']).title()
class BillsPage(LoggedPage, JsonPage):
def get_bill_name(self):
return Dict('nomFichier')(self.doc)
class DocumentsPage(LoggedPage, JsonPage):
def get_documents(self):
documents = []
for document in self.doc:
doc = Bill()
doc.id = document['numFactureLabel']
doc.date = date.fromtimestamp(int(document['dateEmission'] / 1000))
doc.format = 'PDF'
doc.label = 'Facture %s' % document['numFactureLabel']
doc.type = DocumentTypes.BILL
doc.price = CleanDecimal().filter(document['montantTTC'])
doc.currency = '€'
doc._account_billing = document['compteFacturation']
doc._bill_number = document['numFacture']
documents.append(doc)
return documents
class ProfilePage(LoggedPage, JsonPage):
def get_profile(self):
data = self.doc
p = Profile()
p.name = '%s %s %s' % (data['civilite'], data['nom'], data['prenom'])
p.address = '%s %s %s' % (data['adresse'], data['codeSpcPostal'], data['commune'])
p.phone = data['telMobile'] or data['telBureau']
p.email = data['email'].replace('@', '@')
return p