From a0f8d41d8e98b8dc5db137449a87ca5009ba152c Mon Sep 17 00:00:00 2001 From: Brett Smith Date: Thu, 4 Jul 2019 19:10:11 -0400 Subject: [PATCH] importers: New importer eventbrite. --- README.rst | 37 ++++++++++++++++ import2ledger/importers/eventbrite.py | 47 ++++++++++++++++++++ setup.py | 2 +- tests/data/EventBrite.csv | 11 +++++ tests/data/imports.yml | 64 +++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 import2ledger/importers/eventbrite.py create mode 100644 tests/data/EventBrite.csv diff --git a/README.rst b/README.rst index e8da0c2..5d8fe53 100644 --- a/README.rst +++ b/README.rst @@ -180,6 +180,43 @@ BrightFunds type From the corresponding spreadsheet column ================ =========================================================== +Eventbrite +^^^^^^^^^^ + +``eventbrite sales ledger entry`` + Imports one transaction per ticket sale transaction. Generated from CSV export of Eventbrite sales report. + + NOTE: This importer currently only imports sales in the Completed status. In particular, it does not import refunds. It may be extended in the future. + + This template can use these variables. Note that many of the informational fields may be empty if their corresponding columns do not appear in the export. + + ================ =========================================================== + Name Contents + ================ =========================================================== + attendee_id From the ``Attendee #`` spreadsheet column + ---------------- ----------------------------------------------------------- + corporation From the ``Company`` spreadsheet column + ---------------- ----------------------------------------------------------- + event_id From the corresponding spreadsheet column + ---------------- ----------------------------------------------------------- + event_name From the corresponding spreadsheet column + ---------------- ----------------------------------------------------------- + eventbrite_fees From the corresponding spreadsheet column + ---------------- ----------------------------------------------------------- + order_id From the ``Order #`` spreadsheet column + ---------------- ----------------------------------------------------------- + payment_fees From the ``Eventbrite Payment Processing`` spreadsheet + column + ---------------- ----------------------------------------------------------- + quantity From the corresponding spreadsheet column + ---------------- ----------------------------------------------------------- + tax From the ``Tax Paid`` spreadsheet column + ---------------- ----------------------------------------------------------- + ticket_type From the corresponding spreadsheet column + ---------------- ----------------------------------------------------------- + total_fees From the ``Fees Paid`` spreadsheet column + ================ =========================================================== + O'Reilly Media ^^^^^^^^^^^^^^ diff --git a/import2ledger/importers/eventbrite.py b/import2ledger/importers/eventbrite.py new file mode 100644 index 0000000..9958275 --- /dev/null +++ b/import2ledger/importers/eventbrite.py @@ -0,0 +1,47 @@ +import decimal + +from . import _csv +from .. import strparse + +class SalesImporter(_csv.CSVImporterBase): + DECIMAL_FIELDS = { + 'Eventbrite Fees': 'eventbrite_fees', + 'Eventbrite Payment Processing': 'payment_fees', + 'Fees Paid': 'total_fees', + 'Quantity': 'quantity', + 'Tax Paid': 'tax', + 'Total Paid': 'amount', + } + NEEDED_FIELDS = frozenset([ + 'Order Date', + 'Order Type', + *DECIMAL_FIELDS, + ]) + OPTIONAL_FIELDS = { + 'Attendee #': 'attendee_id', + 'Company': 'corporation', + 'Event ID': 'event_id', + 'Event Name': 'event_name', + 'Order #': 'order_id', + 'Ticket Type': 'ticket_type', + } + ENTRY_SEED = {'currency': 'USD'} + + def _read_row(self, row): + if row['Order Type'] != 'Eventbrite Completed': + return None + retval = { + self.DECIMAL_FIELDS[key]: strparse.currency_decimal(row[key]) + for key in self.DECIMAL_FIELDS + } + date_s, _, _ = row['Order Date'].partition(' ') + retval['date'] = strparse.date(date_s, '%Y-%m-%d') + try: + retval['payee'] = '{Buyer First Name} {Buyer Last Name}'.format_map(row) + except KeyError: + retval['payee'] = '{First Name} {Last Name}'.format_map(row) + retval.update( + (self.OPTIONAL_FIELDS[key], row.get(key, '')) + for key in self.OPTIONAL_FIELDS + ) + return retval diff --git a/setup.py b/setup.py index b1bc649..8aac7df 100755 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ REQUIREMENTS['tests_require'] = [ setup( name='import2ledger', description="Import different sources of financial data to Ledger", - version='0.8.0', + version='0.9.0', author='Brett Smith', author_email='brettcsmith@brettcsmith.org', license='GNU AGPLv3+', diff --git a/tests/data/EventBrite.csv b/tests/data/EventBrite.csv new file mode 100644 index 0000000..83b71d8 --- /dev/null +++ b/tests/data/EventBrite.csv @@ -0,0 +1,11 @@ +Event Name,Event ID,Order #,Order Date,First Name,Last Name,Email,Quantity,Price Tier,Ticket Type,Attendee #,Buyer Last Name,Buyer First Name,Buyer Email,Name/Company on Tax Receipt,Buyer Type,Tax Registration ID,Discount,Hold,Order Type,Total Paid,Fees Paid,Eventbrite Fees,Eventbrite Payment Processing,Tax Paid,Attendee Status,Billing Address 1,Billing Address 2,Billing City,Billing State,Billing Zip,Billing Country,Tax Address 1,Tax Address 2,Tax City,Tax State,Tax Zip,Tax Country,Company +First Event,12345678901,123432101,2018-11-27 09:24:37-05:00,Alex,Jones,aj@example.com,1,,Discount Ticket,432123401,Jones,Alex,aj@example.com,,Individual,,,,Eventbrite Completed,10,3.99,2.99,1,0,Attending,,,,,,,,,,,,, +First Event,12345678901,123432102,2018-12-06 08:35:01-05:00,Bret,Baker,bb@example.com,1,,Regular Ticket,432123402,Baker,Bret,bb@example.com,,Individual,,,,Eventbrite Completed,30,3.99,2.99,1,0,Attending,,,,,,,,,,,,, +First Event,12345678901,123432103,2019-01-07 15:09:14-05:00,Cam,Smith,cs@example.com,1,,Premium Ticket,432123403,Smith,Cam,cs@example.com,,Individual,,,,Eventbrite Completed,60,6.39,4.39,2,0,Attending,,,,,,,,,,,,,SampleCo +First Event,12345678901,123432104,2019-01-18 10:53:42-05:00,Dakota,Jones,dj@example.com,1,,Discount Ticket,432123404,Jones,Dakota,dj@example.com,,Individual,,,,Eventbrite Refunded,10,3.99,2.99,1,0,Not Attending,,,,,,,,,,,,, +First Event,12345678901,123432105,2019-01-08 12:37:25-05:00,Eir,Baker,eb@example.com,1,,Regular Ticket,432123405,Baker,Eir,eb@example.com,,Individual,,,,Eventbrite Refunded,30,3.99,2.99,1,0,Not Attending,,,,,,,,,,,,, +First Event,12345678901,123432106,2019-01-22 10:11:42-05:00,Fey,Smith,fs@example.com,1,,Premium Ticket,432123406,Smith,Fey,fs@example.com,,Individual,,,,Eventbrite Refunded,60,6.39,4.39,2,0,Not Attending,,,,,,,,,,,,, +First Event,12345678901,123432107,2019-01-15 14:32:23-05:00,Gir,Jones,gj@example.com,1,,Discount Ticket,432123407,Jones,Gir,gj@example.com,,Individual,,codeword,,Free Order,0,0,0,0,0,Attending,,,,,,,,,,,,, +First Event,12345678901,123432108,2019-02-01 12:13:48-05:00,Hal,Baker,hb@example.com,1,,Regular Ticket,432123408,Baker,Hal,hb@example.com,,Individual,,codeword,,Free Order,0,0,0,0,0,Attending,,,,,,,,,,,,, +First Event,12345678901,123432109,2019-01-11 12:55:34-05:00,Iris,Smith,is@example.com,1,,Premium Ticket,432123409,Smith,Iris,is@example.com,,Individual,,codeword,,Free Order,0,0,0,0,0,Attending,,,,,,,,,,,,, +Second Event,12345678902,123432110,2019-01-23 13:30:12-05:00,Jam,Jones,jj@example.com,1,,Discount Ticket,432123410,Jones,Jam,jj@example.com,,Individual,,,,Eventbrite Completed,25,3.99,2.99,1,0,Attending,,,,,,,,,,,,, diff --git a/tests/data/imports.yml b/tests/data/imports.yml index 6f89039..fdafd4d 100644 --- a/tests/data/imports.yml +++ b/tests/data/imports.yml @@ -678,3 +678,67 @@ payee: Alex Jones donor: Alex Jones corporation: Company C + +- source: EventBrite.csv + importer: eventbrite.SalesImporter + expect: + - date: !!python/object/apply:datetime.date [2018, 11, 27] + currency: USD + event_name: First Event + event_id: "12345678901" + order_id: "123432101" + attendee_id: "432123401" + payee: Alex Jones + corporation: "" + ticket_type: Discount Ticket + quantity: !!python/object/apply:decimal.Decimal ["1"] + amount: !!python/object/apply:decimal.Decimal ["10"] + total_fees: !!python/object/apply:decimal.Decimal ["3.99"] + eventbrite_fees: !!python/object/apply:decimal.Decimal ["2.99"] + payment_fees: !!python/object/apply:decimal.Decimal ["1"] + tax: !!python/object/apply:decimal.Decimal [0] + - date: !!python/object/apply:datetime.date [2018, 12, 6] + currency: USD + event_name: First Event + event_id: "12345678901" + order_id: "123432102" + attendee_id: "432123402" + payee: Bret Baker + corporation: "" + ticket_type: Regular Ticket + quantity: !!python/object/apply:decimal.Decimal ["1"] + amount: !!python/object/apply:decimal.Decimal ["30"] + total_fees: !!python/object/apply:decimal.Decimal ["3.99"] + eventbrite_fees: !!python/object/apply:decimal.Decimal ["2.99"] + payment_fees: !!python/object/apply:decimal.Decimal ["1"] + tax: !!python/object/apply:decimal.Decimal [0] + - date: !!python/object/apply:datetime.date [2019, 1, 7] + currency: USD + event_name: First Event + event_id: "12345678901" + order_id: "123432103" + attendee_id: "432123403" + payee: Cam Smith + corporation: SampleCo + ticket_type: Premium Ticket + quantity: !!python/object/apply:decimal.Decimal ["1"] + amount: !!python/object/apply:decimal.Decimal ["60"] + total_fees: !!python/object/apply:decimal.Decimal ["6.39"] + eventbrite_fees: !!python/object/apply:decimal.Decimal ["4.39"] + payment_fees: !!python/object/apply:decimal.Decimal ["2"] + tax: !!python/object/apply:decimal.Decimal [0] + - date: !!python/object/apply:datetime.date [2019, 1, 23] + currency: USD + event_name: Second Event + event_id: "12345678902" + order_id: "123432110" + attendee_id: "432123410" + payee: Jam Jones + corporation: "" + ticket_type: Discount Ticket + quantity: !!python/object/apply:decimal.Decimal ["1"] + amount: !!python/object/apply:decimal.Decimal ["25"] + total_fees: !!python/object/apply:decimal.Decimal ["3.99"] + eventbrite_fees: !!python/object/apply:decimal.Decimal ["2.99"] + payment_fees: !!python/object/apply:decimal.Decimal ["1"] + tax: !!python/object/apply:decimal.Decimal [0]