Browse Source

banggood: support for shipping, redeeming points and insurance

Fabian Peter Hammerle 7 years ago
parent
commit
676ef51caf

+ 13 - 9
dingguo/__init__.py

@@ -8,11 +8,8 @@ import re
 import yaml
 import yaml.representer
 
-yaml.Dumper.add_representer(unicode, yaml.representer.SafeRepresenter.represent_unicode)
-yaml.Loader.add_constructor(
-    u'tag:yaml.org,2002:str',
-    lambda loader, node: unicode(loader.construct_scalar(node)),
-    )
+ioex.register_yaml_str_as_unicode_constructor(yaml.Loader)
+ioex.register_yaml_unicode_as_str_representer(yaml.Dumper)
 ioex.datetimeex.register_yaml_timestamp_constructor(yaml.Loader)
 ioex.datetimeex.Duration.register_yaml_constructor(yaml.Loader)
 ioex.datetimeex.Duration.register_yaml_representer(yaml.Dumper)
@@ -48,7 +45,7 @@ class Figure(_YamlInitConstructor):
 
     yaml_tag = u"!figure"
 
-    def __init__(self, value, unit):
+    def __init__(self, value = None, unit = None):
         self.value = value
         self.unit = unit
 
@@ -129,8 +126,15 @@ class Sum(ScalarFigure):
 
     yaml_tag = u'!sum'
 
-    def __init__(self, value, currency):
-        super(Sum, self).__init__(value, currency)
+    def __init__(self, value = None, currency = None, unit = None):
+        if not currency is None and not unit is None:
+            raise ValueError('either specify currency or unit')
+        else:
+            unit = currency if currency else unit
+            super(Sum, self).__init__(
+                    value = value, 
+                    unit = currency if currency else unit,
+                    )
 
     @property
     def currency(self):
@@ -162,7 +166,7 @@ class Sum(ScalarFigure):
     @staticmethod
     def parse_text(text):
         match = re.search(
-            ur'^(?P<curr_pre>[\$])(?P<value>\d+([\.,]\d{2})?)( (?P<currency>USD))?$',
+            ur'^(?P<curr_pre>((US)?\$|€))(?P<value>-?\d+([\.,]\d{2})?)( (?P<currency>USD))?$',
             text,
             re.UNICODE,
             )

+ 21 - 0
dingguo/parser/banggood.py

@@ -51,4 +51,25 @@ def parse_order_confirmation_mail(mail):
             quantity = int(attr['quantity']),
             ))
 
+    shipping_line_tag = doc.find(text = re.compile('Sub-Total')).findNext('tr')
+    shipping_option_tag, shipping_price_tag = shipping_line_tag.findAll('td')
+    order.items.append(dingguo.Shipping(
+        name = shipping_option_tag.text,
+        price_brutto = dingguo.Sum.parse_text(shipping_price_tag.text),
+        ))
+
+    insurance_label_tag = shipping_line_tag.findNext(text = re.compile('Insurance'))
+    if insurance_label_tag:
+        order.items.append(dingguo.Service(
+            name = insurance_label_tag.parent.text,
+            price_brutto = dingguo.Sum.parse_text(insurance_label_tag.findNext().text),
+            ))
+
+    points_discount_label_tag = doc.find(text = re.compile('Discount Points'))
+    if points_discount_label_tag:
+        order.discounts.append(dingguo.Discount(
+            name = u'redeem %d banggood points' % int(points_discount_label_tag.split(':')[1]),
+            amount = dingguo.Sum.parse_text(points_discount_label_tag.findNext().text) * -1,
+            ))
+
     return [order]

+ 1 - 1
setup.py

@@ -18,7 +18,7 @@ setup(
         ],
     scripts = glob.glob('scripts/*'),
     install_requires = [
-        'ioex>=0.6',
+        'ioex>=0.7',
         'pdfminer>=20140328', 
         'pytz',
         ],

+ 3 - 3
tests/test_parser_banggood.py → tests/parser/test_banggood.py

@@ -5,11 +5,11 @@ import pytest
 import dingguo.parser.banggood
 import email
 import glob
+import ioex
 import os
-import test_yaml
 import yaml
 
-project_root_path = os.path.realpath(os.path.join(__file__, '..', '..'))
+project_root_path = os.path.realpath(os.path.join(__file__, '..', '..', '..'))
 test_data_path = os.path.join(project_root_path, 'tests', 'data', 'banggood')
 
 @pytest.mark.parametrize('mail_path', glob.glob(os.path.join(test_data_path, '*.eml')))
@@ -21,4 +21,4 @@ def test_parse_confirmation_mail(mail_path):
     with open(mail_path.replace('.eml', '.yml')) as yaml_file:
         expected_orders = yaml.load(yaml_file.read())
     assert expected_orders == parsed_orders, \
-            test_yaml.yaml_diff(expected_orders, parsed_orders)
+            u'\n%s' % ioex.yaml_diff(expected_orders, parsed_orders, colors = True)

+ 41 - 8
tests/test_.py

@@ -42,14 +42,26 @@ def test_person_last_name_string():
         p.last_name = 'äbc'
 
 @pytest.mark.parametrize(('text', 'sum'), [
-    [u'$1,23 USD',  dingguo.Sum(1.23, u'USD')],
-    [u'$1.23 USD',  dingguo.Sum(1.23, u'USD')],
-    [u'$30 USD',    dingguo.Sum(30.0, u'USD')],
-    [u'$30,00 USD', dingguo.Sum(30.0, u'USD')],
-    [u'$30.00 USD', dingguo.Sum(30.0, u'USD')],
-    [u'$8',         dingguo.Sum(8.0,  u'USD')],
-    [u'$8,00',      dingguo.Sum(8.0,  u'USD')],
-    [u'$8.00',      dingguo.Sum(8.0,  u'USD')],
+    [u'$-1,23 USD',  dingguo.Sum(-1.23,  u'USD')],
+    [u'$-1.23 USD',  dingguo.Sum(-1.23,  u'USD')],
+    [u'$-30 USD',    dingguo.Sum(-30.0,  u'USD')],
+    [u'$-30,00 USD', dingguo.Sum(-30.0,  u'USD')],
+    [u'$-30.00 USD', dingguo.Sum(-30.0,  u'USD')],
+    [u'$-8',         dingguo.Sum(-8.0,   u'USD')],
+    [u'$-8,00',      dingguo.Sum(-8.0,   u'USD')],
+    [u'$-8.00',      dingguo.Sum(-8.0,   u'USD')],
+    [u'$1,23 USD',   dingguo.Sum(1.23,  u'USD')],
+    [u'$1.23 USD',   dingguo.Sum(1.23,  u'USD')],
+    [u'$30 USD',     dingguo.Sum(30.0,  u'USD')],
+    [u'$30,00 USD',  dingguo.Sum(30.0,  u'USD')],
+    [u'$30.00 USD',  dingguo.Sum(30.0,  u'USD')],
+    [u'$8',          dingguo.Sum(8.0,   u'USD')],
+    [u'$8,00',       dingguo.Sum(8.0,   u'USD')],
+    [u'$8.00',       dingguo.Sum(8.0,   u'USD')],
+    [u'US$-0.50',    dingguo.Sum(-0.5,   u'USD')],
+    [u'US$0.50',     dingguo.Sum(0.5,   u'USD')],
+    [u'€-0.25',      dingguo.Sum(-0.25, u'EUR')],
+    [u'€1.20',       dingguo.Sum(1.2,   u'EUR')],
     ])
 def test_sum_parse_text(text, sum):
     assert dingguo.Sum.parse_text(text) == sum
@@ -83,3 +95,24 @@ def test_figure_sub(minuend, subtrahend, difference):
 def test_figure_sub_fail(minuend, subtrahend):
     with pytest.raises(Exception):
         (minuend - subtrahend)
+
+@pytest.mark.parametrize(('factor_a', 'factor_b', 'product'), [
+    [dingguo.Sum(5.0, u'USD'), 1.5, dingguo.Sum(7.5, u'USD')],
+    [dingguo.Sum(5.0, u'USD'), 2, dingguo.Sum(10.0, u'USD')],
+    [dingguo.ScalarFigure(5.0, u'cm'), -0.5, dingguo.ScalarFigure(-2.5, u'cm')],
+    [dingguo.ScalarFigure(1.0, u'kg'), 10, dingguo.ScalarFigure(10.0, u'kg')],
+    ])
+def test_scalar_figure_mul(factor_a, factor_b, product):
+    factor_a_copy = copy.deepcopy(factor_a)
+    factor_b_copy = copy.deepcopy(factor_b)
+    assert (factor_a * factor_b) == product
+    assert factor_a_copy == factor_a
+    assert factor_b_copy == factor_b
+
+@pytest.mark.parametrize(('factor_a', 'factor_b'), [
+    [dingguo.Sum(5.0, u'USD'), dingguo.Sum(2.0, u'EUR')],
+    [dingguo.ScalarFigure(5.0, u'cm'), dingguo.ScalarFigure(2.0, u'cm')],
+    ])
+def test_figure_mul_fail(factor_a, factor_b):
+    with pytest.raises(Exception):
+        (factor_a * factor_b)

+ 52 - 0
tests/test_distance.py

@@ -0,0 +1,52 @@
+import pytest
+
+import copy
+import dingguo
+
+@pytest.mark.parametrize(('params', 'kwargs', 'expected_value', 'expected_unit'), [
+    [[1.0, u'dm'], {}, 1.0, u'dm'],
+    [[-4.0], {'unit': u'cm'}, -4.0, u'cm'],
+    [[], {'value': 2.3, 'unit': u'cm'}, 2.3, u'cm'],
+    ])
+def test_init(params, kwargs, expected_value, expected_unit):
+    f = dingguo.Distance(*params, **kwargs)
+    assert type(f.value) == type(expected_value)
+    assert type(f.unit) == type(expected_unit)
+    assert f.value == expected_value
+    assert f.unit == expected_unit
+
+@pytest.mark.parametrize(('params', 'kwargs'), [
+    [[], {}],
+    [[None], {}],
+    [[None, u'kg'], {}],
+    [[1, 'cm'], {}],
+    [[], {'unit': u'cm'}],
+    [[1], {'unit': 'cm'}],
+    [[1, u'cm'], {}],
+    [[1], {'unit': u'cm'}],
+    [[(-1, 3), u'cm'], {}],
+    [[], {'value': (3, -1), 'unit': u'cm'}],
+    [[1.2], {'value': 2.3, 'unit': u'cm'}],
+    ])
+def test_init_fail(params, kwargs):
+    with pytest.raises(Exception):
+        dingguo.Distance(*params, **kwargs)
+
+@pytest.mark.parametrize(('factor_a', 'factor_b', 'product'), [
+    [dingguo.Distance(5.0, u'cm'), -0.5, dingguo.Distance(-2.5, u'cm')],
+    [dingguo.Distance(1.0, u'kg'), 10, dingguo.Distance(10.0, u'kg')],
+    ])
+def test_scalar_figure_mul(factor_a, factor_b, product):
+    factor_a_copy = copy.deepcopy(factor_a)
+    factor_b_copy = copy.deepcopy(factor_b)
+    assert (factor_a * factor_b) == product
+    assert factor_a_copy == factor_a
+    assert factor_b_copy == factor_b
+
+@pytest.mark.parametrize(('factor_a', 'factor_b'), [
+    [dingguo.Distance(5.0, u'cm'), dingguo.Distance(2.0, u'cm')],
+    [dingguo.Distance(5.0, u'cm'), '23'],
+    ])
+def test_figure_mul_fail(factor_a, factor_b):
+    with pytest.raises(Exception):
+        (factor_a * factor_b)

+ 27 - 0
tests/test_figure.py

@@ -0,0 +1,27 @@
+import pytest
+
+import dingguo
+
+@pytest.mark.parametrize(('params', 'kwargs', 'expected_value', 'expected_unit'), [
+    [[1, u'cm'], {}, 1, u'cm'],
+    [[1], {'unit': u'cm'}, 1, u'cm'],
+    [[], {'unit': u'cm'}, None, u'cm'],
+    [[], {'value': 1.0, 'unit': u'cm'}, 1.0, u'cm'],
+    [[], {'value': (3, -1), 'unit': u'cm'}, (3, -1), u'cm'],
+    [[(-1, 3), u'cm'], {}, (-1, 3), u'cm'],
+    ])
+def test_init(params, kwargs, expected_value, expected_unit):
+    f = dingguo.Figure(*params, **kwargs)
+    assert type(f.value) == type(expected_value)
+    assert type(f.unit) == type(expected_unit)
+    assert f.value == expected_value
+    assert f.unit == expected_unit
+
+@pytest.mark.parametrize(('params', 'kwargs'), [
+    [[], {}],
+    [[1, 'cm'], {}],
+    [[1], {'unit': 'cm'}],
+    ])
+def test_init_fail(params, kwargs):
+    with pytest.raises(Exception):
+        dingguo.Figure(*params, **kwargs)

+ 52 - 0
tests/test_scalar_figure.py

@@ -0,0 +1,52 @@
+import pytest
+
+import copy
+import dingguo
+
+@pytest.mark.parametrize(('params', 'kwargs', 'expected_value', 'expected_unit'), [
+    [[1.0, u'cm'], {}, 1.0, u'cm'],
+    [[-4.0], {'unit': u'cm'}, -4.0, u'cm'],
+    [[], {'value': 2.3, 'unit': u'cm'}, 2.3, u'cm'],
+    ])
+def test_init(params, kwargs, expected_value, expected_unit):
+    f = dingguo.ScalarFigure(*params, **kwargs)
+    assert type(f.value) == type(expected_value)
+    assert type(f.unit) == type(expected_unit)
+    assert f.value == expected_value
+    assert f.unit == expected_unit
+
+@pytest.mark.parametrize(('params', 'kwargs'), [
+    [[], {}],
+    [[None], {}],
+    [[None, u'kg'], {}],
+    [[1, 'cm'], {}],
+    [[], {'unit': u'cm'}],
+    [[1], {'unit': 'cm'}],
+    [[1, u'cm'], {}],
+    [[1], {'unit': u'cm'}],
+    [[(-1, 3), u'cm'], {}],
+    [[], {'value': (3, -1), 'unit': u'cm'}],
+    [[1.2], {'value': 2.3, 'unit': u'cm'}],
+    ])
+def test_init_fail(params, kwargs):
+    with pytest.raises(Exception):
+        dingguo.ScalarFigure(*params, **kwargs)
+
+@pytest.mark.parametrize(('factor_a', 'factor_b', 'product'), [
+    [dingguo.ScalarFigure(5.0, u'cm'), -0.5, dingguo.ScalarFigure(-2.5, u'cm')],
+    [dingguo.ScalarFigure(1.0, u'kg'), 10, dingguo.ScalarFigure(10.0, u'kg')],
+    ])
+def test_scalar_figure_mul(factor_a, factor_b, product):
+    factor_a_copy = copy.deepcopy(factor_a)
+    factor_b_copy = copy.deepcopy(factor_b)
+    assert (factor_a * factor_b) == product
+    assert factor_a_copy == factor_a
+    assert factor_b_copy == factor_b
+
+@pytest.mark.parametrize(('factor_a', 'factor_b'), [
+    [dingguo.ScalarFigure(5.0, u'cm'), dingguo.ScalarFigure(2.0, u'cm')],
+    [dingguo.ScalarFigure(5.0, u'cm'), '23'],
+    ])
+def test_figure_mul_fail(factor_a, factor_b):
+    with pytest.raises(Exception):
+        (factor_a * factor_b)

+ 68 - 0
tests/test_sum.py

@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+
+import pytest
+
+import copy
+import dingguo
+
+@pytest.mark.parametrize(('params', 'kwargs', 'expected_value', 'expected_currency'), [
+    [[1.0, u'US$'], {}, 1.0, u'USD'],
+    [[1.0, u'USD'], {}, 1.0, u'USD'],
+    [[-4.0], {'unit': u'EUR'}, -4.0, u'EUR'],
+    [[-4.0], {'unit': u'€'}, -4.0, u'EUR'],
+    [[-4.0], {'currency': u'EUR'}, -4.0, u'EUR'],
+    [[-4.0], {'currency': u'€'}, -4.0, u'EUR'],
+    [[], {'value': 2.3, 'unit': u'EUR'}, 2.3, u'EUR'],
+    [[], {'value': 2.3, 'unit': u'€'}, 2.3, u'EUR'],
+    [[], {'value': 2.3, 'currency': u'EUR'}, 2.3, u'EUR'],
+    [[], {'value': 2.3, 'currency': u'€'}, 2.3, u'EUR'],
+    ])
+def test_init(params, kwargs, expected_value, expected_currency):
+    f = dingguo.Sum(*params, **kwargs)
+    assert type(f.value) == type(expected_value)
+    assert type(f.unit) == type(expected_currency)
+    assert f.value == expected_value
+    assert f.unit == expected_currency
+    assert f.currency == expected_currency
+
+@pytest.mark.parametrize(('params', 'kwargs'), [
+    [[(-1, 3), u'EUR'], {}],
+    [[1, 'EUR'], {}],
+    [[1, u'EUR'], {}],
+    [[1.0, u'USD', u'EUR'], {}],
+    [[1.2], {'value': 2.3, 'unit': u'EUR'}],
+    [[1], {'unit': 'EUR'}],
+    [[1], {'unit': u'EUR'}],
+    [[None, u'EUR'], {}],
+    [[None, u'kg'], {}],
+    [[None], {}],
+    [[], {'unit': u'EUR'}],
+    [[], {'value': (3, -1), 'unit': u'EUR'}],
+    [[], {'value': 2.3, 'unit': u'EUR', 'currency': u'EUR'}],
+    [[], {}],
+    ])
+def test_init_fail(params, kwargs):
+    with pytest.raises(Exception):
+        dingguo.Sum(*params, **kwargs)
+
+@pytest.mark.parametrize(('factor_a', 'factor_b', 'product'), [
+    [dingguo.Sum(5.0, u'USD'), 1.5, dingguo.Sum(7.5, u'USD')],
+    [dingguo.Sum(5.0, u'USD'), 2, dingguo.Sum(10.0, u'USD')],
+    [dingguo.Sum(5.0, u'EUR'), 1.5, dingguo.Sum(7.5, u'EUR')],
+    [dingguo.Sum(5.0, u'EUR'), 2, dingguo.Sum(10.0, u'EUR')],
+    ])
+def test_scalar_figure_mul(factor_a, factor_b, product):
+    factor_a_copy = copy.deepcopy(factor_a)
+    factor_b_copy = copy.deepcopy(factor_b)
+    assert (factor_a * factor_b) == product
+    assert factor_a_copy == factor_a
+    assert factor_b_copy == factor_b
+
+@pytest.mark.parametrize(('factor_a', 'factor_b'), [
+    [dingguo.ScalarFigure(5.0, u'USD'), dingguo.ScalarFigure(2.0, u'USD')],
+    [dingguo.ScalarFigure(5.0, u'EUR'), dingguo.ScalarFigure(2.0, u'USD')],
+    [dingguo.ScalarFigure(5.0, u'USD'), '23'],
+    ])
+def test_figure_mul_fail(factor_a, factor_b):
+    with pytest.raises(Exception):
+        (factor_a * factor_b)