patreon: New importer for new patron report CSV format.

This commit is contained in:
Brett Smith 2020-08-30 18:21:59 -04:00
parent e5b600dae6
commit 4bdea41c3f
5 changed files with 78 additions and 16 deletions

View file

@ -287,6 +287,18 @@ Patreon
``patreon income ledger entry`` ``patreon income ledger entry``
Imports one transaction per patron per month. Generated from Patreon's monthly patron report CSVs. Imports one transaction per patron per month. Generated from Patreon's monthly patron report CSVs.
This template can use these variables:
=============== ===========================================================
Name Contents
=============== ===========================================================
email The patron's email address on Patreon
--------------- -----------------------------------------------------------
tier The name of the tier the patron is supporting at
--------------- -----------------------------------------------------------
patreon_id The patron's user ID on Patreon
=============== ===========================================================
``patreon payout ledger entry`` ``patreon payout ledger entry``
Imports one transaction per month for that month's payout. Generated from Patreon's payout report CSV. Imports one transaction per month for that month's payout. Generated from Patreon's payout report CSV.

View file

@ -5,32 +5,31 @@ from . import _csv
from .. import strparse from .. import strparse
class IncomeImporter(_csv.CSVImporterBase): class IncomeImporter(_csv.CSVImporterBase):
AMOUNT_KEY = 'Pledge $'
DATE_KEY = 'Charged On Date'
STATUS_KEY = 'Charge Status'
NEEDED_FIELDS = frozenset([ NEEDED_FIELDS = frozenset([
'FirstName', AMOUNT_KEY,
'LastName', DATE_KEY,
'Pledge', STATUS_KEY,
'Status',
]) ])
COPIED_FIELDS = { COPIED_FIELDS = {
'Pledge': 'amount', 'Name': 'payee',
'Email': 'email',
'Tier': 'tier',
'User ID': 'patreon_id',
} }
ENTRY_SEED = { ENTRY_SEED = {
'currency': 'USD', 'currency': 'USD',
} }
def __init__(self, input_file):
super().__init__(input_file)
match = re.search(r'(?:\b|_)(\d{4}-\d{2}-\d{2})(?:\b|_)',
pathlib.Path(input_file.name).name)
if match:
self.entry_seed['date'] = strparse.date(match.group(1), '%Y-%m-%d')
def _read_row(self, row): def _read_row(self, row):
if row['Status'] != 'Processed': if row[self.STATUS_KEY] != 'Paid':
return None return None
else: else:
return { return {
'payee': '{0[FirstName]} {0[LastName]}'.format(row), 'amount': strparse.currency_decimal(row[self.AMOUNT_KEY]),
'date': strparse.date(row[self.DATE_KEY], '%Y-%m-%d %H:%M:%S'),
} }
@ -92,3 +91,33 @@ class VATImporter(FeeImporterBase):
'Country Code': 'country_code', 'Country Code': 'country_code',
'Country Name': 'country_name', 'Country Name': 'country_name',
} }
class Income2017Importer(_csv.CSVImporterBase):
NEEDED_FIELDS = frozenset([
'FirstName',
'LastName',
'Pledge',
'Status',
])
COPIED_FIELDS = {
'Pledge': 'amount',
}
ENTRY_SEED = {
'currency': 'USD',
}
def __init__(self, input_file):
super().__init__(input_file)
match = re.search(r'(?:\b|_)(\d{4}-\d{2}-\d{2})(?:\b|_)',
pathlib.Path(input_file.name).name)
if match:
self.entry_seed['date'] = strparse.date(match.group(1), '%Y-%m-%d')
def _read_row(self, row):
if row['Status'] != 'Processed':
return None
else:
return {
'payee': '{0[FirstName]} {0[LastName]}'.format(row),
}

View file

@ -30,7 +30,7 @@ REQUIREMENTS['tests_require'] = [
setup( setup(
name='import2ledger', name='import2ledger',
description="Import different sources of financial data to Ledger", description="Import different sources of financial data to Ledger",
version='1.0.0', version='1.1.0',
author='Brett Smith', author='Brett Smith',
author_email='brettcsmith@brettcsmith.org', author_email='brettcsmith@brettcsmith.org',
license='GNU AGPLv3+', license='GNU AGPLv3+',

View file

@ -0,0 +1,3 @@
Name,Email,Twitter,Patron Status,Follows You,Lifetime $,Pledge $,Charge Frequency,Tier,Addressee,Street,City,State,Zip,Country,Phone,Patronage Since Date,Max Amount,Charged On Date,Charge Status,Additional Details,User ID,Last Updated
Alex Jones,ajones@example.com,,Active patron,No,$28,$2,monthly,Even tier,,,,,,,,2019-10-30 18:25:15.457830,$2,2020-08-01 18:21:04,Paid,,1234567,2020-08-12 12:34:31.348413
Breonna,breonna@example.org,patreonb,Active patron,No,$5,$5,monthly,Odd tier,,,,,,,,2020-08-02 11:59:15.365305,$5,2020-08-02 12:00:02,Paid,,234567,2020-08-12 12:43:08.745681
1 Name Email Twitter Patron Status Follows You Lifetime $ Pledge $ Charge Frequency Tier Addressee Street City State Zip Country Phone Patronage Since Date Max Amount Charged On Date Charge Status Additional Details User ID Last Updated
2 Alex Jones ajones@example.com Active patron No $28 $2 monthly Even tier 2019-10-30 18:25:15.457830 $2 2020-08-01 18:21:04 Paid 1234567 2020-08-12 12:34:31.348413
3 Breonna breonna@example.org patreonb Active patron No $5 $5 monthly Odd tier 2020-08-02 11:59:15.365305 $5 2020-08-02 12:00:02 Paid 234567 2020-08-12 12:43:08.745681

View file

@ -1,5 +1,5 @@
- source: PatreonPatronReport_2017-09-01.csv - source: PatreonPatronReport_2017-09-01.csv
importer: patreon.IncomeImporter importer: patreon.Income2017Importer
expect: expect:
- payee: Alex Jones - payee: Alex Jones
date: !!python/object/apply:datetime.date [2017, 9, 1] date: !!python/object/apply:datetime.date [2017, 9, 1]
@ -10,6 +10,24 @@
amount: !!python/object/apply:decimal.Decimal ["12.00"] amount: !!python/object/apply:decimal.Decimal ["12.00"]
currency: USD currency: USD
- source: PatreonPatronReport_2020-08-01.csv
importer: patreon.IncomeImporter
expect:
- payee: Alex Jones
email: ajones@example.com
tier: Even tier
patreon_id: "1234567"
date: !!python/object/apply:datetime.date [2020, 8, 1]
amount: !!python/object/apply:decimal.Decimal ["2"]
currency: USD
- payee: Breonna
email: breonna@example.org
tier: Odd tier
patreon_id: "234567"
date: !!python/object/apply:datetime.date [2020, 8, 2]
amount: !!python/object/apply:decimal.Decimal ["5.00"]
currency: USD
- source: PatreonEarnings.csv - source: PatreonEarnings.csv
importer: patreon.ServiceFeesImporter importer: patreon.ServiceFeesImporter
expect: expect: