Compare commits

..

No commits in common. "111b1fdf30565575856008e575da4f4284cb7e3f" and "579f6dde4bfe8f0d57a31b7d5d7deb9dc76d37a9" have entirely different histories.

15 changed files with 501 additions and 500 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

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.4.6', version='1.4.5',
author='Brett Smith', author='Brett Smith',
author_email='brettcsmith@brettcsmith.org', author_email='brettcsmith@brettcsmith.org',
license='GNU AGPLv3+', license='GNU AGPLv3+',

View file

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

1 Created Date Disbursement ID Donor Name Name Fund Amount Designation On Behalf Of Donor Email Email Company Name Type Donation Type
2 10/01/2020 10/01/20 123456 Company Company 15 Employed Person Company MatchingTransaction MatchingTransaction
3 09/24/2020 09/24/20 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?,stripe transfer id,tier name,tier monthly amount,transferred amount,is prorated?,status,transaction timestamp 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
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 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 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 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? stripe transfer id transaction id tier name tier monthly amount transferred amount processed amount is prorated? status transaction timestamp transaction date
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,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 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
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_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, 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 Taxes On 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
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] [DEFAULT]
date_format = %%Y-%%m-%%d date_format = %%Y-%%m-%%d
signed_currencies = CAD signed_currencies = USD, CAD
signed_currency_format = ¤#,##0.### signed_currency_format = ¤#,##0.###
unsigned_currency_format = #,##0.### ¤¤ unsigned_currency_format = #,##0.### ¤¤

View file

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

View file

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

View file

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

View file

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