<commit_before># -*- coding: utf-8 -*-

# Copyright(C) 2015      <NAME>
#
# 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.tools.capabilities.bank.transactions import \
    AmericanTransaction as AmTr
from weboob.browser import LoginBrowser, URL, need_login
from weboob.browser.pages import HTMLPage
from weboob.capabilities.base import Currency
from weboob.capabilities.shop import OrderNotFound, Order, Item, Payment
from weboob.exceptions import BrowserIncorrectPassword

from datetime import datetime
from decimal import Decimal
from itertools import chain
import re


__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]
            amount = tr.xpath('td[2]')[0].text_content().strip()
            pmt = Payment()
            pmt.date = self.order_date()
            pmt.method = unicode(method)
            pmt.amount = AmTr.decimal_amount(amount)
            yield pmt

    def items(self):
        for tr in self.doc.xpath('//tbody[@class="order-items"]/tr'):
            label = tr.xpath('*//h1')[0].text_content()
            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 details"]'
                             )[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):
        for node in self.doc.xpath('//tbody[@class="payment-summary"]'
                              '//td[contains(text(),"%s")]/../td[2]' % which):
            x = node.text_content().strip()
            return Decimal(0) if x == u'FREE' else AmTr.decimal_amount(x)
        return Decimal(0)


class VicSec(LoginBrowser):<commit_msg>[vicsec] Handle new numbers notation. Closes #1956<commit_after># -*- coding: utf-8 -*-

# Copyright(C) 2015      <NAME>
#
# 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.tools.capabilities.bank.transactions import \
    AmericanTransaction as AmTr
from weboob.browser import LoginBrowser, URL, need_login
from weboob.browser.pages import HTMLPage
from weboob.capabilities.base import Currency
from weboob.capabilities.shop import OrderNotFound, Order, Item, Payment
from weboob.exceptions import BrowserIncorrectPassword

from datetime import datetime
from decimal import Decimal
from itertools import chain
import re


__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)
            yield pmt

    def items(self):
        for tr in self.doc.xpath('//tbody[@class="order-items"]/tr'):
            label = tr.xpath('*//h1')[0].text_content()
            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 details"]'
                             )[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 <em> 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):
{'fraction_non_alphanumeric': 0.1437109481119261, 'fraction_numerical': 0.006791632708503124, 'mean_word_length': 2.4916218779639583, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4860365', 'n_tokens_mistral': 3472, 'n_tokens_neox': 3361, 'n_words': 863}