From 309ea4ac6ae900171a297977aa34e8df0505302c Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Tue, 3 Jul 2018 10:24:21 -0400 Subject: [PATCH] oreilly: New importer. --- README.rst | 30 ++++++++++ import2ledger/importers/oreilly.py | 62 ++++++++++++++++++++ tests/data/OReillyPayments.csv | 7 +++ tests/data/OReillyRoyalties.csv | 10 ++++ tests/data/imports.yml | 92 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+) create mode 100644 import2ledger/importers/oreilly.py create mode 100644 tests/data/OReillyPayments.csv create mode 100644 tests/data/OReillyRoyalties.csv diff --git a/README.rst b/README.rst index fd9412d..190897b 100644 --- a/README.rst +++ b/README.rst @@ -165,6 +165,36 @@ BrightFunds type From the corresponding spreadsheet column ================ =========================================================== +O'Reilly Media +^^^^^^^^^^^^^^ + +``oreilly payments ledger entry`` + Imports one transaction per payment. Generated from CSV export of O'Reilly's payment history. + + This template can use these variables: + + ================ =========================================================== + Name Contents + ================ =========================================================== + paid_date From the corresponding spreadsheet column. This is usually + the end of the month, while the actual transaction date + might be slightly off. + ---------------- ----------------------------------------------------------- + +``oreilly royalties ledger entry`` + Imports one transaction per royalty period (usually a month, historically a quarter). Generated from CSV export of O'Reilly's royalties statement. + + This template can use these variables: + + ================ =========================================================== + Name Contents + ================ =========================================================== + start_date From the corresponding spreadsheet column + ---------------- ----------------------------------------------------------- + paid_date From the corresponding spreadsheet column. This + corresponds to a row in the payment history as well. + ---------------- ----------------------------------------------------------- + Patreon ^^^^^^^ diff --git a/import2ledger/importers/oreilly.py b/import2ledger/importers/oreilly.py new file mode 100644 index 0000000..0d1016e --- /dev/null +++ b/import2ledger/importers/oreilly.py @@ -0,0 +1,62 @@ +import itertools + +from . import _csv +from .. import strparse + +DATE_FMT = '%B %d, %Y' + +class PaymentsImporter(_csv.CSVImporterBase): + NEEDED_FIELDS = frozenset(['Date', 'Payment Amount', 'Paid Date']) + ENTRY_SEED = { + 'currency': 'USD', + 'payee': "O'Reilly Media, Inc.", + } + + def _read_row(self, row): + return { + 'amount': strparse.currency_decimal(row['Payment Amount']), + 'date': strparse.date(row['Date'], DATE_FMT), + 'paid_date': strparse.date(row['Paid Date'], DATE_FMT), + } + + +class RoyaltiesImporter(_csv.CSVImporterBase): + SENTINEL_ROW = { + 'Start date': 'January 2, 1979', + 'End date': 'January 3, 1979', + 'Amount': '$0.00', + 'Paid Date': 'January 4, 1979', + } + NEEDED_FIELDS = frozenset(SENTINEL_ROW.keys()) + ENTRY_SEED = { + 'currency': 'USD', + 'payee': "O'Reilly Media, Inc.", + } + + def _paid_date(self, date_s): + return None if (date_s == 'null') else strparse.date(date_s, DATE_FMT) + + def __init__(self, input_file): + super().__init__(input_file) + self.in_csv = itertools.chain(self.in_csv, [self.SENTINEL_ROW]) + self.last_row = next(self.in_csv) + self.last_amount = strparse.currency_decimal(self.last_row['Amount']) + self.last_paid_date = self._paid_date(self.last_row['Paid Date']) + + def _read_row(self, row): + row_amount = strparse.currency_decimal(row['Amount']) + row_paid_date = self._paid_date(row['Paid Date']) + if row_paid_date is None: + amount = self.last_amount - row_amount + else: + amount = self.last_amount + retval = { + 'amount': amount, + 'date': strparse.date(self.last_row['End date'], DATE_FMT), + 'paid_date': self.last_paid_date, + 'start_date': strparse.date(self.last_row['Start date'], DATE_FMT), + } + self.last_row = row + self.last_amount = row_amount + self.last_paid_date = row_paid_date or self.last_paid_date + return retval diff --git a/tests/data/OReillyPayments.csv b/tests/data/OReillyPayments.csv new file mode 100644 index 0000000..dd54f20 --- /dev/null +++ b/tests/data/OReillyPayments.csv @@ -0,0 +1,7 @@ +"Date","Royalty Reference #","Payment Amount","Paid Date","Statement Period" +"March 29, 2018","AP-100171","$29.34","March 29, 2018","FEB 2018 O'Reilly" +"April 27, 2017","AP-100157","$26.91","April 28, 2017","MAR 2017 O'Reilly" +"April 24, 2017","AP-100141","$21.48","April 28, 2017","JAN 2017 O'Reilly" +"December 16, 2016","AP-100125","$26.19","December 16, 2016","SEP 2016 O'Reilly" +"November 29, 2016","AP-100112","$27.58","November 30, 2016","AUG 2016 O'Reilly" +"March 31, 2010","AP-100106","$73.85","March 31, 2010","Q1 2010 O'Reilly" diff --git a/tests/data/OReillyRoyalties.csv b/tests/data/OReillyRoyalties.csv new file mode 100644 index 0000000..5fee377 --- /dev/null +++ b/tests/data/OReillyRoyalties.csv @@ -0,0 +1,10 @@ +"Journal Batch Name","Start date","End date","Amount","Paid Date" +"MAR 2018 O'Reilly","March 01, 2018","March 31, 2018","$11.96","null" +"FEB 2018 O'Reilly","February 01, 2018","February 28, 2018","$29.34","March 29, 2018" +"JAN 2018 O'Reilly","January 01, 2018","January 31, 2018","$8.51","null" +"MAR 2017 O'Reilly","March 01, 2017","March 31, 2017","$26.91","April 28, 2017" +"JAN 2017 O'Reilly","January 01, 2017","January 31, 2017","$21.48","April 28, 2017" +"DEC 2016 O'Reilly","December 01, 2016","December 31, 2016","$9.15","null" +"SEP 2016 O'Reilly","September 01, 2016","September 30, 2016","$26.19","December 16, 2016" +"AUG 2016 O'Reilly","August 01, 2016","August 31, 2016","$27.58","November 30, 2016" +"Q1 2010 O'Reilly","January 01, 2010","March 31, 2010","$73.85","March 31, 2010" diff --git a/tests/data/imports.yml b/tests/data/imports.yml index 88baf34..3a809be 100644 --- a/tests/data/imports.yml +++ b/tests/data/imports.yml @@ -337,3 +337,95 @@ fund: "" on_behalf_of: Dakota Smith type: Matched Donation + +- source: OReillyRoyalties.csv + importer: oreilly.RoyaltiesImporter + expect: + - date: !!python/object/apply:datetime.date [2018, 3, 31] + start_date: !!python/object/apply:datetime.date [2018, 3, 1] + paid_date: null + currency: USD + amount: !!python/object/apply:decimal.Decimal ["11.96"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2018, 2, 28] + start_date: !!python/object/apply:datetime.date [2018, 2, 1] + paid_date: !!python/object/apply:datetime.date [2018, 3, 29] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["20.83"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2018, 1, 31] + start_date: !!python/object/apply:datetime.date [2018, 1, 1] + paid_date: !!python/object/apply:datetime.date [2018, 3, 29] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["8.51"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2017, 3, 31] + start_date: !!python/object/apply:datetime.date [2017, 3, 1] + paid_date: !!python/object/apply:datetime.date [2017, 4, 28] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["26.91"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2017, 1, 31] + start_date: !!python/object/apply:datetime.date [2017, 1, 1] + paid_date: !!python/object/apply:datetime.date [2017, 4, 28] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["12.33"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2016, 12, 31] + start_date: !!python/object/apply:datetime.date [2016, 12, 1] + paid_date: !!python/object/apply:datetime.date [2017, 4, 28] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["9.15"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2016, 9, 30] + start_date: !!python/object/apply:datetime.date [2016, 9, 1] + paid_date: !!python/object/apply:datetime.date [2016, 12, 16] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["26.19"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2016, 8, 31] + start_date: !!python/object/apply:datetime.date [2016, 8, 1] + paid_date: !!python/object/apply:datetime.date [2016, 11, 30] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["27.58"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2010, 3, 31] + start_date: !!python/object/apply:datetime.date [2010, 1, 1] + paid_date: !!python/object/apply:datetime.date [2010, 3, 31] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["73.85"] + payee: "O'Reilly Media, Inc." + +- source: OReillyPayments.csv + importer: oreilly.PaymentsImporter + expect: + - date: !!python/object/apply:datetime.date [2018, 3, 29] + paid_date: !!python/object/apply:datetime.date [2018, 3, 29] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["29.34"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2017, 4, 27] + paid_date: !!python/object/apply:datetime.date [2017, 4, 28] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["26.91"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2017, 4, 24] + paid_date: !!python/object/apply:datetime.date [2017, 4, 28] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["21.48"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2016, 12, 16] + paid_date: !!python/object/apply:datetime.date [2016, 12, 16] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["26.19"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2016, 11, 29] + paid_date: !!python/object/apply:datetime.date [2016, 11, 30] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["27.58"] + payee: "O'Reilly Media, Inc." + - date: !!python/object/apply:datetime.date [2010, 3, 31] + paid_date: !!python/object/apply:datetime.date [2010, 3, 31] + currency: USD + amount: !!python/object/apply:decimal.Decimal ["73.85"] + payee: "O'Reilly Media, Inc."