supporting new paypal website

This commit is contained in:
Vincent Paredes 2014-10-31 18:13:10 +01:00 committed by Romain Bignon
commit ffa6d57b47
2 changed files with 120 additions and 9 deletions

View file

@ -20,6 +20,7 @@
from weboob.deprecated.browser import Browser, BrowserIncorrectPassword from weboob.deprecated.browser import Browser, BrowserIncorrectPassword
from .pages import LoginPage, AccountPage, DownloadHistoryPage, LastDownloadHistoryPage, SubmitPage, HistoryParser, UselessPage, HistoryPage, CSVAlreadyAsked from .pages import LoginPage, AccountPage, DownloadHistoryPage, LastDownloadHistoryPage, SubmitPage, HistoryParser, UselessPage, HistoryPage, CSVAlreadyAsked
from .newpages import NewHomePage, NewAccountPage, NewHistoryPage
import datetime import datetime
@ -42,11 +43,22 @@ class Paypal(Browser):
'/cgi-bin/webscr\?cmd=_history-download-recent$': LastDownloadHistoryPage, '/cgi-bin/webscr\?cmd=_history-download-recent$': LastDownloadHistoryPage,
'/cgi-bin/webscr\?dispatch=[a-z0-9]+$': (SubmitPage, HistoryParser()), '/cgi-bin/webscr\?dispatch=[a-z0-9]+$': (SubmitPage, HistoryParser()),
'/cgi-bin/webscr\?cmd=_history-download-recent-submit&dispatch=[a-z0-9]+$': (SubmitPage, HistoryParser()), '/cgi-bin/webscr\?cmd=_history-download-recent-submit&dispatch=[a-z0-9]+$': (SubmitPage, HistoryParser()),
'https://www.paypal.com/webapps/business/\?nav=0.0': NewHomePage,
'https://www.paypal.com/businessexp/money': NewAccountPage,
'https://www.paypal.com/webapps/business/activity\?.*': NewHistoryPage,
} }
DEFAULT_TIMEOUT = 30 # CSV export is slow DEFAULT_TIMEOUT = 30 # CSV export is slow
BEGINNING = datetime.date(1998,6,1) # The day PayPal was founded BEGINNING = datetime.date(1998,6,1) # The day PayPal was founded
website = None
def find_website_version(self):
self.location('/en/cgi-bin/webscr?cmd=_account&nav=0.0')
if self.is_on_page(AccountPage):
self.website = "old"
else:
self.website = "new"
def home(self): def home(self):
self.location('https://' + self.DOMAIN + '/en/cgi-bin/webscr?cmd=_login-run') self.location('https://' + self.DOMAIN + '/en/cgi-bin/webscr?cmd=_login-run')
@ -68,14 +80,19 @@ class Paypal(Browser):
raise BrowserIncorrectPassword() raise BrowserIncorrectPassword()
def get_accounts(self): def get_accounts(self):
if not self.is_on_page(AccountPage): self.find_website_version()
if self.website == "old" and not self.is_on_page(AccountPage):
self.location('/en/cgi-bin/webscr?cmd=_account&nav=0.0') self.location('/en/cgi-bin/webscr?cmd=_account&nav=0.0')
elif not self.is_on_page(NewAccountPage):
self.location('/businessexp/money')
return self.page.get_accounts() return self.page.get_accounts()
def get_account(self, _id): def get_account(self, _id):
if not self.is_on_page(AccountPage): if self.website == "old" and not not self.is_on_page(AccountPage):
self.location('/en/cgi-bin/webscr?cmd=_account&nav=0.0') self.location('/en/cgi-bin/webscr?cmd=_account&nav=0.0')
elif not self.is_on_page(NewAccountPage):
self.location('/businessexp/money')
return self.page.get_account(_id) return self.page.get_account(_id)
@ -101,9 +118,18 @@ class Paypal(Browser):
self.page.filter(start, end) self.page.filter(start, end)
assert self.is_on_page(HistoryPage) assert self.is_on_page(HistoryPage)
def get_download_history(self, account, step_min=90, step_max=365*2): def get_download_history(self, account, step_min=None, step_max=None):
if step_min is None and step_max is None:
if self.website == "old":
step_min = 90
step_max = 365*2
else:
step_min = 90
step_max = 180
def fetch_fn(start, end): def fetch_fn(start, end):
if self.download_history(start, end).rows: if self.website == "old" and self.download_history(start, end).rows:
return self.page.iter_transactions(account)
elif self.download_history(start, end):
return self.page.iter_transactions(account) return self.page.iter_transactions(account)
assert step_max <= 365*2 # PayPal limitations as of 2014-06-16 assert step_max <= 365*2 # PayPal limitations as of 2014-06-16
try: try:
@ -145,11 +171,19 @@ class Paypal(Browser):
However, it is not normalized, and sometimes the download is refused However, it is not normalized, and sometimes the download is refused
and sent later by mail. and sent later by mail.
""" """
self.location('/en/cgi-bin/webscr?cmd=_history-download&nav=0.3.1') if self.website == "old":
assert self.is_on_page(DownloadHistoryPage) self.location('/en/cgi-bin/webscr?cmd=_history-download&nav=0.3.1')
self.page.download(start, end) assert self.is_on_page(DownloadHistoryPage)
assert self.is_on_page(SubmitPage) self.page.download(start, end)
return self.page.document assert self.is_on_page(SubmitPage)
return self.page.document
else:
s = start.strftime('%d/%m/%Y')
e = end.strftime('%d/%m/%Y')
#Settings a big magic number so we get all transaction for the period
LIMIT = '9999'
self.location('/webapps/business/activity?fromdate=' + s + '&todate=' + e + '&transactiontype=ALL_TRANSACTIONS&currency=ALL_TRANSACTIONS_CURRENCY&limit=' + LIMIT)
return self.page.transaction_left()
def download_last_history(self, account): def download_last_history(self, account):
self.location('/en/cgi-bin/webscr?cmd=_history-download-recent') self.location('/en/cgi-bin/webscr?cmd=_history-download-recent')

View file

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2014 Budget Insight
#
# 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 decimal import Decimal
from weboob.deprecated.browser import Page
from weboob.capabilities.bank import Account
from weboob.tools.capabilities.bank.transactions import FrenchTransaction
from weboob.tools.date import parse_french_date
class NewHomePage(Page):
pass
class NewAccountPage(Page):
def get_account(self, _id):
return self.get_accounts().get(_id)
def get_accounts(self):
accounts = {}
content = self.document.xpath('//div[@id="moneyPage"]')[0]
# Primary currency account
primary_account = Account()
primary_account.type = Account.TYPE_CHECKING
primary_account.id = unicode(primary_account.currency)
balance = self.parser.tocleanstring(content.xpath('.//div[@class="col-md-6 available "]')[0])
primary_account.balance = Decimal(FrenchTransaction.clean_amount(balance))
primary_account.currency = Account.get_currency(balance)
primary_account.label = u'%s %s*' % (self.browser.username, balance.split()[-1])
accounts[primary_account.id] = primary_account
return accounts
class NewHistoryPage(Page):
def iter_transactions(self, account):
for trans in self.parse():
if trans._currency == account.currency:
yield trans
def parse(self):
for i, tr in enumerate(self.document.xpath('//tr')):
t = FrenchTransaction(tr.xpath('./td[@class="transactionId"]/span')[0].text.strip())
date = parse_french_date(tr.xpath('./td[@class="date"]')[0].text.strip())
status = tr.xpath('./td[@class="desc"]/ul/li[@class="first"]')[0].text.strip()
#We pass this because it's not transaction
if status == u'Créé' or status == u'Annulé':
continue
raw = tr.xpath('./td[@class="desc"]/strong')[0].text.strip()
t.parse(date=date, raw=raw)
amount = tr.xpath('./td[@class="price"]/span')[0].text.strip()
t.set_amount(amount)
t._currency = Account.get_currency(amount)
yield t
def transaction_left(self):
return (len(self.document.xpath('//div[@class="no-records"]')) == 0)