importers.nbpy2017: Yield entries for the original invoice.
This lets us write up a cleaner separation between the original act of invoicing and the Stripe payment.
This commit is contained in:
		
							parent
							
								
									fb0e4f2235
								
							
						
					
					
						commit
						668906b944
					
				
					 2 changed files with 72 additions and 9 deletions
				
			
		| 
						 | 
				
			
			@ -4,6 +4,10 @@ import functools
 | 
			
		|||
import bs4
 | 
			
		||||
from .. import util
 | 
			
		||||
 | 
			
		||||
STATUS_INVOICED = 'Invoice'
 | 
			
		||||
STATUS_PAID = 'Payment'
 | 
			
		||||
STATUS_REFUNDED = 'Refund'
 | 
			
		||||
 | 
			
		||||
class Invoice2017:
 | 
			
		||||
    STANDARD_TICKET_RATE = decimal.Decimal('42.50')
 | 
			
		||||
    DISCOUNT_TICKET_RATE = STANDARD_TICKET_RATE / 2
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +50,7 @@ class Invoice2017:
 | 
			
		|||
        self.base_data = {
 | 
			
		||||
            'amount': self.amount,
 | 
			
		||||
            'currency': self.CURRENCY,
 | 
			
		||||
            'invoice_date': self.invoice_date,
 | 
			
		||||
            'invoice_id': self.invoice_id,
 | 
			
		||||
            'payee': self.payee,
 | 
			
		||||
            'shirt_rate': self.shirt_rate,
 | 
			
		||||
| 
						 | 
				
			
			@ -62,6 +67,9 @@ class Invoice2017:
 | 
			
		|||
 | 
			
		||||
    def _read_invoice_header(self, table, first_row_text, rows_text):
 | 
			
		||||
        self.invoice_id = first_row_text[1]
 | 
			
		||||
        for key, value in rows_text:
 | 
			
		||||
            if key == 'Issue date':
 | 
			
		||||
                self.invoice_date = self._strpdate(value)
 | 
			
		||||
        recipient_h = table.find('th', text='Recipient')
 | 
			
		||||
        recipient_cell = recipient_h.find_next_sibling('td')
 | 
			
		||||
        self.payee = next(recipient_cell.stripped_strings)
 | 
			
		||||
| 
						 | 
				
			
			@ -83,13 +91,16 @@ class Invoice2017:
 | 
			
		|||
                self.amount += decimal.Decimal(total.lstrip('$'))
 | 
			
		||||
 | 
			
		||||
    def _read_invoice_activity(self, table, first_row_text, rows_text):
 | 
			
		||||
        self.actions = []
 | 
			
		||||
        self.actions = [{
 | 
			
		||||
            'date': self.invoice_date,
 | 
			
		||||
            'status': STATUS_INVOICED,
 | 
			
		||||
        }]
 | 
			
		||||
        for timestamp, description, amount in rows_text:
 | 
			
		||||
            if description.startswith('Paid '):
 | 
			
		||||
                last_stripe_id = util.rslice_words(description, 1, limit=1)
 | 
			
		||||
                action = {
 | 
			
		||||
                    'multiplier': 1,
 | 
			
		||||
                    'payment_id': last_stripe_id,
 | 
			
		||||
                    'status': STATUS_PAID,
 | 
			
		||||
                }
 | 
			
		||||
            else:
 | 
			
		||||
                # Refund handling could go here, if we need it.
 | 
			
		||||
| 
						 | 
				
			
			@ -102,9 +113,6 @@ class Invoice2017:
 | 
			
		|||
        for action in self.actions:
 | 
			
		||||
            data = self.base_data.copy()
 | 
			
		||||
            data.update(action)
 | 
			
		||||
            multiplier = data.pop('multiplier')
 | 
			
		||||
            for key in ['amount', 'tickets_sold', 'shirts_sold']:
 | 
			
		||||
                data[key] *= multiplier
 | 
			
		||||
            yield data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,13 +137,17 @@ class ImporterBase:
 | 
			
		|||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        for entry in self.invoice:
 | 
			
		||||
            if self._should_yield_entry(entry):
 | 
			
		||||
            if entry['status'] == self.YIELD_STATUS:
 | 
			
		||||
                yield entry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Invoice2017Importer(ImporterBase):
 | 
			
		||||
    TEMPLATE_KEY = 'template nbpy2017 invoice'
 | 
			
		||||
    INVOICE_CLASS = Invoice2017
 | 
			
		||||
    YIELD_STATUS = STATUS_INVOICED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Payment2017Importer(ImporterBase):
 | 
			
		||||
    TEMPLATE_KEY = 'template nbpy2017 payment'
 | 
			
		||||
    INVOICE_CLASS = Invoice2017
 | 
			
		||||
 | 
			
		||||
    def _should_yield_entry(self, entry):
 | 
			
		||||
        return entry['amount'] > 0
 | 
			
		||||
    YIELD_STATUS = STATUS_PAID
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,6 +82,51 @@
 | 
			
		|||
      payment_id: ch_hHee9ef1aeyee1ruo7ochee9
 | 
			
		||||
      description: "Payment for invoice #100"
 | 
			
		||||
 | 
			
		||||
- source: nbpy2017a.html
 | 
			
		||||
  importer: nbpy2017.Invoice2017Importer
 | 
			
		||||
  expect:
 | 
			
		||||
    - payee: Python Person A
 | 
			
		||||
      date: !!python/object/apply:datetime.date [2017, 10, 19]
 | 
			
		||||
      amount: !!python/object/apply:decimal.Decimal ["80.00"]
 | 
			
		||||
      tickets_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      ticket_rate: !!python/object/apply:decimal.Decimal ["21.25"]
 | 
			
		||||
      shirts_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      shirt_rate: !!python/object/apply:decimal.Decimal ["25.50"]
 | 
			
		||||
      currency: USD
 | 
			
		||||
      status: Invoice
 | 
			
		||||
      invoice_id: "83"
 | 
			
		||||
      invoice_date: !!python/object/apply:datetime.date [2017, 10, 19]
 | 
			
		||||
 | 
			
		||||
- source: nbpy2017b.html
 | 
			
		||||
  importer: nbpy2017.Invoice2017Importer
 | 
			
		||||
  expect:
 | 
			
		||||
    - payee: Python Person B
 | 
			
		||||
      date: !!python/object/apply:datetime.date [2017, 12, 3]
 | 
			
		||||
      amount: !!python/object/apply:decimal.Decimal ["50.00"]
 | 
			
		||||
      tickets_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      ticket_rate: !!python/object/apply:decimal.Decimal ["42.50"]
 | 
			
		||||
      shirts_sold: !!python/object/apply:decimal.Decimal ["0"]
 | 
			
		||||
      shirt_rate: !!python/object/apply:decimal.Decimal ["25.50"]
 | 
			
		||||
      status: Invoice
 | 
			
		||||
      currency: USD
 | 
			
		||||
      invoice_date: !!python/object/apply:datetime.date [2017, 12, 3]
 | 
			
		||||
      invoice_id: "304"
 | 
			
		||||
 | 
			
		||||
- source: nbpy2017c.html
 | 
			
		||||
  importer: nbpy2017.Invoice2017Importer
 | 
			
		||||
  expect:
 | 
			
		||||
    - payee: Python Person C
 | 
			
		||||
      date: !!python/object/apply:datetime.date [2017, 10, 5]
 | 
			
		||||
      amount: !!python/object/apply:decimal.Decimal ["55.00"]
 | 
			
		||||
      tickets_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      ticket_rate: !!python/object/apply:decimal.Decimal ["21.25"]
 | 
			
		||||
      shirts_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      shirt_rate: !!python/object/apply:decimal.Decimal ["25.50"]
 | 
			
		||||
      status: Invoice
 | 
			
		||||
      currency: USD
 | 
			
		||||
      invoice_date: !!python/object/apply:datetime.date [2017, 10, 5]
 | 
			
		||||
      invoice_id: "11"
 | 
			
		||||
 | 
			
		||||
- source: nbpy2017a.html
 | 
			
		||||
  importer: nbpy2017.Payment2017Importer
 | 
			
		||||
  expect:
 | 
			
		||||
| 
						 | 
				
			
			@ -93,7 +138,9 @@
 | 
			
		|||
      shirts_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      shirt_rate: !!python/object/apply:decimal.Decimal ["25.50"]
 | 
			
		||||
      currency: USD
 | 
			
		||||
      status: Payment
 | 
			
		||||
      invoice_id: "83"
 | 
			
		||||
      invoice_date: !!python/object/apply:datetime.date [2017, 10, 19]
 | 
			
		||||
      payment_id: ch_ahr0ue8lai1ohqu4Gei4Biem
 | 
			
		||||
      stripe_id: ch_ahr0ue8lai1ohqu4Gei4Biem
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +154,9 @@
 | 
			
		|||
      ticket_rate: !!python/object/apply:decimal.Decimal ["42.50"]
 | 
			
		||||
      shirts_sold: !!python/object/apply:decimal.Decimal ["0"]
 | 
			
		||||
      shirt_rate: !!python/object/apply:decimal.Decimal ["25.50"]
 | 
			
		||||
      status: Payment
 | 
			
		||||
      currency: USD
 | 
			
		||||
      invoice_date: !!python/object/apply:datetime.date [2017, 12, 3]
 | 
			
		||||
      payment_id: ch_eishei9aiY8aiqu4lieYiu9i
 | 
			
		||||
      stripe_id: ch_eishei9aiY8aiqu4lieYiu9i
 | 
			
		||||
      invoice_id: "304"
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +171,9 @@
 | 
			
		|||
      ticket_rate: !!python/object/apply:decimal.Decimal ["21.25"]
 | 
			
		||||
      shirts_sold: !!python/object/apply:decimal.Decimal ["1"]
 | 
			
		||||
      shirt_rate: !!python/object/apply:decimal.Decimal ["25.50"]
 | 
			
		||||
      status: Payment
 | 
			
		||||
      currency: USD
 | 
			
		||||
      invoice_date: !!python/object/apply:datetime.date [2017, 10, 5]
 | 
			
		||||
      payment_id: ch_daer0ahwoh9oDeiqu2eimoD7
 | 
			
		||||
      stripe_id: ch_daer0ahwoh9oDeiqu2eimoD7
 | 
			
		||||
      invoice_id: "11"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue