From 668906b944c1a123f97e124e3776151b9ded1dd1 Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Mon, 18 Dec 2017 10:47:04 -0500 Subject: [PATCH] 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. --- import2ledger/importers/nbpy2017.py | 30 ++++++++++++----- tests/data/imports.yml | 51 +++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/import2ledger/importers/nbpy2017.py b/import2ledger/importers/nbpy2017.py index bfa0ca6..338871a 100644 --- a/import2ledger/importers/nbpy2017.py +++ b/import2ledger/importers/nbpy2017.py @@ -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 diff --git a/tests/data/imports.yml b/tests/data/imports.yml index 42bb022..18b950b 100644 --- a/tests/data/imports.yml +++ b/tests/data/imports.yml @@ -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"