import2ledger/import2ledger/importers/patreon.py
Brett Smith 742fccca0c patreon: Exclude tax from full amount.
This makes the balancing logic in entry generation work the way we want.
2020-12-10 09:43:47 -05:00

172 lines
4.6 KiB
Python

import pathlib
import re
from . import _csv
from .. import strparse
class EarningsImporter(_csv.CSVImporterBase):
AMOUNT_FIELDS = {
'Creator Share': 'net_amount',
'Creator Platform Fee': 'platform_fee',
'Creator Payment Processing Fee': 'processing_fee',
'Creator Currency Conversion Fee': 'currency_fee',
'Creator Equivalent of Patron Tax': 'tax_amount',
}
DATE_KEY = 'Date'
TYPE_KEY = 'Event Type'
NEEDED_FIELDS = frozenset([*AMOUNT_FIELDS, DATE_KEY, TYPE_KEY])
COPIED_FIELDS = {
'Creator Currency': 'currency',
'Event ID': 'event_id',
'Patron Email': 'email',
'Patron Name': 'payee',
'Patron User ID': 'user_id',
}
DATE_FMT = '%Y-%m-%d %H:%M:%S'
def _read_row(self, row):
if row[self.TYPE_KEY] != 'Payment':
return None
retval = {
ret_key: strparse.currency_decimal(row[src_key] or 0)
for src_key, ret_key in self.AMOUNT_FIELDS.items()
}
retval['amount'] = sum(retval.values()) - retval['tax_amount']
retval['date'] = strparse.date(row[self.DATE_KEY], self.DATE_FMT)
return retval
class IncomeImporter(_csv.CSVImporterBase):
AMOUNT_KEY = 'Pledge Amount'
DATE_KEY = 'Last Charge Date'
STATUS_KEY = 'Last Charge Status'
NEEDED_FIELDS = frozenset([
AMOUNT_KEY,
DATE_KEY,
STATUS_KEY,
])
COPIED_FIELDS = {
'Name': 'payee',
'Email': 'email',
'Tier': 'tier',
'User ID': 'patreon_id',
}
ENTRY_SEED = {
'currency': 'USD',
}
def __init_subclass__(cls):
cls.NEEDED_FIELDS = frozenset([
cls.AMOUNT_KEY,
cls.DATE_KEY,
cls.STATUS_KEY,
])
def _read_row(self, row):
if row[self.STATUS_KEY] != 'Paid':
return None
else:
return {
'amount': strparse.currency_decimal(row[self.AMOUNT_KEY]),
'date': strparse.date(row[self.DATE_KEY], '%Y-%m-%d %H:%M:%S'),
}
class PayoutImporter(_csv.CSVImporterBase):
AMOUNT_KEY = 'Total funds deducted from creator balance'
PLEDGE_KEY = 'Funds used for pledges to other creators'
TRANSFER_KEY = 'Funds transferred to you'
NEEDED_FIELDS = frozenset([
'Month',
TRANSFER_KEY,
PLEDGE_KEY,
AMOUNT_KEY,
])
ENTRY_SEED = {
'currency': 'USD',
'payee': 'Patreon',
}
def _read_row(self, row):
amount = strparse.currency_decimal(row[self.AMOUNT_KEY])
if not amount:
return None
else:
return {
'amount': amount,
'date': strparse.date(row['Month'], '%Y-%m'),
'pledges_amount': strparse.currency_decimal(row[self.PLEDGE_KEY]),
'transfer_amount': strparse.currency_decimal(row[self.TRANSFER_KEY]),
}
class FeeImporterBase(_csv.CSVImporterBase):
ENTRY_SEED = {
'currency': 'USD',
'payee': "Patreon",
}
def _read_row(self, row):
return {
'amount': row[self.AMOUNT_FIELD],
'date': strparse.date(row['Month'], '%Y-%m'),
}
class ServiceFeesImporter(FeeImporterBase):
AMOUNT_FIELD = 'Patreon Fee'
NEEDED_FIELDS = frozenset(['Month', AMOUNT_FIELD])
class CardFeesImporter(FeeImporterBase):
AMOUNT_FIELD = 'Processing Fees'
NEEDED_FIELDS = frozenset(['Month', AMOUNT_FIELD])
class VATImporter(FeeImporterBase):
AMOUNT_FIELD = 'Vat Charged'
NEEDED_FIELDS = frozenset(['Month', AMOUNT_FIELD])
COPIED_FIELDS = {
'Country Code': 'country_code',
'Country Name': 'country_name',
}
class Income2020OctoberImporter(IncomeImporter):
AMOUNT_KEY = 'Pledge $'
class Income2020AugustImporter(Income2020OctoberImporter):
DATE_KEY = 'Charged On Date'
STATUS_KEY = 'Charge Status'
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),
}