pax_global_header 0000666 0000000 0000000 00000000064 13443176003 0014513 g ustar 00root root 0000000 0000000 52 comment=59a1e63422915d12d876b5310af95271c3789e66
woob-59a1e63422915d12d876b5310af95271c3789e66-modules-vicsec/ 0000775 0000000 0000000 00000000000 13443176003 0021760 5 ustar 00root root 0000000 0000000 woob-59a1e63422915d12d876b5310af95271c3789e66-modules-vicsec/modules/ 0000775 0000000 0000000 00000000000 13443176003 0023430 5 ustar 00root root 0000000 0000000 woob-59a1e63422915d12d876b5310af95271c3789e66-modules-vicsec/modules/vicsec/ 0000775 0000000 0000000 00000000000 13443176003 0024704 5 ustar 00root root 0000000 0000000 woob-59a1e63422915d12d876b5310af95271c3789e66-modules-vicsec/modules/vicsec/__init__.py 0000664 0000000 0000000 00000001515 13443176003 0027017 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2015 Oleg Plakhotniuk
#
# This file is part of a weboob module.
#
# This weboob module 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.
#
# This weboob module 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 this weboob module. If not, see .
from .module import VicSecModule
__all__ = ['VicSecModule']
woob-59a1e63422915d12d876b5310af95271c3789e66-modules-vicsec/modules/vicsec/browser.py 0000664 0000000 0000000 00000016562 13443176003 0026753 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
# Copyright(C) 2015 Oleg Plakhotniuk
#
# This file is part of a weboob module.
#
# This weboob module 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.
#
# This weboob module 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 this weboob module. If not, see .
import re
from datetime import datetime
from decimal import Decimal
from itertools import chain
from weboob.browser import URL, LoginBrowser, need_login
from weboob.browser.pages import HTMLPage
from weboob.capabilities.base import Currency
from weboob.capabilities.shop import Item, Order, Payment
from weboob.exceptions import BrowserIncorrectPassword
from weboob.tools.capabilities.bank.transactions import AmericanTransaction as AmTr
from weboob.tools.compat import unicode
__all__ = ['VicSec']
class VicSecPage(HTMLPage):
@property
def logged(self):
return bool(self.doc.xpath(
'//a[@href="https://www.victoriassecret.com/account/profile"]'))
class LoginPage(VicSecPage):
def login(self, email, password):
form = self.get_form(name='accountLogonForm')
form['j_username'] = email
form['j_password'] = password
form.submit()
class HistoryPage(VicSecPage):
def iter_orders(self):
return [onum for date, onum in sorted(
chain(self.orders(), self.returns()), reverse=True)]
def orders(self):
for tr in self.doc.xpath('//table[@class="order-status"]/tbody[1]/tr'):
date = datetime.strptime(tr.xpath('td[1]/text()')[0], '%m/%d/%Y')
num = tr.xpath('td[2]/a/text()')[0]
status = tr.xpath('td[4]/span/text()')[0]
if status == u'Delivered':
yield date, num
def returns(self):
for tr in self.doc.xpath('//table[@class="order-status"]/tbody[3]/tr'):
num = tr.xpath('td[1]/a/text()')[0]
date = datetime.strptime(tr.xpath('td[2]/text()')[0], '%m/%d/%Y')
status = tr.xpath('td[4]/span/text()')[0]
if status == u'Complete':
yield date, num
class OrderPage(VicSecPage):
def order(self):
order = Order(id=self.order_number())
order.date = self.order_date()
order.tax = self.tax()
order.discount = self.discount()
order.shipping = self.shipping()
return order
def payments(self):
for tr in self.doc.xpath('//tbody[@class="payment-summary"]'
'//th[text()="Payment Summary"]/../../../tbody/tr'):
method = tr.xpath('td[1]/text()')[0]
amnode = tr.xpath('td[2]')[0]
amsign = -1 if amnode.xpath('em') else 1
amount = amnode.text_content().strip()
pmt = Payment()
pmt.date = self.order_date()
pmt.method = unicode(method)
pmt.amount = amsign * AmTr.decimal_amount(amount)
if pmt.method not in [u'Funds to be applied on backorder']:
yield pmt
def items(self):
for tr in self.doc.xpath('//tbody[@class="order-items"]/tr'):
label = tr.xpath('*//h1')[0].text_content().strip()
price = AmTr.decimal_amount(re.match(r'^\s*([^\s]+)(\s+.*)?',
tr.xpath('*//div[@class="price"]')[0].text_content(),
re.DOTALL).group(1))
url = 'http:' + tr.xpath('*//img/@src')[0]
item = Item()
item.label = unicode(label)
item.url = unicode(url)
item.price = price
yield item
def is_void(self):
return not self.doc.xpath('//tbody[@class="order-items"]/tr')
def order_number(self):
return self.order_info(u'Order Number')
def order_date(self):
return datetime.strptime(self.order_info(u'Order Date'), '%m/%d/%Y')
def tax(self):
return self.payment_part(u'Sales Tax')
def shipping(self):
return self.payment_part(u'Shipping & Handling')
def order_info(self, which):
info = self.doc.xpath('//p[@class="orderinfo"]')[0].text_content()
return re.match(u'.*%s:\\s+([^\\s]+)\\s' % which, info, re.DOTALL).group(1)
def discount(self):
# Sometimes subtotal doesn't add up with items.
# I saw that "Special Offer" was actually added to the item's price,
# instead of being subtracted. Looks like a bug on VS' side.
# To compensate for it I'm correcting discount value.
dcnt = self.payment_part(u'Special Offer')
subt = self.payment_part(u'Merchandise Subtotal')
rett = self.payment_part(u'Return Merchandise Total')
items = sum(i.price for i in self.items())
return dcnt + subt + rett - items
def payment_part(self, which):
# The numbers notation on VS is super wierd.
# Sometimes negative amounts are represented by element.
for node in self.doc.xpath('//tbody[@class="payment-summary"]'
'//td[contains(text(),"%s")]/../td[2]' % which):
strv = node.text_content().strip()
v = Decimal(0) if strv == u'FREE' else AmTr.decimal_amount(strv)
return -v if node.xpath('em') and v > 0 else v
return Decimal(0)
class VicSec(LoginBrowser):
BASEURL = 'https://www.victoriassecret.com'
login = URL(r'/account/signin/overlay$', LoginPage)
history = URL(r'/account/orderlist$', HistoryPage)
order = URL(r'/account/orderstatus/submit/view\?emailId=(?P.*)&orderNumber=(?P\d+)$',
r'/account/orderstatus.*$',
OrderPage)
unknown = URL(r'/.*$', VicSecPage)
def get_currency(self):
# Victoria's Secret uses only U.S. dollars.
return Currency.get_currency(u'$')
def get_order(self, id_):
return self.to_order(id_).order()
def iter_orders(self):
for order in self.to_history().iter_orders():
if not self.to_order(order).is_void():
yield self.page.order()
def iter_payments(self, order):
return self.to_order(order.id).payments()
def iter_items(self, order):
return self.to_order(order.id).items()
@need_login
def to_history(self):
self.history.stay_or_go()
assert self.history.is_here()
return self.page
@need_login
def to_order(self, order_num):
self.order.stay_or_go(order_num=order_num, email=self.username.upper())
assert self.order.is_here(order_num=order_num,
email=self.username.upper())
return self.page
def do_login(self):
self.session.cookies.clear()
# Need to go there two times. Perhaps because of cookies...
self.location('/secureoverlay/wrapper/medium/account/signin/overlay/show')
self.login.go()
self.login.go().login(self.username, self.password)
self.history.go()
if not self.history.is_here():
raise BrowserIncorrectPassword()
woob-59a1e63422915d12d876b5310af95271c3789e66-modules-vicsec/modules/vicsec/favicon.png 0000664 0000000 0000000 00000003752 13443176003 0027046 0 ustar 00root root 0000000 0000000 PNG
IHDR @ @ . gAMA a cHRM z&