# -*- coding: utf-8 -*-
# Copyright(C) 2013-2015 Christophe Lampin
#
# This file is part of weboob.
#
# weboob 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.
#
# weboob 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 weboob. If not, see .
from __future__ import unicode_literals
from datetime import datetime
import re
from decimal import Decimal
from weboob.browser.filters.html import Attr, XPathNotFound
from weboob.browser.pages import HTMLPage, RawPage, LoggedPage
from weboob.capabilities.bill import Subscription, Detail, Bill
from weboob.browser.filters.standard import CleanText, Regexp
# Ugly array to avoid the use of french locale
FRENCH_MONTHS = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre']
class AmeliBasePage(HTMLPage):
@property
def logged(self):
if self.doc.xpath('//a[contains(text(), "Déconnexion")]'):
logged = True
else:
logged = False
self.logger.debug('logged: %s' % (logged))
return logged
def is_error(self):
errors = self.doc.xpath('//*[@id="r_errors"]')
if errors:
return errors[0].text_content()
errors = CleanText('//p[@class="msg_erreur"]', default='')(self.doc)
if errors:
return errors
errors = CleanText('//div[@class="zone-alerte"]/span')(self.doc)
if errors:
return errors
return False
class LoginPage(AmeliBasePage):
def login(self, login, password):
form = self.get_form('//form[@name="connexionCompteForm"]')
form['connexioncompte_2numSecuriteSociale'] = login.encode('utf8')
form['connexioncompte_2codeConfidentiel'] = password.encode('utf8')
form.submit()
def locate_to_cgu_page(self):
try:
# they've put a head tag inside body, yes i know...
url = Regexp(Attr('//div[@id="connexioncompte_2"]//meta', 'content'), r'url=(.*)')(self.doc)
except XPathNotFound:
# no cgu to validate
return
self.browser.location(url)
class CguPage(AmeliBasePage):
def get_cgu(self):
return CleanText('//div[@class="page_nouvelles_cgus"]/p[1]')(self.doc)
class HomePage(AmeliBasePage):
pass
class AccountPage(AmeliBasePage):
def iter_subscription_list(self):
names_list = self.doc.xpath('//span[@class="NomEtPrenomLabel"]')
fullname = CleanText(newlines=True).filter(names_list[0])
number = re.sub(r'[^\d]+', '', CleanText('//span[@class="blocNumSecu"]', replace=[(' ', '')])(self.doc))
sub = Subscription(number)
sub._id = number
sub.label = fullname
firstname = CleanText('//span[@class="prenom-titulaire"]')(self.doc)
sub.subscriber = firstname
yield sub
class PaymentsPage(AmeliBasePage):
def get_last_payments_url(self):
begin_date = self.doc.xpath('//input[@id="paiements_1dateDebut"]/@data-mindate')[0]
end_date = self.doc.xpath('//input[@id="paiements_1dateFin"]/@data-maxdate')[0]
url = ('/PortailAS/paiements.do?actionEvt=afficherPaiementsComplementaires&DateDebut='
+ begin_date + '&DateFin=' + end_date +
'&Beneficiaire=tout_selectionner&afficherReleves=false&afficherIJ=false&afficherInva=false'
'&afficherRentes=false&afficherRS=false&indexPaiement=&idNotif=')
return url
class LastPaymentsPage(LoggedPage, AmeliBasePage):
def iter_last_payments(self):
elts = self.doc.xpath('//li[@class="rowitem remboursement"]')
for elt in elts:
items = Regexp(CleanText('./@onclick'), r".*ajaxCallRemoteChargerDetailPaiement \('(\w+={0,2})', '(\w+)', '(\d+)', '(\d+)'\).*", '\\1,\\2,\\3,\\4')(elt).split(',')
yield "/PortailAS/paiements.do?actionEvt=chargerDetailPaiements&idPaiement=" + items[0] + "&naturePaiement=" + items[1] + "&indexGroupe=" + items[2] + "&indexPaiement=" + items[3]
def iter_documents(self, sub):
elts = self.doc.xpath('//li[@class="rowdate"]')
for elt in elts:
try:
elt.xpath('.//a[contains(@id,"lienPDFReleve")]')[0]
except IndexError:
continue
date_str = elt.xpath('.//span[contains(@id,"moisEnCours")]')[0].text
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()
bil = Bill()
bil.id = sub._id + "." + date.strftime("%Y%m")
bil.date = date
bil.format = 'pdf'
bil.type = 'bill'
bil.label = date.strftime("%Y%m%d")
bil.url = '/PortailAS/PDFServletReleveMensuel.dopdf?PDF.moisRecherche=' + date.strftime("%m%Y")
yield bil
def get_document(self, bill):
self.location(bill.url, params=bill._args)
class PaymentDetailsPage(AmeliBasePage):
def iter_payment_details(self, sub):
id_str = self.doc.xpath('//div[@class="entete container"]/h2')[0].text.strip()
m = re.match(r'.*le (.*) pour un montant de.*', id_str)
if m:
blocs_benes = self.doc.xpath('//span[contains(@id,"nomBeneficiaire")]')
blocs_prestas = self.doc.xpath('//table[@id="tableauPrestation"]')
i = 0
last_bloc = len(blocs_benes)
for i in range(0, last_bloc):
bene = blocs_benes[i].text
id_str = m.group(1)
id_date = datetime.strptime(id_str, '%d/%m/%Y').date()
id = sub._id + "." + datetime.strftime(id_date, "%Y%m%d")
table = blocs_prestas[i].xpath('.//tr')
line = 1
last_date = None
for tr in table:
tds = tr.xpath('.//td')
if len(tds) == 0:
continue
det = Detail()
# TO TEST : Indemnités journalières : Pas pu tester de cas de figure similaire dans la nouvelle mouture du site
if len(tds) == 4:
date_str = Regexp(pattern=r'.*
(\d+/\d+/\d+)\).*').filter(tds[0].text)
det.id = id + "." + str(line)
det.label = tds[0].xpath('.//span')[0].text.strip()
jours = tds[1].text
if jours is None:
jours = '0'
montant = tds[2].text
if montant is None:
montant = '0'
price = tds[3].text
if price is None:
price = '0'
if date_str is None or date_str == '':
det.infos = ''
det.datetime = last_date
else:
det.infos = date_str + ' (' + re.sub(r'[^\d,-]+', '', jours) + 'j) * ' + re.sub(r'[^\d,-]+', '', montant) + '€'
det.datetime = datetime.strptime(date_str.split(' ')[3], '%d/%m/%Y').date()
last_date = det.datetime
det.price = Decimal(re.sub(r'[^\d,-]+', '', price).replace(',', '.'))
if len(tds) == 5:
date_str = Regexp(pattern=r'\w*(\d{2})/(\d{2})/(\d{4}).*', template='\\1/\\2/\\3', default="").filter("".join(tds[0].itertext()))
det.id = id + "." + str(line)
det.label = bene + ' - ' + tds[0].xpath('.//span')[0].text.strip()
paye = tds[1].text
if paye is None:
paye = '0'
base = tds[2].text
if base is None:
base = '0'
tdtaux = tds[3].xpath('.//span')[0].text
if tdtaux is None:
taux = '0'
else:
taux = tdtaux.strip()
tdprice = tds[4].xpath('.//span')[0].text
if tdprice is None:
price = '0'
else:
price = tdprice.strip()
if date_str is None or date_str == '':
det.infos = ''
det.datetime = last_date
else:
det.infos = ' Payé ' + re.sub(r'[^\d,-]+', '', paye) + '€ / Base ' + re.sub(r'[^\d,-]+', '', base) + '€ / Taux ' + re.sub(r'[^\d,-]+', '', taux) + '%'
det.datetime = datetime.strptime(date_str, '%d/%m/%Y').date()
last_date = det.datetime
det.price = Decimal(re.sub(r'[^\d,-]+', '', price).replace(',', '.'))
line = line + 1
yield det
class Raw(LoggedPage, RawPage):
pass