|
@@ -25,7 +25,9 @@ class Order(object):
|
|
self.platform = platform
|
|
self.platform = platform
|
|
assert type(order_id) is unicode
|
|
assert type(order_id) is unicode
|
|
self.order_id = order_id
|
|
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
|
|
self.order_date = order_date
|
|
assert customer_id is None or type(customer_id) is unicode
|
|
assert customer_id is None or type(customer_id) is unicode
|
|
self.customer_id = customer_id
|
|
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()))
|
|
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):
|
|
class Sum(object):
|
|
|
|
|
|
def __init__(self, value, currency):
|
|
def __init__(self, value, currency):
|
|
@@ -139,18 +160,21 @@ yaml.SafeDumper.add_representer(Article, lambda dumper, article: dumper.represen
|
|
|
|
|
|
class Transportation(Item):
|
|
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)
|
|
super(Transportation, self).__init__(**kwargs)
|
|
assert type(departure_point) is unicode
|
|
assert type(departure_point) is unicode
|
|
self.departure_point = departure_point
|
|
self.departure_point = departure_point
|
|
assert type(destination_point) is unicode
|
|
assert type(destination_point) is unicode
|
|
self.destination_point = destination_point
|
|
self.destination_point = destination_point
|
|
|
|
+ assert distance is None or type(distance) is Distance
|
|
|
|
+ self.distance = distance
|
|
|
|
|
|
def dict_repr(self):
|
|
def dict_repr(self):
|
|
attr = Item.dict_repr(self)
|
|
attr = Item.dict_repr(self)
|
|
attr.update({
|
|
attr.update({
|
|
'departure_point': self.departure_point,
|
|
'departure_point': self.departure_point,
|
|
'destination_point': self.destination_point,
|
|
'destination_point': self.destination_point,
|
|
|
|
+ 'distance_metres': self.distance.metres() if self.distance else None,
|
|
})
|
|
})
|
|
return attr
|
|
return attr
|
|
|
|
|
|
@@ -158,18 +182,23 @@ yaml.SafeDumper.add_representer(Transportation, lambda dumper, transportation: d
|
|
|
|
|
|
class TaxiRide(Transportation):
|
|
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
|
|
assert type(driver) is unicode
|
|
self.driver = driver
|
|
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
|
|
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):
|
|
def dict_repr(self):
|
|
attr = Transportation.dict_repr(self)
|
|
attr = Transportation.dict_repr(self)
|
|
attr.update({
|
|
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,
|
|
'driver': self.driver,
|
|
- 'arrival_time': self.arrival_time.strftime('%Y-%m-%d %H:%M'),
|
|
|
|
})
|
|
})
|
|
return attr
|
|
return attr
|
|
|
|
|
|
@@ -353,6 +382,71 @@ def parse_mytaxi(msg):
|
|
))
|
|
))
|
|
return [order]
|
|
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):
|
|
def parse_yipbee(msg):
|
|
|
|
|
|
text = msg.get_payload()[0].get_payload()[0].get_payload(decode = True).decode('utf-8')
|
|
text = msg.get_payload()[0].get_payload()[0].get_payload(decode = True).decode('utf-8')
|
|
@@ -489,6 +583,11 @@ def parse(msg):
|
|
except:
|
|
except:
|
|
tracebacks['mytaxi'] = traceback.format_exc()
|
|
tracebacks['mytaxi'] = traceback.format_exc()
|
|
|
|
|
|
|
|
+ try:
|
|
|
|
+ return parse_uber(msg)
|
|
|
|
+ except:
|
|
|
|
+ tracebacks['uber'] = traceback.format_exc()
|
|
|
|
+
|
|
try:
|
|
try:
|
|
return parse_yipbee(msg)
|
|
return parse_yipbee(msg)
|
|
except:
|
|
except:
|