Browse Source

added support for uber

Fabian Peter Hammerle 8 years ago
parent
commit
fca63b27de
1 changed files with 105 additions and 6 deletions
  1. 105 6
      order-confirmation-mail-parser

+ 105 - 6
order-confirmation-mail-parser

@@ -25,7 +25,9 @@ class Order(object):
         self.platform = platform
         assert type(order_id) is unicode
         self.order_id = order_id
-        assert type(order_date) is datetime.datetime
+        if type(order_date) is datetime.datetime:
+            order_date = order_date.date()
+        assert type(order_date) is datetime.date
         self.order_date = order_date
         assert customer_id is None or type(customer_id) is unicode
         self.customer_id = customer_id
@@ -44,6 +46,25 @@ class Order(object):
 
 yaml.SafeDumper.add_representer(Order, lambda dumper, order: dumper.represent_dict(order.dict_repr()))
 
+class Figure(object):
+
+    def __init__(self, value, unit):
+        self.value = value
+        assert type(unit) is unicode
+        self.unit = unit
+
+class Distance(Figure):
+
+    def __init__(self, value, unit):
+        assert type(value) is float
+        super(Distance, self).__init__(value, unit)
+
+    def metres(self):
+        if self.unit == 'km':
+            return self.value * 1000
+        else:
+            raise Exception()
+
 class Sum(object):
 
     def __init__(self, value, currency):
@@ -139,18 +160,21 @@ yaml.SafeDumper.add_representer(Article, lambda dumper, article: dumper.represen
 
 class Transportation(Item):
 
-    def __init__(self, departure_point = None, destination_point = None, **kwargs):
+    def __init__(self, departure_point = None, destination_point = None, distance = None, **kwargs):
         super(Transportation, self).__init__(**kwargs)
         assert type(departure_point) is unicode
         self.departure_point = departure_point
         assert type(destination_point) is unicode
         self.destination_point = destination_point
+        assert distance is None or type(distance) is Distance
+        self.distance = distance
 
     def dict_repr(self):
         attr = Item.dict_repr(self)
         attr.update({
             'departure_point': self.departure_point,
             'destination_point': self.destination_point,
+            'distance_metres': self.distance.metres() if self.distance else None,
             })
         return attr
 
@@ -158,18 +182,23 @@ yaml.SafeDumper.add_representer(Transportation, lambda dumper, transportation: d
 
 class TaxiRide(Transportation):
 
-    def __init__(self, driver = None, arrival_time = None, **kwargs):
-        super(TaxiRide, self).__init__(name = u'Taxi Ride', **kwargs)
+    def __init__(self, name = None, driver = None, arrival_time = None, departure_time = None, **kwargs):
+        if name is None:
+            name = u'Taxi Ride'
+        super(TaxiRide, self).__init__(name = name, **kwargs)
         assert type(driver) is unicode
         self.driver = driver
-        assert type(arrival_time) is datetime.datetime
+        assert arrival_time is None or type(arrival_time) is datetime.datetime
         self.arrival_time = arrival_time
+        assert departure_time is None or type(departure_time) is datetime.datetime
+        self.departure_time = departure_time
 
     def dict_repr(self):
         attr = Transportation.dict_repr(self)
         attr.update({
+            'arrival_time': self.arrival_time.strftime('%Y-%m-%d %H:%M') if self.arrival_time else None,
+            'departure_time': self.departure_time.strftime('%Y-%m-%d %H:%M') if self.departure_time else None,
             'driver': self.driver,
-            'arrival_time': self.arrival_time.strftime('%Y-%m-%d %H:%M'),
             })
         return attr
 
@@ -353,6 +382,71 @@ def parse_mytaxi(msg):
         ))
     return [order]
 
+def parse_uber(msg):
+
+    html = msg.get_payload()[0].get_payload(decode = True)
+
+    """ document in html2 has the same structure as the one in html.
+        only difference is that hyperlink urls in html2 have been
+        replaced by 'email.uber.com/wf/click?upn=.*' urls.
+        """
+    html2 = msg.get_payload()[1].get_payload()[0].get_payload(decode = True)
+
+    route_map = msg.get_payload()[1].get_payload()[1].get_payload(decode = True)
+
+    doc = BeautifulSoup.BeautifulSoup(
+        html,
+        convertEntities = BeautifulSoup.BeautifulSoup.HTML_ENTITIES,
+        )
+
+    # strptime
+    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
+
+    trip_id = re.search(
+        ur'[\da-f\-]{36}',
+        doc.find(text = 'Visit the trip page').parent['href'],
+        ).group(0)
+    order = Order(
+        u'uber',
+        trip_id,
+        datetime.datetime.strptime(
+            doc.find(attrs = {'class': 'date'}).text,
+            '%B %d, %Y',
+            ),
+        )
+
+    departure_time_tag = doc.find(attrs = {'class': 'from time'})
+    departure_time = datetime.datetime.strptime(
+        departure_time_tag.text,
+        '%I:%M%p',
+        ).time()
+
+    arrival_time_tag = doc.find(attrs = {'class': 'to time'})
+    arrival_time = datetime.datetime.strptime(
+        arrival_time_tag.text,
+        '%I:%M%p',
+        ).time()
+
+    distance = Distance(
+        float(doc.find(text = 'kilometers').parent.parent.find(attrs = {'class': 'data'}).text),
+        u'km',
+        )
+
+    fare = doc.find(attrs = {'class': 'header-price'}).find(attrs = {'class': 'header-fare text-pad'}).text
+
+    order.items.append(TaxiRide(
+        name = doc.find(text = 'CAR').parent.parent.find(attrs = {'class': 'data'}).text + ' Ride',
+        price_brutto = Sum(float(fare[1:]), fare[0]),
+        arrival_time = datetime.datetime.combine(order.order_date, arrival_time),
+        departure_time = datetime.datetime.combine(order.order_date, departure_time),
+        departure_point = departure_time_tag.parent.find(attrs = {'class': 'address'}).text,
+        destination_point = arrival_time_tag.parent.find(attrs = {'class': 'address'}).text,
+        distance = distance,
+        driver = doc.find(attrs = {'class': 'driver-info'}).text[len('You rode with '):],
+        ))
+
+    return [order]
+
 def parse_yipbee(msg):
 
     text = msg.get_payload()[0].get_payload()[0].get_payload(decode = True).decode('utf-8')
@@ -489,6 +583,11 @@ def parse(msg):
     except:
         tracebacks['mytaxi'] = traceback.format_exc()
 
+    try:
+        return parse_uber(msg)
+    except:
+        tracebacks['uber'] = traceback.format_exc()
+
     try:
         return parse_yipbee(msg)
     except: