Compare commits

...

6 commits

Author SHA1 Message Date
111b1fdf30
Fix some unused import lint warnings 2025-09-30 23:38:12 +10:00
2e87f9eaf0
Update Eventbrite importer for new CSV format 2025-09-30 23:33:23 +10:00
9f8e5d7942
Fix DeprecationWarning 2025-09-30 22:44:12 +10:00
1e8b2a77eb
Update test CSVs to match importer implementations
Some upstream column names have changed over time and the importer
implementations have been updated, but not the test examples.
2025-09-19 20:46:17 +10:00
7aad059d3d
Change from "$xx" to "xx USD" to fix tests 2025-09-19 17:55:41 +10:00
61b9683743
Add !date and !decimal YAML constructors to avoid unsafe parsing mode
At some point the defaults for pyyaml were switched to safe parsing mode, so
that the previous arbitrary Python YAML tags like
"!!python/object/apply:datetime.date [2017, 9, 1]" no longer work. A better way
is to define our own explicit constructors to avoid unsafe mode.
2025-09-19 17:21:47 +10:00
15 changed files with 500 additions and 501 deletions

View file

@ -1,4 +1,3 @@
import datetime
import itertools
from . import _csv

View file

@ -1,30 +1,28 @@
import decimal
import datetime
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',
'Eventbrite service fee': 'service_fee',
'Eventbrite payment processing fee': 'payment_processing_fee',
'Ticket quantity': 'ticket_quantity',
'Eventbrite tax': 'eventbrite_tax',
'Organizer tax': 'organizer_tax',
'Gross sales': 'amount',
}
NEEDED_FIELDS = frozenset([
'Order Date',
'Order Type',
'Order date',
'Payment status',
*DECIMAL_FIELDS,
])
OPTIONAL_FIELDS = {
'Attendee #': 'attendee_id',
'Company': 'corporation',
'Currency': 'currency',
'Event ID': 'event_id',
'Event Name': 'event_name',
'Order #': 'order_id',
'Ticket Type': 'ticket_type',
'Event name': 'event_name',
'Order ID': 'order_id',
}
ENTRY_SEED = {'currency': 'USD'}
@ -36,12 +34,9 @@ class SalesImporter(_csv.CSVImporterBase):
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['date'] = datetime.datetime.fromisoformat(row['Order date']).date()
retval['payee'] = '{Buyer first name} {Buyer last name}'.format_map(row)
retval['total_fees'] = retval['service_fee'] + retval['payment_processing_fee']
retval.update(
(self.OPTIONAL_FIELDS[key], row.get(key, ''))
for key in self.OPTIONAL_FIELDS

View file

@ -1,5 +1,3 @@
import decimal
from . import _csv
from .. import strparse

View file

@ -71,7 +71,7 @@ class Invoice2017:
for key, value in rows_text:
if key == 'Issue date':
self.invoice_date = self._strpdate(value)
recipient_h = table.find('th', text='Recipient')
recipient_h = table.find('th', string='Recipient')
recipient_cell = recipient_h.find_next_sibling('td')
self.payee = next(recipient_cell.stripped_strings)
@ -139,6 +139,7 @@ def _parse_invoice(parser_class, source_file):
except AttributeError:
return None
class InvoiceImporter:
INVOICE_CLASS = Invoice2017
LEDGER_TEMPLATE_KEY_FMT = 'nbpy2017 {0} ledger entry'

View file

@ -132,7 +132,6 @@ class VATImporter(FeeImporterBase):
}
class Income2020OctoberImporter(IncomeImporter):
AMOUNT_KEY = 'Pledge $'

View file

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

View file

@ -1,3 +1,3 @@
Date,Disbursement ID,Name,Fund,Amount,Designation,On Behalf Of,Email,Company Name,Donation Type
10/01/20,123456,Company ,,15,,Employed Person,,Company,MatchingTransaction
09/24/20,123456,Employed Person ,,15,,-,person@example.com,Company,CreditCardTransaction
Created,Disbursement ID,Donor Name,Fund,Amount,Designation,On Behalf Of,Donor Email,Company Name,Type
10/01/2020,123456,Company ,,15,,Employed Person,,Company,MatchingTransaction
09/24/2020,123456,Employed Person ,,15,,-,person@example.com,Company,CreditCardTransaction

1 Date Created Disbursement ID Name Donor Name Fund Amount Designation On Behalf Of Email Donor Email Company Name Donation Type Type
2 10/01/20 10/01/2020 123456 Company Company 15 Employed Person Company MatchingTransaction MatchingTransaction
3 09/24/20 09/24/2020 123456 Employed Person Employed Person 15 - person@example.com person@example.com Company CreditCardTransaction CreditCardTransaction

View file

@ -1,4 +1,4 @@
sponsor handle,sponsor email,sponsorship started on,is public?,is yearly?,transaction id,tier name,tier monthly amount,processed amount,is prorated?,status,transaction date
sponsor handle,sponsor email,sponsorship started on,is public?,is yearly?,stripe transfer id,tier name,tier monthly amount,transferred amount,is prorated?,status,transaction timestamp
exampleA,ajones@example.com,2019-10-01 10:00:00 -0400,TRUE,FALSE,ch_1Gabcdefghijklmnopqrstuv,$1/month,$1.00,$1.00,FALSE,settled,2020-01-02 14:02:00 -0500
exampleB,,2019-11-01 11:00:00 -0400,FALSE,FALSE,1023ABCD5678EFGHI,$10/month,$10.00,$10.00,FALSE,settled,2020-01-03 15:03:00 -0500
exampleC,info@example.com,2019-12-01 12:00:00 -0500,TRUE,TRUE,ch_1Gabcdefghijklmnopqrstuw,$10/month,$10.00,$120.00,FALSE,settled,2020-01-04 16:04:00 -0500

1 sponsor handle sponsor email sponsorship started on is public? is yearly? transaction id stripe transfer id tier name tier monthly amount processed amount transferred amount is prorated? status transaction date transaction timestamp
2 exampleA ajones@example.com 2019-10-01 10:00:00 -0400 TRUE FALSE ch_1Gabcdefghijklmnopqrstuv ch_1Gabcdefghijklmnopqrstuv $1/month $1.00 $1.00 $1.00 FALSE settled 2020-01-02 14:02:00 -0500 2020-01-02 14:02:00 -0500
3 exampleB 2019-11-01 11:00:00 -0400 FALSE FALSE 1023ABCD5678EFGHI 1023ABCD5678EFGHI $10/month $10.00 $10.00 $10.00 FALSE settled 2020-01-03 15:03:00 -0500 2020-01-03 15:03:00 -0500
4 exampleC info@example.com 2019-12-01 12:00:00 -0500 TRUE TRUE ch_1Gabcdefghijklmnopqrstuw ch_1Gabcdefghijklmnopqrstuw $10/month $10.00 $120.00 $120.00 FALSE settled 2020-01-04 16:04:00 -0500 2020-01-04 16:04:00 -0500

View file

@ -1,3 +1,3 @@
id,Description,Created (UTC),Amount,Amount Refunded,Currency,Converted Amount,Converted Amount Refunded,Fee,Tax,Converted Currency,Mode,Status,Statement Descriptor,Customer ID,Customer Description,Customer Email,Captured,Card ID,Card Last4,Card Brand,Card Funding,Card Exp Month,Card Exp Year,Card Name,Card Address Line1,Card Address Line2,Card Address City,Card Address State,Card Address Country,Card Address Zip,Card Issue Country,Card Fingerprint,Card CVC Status,Card AVS Zip Status,Card AVS Line1 Status,Card Tokenization Method,Disputed Amount,Dispute Status,Dispute Reason,Dispute Date (UTC),Dispute Evidence Due (UTC),Invoice ID,Payment Source Type,Destination,Transfer,Transfer Group
id,Description,Created (UTC),Amount,Amount Refunded,Currency,Converted Amount,Converted Amount Refunded,Fee,Taxes On Fee,Converted Currency,Mode,Status,Statement Descriptor,Customer ID,Customer Description,Customer Email,Captured,Card ID,Card Last4,Card Brand,Card Funding,Card Exp Month,Card Exp Year,Card Name,Card Address Line1,Card Address Line2,Card Address City,Card Address State,Card Address Country,Card Address Zip,Card Issue Country,Card Fingerprint,Card CVC Status,Card AVS Zip Status,Card AVS Line1 Status,Card Tokenization Method,Disputed Amount,Dispute Status,Dispute Reason,Dispute Date (UTC),Dispute Evidence Due (UTC),Invoice ID,Payment Source Type,Destination,Transfer,Transfer Group
ch_oxuish6phae2Raighooghi3U,Payment for invoice #102,2017-11-08 16:56,100,0,usd,100,0,3,0,usd,Live,Paid,,cus_DohSheeQu8eng3,,one@example.org,true,card_na1joNohg9Aim6eg9eefooRe,0,American Express,credit,1,2010,Dakota Smith,1 Example St,,City,State,United States,12345,US,queiheVu2ohyei2u,pass,pass,pass,,,,,,,,card,,po_aeYees2ahtier8ohju7Eeyie,
ch_hHee9ef1aeyee1ruo7ochee9,Payment for invoice #100,2017-10-28 02:32,50,0,usd,50,0,1.4,0,usd,Live,Paid,,cus_iepae2Iecae8Ei,,two@example.org,true,card_sitej3Xi2aNgo1ohfoahue8e,1,Visa,credit,2,2011,Dakota Jones,2 Example St,,City,State,United States,12345,US,men2shi3xo1Mao4u,pass,pass,pass,,,,,,,,card,,po_aeYees2ahtier8ohju7Eeyie,

1 id Description Created (UTC) Amount Amount Refunded Currency Converted Amount Converted Amount Refunded Fee Tax Taxes On Fee Converted Currency Mode Status Statement Descriptor Customer ID Customer Description Customer Email Captured Card ID Card Last4 Card Brand Card Funding Card Exp Month Card Exp Year Card Name Card Address Line1 Card Address Line2 Card Address City Card Address State Card Address Country Card Address Zip Card Issue Country Card Fingerprint Card CVC Status Card AVS Zip Status Card AVS Line1 Status Card Tokenization Method Disputed Amount Dispute Status Dispute Reason Dispute Date (UTC) Dispute Evidence Due (UTC) Invoice ID Payment Source Type Destination Transfer Transfer Group
2 ch_oxuish6phae2Raighooghi3U Payment for invoice #102 2017-11-08 16:56 100 0 usd 100 0 3 0 0 usd Live Paid cus_DohSheeQu8eng3 one@example.org true card_na1joNohg9Aim6eg9eefooRe 0 American Express credit 1 2010 Dakota Smith 1 Example St City State United States 12345 US queiheVu2ohyei2u pass pass pass card po_aeYees2ahtier8ohju7Eeyie
3 ch_hHee9ef1aeyee1ruo7ochee9 Payment for invoice #100 2017-10-28 02:32 50 0 usd 50 0 1.4 0 0 usd Live Paid cus_iepae2Iecae8Ei two@example.org true card_sitej3Xi2aNgo1ohfoahue8e 1 Visa credit 2 2011 Dakota Jones 2 Example St City State United States 12345 US men2shi3xo1Mao4u pass pass pass card po_aeYees2ahtier8ohju7Eeyie

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[DEFAULT]
date_format = %%Y-%%m-%%d
signed_currencies = USD, CAD
signed_currencies = CAD
signed_currency_format = ¤#,##0.###
unsigned_currency_format = #,##0.### ¤¤

View file

@ -1,7 +1,7 @@
[DEFAULT]
default_date = 2016/04/04
loglevel = critical
signed_currencies = USD
signed_currencies =
[One]
patreon cardfees ledger entry =

View file

@ -1,19 +1,19 @@
2017/09/01 Patreon
Accrued:Accounts Receivable $-52.47
Expenses:Fees:Credit Card $52.47
Accrued:Accounts Receivable -52.47 USD
Expenses:Fees:Credit Card 52.47 USD
2017/10/01 Patreon
Accrued:Accounts Receivable $-99.47
Expenses:Fees:Credit Card $99.47
Accrued:Accounts Receivable -99.47 USD
Expenses:Fees:Credit Card 99.47 USD
2017/09/01 Patreon
;SourcePath: {source_abspath}
;SourceName: {source_name}
Accrued:Accounts Receivable $-61.73
Expenses:Fundraising $61.73
Accrued:Accounts Receivable -61.73 USD
Expenses:Fundraising 61.73 USD
2017/10/01 Patreon
;SourcePath: {source_abspath}
;SourceName: {source_name}
Accrued:Accounts Receivable $-117.03
Expenses:Fundraising $117.03
Accrued:Accounts Receivable -117.03 USD
Expenses:Fundraising 117.03 USD

View file

@ -60,7 +60,7 @@ def test_date_formatting():
def test_currency_formatting():
tmpl = template_from('Simplest', signed_currencies=['USD'])
assert_easy_render(tmpl, 'CC', '7.99', 'USD', '2015/03/14', '$7.99')
assert_easy_render(tmpl, 'CC', '7.99', 'USD', '2015/03/14', 'USD7.99')
def test_empty_template():
tmpl = ledger_entry.Template("\n \n")
@ -76,19 +76,18 @@ def test_complex_template():
lines = render_lines(
render_vars, 'Complex',
date_fmt='%Y-%m-%d',
signed_currencies=['USD'],
)
assert lines == [
"",
"2015-03-14 TT",
" ;Tag: Value",
" ;TransactionID: ABCDEF",
" Accrued:Accounts Receivable $125.50",
" Accrued:Accounts Receivable 125.50 USD",
" ;Entity: Supplier",
" Income:Donations:Spectrum Defense $-119.85",
" Income:Donations:Spectrum Defense -119.85 USD",
" ;Program: Spectrum Defense",
" ;Entity: T-T",
" Income:Donations:General $-5.65",
" Income:Donations:General -5.65 USD",
" ;Entity: T-T",
]
@ -108,19 +107,18 @@ def test_variable_whitespace_cleaned():
lines = render_lines(
render_vars, 'Complex',
date_fmt='%Y-%m-%d',
signed_currencies=['USD'],
)
assert lines == [
"",
"2015-03-14 W S",
" ;Tag: Value",
" ;TransactionID: ABC DEF",
" Accrued:Accounts Receivable $125.50",
" Accrued:Accounts Receivable 125.50 USD",
" ;Entity: Supplier",
" Income:Donations:Spectrum Defense $-119.85",
" Income:Donations:Spectrum Defense -119.85 USD",
" ;Program: Spectrum Defense",
" ;Entity: W S",
" Income:Donations:General $-5.65",
" Income:Donations:General -5.65 USD",
" ;Entity: W S",
]
@ -342,8 +340,8 @@ def test_hook_renders_template():
assert lines == [
"",
"2015-03-14 BB",
" Accrued:Accounts Receivable $0.99",
" Income:Donations -$0.99",
" Accrued:Accounts Receivable 0.99 USD",
" Income:Donations -0.99 USD",
]
def test_hook_handles_empty_template():

View file

@ -6,7 +6,6 @@ import importlib
import itertools
import pathlib
import shutil
import re
import pytest
import yaml
@ -14,14 +13,23 @@ from import2ledger import importers, strparse
from . import DATA_DIR
try:
load_yaml = yaml.full_load
except AttributeError:
load_yaml = yaml.load
def decimal_constructor(loader, node):
value = loader.construct_scalar(node)
return decimal.Decimal(value)
def date_constructor(loader, node):
value = loader.construct_scalar(node)
return datetime.date.fromisoformat(value)
class TestImporters:
Loader = yaml.Loader
Loader.add_constructor('!decimal', decimal_constructor)
Loader.add_constructor('!date', date_constructor)
with pathlib.Path(DATA_DIR, 'imports.yml').open() as yaml_file:
test_data = load_yaml(yaml_file)
test_data = yaml.load(yaml_file, Loader=Loader)
for test in test_data:
test['source'] = DATA_DIR / test['source']