Browse Source

added support for amazon.cn

Fabian Peter Hammerle 7 years ago
parent
commit
a24eaf46e4

+ 17 - 4
dingguo/__init__.py

@@ -111,6 +111,13 @@ class ScalarFigure(Figure):
                 '%s %s' % (repr(s.value), s.unit),
                 )
 
+    def __mul__(self, factor):
+        assert type(factor) in [int, float]
+        return self.__class__(
+                unit = self.unit,
+                value = self.value * factor,
+                )
+
 class Distance(ScalarFigure):
 
     yaml_tag = u'!distance'
@@ -132,7 +139,7 @@ class Sum(ScalarFigure):
         else:
             unit = currency if currency else unit
             super(Sum, self).__init__(
-                    value = value, 
+                    value = value,
                     unit = currency if currency else unit,
                     )
 
@@ -146,10 +153,16 @@ class Sum(ScalarFigure):
     def set_unit(self, currency):
         if currency == u'€':
             currency = u'EUR'
-        if currency == u'US$':
+        elif currency == u'US$':
             currency = u'USD'
+        elif currency == u'¥':
+            currency = u'CNY'
         assert type(currency) is unicode
-        assert currency in [u'EUR', u'USD']
+        assert currency in [
+                u'CNY',
+                u'EUR',
+                u'USD',
+                ]
         super(Sum, self).set_unit(currency)
 
     """ use property() instead of decorator to enable overriding """
@@ -166,7 +179,7 @@ class Sum(ScalarFigure):
     @staticmethod
     def parse_text(text):
         match = re.search(
-            ur'^(?P<curr_pre>((US)?\$|€))(?P<value>-?\d+([\.,]\d{2})?)( (?P<currency>USD))?$',
+            ur'^(?P<curr_pre>((US)?\$|€|¥)) *(?P<value>-?\d+([\.,]\d{2})?)( (?P<currency>USD))?$',
             text,
             re.UNICODE,
             )

+ 2 - 0
dingguo/parser/__init__.py

@@ -4,6 +4,7 @@ import email
 import traceback
 
 import amazon
+import amazon_cn
 import banggood
 import hm
 import ikea
@@ -21,6 +22,7 @@ import yipbee
 
 order_confirmation_parsers = [
     amazon.parse_order_confirmation_mail,
+    amazon_cn.parse_order_confirmation_mail,
     banggood.parse_order_confirmation_mail,
     hm.parse_order_confirmation_mail,
     ikea.parse_order_confirmation_mail,

+ 70 - 0
dingguo/parser/amazon_cn.py

@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+
+import BeautifulSoup
+import datetime
+import dateutil.parser
+import dingguo
+import email.message
+import ioex
+import pytz
+import re
+
+def parse_order_confirmation_mail(mail):
+
+    assert isinstance(mail, email.message.Message)
+
+    html = mail.get_payload()[1].get_payload(decode = True).decode('utf-8')
+
+    if not u'订单详情' in html:
+        raise Exception()
+
+    doc = BeautifulSoup.BeautifulSoup(html)
+
+    for br in doc.findAll('br'):
+        br.replaceWith('\n')
+
+    def get_text(tag):
+        return u''.join([c if type(c) is BeautifulSoup.NavigableString else get_text(c) for c in tag.contents])
+
+    order = dingguo.Order(
+        platform = u'amazon.cn',
+        order_id = doc.find(text = re.compile(u'订单号')).findNext().text,
+        order_date = dateutil.parser.parse(mail['date']),
+        )
+
+    article_table = doc.find(text = re.compile(u'订购日期')).findNext('table')
+    for a in article_table.find('tbody').findChildren(recursive = False):
+        image_col_tag, details_tag, price_tag = a.findAll('td', recursive = False)
+        name_tag = details_tag.find('a')
+        order.items.append(dingguo.Article(
+            name = name_tag.text.strip(),
+            price_brutto = dingguo.Sum.parse_text(price_tag.text),
+            quantity = 1,
+            reseller = name_tag.findNext(text = re.compile(u'由')).findNext().text,
+            ))
+
+    with ioex.setlocale('zh_CN.utf-8'):
+        estimated_arrival_date_start = pytz.timezone('Asia/Shanghai').localize(
+            datetime.datetime.strptime(
+                doc.find(text = re.compile(u'预计送达日期:')).findNext('b').text.encode('utf-8'),
+                '%A, %m/%d',
+                ).replace(year = order.order_date.year)
+            )
+        assert estimated_arrival_date_start >= order.order_date
+    order.items.append(dingguo.Shipping(
+        name = doc.find(text = re.compile(u'送货方式:')).findNext('b').text,
+        price_brutto = dingguo.Sum.parse_text(
+            doc.find(text = re.compile(u'配送费:')).findNext().text
+            ),
+        estimated_arrival_time = ioex.datetimeex.Period(
+            start = estimated_arrival_date_start,
+            end = (estimated_arrival_date_start + datetime.timedelta(days = 1)),
+            ),
+        destination_point = '\n'.join([l.strip() for l in
+            get_text(
+                doc.find(text = re.compile(u'您的订单发送至:')).findNext('b')
+                ).split('\n')
+            ]),
+        ))
+
+    return [order]

+ 24 - 0
tests/parser/test_amazon_cn.py

@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+import pytest
+
+import dingguo.parser.amazon_cn
+import email
+import glob
+import ioex
+import os
+import yaml
+
+project_root_path = os.path.realpath(os.path.join(__file__, '..', '..', '..'))
+test_data_path = os.path.join(project_root_path, 'tests', 'data', 'amazon.cn')
+
+@pytest.mark.parametrize('mail_path', glob.glob(os.path.join(test_data_path, '*.eml')))
+def test_parse_confirmation_mail(mail_path):
+    with open(mail_path) as mail:
+        parsed_orders = dingguo.parser.amazon_cn.parse_order_confirmation_mail(
+                email.message_from_file(mail)
+                )
+    with open(mail_path.replace('.eml', '.yml')) as yaml_file:
+        expected_orders = yaml.load(yaml_file.read())
+    assert expected_orders == parsed_orders, \
+            u'\n%s' % ioex.yaml_diff(expected_orders, parsed_orders, colors = True)

+ 10 - 9
tests/test_.py

@@ -42,14 +42,14 @@ 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')],
@@ -58,10 +58,11 @@ def test_person_last_name_string():
     [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'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')],
+    [u'¥ 4.27',     dingguo.Sum(4.27,  u'CNY')],
     ])
 def test_sum_parse_text(text, sum):
     assert dingguo.Sum.parse_text(text) == sum

+ 1 - 0
tests/test_parser.py

@@ -11,6 +11,7 @@ test_data_path = os.path.join(project_root_path, 'tests', 'data')
 
 @pytest.mark.parametrize('platform,mail_path', [
     ('amazon.de', os.path.join(test_data_path, 'amazon', 'mail_1.eml')),
+    ('amazon.cn', os.path.join(test_data_path, 'amazon.cn', '1.eml')),
     ('banggood', os.path.join(test_data_path, 'banggood', '1.eml')),
     ('hm', os.path.join(test_data_path, 'hm', '1.eml')),
     ('ikea', os.path.join(test_data_path, 'ikea', '1.eml')),

+ 2 - 2
tests/test_sum.py

@@ -51,7 +51,7 @@ def test_init_fail(params, kwargs):
     [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):
+def test_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
@@ -63,6 +63,6 @@ def test_scalar_figure_mul(factor_a, factor_b, product):
     [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):
+def test_mul_fail(factor_a, factor_b):
     with pytest.raises(Exception):
         (factor_a * factor_b)