gdfsuez-dolcevita.fr website
Signed-off-by: Mathieu Jourdan <mathieu.jourdan@gresille.org> Signed-off-by: Romain Bignon <romain@symlink.me>
This commit is contained in:
parent
2c633a43c8
commit
79d1bcfea6
7 changed files with 536 additions and 0 deletions
3
modules/gdfsuez/__init__.py
Normal file
3
modules/gdfsuez/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
from .backend import GdfSuezBackend
|
||||||
|
|
||||||
|
__all__ = ['GdfSuezBackend']
|
||||||
95
modules/gdfsuez/backend.py
Normal file
95
modules/gdfsuez/backend.py
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Mathieu Jourdan
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from weboob.capabilities.bill import ICapBill, SubscriptionNotFound,\
|
||||||
|
BillNotFound, Subscription, Bill
|
||||||
|
from weboob.tools.backend import BaseBackend, BackendConfig
|
||||||
|
from weboob.tools.value import ValueBackendPassword
|
||||||
|
from .browser import GdfSuez
|
||||||
|
|
||||||
|
__all__ = ['GdfSuezBackend']
|
||||||
|
|
||||||
|
class GdfSuezBackend(BaseBackend, ICapBill):
|
||||||
|
NAME = 'gdfsuez'
|
||||||
|
MAINTAINER = u'Mathieu Jourdan'
|
||||||
|
EMAIL = 'mathieu.jourdan@gresille.org'
|
||||||
|
VERSION = '0.g'
|
||||||
|
LICENSE = 'AGPLv3+'
|
||||||
|
DESCRIPTION = 'GdF-Suez website'
|
||||||
|
CONFIG = BackendConfig(ValueBackendPassword('login',
|
||||||
|
label='Account ID (e-mail)',
|
||||||
|
masked=False),
|
||||||
|
ValueBackendPassword('password',
|
||||||
|
label='Password',
|
||||||
|
masked=True)
|
||||||
|
)
|
||||||
|
BROWSER = GdfSuez
|
||||||
|
|
||||||
|
def create_default_browser(self):
|
||||||
|
return self.create_browser(self.config['login'].get(),
|
||||||
|
self.config['password'].get())
|
||||||
|
|
||||||
|
def iter_subscription(self):
|
||||||
|
for subscription in self.browser.get_subscription_list():
|
||||||
|
yield subscription
|
||||||
|
|
||||||
|
def get_subscription(self, _id):
|
||||||
|
if not _id.isdigit():
|
||||||
|
raise SubscriptionnotFound()
|
||||||
|
with self.browser:
|
||||||
|
subscription = self.browser.get_subscription(_id)
|
||||||
|
if not subscription:
|
||||||
|
raise SubscriptionNotFound()
|
||||||
|
else:
|
||||||
|
return subscription
|
||||||
|
|
||||||
|
def iter_bills_history(self, subscription):
|
||||||
|
if not isinstance(subscription, Subscription):
|
||||||
|
subscription = self.get_subscription(subscription)
|
||||||
|
with self.browser:
|
||||||
|
for history in self.browser.get_history(subscription):
|
||||||
|
yield history
|
||||||
|
|
||||||
|
def get_details(self, subscription):
|
||||||
|
if not isinstance(subscription, Subscription):
|
||||||
|
subscription = self.get_subscription(subscription)
|
||||||
|
with self.browser:
|
||||||
|
for detail in self.browser.get_details(subscription):
|
||||||
|
yield detail
|
||||||
|
|
||||||
|
def iter_bills(self, subscription):
|
||||||
|
if not isinstance(subscription, Subscription):
|
||||||
|
subscription = self.get_subscription(subscription)
|
||||||
|
with self.browser:
|
||||||
|
for bill in self.browser.iter_bills():
|
||||||
|
yield bill
|
||||||
|
|
||||||
|
def get_bill(self, id):
|
||||||
|
with self.browser:
|
||||||
|
bill = self.browser.get_bill(id)
|
||||||
|
if not bill:
|
||||||
|
raise BillNotFound()
|
||||||
|
else:
|
||||||
|
return bill
|
||||||
|
|
||||||
|
def download_bill(self, bill):
|
||||||
|
if not isinstance(bill, Bill):
|
||||||
|
bill = self.get_bill(bill)
|
||||||
|
with self.browser:
|
||||||
|
return self.browser.readurl(bill._url)
|
||||||
99
modules/gdfsuez/browser.py
Normal file
99
modules/gdfsuez/browser.py
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Mathieu Jourdan
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import StringIO
|
||||||
|
from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword
|
||||||
|
from .pages import LoginPage, HomePage, AccountPage, TimeoutPage, HistoryPage, PdfPage
|
||||||
|
|
||||||
|
__all__ = ['GdfSuez']
|
||||||
|
|
||||||
|
class GdfSuez(BaseBrowser):
|
||||||
|
PROTOCOL = 'https'
|
||||||
|
DOMAIN = 'www.gdfsuez-dolcevita.fr'
|
||||||
|
PAGES = {'.*portail/clients.*?_nfpb=true&_pageLabel=page_identification': LoginPage,
|
||||||
|
'.*portail/clients.*?_nfpb=true&_pageLabel=page_accueil_compte_en_ligne': HomePage,
|
||||||
|
'.*p/visualiser_mes_contrats.*?_nfpb=true': AccountPage,
|
||||||
|
'.*p/page_historique_de_mes_factures': HistoryPage,
|
||||||
|
'.*clients.*?_nfpb=true&_nfls=false&_pageLabel=page_erreur_timeout_session': TimeoutPage
|
||||||
|
}
|
||||||
|
|
||||||
|
loginp = '/portailClients/appmanager/portail/clients'
|
||||||
|
homep = '/portailClients/appmanager/portail/clients?_nfpb=true&_pageLabel=page_accueil_compte_en_ligne'
|
||||||
|
accountp = '/portailClients/client/p/visualiser_mes_contrats?_nfpb=true'
|
||||||
|
historyp = '/portailClients/client/p/page_historique_de_mes_factures'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
BaseBrowser.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
def home(self):
|
||||||
|
self.location(self.homep)
|
||||||
|
|
||||||
|
def is_logged(self):
|
||||||
|
if self.is_on_page(LoginPage) or self.is_on_page(TimeoutPage):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
assert isinstance(self.username, basestring)
|
||||||
|
assert isinstance(self.password, basestring)
|
||||||
|
#assert isemail(self.username)
|
||||||
|
if not self.is_on_page(LoginPage):
|
||||||
|
self.location(self.loginp)
|
||||||
|
self.page.login(self.username, self.password)
|
||||||
|
if self.is_on_page(LoginPage):
|
||||||
|
raise BrowserIncorrectPassword()
|
||||||
|
|
||||||
|
def get_subscription_list(self):
|
||||||
|
if not self.is_on_page(AccountPage):
|
||||||
|
self.location(self.accountp)
|
||||||
|
return self.page.get_subscription_list()
|
||||||
|
|
||||||
|
def get_subscription(self, id):
|
||||||
|
assert isinstance(id, basestring)
|
||||||
|
for sub in self.get_subscription_list():
|
||||||
|
if sub.id == id:
|
||||||
|
return sub
|
||||||
|
|
||||||
|
def get_history(self, subscription):
|
||||||
|
if not self.is_on_page(HistoryPage):
|
||||||
|
self.location(self.historyp)
|
||||||
|
return self.page.get_history()
|
||||||
|
|
||||||
|
def get_details(self, subscription):
|
||||||
|
bills = self.iter_bills()
|
||||||
|
id = bills[0].id
|
||||||
|
if not self.is_on_page(HistoryPage):
|
||||||
|
self.location(self.historyp)
|
||||||
|
url = 'https://www.gdfsuez-dolcevita.fr/' + self.get_bill(id)._url
|
||||||
|
response = self.openurl(url)
|
||||||
|
pdf = PdfPage(StringIO.StringIO(response.read()))
|
||||||
|
for detail in pdf.get_details(subscription.label):
|
||||||
|
yield detail
|
||||||
|
|
||||||
|
def iter_bills(self):
|
||||||
|
if not self.is_on_page(HistoryPage):
|
||||||
|
self.location(self.historyp)
|
||||||
|
return self.page.get_bills()
|
||||||
|
|
||||||
|
def get_bill(self, id):
|
||||||
|
assert isinstance(id, basestring)
|
||||||
|
for b in self.iter_bills():
|
||||||
|
if b.id == id:
|
||||||
|
return b
|
||||||
|
|
||||||
23
modules/gdfsuez/pages/__init__.py
Normal file
23
modules/gdfsuez/pages/__init__.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Mathieu Jourdan
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .history import HistoryPage, PdfPage
|
||||||
|
from .homepage import LoginPage, HomePage, AccountPage, TimeoutPage
|
||||||
|
|
||||||
|
__all__ = ['LoginPage', 'HomePage', 'AccountPage', 'HistoryPage', 'PdfPage', 'TimeoutPage']
|
||||||
213
modules/gdfsuez/pages/history.py
Normal file
213
modules/gdfsuez/pages/history.py
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Mathieu Jourdan
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from datetime import datetime, date
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from weboob.tools.browser import BasePage
|
||||||
|
from weboob.capabilities.base import NotAvailable
|
||||||
|
from weboob.capabilities.bill import Detail, Bill
|
||||||
|
|
||||||
|
__all__ = ['HistoryPage', 'PdfPage']
|
||||||
|
|
||||||
|
class HistoryPage(BasePage):
|
||||||
|
|
||||||
|
def on_loaded(self):
|
||||||
|
self.details = []
|
||||||
|
self.bills = []
|
||||||
|
|
||||||
|
# Latest bill
|
||||||
|
div = self.document.xpath('//div[@class="consulter_dernierefacture"]')[0]
|
||||||
|
bdate = div.xpath('p[@class="date"]/span[@class="textetertiaire"]')[0].text
|
||||||
|
bprice = div.xpath('p[@class="montant"]/span[@class="textetertiaire"]')[0].text
|
||||||
|
link = div.xpath('a[@id="display_popin"]')[0].attrib['href']
|
||||||
|
mydate = date(*reversed([int(x) for x in bdate.split("/")]))
|
||||||
|
price = Decimal(bprice.strip(u' € TTC').replace(',', '.'))
|
||||||
|
self.bills.append(self._create_bill(mydate, price, link))
|
||||||
|
|
||||||
|
# Previous bills
|
||||||
|
table = self.document.xpath('//table[@class="afficher_factures"]')[0]
|
||||||
|
for tr in table[0].xpath('//tbody/tr'):
|
||||||
|
cells = tr.xpath('td')
|
||||||
|
bdate = unicode(cells[0].text.strip())
|
||||||
|
mydate = date(*reversed([int(x) for x in bdate.split("/")]))
|
||||||
|
bprice = unicode(cells[1].text)
|
||||||
|
price = Decimal(bprice.strip(u' €').replace(',', '.'))
|
||||||
|
link = cells[3].xpath('a')[0].attrib['href']
|
||||||
|
self.bills.append(self._create_bill(mydate, price, link))
|
||||||
|
|
||||||
|
def _create_bill(self, date, price, link):
|
||||||
|
bill = Bill()
|
||||||
|
bill.id = date.__str__().replace('-', '')
|
||||||
|
bill.date = date
|
||||||
|
bill._price = price
|
||||||
|
bill._url = link
|
||||||
|
bill.format = u'pdf'
|
||||||
|
bill.label = unicode(price)
|
||||||
|
return bill
|
||||||
|
|
||||||
|
def get_details(self):
|
||||||
|
return self.details
|
||||||
|
|
||||||
|
def get_bills(self):
|
||||||
|
return self.bills
|
||||||
|
|
||||||
|
class PdfPage():
|
||||||
|
|
||||||
|
def __init__(self, file):
|
||||||
|
self.pdf = file
|
||||||
|
|
||||||
|
def _parse_pdf(self):
|
||||||
|
pdffile = tempfile.NamedTemporaryFile(bufsize=100000, mode='w', suffix='.pdf')
|
||||||
|
temptxt = pdffile.name.replace('.pdf', '.txt')
|
||||||
|
cmd = "ebook-convert"
|
||||||
|
stdout = open("/dev/null", "w")
|
||||||
|
shutil.copyfileobj(self.pdf, pdffile)
|
||||||
|
pdffile.flush()
|
||||||
|
subprocess.call([cmd, pdffile.name, temptxt], stdout=stdout)
|
||||||
|
pdffile.close()
|
||||||
|
txtfile = open(temptxt, 'r')
|
||||||
|
txt = txtfile.read()
|
||||||
|
txtfile.close()
|
||||||
|
os.remove(temptxt)
|
||||||
|
return txt
|
||||||
|
|
||||||
|
def _parse_page(self, page):
|
||||||
|
|
||||||
|
# Regexp
|
||||||
|
footnote = re.compile(r'\([0-9]\) ') # (f)
|
||||||
|
ht = re.compile('HT par mois')
|
||||||
|
base = re.compile('la base de')
|
||||||
|
begindate = re.compile(' \d\d\/\d\d ') # MM/DD
|
||||||
|
enddate = re.compile('\d\d\/\d\d\/\d\d') # YY/MM/DD
|
||||||
|
endwithdigit = re.compile('\d+$') # blah blah 42
|
||||||
|
endwitheuro = re.compile('€$') # blah 00,00 €
|
||||||
|
textwithcoma = re.compile('([a-z]|\d{4})\,') # blah 2012, blah blah
|
||||||
|
|
||||||
|
# Parsing
|
||||||
|
details = []
|
||||||
|
for title in [ 'Abonnement',
|
||||||
|
'Consommation',
|
||||||
|
'Contributions et taxes liées à l\'énergie']:
|
||||||
|
section = page.split(title,1)[1].split('Total ')[0]
|
||||||
|
|
||||||
|
# When a line holds '(0)', a newline is missing.
|
||||||
|
section = re.sub(footnote,'\n', section)
|
||||||
|
|
||||||
|
lines = section.split('\n')
|
||||||
|
lines = [x for x in lines if len(x) > 0] # Remove empty lines
|
||||||
|
detail = None
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if re.match('[A-Za-z]', line[0]):
|
||||||
|
|
||||||
|
# Things we want to merge with the one just before
|
||||||
|
if 'facturées' in line:
|
||||||
|
# Long lines are sometimes split, so we try to join them
|
||||||
|
# That is the case for:
|
||||||
|
# 'Déduction du montant des consommations
|
||||||
|
# estimées facturées du 00/00/00 au 00/00/00'
|
||||||
|
detail.label = detail.label + u' ' + unicode(line, encoding='utf-8')
|
||||||
|
|
||||||
|
# Things for which we want a new detail
|
||||||
|
else:
|
||||||
|
# Entering here, we will instantiate a new detail.
|
||||||
|
# We hadn't so before because of fragmented lines.
|
||||||
|
if detail is not None and detail.label is not NotAvailable:
|
||||||
|
# We have a new element, return the other one
|
||||||
|
details.append(detail)
|
||||||
|
detail = Detail()
|
||||||
|
detail.price = Decimal(0)
|
||||||
|
|
||||||
|
# If the coma is not a decimal separator, then
|
||||||
|
# this is is probably a loooong sentence.
|
||||||
|
# When it comes to jokes, keep it short and sweet.
|
||||||
|
line = re.split(textwithcoma, line)[0]
|
||||||
|
|
||||||
|
# Things we want for sure
|
||||||
|
if re.findall(enddate, line):
|
||||||
|
# When a line has been badly split after a date,
|
||||||
|
# We want the label to end after the date, and maybe
|
||||||
|
# the second part to be the info
|
||||||
|
mydate = re.search(enddate, line).group(0)
|
||||||
|
mylist = line.rpartition(mydate)
|
||||||
|
label = mylist[0] + mylist[1]
|
||||||
|
detail.label = unicode(label, encoding='utf-8')
|
||||||
|
elif re.findall(endwithdigit, line):
|
||||||
|
# What is this stupid number at the end of the line?
|
||||||
|
# Line should have been split before the number
|
||||||
|
detail.label = unicode(re.split(endwithdigit, line)[0], encoding='utf-8')
|
||||||
|
# Things we don't want for sure
|
||||||
|
elif ')' in line and '(' not in line:
|
||||||
|
# First part of the parenthesis should have been drop before
|
||||||
|
# Avoid to create a new empty detail
|
||||||
|
detail.label = NotAvailable
|
||||||
|
elif re.match(base, line):
|
||||||
|
# This string should come always after a date,
|
||||||
|
# usually, it will match one of the cases above.
|
||||||
|
# Sometimes, it appears on a new line we don't need.
|
||||||
|
detail.label = NotAvailable
|
||||||
|
elif re.match(ht, line):
|
||||||
|
# '00,00 € HT par mois' may have been split after HT
|
||||||
|
# We don't need of the second line
|
||||||
|
detail.label = NotAvailable
|
||||||
|
# Things we probably want to keep
|
||||||
|
else:
|
||||||
|
# Well, maybe our line is correct, after all.
|
||||||
|
# Not much to do.
|
||||||
|
detail.label = unicode(line, encoding='utf-8')
|
||||||
|
detail.infos = NotAvailable
|
||||||
|
elif ' %' in line:
|
||||||
|
if isinstance(detail, Detail):
|
||||||
|
# Sometimes the vat is not on a new line:
|
||||||
|
# '00,00 00,0 %' instead of '00,0 %'
|
||||||
|
vat = line.split()[line.count(' ')-1].replace(',', '.')
|
||||||
|
detail.infos = unicode('TVA: ' + vat)
|
||||||
|
elif ' €' in line:
|
||||||
|
price = line.replace(',','.')
|
||||||
|
if isinstance(detail, Detail):
|
||||||
|
detail.price = Decimal(price.strip(' €'))
|
||||||
|
elif re.match(enddate, line):
|
||||||
|
# Line holding dates may have been mixed up
|
||||||
|
label = detail.label.split(' au ')[0] + u' au ' + unicode(line, encoding='utf-8')
|
||||||
|
detail.label = label
|
||||||
|
if detail.label is not NotAvailable:
|
||||||
|
# Do not append empty details to the list
|
||||||
|
# It seemed easier to create details anyway than dealing
|
||||||
|
# with None objects
|
||||||
|
details.append(detail)
|
||||||
|
return details
|
||||||
|
|
||||||
|
def get_details(self, label):
|
||||||
|
txt = self._parse_pdf()
|
||||||
|
page = None
|
||||||
|
if label == u'Gaz naturel':
|
||||||
|
page = txt.split('GAZ NATUREL')[1].split('TOTAL GAZ NATUREL TTC')[0]
|
||||||
|
elif label == u'Electricité':
|
||||||
|
page = txt.split('ELECTRICITE')[1].split('TOTAL ELECTRICITE TTC')[0]
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
return self._parse_page(page)
|
||||||
|
|
||||||
68
modules/gdfsuez/pages/homepage.py
Normal file
68
modules/gdfsuez/pages/homepage.py
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2013 Mathieu Jourdan
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from datetime import datetime, date
|
||||||
|
|
||||||
|
from weboob.tools.browser import BasePage
|
||||||
|
from weboob.tools.mech import ClientForm
|
||||||
|
from weboob.capabilities.bill import Subscription
|
||||||
|
|
||||||
|
__all__ = ['LoginPage', 'HomePage', 'AccountPage', 'TimeoutPage']
|
||||||
|
|
||||||
|
class LoginPage(BasePage):
|
||||||
|
|
||||||
|
def login(self, login, password):
|
||||||
|
self.browser.select_form('symConnexionForm')
|
||||||
|
self.browser["portlet_login_plein_page_3{pageFlow.mForm.login}"] = str(login)
|
||||||
|
self.browser["portlet_login_plein_page_3{pageFlow.mForm.password}"] = str(password)
|
||||||
|
self.browser.submit()
|
||||||
|
|
||||||
|
class HomePage(BasePage):
|
||||||
|
|
||||||
|
def on_loaded(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class AccountPage(BasePage):
|
||||||
|
|
||||||
|
def get_subscription_list(self):
|
||||||
|
table = self.document.xpath('//table[@id="ensemble_contrat_N0"]')[0]
|
||||||
|
if len(table) > 0:
|
||||||
|
# some clients may have subscriptions to gas and electricity,
|
||||||
|
# but they receive a single bill
|
||||||
|
# to avoid "boobill details" and "boobill bills" returning the same
|
||||||
|
# table twice, we could return only one subscription for both.
|
||||||
|
# We do not, and "boobill details" will take care of parsing only the
|
||||||
|
# relevant section in the bill files.
|
||||||
|
for line in table[0].xpath('//tbody/tr'):
|
||||||
|
cells = line.xpath('td')
|
||||||
|
snumber = cells[2].attrib['id'].replace('Contrat_', '')
|
||||||
|
slabel = cells[0].xpath('a')[0].text.replace('offre', '').strip()
|
||||||
|
d = unicode(cells[3].xpath('strong')[0].text.strip())
|
||||||
|
sdate = date(*reversed([int(x) for x in d.split("/")]))
|
||||||
|
sub = Subscription(snumber)
|
||||||
|
sub._id = snumber
|
||||||
|
sub.label = slabel
|
||||||
|
sub.subscriber = unicode(cells[1])
|
||||||
|
sub.renewdate = sdate
|
||||||
|
yield sub
|
||||||
|
|
||||||
|
class TimeoutPage(BasePage):
|
||||||
|
|
||||||
|
def on_loaded(self):
|
||||||
|
pass
|
||||||
35
modules/gdfsuez/test.py
Normal file
35
modules/gdfsuez/test.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Copyright(C) 2012 Romain Bignon
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
# This is a clone of freemobile/test.py for the gdfsuez module
|
||||||
|
from weboob.tools.test import BackendTest
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ['GdfSuezTest']
|
||||||
|
|
||||||
|
|
||||||
|
class GdfSuezTest(BackendTest):
|
||||||
|
BACKEND = 'gdfsuez'
|
||||||
|
|
||||||
|
def test_gdfsuez(self):
|
||||||
|
for subscription in self.backend.iter_subscription():
|
||||||
|
list(self.backend.iter_history(subscription.id))
|
||||||
|
for bill in self.backend.iter_bills(subscription.id):
|
||||||
|
self.backend.download_bill(bill.id)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue