From eeae473ce68b9a8275d9b153bf01c7f39faeeb90 Mon Sep 17 00:00:00 2001 From: Oleg Plakhotniuk Date: Tue, 24 Feb 2015 23:29:31 -0600 Subject: [PATCH] Victoria's Secret store credit card module. Closes #1732 --- modules/vicseccard/__init__.py | 22 ++++++ modules/vicseccard/browser.py | 119 +++++++++++++++++++++++++++++++++ modules/vicseccard/favicon.png | Bin 0 -> 15665 bytes modules/vicseccard/module.py | 53 +++++++++++++++ modules/vicseccard/test.py | 34 ++++++++++ 5 files changed, 228 insertions(+) create mode 100644 modules/vicseccard/__init__.py create mode 100644 modules/vicseccard/browser.py create mode 100644 modules/vicseccard/favicon.png create mode 100644 modules/vicseccard/module.py create mode 100644 modules/vicseccard/test.py diff --git a/modules/vicseccard/__init__.py b/modules/vicseccard/__init__.py new file mode 100644 index 00000000..0a1c9a4d --- /dev/null +++ b/modules/vicseccard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Oleg Plakhotniuk +# +# 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 .module import VicSecCardModule + +__all__ = ['VicSecCardModule'] diff --git a/modules/vicseccard/browser.py b/modules/vicseccard/browser.py new file mode 100644 index 00000000..8154e742 --- /dev/null +++ b/modules/vicseccard/browser.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Oleg Plakhotniuk +# +# 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 weboob.capabilities.bank import AccountNotFound, Account, Transaction +from weboob.tools.capabilities.bank.transactions import \ + AmericanTransaction as AmTr +from weboob.browser import LoginBrowser, URL, need_login +from weboob.browser.pages import HTMLPage +from weboob.exceptions import BrowserIncorrectPassword +from datetime import datetime + + +__all__ = ['VicSecCard'] + + +class SomePage(HTMLPage): + @property + def logged(self): + return bool(self.doc.xpath(u'//a[text()="Sign out"]')) + + +class LoginPage(SomePage): + def login(self, username, password): + form = self.get_form(name='frmLogin') + form['username_input'] = username + form['userName'] = username + form['password_input'] = password + form['hiddenPassword'] = password + form['btnLogin'] = 'btnLogin' + form.submit() + + +class HomePage(SomePage): + def account(self): + id_ = self.doc.xpath(u'//h1[contains(text(),' + '"Information for account ending in")]/text()')[0].strip()[-4:] + balance = self.amount(u'Current balance') + cardlimit = self.amount(u'Credit limit') + paymin = self.amount(u'Minimum payment') + a = Account() + a.id = id_ + a.label = u'ACCOUNT ENDING IN %s' % id_ + a.currency = Account.get_currency(balance) + a.balance = -AmTr.decimal_amount(balance) + a.type = Account.TYPE_CARD + a.cardlimit = AmTr.decimal_amount(cardlimit) + a.paymin = AmTr.decimal_amount(paymin) + #TODO: Add paydate. + #Oleg: I don't have an account with scheduled payment. + # Need to wait for a while... + return a + + def amount(self, name): + return self.doc.xpath( + u'//td[contains(text(),"%s")]/../td[2]/text()' % name)[0].strip() + + +class RecentPage(SomePage): + def iter_transactions(self): + for tr in self.doc.xpath('//table[@id="allTransactionList_table1"]' + '/tbody/tr'): + date = tr.xpath('td[1]/text()')[0] + label = u''.join(x.strip() for x in tr.xpath('td[2]/a/text()') + + tr.xpath('td[2]/text()')) + amount = tr.xpath('td[4]/text()')[0] + t = Transaction() + t.date = datetime.strptime(date, '%m/%d/%Y') + t.rdate = datetime.strptime(date, '%m/%d/%Y') + t.type = Transaction.TYPE_UNKNOWN + t.raw = unicode(label) + t.label = unicode(label) + t.amount = -AmTr.decimal_amount(amount) + yield t + + +class VicSecCard(LoginBrowser): + BASEURL = 'https://c.comenity.net' + login = URL(r'/victoriassecret/$', LoginPage) + home = URL(r'/victoriassecret/secure/SecureHome.xhtml', HomePage) + recent = URL(r'/victoriassecret/secure/accountactivity/Transactions.xhtml', + RecentPage) + unknown = URL('.*', SomePage) + + def get_account(self, id_): + a = next(self.iter_accounts()) + if (a.id != id_): + raise AccountNotFound() + return a + + @need_login + def iter_accounts(self): + yield self.home.stay_or_go().account() + + @need_login + def iter_history(self, account): + for trans in self.recent.stay_or_go().iter_transactions(): + yield trans + + def do_login(self): + self.session.cookies.clear() + self.login.go().login(self.username, self.password) + if not self.page.logged: + raise BrowserIncorrectPassword() diff --git a/modules/vicseccard/favicon.png b/modules/vicseccard/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..34624cf5d8a532d65842ea5cb67ded70af664fa9 GIT binary patch literal 15665 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

{G|h% zn!Xwe$^Skr5bhRt`+FM4W`xF_a7g$oJrCOrZ~N0*f0PxNmGnt?Yek6&RW<)Sey6;; z&-3^E(nN8>mB|kjxZ3$oe^E%tsbHfo!U^FsN^QH(5mggj6cUU>pVU32NGT;2c&2cF ztJ!c-4#R_8Ds@R!V@YJ2Ox3M@Y@ne=FWGIqTAJul;cD3nj6S7Us3H26`W#5~F zO=mF3eqG}M;_-ajeqEYViLy0Ij%%&rVXs$BJIry%ivq-! zM$?@92C!tRJ0ge|dwU!hNZ-|G;B(0~tK>1NQ4YSR`pC}>zw{o*aZpUlK6f|~jEvA! zT%_y*7PRmZEU|6Zko;gQ-F1yor=l>PLcT1v)Du3mdhz2(N?9Ovn`Mq*dV9v1L{s;| z)R%a3Yb5xLu>Y9XGM{bp3*szKK2oBme0q<&B^A)CF__?p>y`g z(1z|$iol~_9UVFJ?dSULK#*vg*8S`b;eXfOcRO4A=$5M9J3e06{SE!;!TIukzyC*x zx&K%4F6e2=2p3wHP3>P!F_)K`iI?pwFFV=S9(Ml(j;P3E2|*E2K~XV-$D*?0;=b4(eYK5|O`2Pa#RG_N> literal 0 HcmV?d00001 diff --git a/modules/vicseccard/module.py b/modules/vicseccard/module.py new file mode 100644 index 00000000..d3942eb1 --- /dev/null +++ b/modules/vicseccard/module.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Oleg Plakhotniuk +# +# 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 weboob.capabilities.bank import CapBank +from weboob.tools.backend import Module, BackendConfig +from weboob.tools.value import ValueBackendPassword + +from .browser import VicSecCard + + +__all__ = ['VicSecCardModule'] + + +class VicSecCardModule(Module, CapBank): + NAME = 'vicseccard' + MAINTAINER = u'Oleg Plakhotniuk' + EMAIL = 'olegus8@gmail.com' + VERSION = '1.1' + LICENSE = 'AGPLv3+' + DESCRIPTION = u'Victoria\'s Secret Angel Card' + CONFIG = BackendConfig( + ValueBackendPassword('username', label='User name', masked=False), + ValueBackendPassword('password', label='Password')) + BROWSER = VicSecCard + + def create_default_browser(self): + return self.create_browser(self.config['username'].get(), + self.config['password'].get()) + + def iter_accounts(self): + return self.browser.iter_accounts() + + def get_account(self, id_): + return self.browser.get_account(id_) + + def iter_history(self, account): + return self.browser.iter_history(account) diff --git a/modules/vicseccard/test.py b/modules/vicseccard/test.py new file mode 100644 index 00000000..14cf85bc --- /dev/null +++ b/modules/vicseccard/test.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2015 Oleg Plakhotniuk +# +# 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 weboob.tools.test import BackendTest +from itertools import chain + + +class VicSecCardTest(BackendTest): + MODULE = 'vicseccard' + + def test_history(self): + """ + Test that there's at least one transaction in the whole history. + """ + b = self.backend + ts = chain(*[b.iter_history(a) for a in b.iter_accounts()]) + t = next(ts, None) + self.assertNotEqual(t, None)