|  | @@ -28,11 +28,11 @@ class Order(object):
 | 
	
		
			
				|  |  |          self.order_date = order_date
 | 
	
		
			
				|  |  |          assert customer_id is None or type(customer_id) is unicode
 | 
	
		
			
				|  |  |          self.customer_id = customer_id
 | 
	
		
			
				|  |  | -        self.articles = []
 | 
	
		
			
				|  |  | +        self.items = []
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      def dict_repr(self):
 | 
	
		
			
				|  |  |          return {k: v for (k, v) in {
 | 
	
		
			
				|  |  | -            'articles': self.articles,
 | 
	
		
			
				|  |  | +            'articles': self.items,
 | 
	
		
			
				|  |  |              'customer_id': self.customer_id,
 | 
	
		
			
				|  |  |              'order_date': self.order_date.strftime('%Y-%m-%d'),
 | 
	
		
			
				|  |  |              'order_id': self.order_id,
 | 
	
	
		
			
				|  | @@ -41,6 +41,104 @@ class Order(object):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  yaml.SafeDumper.add_representer(Order, lambda dumper, order: dumper.represent_dict(order.dict_repr()))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +class Item(object):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(
 | 
	
		
			
				|  |  | +            self,
 | 
	
		
			
				|  |  | +            name = None,
 | 
	
		
			
				|  |  | +            price_brutto = None,
 | 
	
		
			
				|  |  | +            price_brutto_currency = None,
 | 
	
		
			
				|  |  | +            ):
 | 
	
		
			
				|  |  | +        assert type(name) is unicode
 | 
	
		
			
				|  |  | +        self.name = name
 | 
	
		
			
				|  |  | +        assert type(price_brutto) is float
 | 
	
		
			
				|  |  | +        self.price_brutto = price_brutto
 | 
	
		
			
				|  |  | +        if price_brutto_currency == u'€':
 | 
	
		
			
				|  |  | +            price_brutto_currency = u'EUR'
 | 
	
		
			
				|  |  | +        assert type(price_brutto_currency) is unicode
 | 
	
		
			
				|  |  | +        assert price_brutto_currency in [u'EUR']
 | 
	
		
			
				|  |  | +        self.price_brutto_currency = price_brutto_currency
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def dict_repr(self):
 | 
	
		
			
				|  |  | +        return {
 | 
	
		
			
				|  |  | +            'name': self.name,
 | 
	
		
			
				|  |  | +            'price_brutto': self.price_brutto,
 | 
	
		
			
				|  |  | +            'price_brutto_currency': self.price_brutto_currency,
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +yaml.SafeDumper.add_representer(Item, lambda dumper, item: dumper.represent_dict(item.dict_repr()))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Article(Item):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(
 | 
	
		
			
				|  |  | +            self,
 | 
	
		
			
				|  |  | +            authors = [],
 | 
	
		
			
				|  |  | +            state = None,
 | 
	
		
			
				|  |  | +            reseller = None,
 | 
	
		
			
				|  |  | +            shipper = None,
 | 
	
		
			
				|  |  | +            **kwargs
 | 
	
		
			
				|  |  | +            ):
 | 
	
		
			
				|  |  | +        super(Article, self).__init__(**kwargs)
 | 
	
		
			
				|  |  | +        assert type(authors) is list
 | 
	
		
			
				|  |  | +        self.authors = authors
 | 
	
		
			
				|  |  | +        assert state is None or type(state) is unicode
 | 
	
		
			
				|  |  | +        self.state = state
 | 
	
		
			
				|  |  | +        assert reseller is None or type(reseller) is unicode
 | 
	
		
			
				|  |  | +        self.reseller = reseller
 | 
	
		
			
				|  |  | +        assert shipper is None or type(shipper) is unicode
 | 
	
		
			
				|  |  | +        self.shipper = shipper
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def dict_repr(self):
 | 
	
		
			
				|  |  | +        attr = Item.dict_repr(self)
 | 
	
		
			
				|  |  | +        attr.update({
 | 
	
		
			
				|  |  | +            'state': self.state,
 | 
	
		
			
				|  |  | +            'reseller': self.reseller,
 | 
	
		
			
				|  |  | +            'shipper': self.shipper,
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +        if len(self.authors) > 0:
 | 
	
		
			
				|  |  | +            attr['authors'] = self.authors
 | 
	
		
			
				|  |  | +        return attr
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +yaml.SafeDumper.add_representer(Article, lambda dumper, article: dumper.represent_dict(article.dict_repr()))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Transportation(Item):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self, departure_point = None, destination_point = 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
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def dict_repr(self):
 | 
	
		
			
				|  |  | +        attr = Item.dict_repr(self)
 | 
	
		
			
				|  |  | +        attr.update({
 | 
	
		
			
				|  |  | +            'departure_point': self.departure_point,
 | 
	
		
			
				|  |  | +            'destination_point': self.destination_point,
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +        return attr
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +yaml.SafeDumper.add_representer(Transportation, lambda dumper, transportation: dumper.represent_dict(transportation.dict_repr()))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class TaxiRide(Transportation):
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __init__(self, driver = None, arrival_time = None, **kwargs):
 | 
	
		
			
				|  |  | +        super(TaxiRide, self).__init__(name = u'Taxi Ride', **kwargs)
 | 
	
		
			
				|  |  | +        assert type(driver) is unicode
 | 
	
		
			
				|  |  | +        self.driver = driver
 | 
	
		
			
				|  |  | +        assert type(arrival_time) is datetime.datetime
 | 
	
		
			
				|  |  | +        self.arrival_time = arrival_time
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def dict_repr(self):
 | 
	
		
			
				|  |  | +        attr = Transportation.dict_repr(self)
 | 
	
		
			
				|  |  | +        attr.update({
 | 
	
		
			
				|  |  | +            'driver': self.driver,
 | 
	
		
			
				|  |  | +            'arrival_time': self.arrival_time.strftime('%Y-%m-%d %H:%M'),
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +        return attr
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +yaml.SafeDumper.add_representer(TaxiRide, lambda dumper, taxi_ride: dumper.represent_dict(taxi_ride.dict_repr()))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  def parse_amazon(msg):
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      msg_text = msg.get_payload()[0].get_payload(decode = True).decode('utf-8')
 | 
	
	
		
			
				|  | @@ -57,7 +155,6 @@ def parse_amazon(msg):
 | 
	
		
			
				|  |  |          order_date
 | 
	
		
			
				|  |  |          )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    articles = []
 | 
	
		
			
				|  |  |      articles_text = msg_text.split('Bestellte(r) Artikel:')[1].split('_' * 10)[0].strip()
 | 
	
		
			
				|  |  |      for article_text in articles_text.split('\n\n'):
 | 
	
		
			
				|  |  |          article_match = re.match(
 | 
	
	
		
			
				|  | @@ -74,12 +171,15 @@ def parse_amazon(msg):
 | 
	
		
			
				|  |  |              sys.stderr.write(repr(article_text) + '\n')
 | 
	
		
			
				|  |  |              raise Exception('could not match article')
 | 
	
		
			
				|  |  |          article = article_match.groupdict()
 | 
	
		
			
				|  |  | -        if article['authors']:
 | 
	
		
			
				|  |  | -            article['authors'] = article['authors'].split(',')
 | 
	
		
			
				|  |  | -        else:
 | 
	
		
			
				|  |  | -            del article['authors']
 | 
	
		
			
				|  |  | -        article['price_brutto'] = float(article['price_brutto'].replace(',', '.'))
 | 
	
		
			
				|  |  | -        order.articles.append(article)
 | 
	
		
			
				|  |  | +        order.items.append(Article(
 | 
	
		
			
				|  |  | +            name = article['name'],
 | 
	
		
			
				|  |  | +            price_brutto = float(article['price_brutto'].replace(',', '.')),
 | 
	
		
			
				|  |  | +            price_brutto_currency = article['price_brutto_currency'],
 | 
	
		
			
				|  |  | +            authors = article['authors'].split(',') if article['authors'] else [],
 | 
	
		
			
				|  |  | +            state = article['state'],
 | 
	
		
			
				|  |  | +            reseller = article['reseller'],
 | 
	
		
			
				|  |  | +            shipper = article['shipper'],
 | 
	
		
			
				|  |  | +            ))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return order
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -115,7 +215,7 @@ def parse_oebb(msg):
 | 
	
		
			
				|  |  |          customer_id = order_match_groups['customer_id'],
 | 
	
		
			
				|  |  |          )
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    article_match = re.search(
 | 
	
		
			
				|  |  | +    item_match = re.search(
 | 
	
		
			
				|  |  |          ur'(?P<price_brutto_currency>.)(?P<price_brutto>\d+\.\d+)'
 | 
	
		
			
				|  |  |              + ur'[\W\w]+'
 | 
	
		
			
				|  |  |              + ur'Your Booking\s+'
 | 
	
	
		
			
				|  | @@ -123,14 +223,14 @@ def parse_oebb(msg):
 | 
	
		
			
				|  |  |          msg_text,
 | 
	
		
			
				|  |  |          re.MULTILINE | re.UNICODE
 | 
	
		
			
				|  |  |          )
 | 
	
		
			
				|  |  | -    article = article_match.groupdict()
 | 
	
		
			
				|  |  | -    article['name'] = 'Train Ticket'
 | 
	
		
			
				|  |  | -    article['price_brutto'] = float(article['price_brutto'])
 | 
	
		
			
				|  |  | -    if article['price_brutto_currency'] == u'€':
 | 
	
		
			
				|  |  | -        article['price_brutto_currency'] = 'EUR'
 | 
	
		
			
				|  |  | -    else:
 | 
	
		
			
				|  |  | -        raise Exception('currency %s is not supported' % article['price_brutto_currency'])
 | 
	
		
			
				|  |  | -    order.articles.append(article)
 | 
	
		
			
				|  |  | +    item = item_match.groupdict()
 | 
	
		
			
				|  |  | +    order.items.append(Transportation(
 | 
	
		
			
				|  |  | +        name = u'Train Ticket',
 | 
	
		
			
				|  |  | +        price_brutto = float(item['price_brutto']),
 | 
	
		
			
				|  |  | +        price_brutto_currency = item['price_brutto_currency'],
 | 
	
		
			
				|  |  | +        departure_point = item['departure_point'],
 | 
	
		
			
				|  |  | +        destination_point = item['destination_point'],
 | 
	
		
			
				|  |  | +        ))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return order
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -155,7 +255,7 @@ def parse_mytaxi(msg):
 | 
	
		
			
				|  |  |          )
 | 
	
		
			
				|  |  |      order_id = order_match.groupdict()['order_id']
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    article_match = re.search(
 | 
	
		
			
				|  |  | +    ride_match_groups = re.search(
 | 
	
		
			
				|  |  |          ur'\(Bruttobetrag\)'
 | 
	
		
			
				|  |  |              + ur'[^\(]+'
 | 
	
		
			
				|  |  |              + ur'\((?P<price_brutto>\d+,\d+) (?P<price_brutto_currency>.+)\)'
 | 
	
	
		
			
				|  | @@ -173,26 +273,30 @@ def parse_mytaxi(msg):
 | 
	
		
			
				|  |  |              + ur'Belegdatum \\\(Leistungszeitpunkt\\\):[^\(]+\((?P<arrival_time>\d\d.\d\d.\d\d \d\d:\d\d)\)',
 | 
	
		
			
				|  |  |          pdf_uncompressed,
 | 
	
		
			
				|  |  |          re.MULTILINE | re.UNICODE
 | 
	
		
			
				|  |  | -        )
 | 
	
		
			
				|  |  | -    article = article_match.groupdict()
 | 
	
		
			
				|  |  | -    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
 | 
	
		
			
				|  |  | +        ).groupdict()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      arrival_time = datetime.datetime.strptime(
 | 
	
		
			
				|  |  | -        article['arrival_time'],
 | 
	
		
			
				|  |  | +        ride_match_groups['arrival_time'],
 | 
	
		
			
				|  |  |          '%d.%m.%y %H:%M'
 | 
	
		
			
				|  |  |          )
 | 
	
		
			
				|  |  | -    article['arrival_time'] = arrival_time.strftime('%Y-%m-%d %H:%M')
 | 
	
		
			
				|  |  | -    article['price_brutto'] = float(article['price_brutto'].replace(',', '.'))
 | 
	
		
			
				|  |  | -    if article['price_brutto_currency'] in [u'€', u'\x80']:
 | 
	
		
			
				|  |  | -        article['price_brutto_currency'] = 'EUR'
 | 
	
		
			
				|  |  | -    else:
 | 
	
		
			
				|  |  | -        raise Exception('currency %s is not supported' % article['price_brutto_currency'])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      order = Order(
 | 
	
		
			
				|  |  |          u'mytaxi',
 | 
	
		
			
				|  |  |          order_id,
 | 
	
		
			
				|  |  |          arrival_time,
 | 
	
		
			
				|  |  |          )
 | 
	
		
			
				|  |  | -    order.articles.append(article)
 | 
	
		
			
				|  |  | +    locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
 | 
	
		
			
				|  |  | +    order.items.append(TaxiRide(
 | 
	
		
			
				|  |  | +        price_brutto = float(ride_match_groups['price_brutto'].replace(',', '.')),
 | 
	
		
			
				|  |  | +        # why 0x80 ?
 | 
	
		
			
				|  |  | +        price_brutto_currency = u'EUR'
 | 
	
		
			
				|  |  | +            if (ride_match_groups['price_brutto_currency'] == u'\x80')
 | 
	
		
			
				|  |  | +            else ride_match_groups['price_brutto_currency'],
 | 
	
		
			
				|  |  | +        departure_point = ride_match_groups['departure_point'],
 | 
	
		
			
				|  |  | +        destination_point = ride_match_groups['destination_point'],
 | 
	
		
			
				|  |  | +        driver = ride_match_groups['driver'],
 | 
	
		
			
				|  |  | +        arrival_time = arrival_time,
 | 
	
		
			
				|  |  | +        ))
 | 
	
		
			
				|  |  |      return order
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  def parse(msg):
 |