[Ameli]&[Amelipro] Update after sites changes, and upgrade to new browser

This commit is contained in:
Kitof 2013-12-17 22:22:52 +01:00 committed by Romain Bignon
commit 10c5abc3d4
7 changed files with 251 additions and 229 deletions

View file

@ -24,10 +24,8 @@ from weboob.tools.value import ValueBackendPassword
from .browser import Amazon from .browser import Amazon
__all__ = ['AmazonModule'] __all__ = ['AmazonModule']
class AmazonModule(Module, CapShop): class AmazonModule(Module, CapShop):
NAME = 'amazon' NAME = 'amazon'
MAINTAINER = u'Oleg Plakhotniuk' MAINTAINER = u'Oleg Plakhotniuk'

91
modules/ameli/browser.py Normal file → Executable file
View file

@ -17,7 +17,8 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword
from weboob.capabilities.bill import Detail from weboob.capabilities.bill import Detail
from decimal import Decimal from decimal import Decimal
from .pages import LoginPage, HomePage, AccountPage, LastPaymentsPage, PaymentDetailsPage, BillsPage from .pages import LoginPage, HomePage, AccountPage, LastPaymentsPage, PaymentDetailsPage, BillsPage
@ -25,80 +26,66 @@ from .pages import LoginPage, HomePage, AccountPage, LastPaymentsPage, PaymentDe
__all__ = ['AmeliBrowser'] __all__ = ['AmeliBrowser']
class AmeliBrowser(Browser): class AmeliBrowser(LoginBrowser):
PROTOCOL = 'https' BASEURL = 'https://assure.ameli.fr'
DOMAIN = 'assure.ameli.fr'
ENCODING = None
PAGES = {'.*_pageLabel=as_login_page.*': LoginPage, loginp = URL('/PortailAS/appmanager/PortailAS/assure\?.*_pageLabel=as_login_page', LoginPage)
'.*_pageLabel=as_accueil_page.*': HomePage, homep = URL('/PortailAS/appmanager/PortailAS/assure\?_nfpb=true&_pageLabel=as_accueil_page', HomePage)
'.*_pageLabel=as_etat_civil_page.*': AccountPage, accountp = URL('/PortailAS/appmanager/PortailAS/assure\?_nfpb=true&_pageLabel=as_info_perso_page', AccountPage)
'.*_pageLabel=as_revele_mensuel_presta_page.*': BillsPage, billsp = URL('/PortailAS/appmanager/PortailAS/assure\?_nfpb=true&_pageLabel=as_revele_mensuel_presta_page', BillsPage)
'.*_pageLabel=as_dernier_paiement_page': LastPaymentsPage, paymentdetailsp = URL('/PortailAS/appmanager/PortailAS/assure\?_nfpb=true&_pageLabel=as_dernier_paiement_page&paiements_1_actionOverride=%2Fportlets%2Fpaiements%2Fdetailpaiements&paiements_1idPaiement=.*', PaymentDetailsPage)
'.*_actionOverride=%2Fportlets%2Fpaiements%2Fdetailpaiements&paiements.*': PaymentDetailsPage lastpaymentsp = URL('/PortailAS/appmanager/PortailAS/assure\?_nfpb=true&_pageLabel=as_dernier_paiement_page$', LastPaymentsPage)
}
loginp = '/PortailAS/appmanager/PortailAS/assure?_somtc=true&_pageLabel=as_login_page' logged = False
homep = '/PortailAS/appmanager/PortailAS/assure?_nfpb=true&_pageLabel=as_accueil_page'
accountp = '/PortailAS/appmanager/PortailAS/assure?_nfpb=true&_pageLabel=as_etat_civil_page'
billsp = '/PortailAS/appmanager/PortailAS/assure?_nfpb=true&_pageLabel=as_revele_mensuel_presta_page'
lastpaymentsp = '/PortailAS/appmanager/PortailAS/assure?_nfpb=true&_pageLabel=as_dernier_paiement_page'
is_logging = False def do_login(self):
self.logger.debug('call Browser.do_login')
if self.logged:
return True
def home(self): self.loginp.stay_or_go()
self.logger.debug('call Browser.home') if self.homep.is_here():
self.location(self.homep) self.logged = True
if ((not self.is_logged()) and (not self.is_logging)): return True
self.login()
def is_logged(self):
self.logger.debug('call Browser.is_logged')
return self.page.is_logged()
def login(self):
self.logger.debug('call Browser.login')
# Do we really need to login?
if self.is_logged():
self.logger.debug('Already logged in')
return
if self.is_logging:
return
self.is_logging = True
self.location(self.loginp)
self.page.login(self.username, self.password) self.page.login(self.username, self.password)
if not self.is_logged(): self.homep.stay_or_go() # Redirection not interpreted by browser. Mannually redirect on homep
if not self.homep.is_here():
raise BrowserIncorrectPassword() raise BrowserIncorrectPassword()
self.is_logging = False self.logged = True
@need_login
def iter_subscription_list(self): def iter_subscription_list(self):
if not self.is_on_page(AccountPage): self.logger.debug('call Browser.iter_subscription_list')
self.location(self.accountp) self.accountp.stay_or_go()
return self.page.iter_subscription_list() return self.page.iter_subscription_list()
@need_login
def get_subscription(self, id): def get_subscription(self, id):
self.logger.debug('call Browser.get_subscription')
assert isinstance(id, basestring) assert isinstance(id, basestring)
for sub in self.iter_subscription_list(): for sub in self.iter_subscription_list():
if id == sub._id: if id == sub._id:
return sub return sub
return None return None
@need_login
def iter_history(self, sub): def iter_history(self, sub):
if not self.is_on_page(LastPaymentsPage): self.logger.debug('call Browser.iter_history')
self.location(self.lastpaymentsp) self.lastpaymentsp.stay_or_go()
urls = self.page.iter_last_payments() urls = self.page.iter_last_payments()
for url in urls: for url in urls:
self.location(url) self.location(url)
assert self.is_on_page(PaymentDetailsPage) assert self.paymentdetailsp.is_here()
for payment in self.page.iter_payment_details(sub): for payment in self.page.iter_payment_details(sub):
yield payment yield payment
@need_login
def iter_details(self, sub): def iter_details(self, sub):
self.logger.debug('call Browser.iter_details')
det = Detail() det = Detail()
det.id = sub.id det.id = sub.id
det.label = sub.label det.label = sub.label
@ -106,17 +93,21 @@ class AmeliBrowser(Browser):
det.price = Decimal('0.0') det.price = Decimal('0.0')
yield det yield det
@need_login
def iter_bills(self, sub): def iter_bills(self, sub):
self.logger.debug('call Browser.iter_bills')
if not sub._id.isdigit(): if not sub._id.isdigit():
return [] return []
if not self.is_on_page(BillsPage): self.billsp.stay_or_go()
self.location(self.billsp) return self.page.iter_bills(sub)
return self.page.iter_bills(sub)
@need_login
def get_bill(self, id): def get_bill(self, id):
self.logger.debug('call Browser.get_bill')
assert isinstance(id, basestring) assert isinstance(id, basestring)
subs = self.iter_subscription_list() subs = self.iter_subscription_list()
for sub in subs: for sub in subs:
for b in self.iter_bills(sub): for b in self.iter_bills(sub):
if id == b.id: if id == b.id:
return b return b
return False

24
modules/ameli/module.py Normal file → Executable file
View file

@ -17,7 +17,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
import urllib
from weboob.capabilities.bill import CapBill, SubscriptionNotFound, BillNotFound, Subscription, Bill from weboob.capabilities.bill import CapBill, SubscriptionNotFound, BillNotFound, Subscription, Bill
from weboob.tools.backend import Module, BackendConfig from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword from weboob.tools.value import ValueBackendPassword
@ -35,13 +34,12 @@ class AmeliModule(Module, CapBill):
LICENSE = 'AGPLv3+' LICENSE = 'AGPLv3+'
BROWSER = AmeliBrowser BROWSER = AmeliBrowser
CONFIG = BackendConfig(ValueBackendPassword('login', CONFIG = BackendConfig(ValueBackendPassword('login',
label='numero de SS', label='Numero de SS',
masked=False), masked=False),
ValueBackendPassword('password', ValueBackendPassword('password',
label='Password', label='Password',
masked=True) masked=True)
) )
BROWSER = AmeliBrowser
def create_default_browser(self): def create_default_browser(self):
return self.create_browser(self.config['login'].get(), return self.create_browser(self.config['login'].get(),
@ -51,8 +49,7 @@ class AmeliModule(Module, CapBill):
return self.browser.iter_subscription_list() return self.browser.iter_subscription_list()
def get_subscription(self, _id): def get_subscription(self, _id):
with self.browser: subscription = self.browser.get_subscription(_id)
subscription = self.browser.get_subscription(_id)
if not subscription: if not subscription:
raise SubscriptionNotFound() raise SubscriptionNotFound()
else: else:
@ -61,24 +58,20 @@ class AmeliModule(Module, CapBill):
def iter_bills_history(self, subscription): def iter_bills_history(self, subscription):
if not isinstance(subscription, Subscription): if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription) subscription = self.get_subscription(subscription)
with self.browser: return self.browser.iter_history(subscription)
return self.browser.iter_history(subscription)
def get_details(self, subscription): def get_details(self, subscription):
if not isinstance(subscription, Subscription): if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription) subscription = self.get_subscription(subscription)
with self.browser: return self.browser.iter_details(subscription)
return self.browser.iter_details(subscription)
def iter_bills(self, subscription): def iter_bills(self, subscription):
if not isinstance(subscription, Subscription): if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription) subscription = self.get_subscription(subscription)
with self.browser: return self.browser.iter_bills(subscription)
return self.browser.iter_bills(subscription)
def get_bill(self, id): def get_bill(self, id):
with self.browser: bill = self.browser.get_bill(id)
bill = self.browser.get_bill(id)
if not bill: if not bill:
raise BillNotFound() raise BillNotFound()
else: else:
@ -87,5 +80,6 @@ class AmeliModule(Module, CapBill):
def download_bill(self, bill): def download_bill(self, bill):
if not isinstance(bill, Bill): if not isinstance(bill, Bill):
bill = self.get_bill(bill) bill = self.get_bill(bill)
with self.browser: request = self.browser.open(bill._url, stream=True)
return self.browser.readurl(bill._url, urllib.urlencode(bill._args)) assert(request.headers['content-type'] == "application/pdf")
return request.content

View file

@ -22,53 +22,48 @@ from datetime import datetime
import re import re
import urllib import urllib
from decimal import Decimal from decimal import Decimal
from weboob.deprecated.browser import Page, BrokenPageError from weboob.browser.pages import HTMLPage
from weboob.capabilities.bill import Subscription, Detail, Bill from weboob.capabilities.bill import Subscription, Detail, Bill
from weboob.browser.filters.standard import CleanText
# Ugly array to avoid the use of french locale # Ugly array to avoid the use of french locale
FRENCH_MONTHS = [u'janvier', u'février', u'mars', u'avril', u'mai', u'juin', u'juillet', u'août', u'septembre', u'octobre', u'novembre', u'décembre'] FRENCH_MONTHS = [u'janvier', u'février', u'mars', u'avril', u'mai', u'juin', u'juillet', u'août', u'septembre', u'octobre', u'novembre', u'décembre']
class AmeliBasePage(HTMLPage):
class AmeliBasePage(Page):
def is_logged(self): def is_logged(self):
try: if self.doc.xpath('//a[@id="id_lien_deco"]'):
self.parser.select(self.document.getroot(), 'a.logout', 1)
except BrokenPageError:
logged = False
else:
logged = True logged = True
else:
logged = False
self.logger.debug('logged: %s' % (logged)) self.logger.debug('logged: %s' % (logged))
return logged return logged
class LoginPage(AmeliBasePage): class LoginPage(AmeliBasePage):
def login(self, login, password): def login(self, login, password):
self.browser.select_form('connexionCompteForm') form = self.get_form('//form[@name="connexionCompteForm"]')
self.browser["connexioncompte_2numSecuriteSociale"] = login.encode('utf8') form['connexioncompte_2numSecuriteSociale'] = login.encode('utf8')
self.browser["connexioncompte_2codeConfidentiel"] = password.encode('utf8') form['connexioncompte_2codeConfidentiel'] = password.encode('utf8')
self.browser.submit() form.submit()
class HomePage(AmeliBasePage): class HomePage(AmeliBasePage):
pass pass
class AccountPage(AmeliBasePage): class AccountPage(AmeliBasePage):
def iter_subscription_list(self): def iter_subscription_list(self):
idents = self.document.xpath('//div[contains(@class, "blocfond")]') name = CleanText('//div[@id="bloc_contenu_masituation"]/h3', replace=[('Titulaire du compte : ', '')])(self.doc)
enfants = 0 number = re.sub('[^\d]+', '', self.doc.xpath('//div[@id="bloc_contenu_masituation"]/ul/li')[2].text)
for ident in idents: sub = Subscription(number)
if len(ident.xpath('.//h3')) == 0: sub._id = number
continue sub.label = unicode(name)
sub.subscriber = unicode(name)
yield sub
name = self.parser.tocleanstring(ident.xpath('.//h3')[0]) nb_childs = 0
lis = ident.xpath('.//li') childs = self.doc.xpath('//div[@class="bloc_infos"]')
if len(lis) > 3: for child in childs:
number = re.sub('[^\d]+', '', ident.xpath('.//li')[3].text) name = CleanText('.//h3[1]')(child)
else: nb_childs = nb_childs + 1
enfants = enfants + 1 number = "AFFILIE" + str(nb_childs)
number = "AFFILIE" + str(enfants)
sub = Subscription(number) sub = Subscription(number)
sub._id = number sub._id = number
sub.label = unicode(name) sub.label = unicode(name)
@ -78,14 +73,14 @@ class AccountPage(AmeliBasePage):
class LastPaymentsPage(AmeliBasePage): class LastPaymentsPage(AmeliBasePage):
def iter_last_payments(self): def iter_last_payments(self):
list_table = self.document.xpath('//table[@id="tabDerniersPaiements"]') list_table = self.doc.xpath('//table[@id="tabDerniersPaiements"]')
if len(list_table) > 0: if len(list_table) > 0:
table = list_table[0].xpath('.//tr') table = list_table[0].xpath('.//tr')
for tr in table: for tr in table:
list_a = tr.xpath('.//a') list_a = tr.xpath('.//a')
if len(list_a) == 0: if len(list_a) == 0:
continue continue
yield list_a[0].attrib.get('href') yield list_a[0].attrib.get('href').replace(':443','')
class PaymentDetailsPage(AmeliBasePage): class PaymentDetailsPage(AmeliBasePage):
@ -94,39 +89,86 @@ class PaymentDetailsPage(AmeliBasePage):
idx = 0 idx = 0
else: else:
idx = sub._id.replace('AFFILIE', '') idx = sub._id.replace('AFFILIE', '')
if len(self.document.xpath('//div[@class="centrepage"]/h2')) > idx or self.document.xpath('//table[@id="DetailPaiement3"]') > idx: if len(self.doc.xpath('//div[@class="centrepage"]/h2')) > idx or self.doc.xpath('//table[@id="DetailPaiement3"]') > idx:
id_str = self.document.xpath('//div[@class="centrepage"]/h2')[idx].text.strip() id_str = self.doc.xpath('//div[@class="centrepage"]/h2')[idx].text.strip()
m = re.match('.*le (.*) pour un montant de.*', id_str) m = re.match('.*le (.*) pour un montant de.*', id_str)
if m: if m:
id_str = m.group(1) id_str = m.group(1)
id_date = datetime.strptime(id_str, '%d/%m/%Y').date() id_date = datetime.strptime(id_str, '%d/%m/%Y').date()
id = sub._id + "." + datetime.strftime(id_date, "%Y%m%d") id = sub._id + "." + datetime.strftime(id_date, "%Y%m%d")
table = self.document.xpath('//table[@class="tableau"]')[idx].xpath('.//tr') table = self.doc.xpath('//table[@class="tableau"]')[idx].xpath('.//tr')
line = 1 line = 1
last_date = None last_date = None
for tr in table: for tr in table:
tds = tr.xpath('.//td') tds = tr.xpath('.//td')
if len(tds) == 0: if len(tds) == 0:
continue continue
date_str = tds[0].text
det = Detail() det = Detail()
det.id = id + "." + str(line)
det.label = unicode(tds[1].text.strip()) if len(tds) == 5:
if date_str is None or date_str == '': date_str = tds[0].text
det.infos = u'' det.id = id + "." + str(line)
det.datetime = last_date det.label = unicode(tds[1].text.strip())
else:
det.infos = u'Payé ' + unicode(re.sub('[^\d,-]+', '', tds[2].text)) + u'€ / Base ' + unicode(re.sub('[^\d,-]+', '', tds[3].text)) + u'€ / Taux ' + unicode(re.sub('[^\d,-]+', '', tds[4].text)) + '%' jours = tds[2].text
det.datetime = datetime.strptime(date_str, '%d/%m/%Y').date() if jours is None:
last_date = det.datetime jours = '0'
det.price = Decimal(re.sub('[^\d,-]+', '', tds[5].text).replace(',', '.'))
montant = tds[3].text
if montant is None:
montant = '0'
price = tds[4].text
if price is None:
price = '0'
if date_str is None or date_str == '':
det.infos = u''
det.datetime = last_date
else:
det.infos = date_str + u' (' + unicode(re.sub('[^\d,-]+', '', jours)) + u'j) * ' + unicode(re.sub('[^\d,-]+', '', montant)) + u''
det.datetime = datetime.strptime(date_str.split(' ')[3], '%d/%m/%Y').date()
last_date = det.datetime
det.price = Decimal(re.sub('[^\d,-]+', '', price).replace(',', '.'))
if len(tds) == 6:
date_str = tds[0].text
det.id = id + "." + str(line)
det.label = unicode(tds[1].text.strip())
paye = tds[2].text
if paye is None:
paye = '0'
base = tds[3].text
if base is None:
base = '0'
taux = tds[4].text
if taux is None:
taux = '0'
price = tds[5].text
if price is None:
price = '0'
if date_str is None or date_str == '':
det.infos = u''
det.datetime = last_date
else:
det.infos = u'Payé ' + unicode(re.sub('[^\d,-]+', '', paye)) + u'€ / Base ' + unicode(re.sub('[^\d,-]+', '', base)) + u'€ / Taux ' + unicode(re.sub('[^\d,-]+', '', taux)) + '%'
det.datetime = datetime.strptime(date_str, '%d/%m/%Y').date()
last_date = det.datetime
det.price = Decimal(re.sub('[^\d,-]+', '', price).replace(',', '.'))
line = line + 1 line = line + 1
yield det yield det
class BillsPage(AmeliBasePage): class BillsPage(AmeliBasePage):
def iter_bills(self, sub): def iter_bills(self, sub):
table = self.document.xpath('//table[@id="tableauDecompte"]')[0].xpath('.//tr') table = self.doc.xpath('//table[@id="relevesMensuels"]')[0].xpath('.//tr')
for tr in table: for tr in table:
list_tds = tr.xpath('.//td') list_tds = tr.xpath('.//td')
if len(list_tds) == 0: if len(list_tds) == 0:
@ -137,15 +179,14 @@ class BillsPage(AmeliBasePage):
amount = list_tds[1].text amount = list_tds[1].text
if amount is None: if amount is None:
continue continue
amount = re.sub(' euros', '', amount) amount = re.sub('[^\d,-]+', '', amount)
bil = Bill() bil = Bill()
bil.id = sub._id + "." + date.strftime("%Y%m") bil.id = sub._id + "." + date.strftime("%Y%m")
bil.date = date bil.date = date
bil.label = u''+amount.strip() bil.price = Decimal('-'+amount.strip().replace(',','.'))
bil.format = u'pdf' bil.format = u'pdf'
filedate = date.strftime("%m%Y") bil.label = date.strftime("%Y%m%d")
bil._url = '/PortailAS/PDFServletReleveMensuel.dopdf' bil._url = '/PortailAS/PDFServletReleveMensuel.dopdf?PDF.moisRecherche='+date.strftime("%m%Y")
bil._args = {'PDF.moisRecherche': filedate}
yield bil yield bil
def get_bill(self, bill): def get_bill(self, bill):

90
modules/amelipro/browser.py Normal file → Executable file
View file

@ -18,65 +18,60 @@
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
import urllib import urllib
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword from weboob.browser import LoginBrowser, URL, need_login
from weboob.exceptions import BrowserIncorrectPassword
from weboob.capabilities.bill import Detail from weboob.capabilities.bill import Detail
from decimal import Decimal from decimal import Decimal
from .pages import LoginPage, HomePage, AccountPage, HistoryPage, BillsPage from .pages import LoginPage, HomePage, AccountPage, HistoryPage, BillsPage, SearchPage
__all__ = ['AmeliProBrowser'] __all__ = ['AmeliProBrowser']
class AmeliProBrowser(LoginBrowser):
BASEURL = 'https://espacepro.ameli.fr:443'
class AmeliProBrowser(Browser): loginp = URL('/PortailPS/appmanager/portailps/professionnelsante\?_nfpb=true&_pageLabel=vp_login_page', LoginPage)
PROTOCOL = 'https' homep = URL('/PortailPS/appmanager/portailps/professionnelsante\?_nfpb=true&_pageLabel=vp_accueil_page', HomePage)
DOMAIN = 'espacepro.ameli.fr' accountp = URL('/PortailPS/appmanager/portailps/professionnelsante\?_nfpb=true&_pageLabel=vp_coordonnees_infos_perso_page', AccountPage)
ENCODING = None billsp = URL('/PortailPS/appmanager/portailps/professionnelsante\?_nfpb=true&_pageLabel=vp_releves_mensuels_page', BillsPage)
searchp = URL('/PortailPS/appmanager/portailps/professionnelsante\?_nfpb=true&_pageLabel=vp_recherche_par_date_paiements_page', SearchPage)
historyp = URL('/PortailPS/appmanager/portailps/professionnelsante\?_nfpb=true&_windowLabel=vp_recherche_paiement_tiers_payant_portlet_1&vp_recherche_paiement_tiers_payant_portlet_1_actionOverride=%2Fportlets%2Fpaiements%2Frecherche&_pageLabel=vp_recherche_par_date_paiements_page', HistoryPage)
PAGES = {'.*_pageLabel=vp_login_page.*': LoginPage, logged = False
'.*_pageLabel=vp_accueil.*': HomePage,
'.*_pageLabel=vp_coordonnees_infos_perso_page.*': AccountPage,
'.*_pageLabel=vp_recherche_par_date_paiements_page.*': HistoryPage,
'.*_pageLabel=vp_releves_mensuels_page.*': BillsPage,
}
loginp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_login_page' def do_login(self):
homep = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_accueil_book' self.logger.debug('call Browser.do_login')
accountp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_coordonnees_infos_perso_page' if self.logged:
billsp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_releves_mensuels_page' return True
searchp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_pageLabel=vp_recherche_par_date_paiements_page'
historyp = '/PortailPS/appmanager/portailps/professionnelsante?_nfpb=true&_windowLabel=vp_recherche_paiement_tiers_payant_portlet_1&vp_recherche_paiement_tiers_payant_portlet_1_actionOverride=%2Fportlets%2Fpaiements%2Frecherche&_pageLabel=vp_recherche_par_date_paiements_page'
def home(self): self.loginp.stay_or_go()
self.location(self.homep) if self.homep.is_here():
self.logged = True
return True
def is_logged(self):
if self.is_on_page(LoginPage):
return False
return True
def login(self):
assert isinstance(self.username, basestring)
assert isinstance(self.password, basestring)
if not self.is_on_page(LoginPage):
self.location(self.loginp)
self.page.login(self.username, self.password) self.page.login(self.username, self.password)
if self.is_on_page(LoginPage):
if not self.homep.is_here():
raise BrowserIncorrectPassword() raise BrowserIncorrectPassword()
def get_subscription_list(self): self.logged = True
if not self.is_on_page(AccountPage):
self.location(self.accountp)
return self.page.get_subscription_list()
@need_login
def get_subscription_list(self):
self.logger.debug('call Browser.get_subscription_list')
self.accountp.stay_or_go()
return self.page.iter_subscription_list()
@need_login
def get_subscription(self, id): def get_subscription(self, id):
assert isinstance(id, basestring) assert isinstance(id, basestring)
return self.get_subscription_list() return self.get_subscription_list()
@need_login
def iter_history(self, subscription): def iter_history(self, subscription):
if not self.is_on_page(HistoryPage): self.searchp.stay_or_go()
self.location(self.searchp)
date_deb = self.page.document.xpath('//input[@name="vp_recherche_paiement_tiers_payant_portlet_1dateDebutRecherche"]')[0].value date_deb = self.page.doc.xpath('//input[@name="vp_recherche_paiement_tiers_payant_portlet_1dateDebutRecherche"]')[0].value
date_fin = self.page.document.xpath('//input[@name="vp_recherche_paiement_tiers_payant_portlet_1dateFinRecherche"]')[0].value date_fin = self.page.doc.xpath('//input[@name="vp_recherche_paiement_tiers_payant_portlet_1dateFinRecherche"]')[0].value
data = {'vp_recherche_paiement_tiers_payant_portlet_1dateDebutRecherche': date_deb, data = {'vp_recherche_paiement_tiers_payant_portlet_1dateDebutRecherche': date_deb,
'vp_recherche_paiement_tiers_payant_portlet_1dateFinRecherche': date_fin, 'vp_recherche_paiement_tiers_payant_portlet_1dateFinRecherche': date_fin,
@ -85,9 +80,12 @@ class AmeliProBrowser(Browser):
'vp_recherche_paiement_tiers_payant_portlet_1codeRegime': '01', 'vp_recherche_paiement_tiers_payant_portlet_1codeRegime': '01',
} }
self.location(self.historyp, urllib.urlencode(data)) self.session.headers.update({'Content-Type': 'application/x-www-form-urlencoded'})
return self.page.iter_history() self.historyp.go(data=urllib.urlencode(data))
if self.historyp.is_here():
return self.page.iter_history()
@need_login
def get_details(self, sub): def get_details(self, sub):
det = Detail() det = Detail()
det.id = sub.id det.id = sub.id
@ -96,14 +94,20 @@ class AmeliProBrowser(Browser):
det.price = Decimal('0.0') det.price = Decimal('0.0')
return det return det
@need_login
def iter_bills(self): def iter_bills(self):
if not self.is_on_page(BillsPage): self.billsp.stay_or_go()
self.location(self.billsp)
return self.page.iter_bills() return self.page.iter_bills()
@need_login
def get_bill(self, id): def get_bill(self, id):
assert isinstance(id, basestring) assert isinstance(id, basestring)
for b in self.iter_bills(): for b in self.iter_bills():
if id == b.id: if id == b.id:
return b return b
return None return None
@need_login
def download_bill(self, bill):
request = self.open(bill._url, data=bill._data, stream=True)
return request.content

22
modules/amelipro/module.py Normal file → Executable file
View file

@ -17,7 +17,6 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>. # along with weboob. If not, see <http://www.gnu.org/licenses/>.
import urllib
from weboob.capabilities.bill import CapBill, SubscriptionNotFound, BillNotFound, Subscription, Bill from weboob.capabilities.bill import CapBill, SubscriptionNotFound, BillNotFound, Subscription, Bill
from weboob.tools.backend import Module, BackendConfig from weboob.tools.backend import Module, BackendConfig
from weboob.tools.value import ValueBackendPassword from weboob.tools.value import ValueBackendPassword
@ -25,7 +24,6 @@ from .browser import AmeliProBrowser
__all__ = ['AmeliProModule'] __all__ = ['AmeliProModule']
class AmeliProModule(Module, CapBill): class AmeliProModule(Module, CapBill):
NAME = 'amelipro' NAME = 'amelipro'
DESCRIPTION = u'Ameli website: French Health Insurance for Professionals' DESCRIPTION = u'Ameli website: French Health Insurance for Professionals'
@ -41,9 +39,9 @@ class AmeliProModule(Module, CapBill):
label='Password', label='Password',
masked=True) masked=True)
) )
BROWSER = AmeliProBrowser
def create_default_browser(self): def create_default_browser(self):
self.logger.settings['save_responses'] = False # Set to True to help debugging
return self.create_browser(self.config['login'].get(), return self.create_browser(self.config['login'].get(),
self.config['password'].get()) self.config['password'].get())
@ -53,8 +51,7 @@ class AmeliProModule(Module, CapBill):
def get_subscription(self, _id): def get_subscription(self, _id):
if not _id.isdigit(): if not _id.isdigit():
raise SubscriptionNotFound() raise SubscriptionNotFound()
with self.browser: subscription = self.browser.get_subscription(_id)
subscription = self.browser.get_subscription(_id)
if not subscription: if not subscription:
raise SubscriptionNotFound() raise SubscriptionNotFound()
else: else:
@ -63,24 +60,20 @@ class AmeliProModule(Module, CapBill):
def iter_bills_history(self, subscription): def iter_bills_history(self, subscription):
if not isinstance(subscription, Subscription): if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription) subscription = self.get_subscription(subscription)
with self.browser: return self.browser.iter_history(subscription)
return self.browser.iter_history(subscription)
def get_details(self, subscription): def get_details(self, subscription):
if not isinstance(subscription, Subscription): if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription) subscription = self.get_subscription(subscription)
with self.browser: return self.browser.get_details(subscription)
return self.browser.get_details(subscription)
def iter_bills(self, subscription): def iter_bills(self, subscription):
if not isinstance(subscription, Subscription): if not isinstance(subscription, Subscription):
subscription = self.get_subscription(subscription) subscription = self.get_subscription(subscription)
with self.browser: return self.browser.iter_bills()
return self.browser.iter_bills()
def get_bill(self, id): def get_bill(self, id):
with self.browser: bill = self.browser.get_bill(id)
bill = self.browser.get_bill(id)
if not bill: if not bill:
raise BillNotFound() raise BillNotFound()
else: else:
@ -89,5 +82,4 @@ class AmeliProModule(Module, CapBill):
def download_bill(self, bill): def download_bill(self, bill):
if not isinstance(bill, Bill): if not isinstance(bill, Bill):
bill = self.get_bill(bill) bill = self.get_bill(bill)
with self.browser: return self.browser.download_bill(bill)
return self.browser.readurl(bill._url, urllib.urlencode(bill._args))

98
modules/amelipro/pages.py Normal file → Executable file
View file

@ -19,10 +19,9 @@
from datetime import datetime from datetime import datetime
from decimal import Decimal
import re import re
import urllib from decimal import Decimal
from weboob.deprecated.browser import Page from weboob.browser.pages import HTMLPage
from weboob.capabilities.bill import Subscription, Detail, Bill from weboob.capabilities.bill import Subscription, Detail, Bill
@ -30,25 +29,25 @@ from weboob.capabilities.bill import Subscription, Detail, Bill
FRENCH_MONTHS = [u'janvier', u'février', u'mars', u'avril', u'mai', u'juin', u'juillet', u'août', u'septembre', u'octobre', u'novembre', u'décembre'] FRENCH_MONTHS = [u'janvier', u'février', u'mars', u'avril', u'mai', u'juin', u'juillet', u'août', u'septembre', u'octobre', u'novembre', u'décembre']
class LoginPage(Page): class LoginPage(HTMLPage):
def login(self, login, password): def login(self, login, password):
self.browser.select_form('connexionCompteForm') form = self.get_form('//form[@name="connexionCompteForm"]')
self.browser["vp_connexion_portlet_1numPS"] = login.encode('utf8') form['vp_connexion_portlet_1numPS'] = login.encode('utf8')
self.browser["vp_connexion_portlet_1password"] = password.encode('utf8') form['vp_connexion_portlet_1password'] = password.encode('utf8')
self.browser.submit() form.submit()
class HomePage(Page):
class HomePage(HTMLPage):
def on_loaded(self): def on_loaded(self):
pass pass
class SearchPage(HTMLPage):
def on_loaded(self):
pass
class AccountPage(Page): class AccountPage(HTMLPage):
def iter_subscription_list(self):
def get_subscription_list(self): ident = self.doc.xpath('//div[@id="identification"]')[0]
ident = self.document.xpath('//div[@id="identification"]')[0] prof = self.doc.xpath('//div[@id="profession"]')[0]
prof = self.document.xpath('//div[@id="profession"]')[0]
name = ident.xpath('//p/b')[0].text.replace('&nbsp;', ' ').strip() name = ident.xpath('//p/b')[0].text.replace('&nbsp;', ' ').strip()
number = ident.xpath('//p')[1].text.replace('Cabinet', '').strip() number = ident.xpath('//p')[1].text.replace('Cabinet', '').strip()
label = prof.xpath('//div[@class="zoneTexte"]')[0].text.strip() label = prof.xpath('//div[@class="zoneTexte"]')[0].text.strip()
@ -59,34 +58,38 @@ class AccountPage(Page):
return sub return sub
class HistoryPage(Page): class HistoryPage(HTMLPage):
def iter_history(self): def iter_history(self):
table = self.document.xpath('//table[contains(concat(" ", @class, " "), " cTableauTriable ")]')[0].xpath('.//tr') tables = self.doc.xpath('//table[contains(concat(" ", @class, " "), " cTableauTriable ")]')
for tr in table: if len(tables) > 0:
list_a = tr.xpath('.//a') lines = tables[0].xpath('.//tr')
if len(list_a) == 0: sno = 0
continue for tr in lines:
date = tr.xpath('.//td')[0].text.strip() list_a = tr.xpath('.//a')
lot = list_a[0].text if len(list_a) == 0:
factures = tr.xpath('.//div[@class="cAlignGauche"]/a') continue
factures_lbl = '' date = tr.xpath('.//td')[0].text.strip()
for a in factures: lot = list_a[0].text.replace('(*)', '').strip()
factures_lbl = factures_lbl + a.text + ' ' if lot == 'SNL':
montant = tr.xpath('.//div[@class="cAlignDroite"]')[0].text.strip() sno = sno + 1
det = Detail() lot = lot + str(sno)
det.id = lot factures = tr.xpath('.//div[@class="cAlignGauche"]/a')
det.label = lot factures_lbl = ''
det.infos = factures_lbl for a in factures:
det.datetime = datetime.strptime(date, "%d/%m/%Y").date() factures_lbl = factures_lbl + a.text.replace('(**)', '').strip() + ' '
det.price = Decimal(montant.replace(',', '.')) montant = tr.xpath('.//div[@class="cAlignDroite"]')[0].text.strip()
yield det det = Detail()
det.id = u''+lot
det.label = u''+lot
det.infos = u''+factures_lbl
det.datetime = datetime.strptime(date, "%d/%m/%Y").date()
det.price = Decimal(montant.replace(',', '.'))
yield det
class BillsPage(Page): class BillsPage(HTMLPage):
def iter_bills(self): def iter_bills(self):
table = self.document.xpath('//table[@id="releveCompteMensuel"]')[0].xpath('.//tr') table = self.doc.xpath('//table[@id="releveCompteMensuel"]')[0].xpath('.//tr')
for tr in table: for tr in table:
list_tds = tr.xpath('.//td') list_tds = tr.xpath('.//td')
if len(list_tds) == 0: if len(list_tds) == 0:
@ -96,19 +99,18 @@ class BillsPage(Page):
month_str = date_str.split()[0] month_str = date_str.split()[0]
date = datetime.strptime(re.sub(month_str, str(FRENCH_MONTHS.index(month_str) + 1), date_str), "%m %Y").date() date = datetime.strptime(re.sub(month_str, str(FRENCH_MONTHS.index(month_str) + 1), date_str), "%m %Y").date()
amount = tr.xpath('.//td[@class="cAlignDroite"]')[0].text amount = tr.xpath('.//td[@class="cAlignDroite"]')[0].text
amount = re.sub('[^\d,-]+', '', amount)
for format in ('CSV', 'PDF'): for format in ('CSV', 'PDF'):
bil = Bill() bil = Bill()
bil.id = date.strftime("%Y%m") + format bil.id = date.strftime("%Y%m") + format
bil.date = date bil.date = date
bil.label = u''+amount.strip() bil.price = Decimal('-'+amount.strip().replace(',','.'))
bil.label = u''+date.strftime("%Y%m%d")
bil.format = u''+format bil.format = u''+format
filedate = date.strftime("%m%Y") filedate = date.strftime("%m%Y")
bil._url = '/PortailPS/fichier.do' bil._url = '/PortailPS/fichier.do'
bil._args = {'FICHIER.type': format.lower() + '.releveCompteMensuel', bil._data = {'FICHIER.type': format.lower()+'.releveCompteMensuel',
'dateReleve': filedate, 'dateReleve': filedate,
'FICHIER.titre': '', 'FICHIER.titre': 'Releve' + filedate
} }
yield bil yield bil
def get_bill(self, bill):
self.location(bill._url, urllib.urlencode(bill._args))