Compare commits
6 commits
579f6dde4b
...
111b1fdf30
| Author | SHA1 | Date | |
|---|---|---|---|
| 111b1fdf30 | |||
| 2e87f9eaf0 | |||
| 9f8e5d7942 | |||
| 1e8b2a77eb | |||
| 7aad059d3d | |||
| 61b9683743 |
15 changed files with 500 additions and 501 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
import datetime
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from . import _csv
|
from . import _csv
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,28 @@
|
||||||
import decimal
|
import datetime
|
||||||
|
|
||||||
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 Fees': 'eventbrite_fees',
|
'Eventbrite service fee': 'service_fee',
|
||||||
'Eventbrite Payment Processing': 'payment_fees',
|
'Eventbrite payment processing fee': 'payment_processing_fee',
|
||||||
'Fees Paid': 'total_fees',
|
'Ticket quantity': 'ticket_quantity',
|
||||||
'Quantity': 'quantity',
|
'Eventbrite tax': 'eventbrite_tax',
|
||||||
'Tax Paid': 'tax',
|
'Organizer tax': 'organizer_tax',
|
||||||
'Total Paid': 'amount',
|
'Gross sales': 'amount',
|
||||||
}
|
}
|
||||||
NEEDED_FIELDS = frozenset([
|
NEEDED_FIELDS = frozenset([
|
||||||
'Order Date',
|
'Order date',
|
||||||
'Order Type',
|
'Payment status',
|
||||||
*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 #': 'order_id',
|
'Order ID': 'order_id',
|
||||||
'Ticket Type': 'ticket_type',
|
|
||||||
}
|
}
|
||||||
ENTRY_SEED = {'currency': 'USD'}
|
ENTRY_SEED = {'currency': 'USD'}
|
||||||
|
|
||||||
|
|
@ -36,12 +34,9 @@ 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
|
||||||
}
|
}
|
||||||
date_s, _, _ = row['Order Date'].partition(' ')
|
retval['date'] = datetime.datetime.fromisoformat(row['Order date']).date()
|
||||||
retval['date'] = strparse.date(date_s, '%Y-%m-%d')
|
retval['payee'] = '{Buyer first name} {Buyer last name}'.format_map(row)
|
||||||
try:
|
retval['total_fees'] = retval['service_fee'] + retval['payment_processing_fee']
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import decimal
|
|
||||||
|
|
||||||
from . import _csv
|
from . import _csv
|
||||||
from .. import strparse
|
from .. import strparse
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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', text='Recipient')
|
recipient_h = table.find('th', string='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,6 +139,7 @@ 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'
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,6 @@ class VATImporter(FeeImporterBase):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Income2020OctoberImporter(IncomeImporter):
|
class Income2020OctoberImporter(IncomeImporter):
|
||||||
AMOUNT_KEY = 'Pledge $'
|
AMOUNT_KEY = 'Pledge $'
|
||||||
|
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -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.5',
|
version='1.4.6',
|
||||||
author='Brett Smith',
|
author='Brett Smith',
|
||||||
author_email='brettcsmith@brettcsmith.org',
|
author_email='brettcsmith@brettcsmith.org',
|
||||||
license='GNU AGPLv3+',
|
license='GNU AGPLv3+',
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
Date,Disbursement ID,Name,Fund,Amount,Designation,On Behalf Of,Email,Company Name,Donation Type
|
Created,Disbursement ID,Donor Name,Fund,Amount,Designation,On Behalf Of,Donor Email,Company Name,Type
|
||||||
10/01/20,123456,Company ,,15,,Employed Person,,Company,MatchingTransaction
|
10/01/2020,123456,Company ,,15,,Employed Person,,Company,MatchingTransaction
|
||||||
09/24/20,123456,Employed Person ,,15,,-,person@example.com,Company,CreditCardTransaction
|
09/24/2020,123456,Employed Person ,,15,,-,person@example.com,Company,CreditCardTransaction
|
||||||
|
|
|
||||||
|
|
|
@ -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
|
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,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_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,
|
||||||
|
|
|
||||||
|
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
date_format = %%Y-%%m-%%d
|
date_format = %%Y-%%m-%%d
|
||||||
signed_currencies = USD, CAD
|
signed_currencies = CAD
|
||||||
signed_currency_format = ¤#,##0.###
|
signed_currency_format = ¤#,##0.###
|
||||||
unsigned_currency_format = #,##0.### ¤¤
|
unsigned_currency_format = #,##0.### ¤¤
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
default_date = 2016/04/04
|
default_date = 2016/04/04
|
||||||
loglevel = critical
|
loglevel = critical
|
||||||
signed_currencies = USD
|
signed_currencies =
|
||||||
|
|
||||||
[One]
|
[One]
|
||||||
patreon cardfees ledger entry =
|
patreon cardfees ledger entry =
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
2017/09/01 Patreon
|
2017/09/01 Patreon
|
||||||
Accrued:Accounts Receivable $-52.47
|
Accrued:Accounts Receivable -52.47 USD
|
||||||
Expenses:Fees:Credit Card $52.47
|
Expenses:Fees:Credit Card 52.47 USD
|
||||||
|
|
||||||
2017/10/01 Patreon
|
2017/10/01 Patreon
|
||||||
Accrued:Accounts Receivable $-99.47
|
Accrued:Accounts Receivable -99.47 USD
|
||||||
Expenses:Fees:Credit Card $99.47
|
Expenses:Fees:Credit Card 99.47 USD
|
||||||
|
|
||||||
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
|
Accrued:Accounts Receivable -61.73 USD
|
||||||
Expenses:Fundraising $61.73
|
Expenses:Fundraising 61.73 USD
|
||||||
|
|
||||||
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
|
Accrued:Accounts Receivable -117.03 USD
|
||||||
Expenses:Fundraising $117.03
|
Expenses:Fundraising 117.03 USD
|
||||||
|
|
|
||||||
|
|
@ -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', '$7.99')
|
assert_easy_render(tmpl, 'CC', '7.99', 'USD', '2015/03/14', 'USD7.99')
|
||||||
|
|
||||||
def test_empty_template():
|
def test_empty_template():
|
||||||
tmpl = ledger_entry.Template("\n \n")
|
tmpl = ledger_entry.Template("\n \n")
|
||||||
|
|
@ -76,19 +76,18 @@ 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",
|
" Accrued:Accounts Receivable 125.50 USD",
|
||||||
" ;Entity: Supplier",
|
" ;Entity: Supplier",
|
||||||
" Income:Donations:Spectrum Defense $-119.85",
|
" Income:Donations:Spectrum Defense -119.85 USD",
|
||||||
" ;Program: Spectrum Defense",
|
" ;Program: Spectrum Defense",
|
||||||
" ;Entity: T-T",
|
" ;Entity: T-T",
|
||||||
" Income:Donations:General $-5.65",
|
" Income:Donations:General -5.65 USD",
|
||||||
" ;Entity: T-T",
|
" ;Entity: T-T",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -108,19 +107,18 @@ 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",
|
" Accrued:Accounts Receivable 125.50 USD",
|
||||||
" ;Entity: Supplier",
|
" ;Entity: Supplier",
|
||||||
" Income:Donations:Spectrum Defense $-119.85",
|
" Income:Donations:Spectrum Defense -119.85 USD",
|
||||||
" ;Program: Spectrum Defense",
|
" ;Program: Spectrum Defense",
|
||||||
" ;Entity: W S",
|
" ;Entity: W S",
|
||||||
" Income:Donations:General $-5.65",
|
" Income:Donations:General -5.65 USD",
|
||||||
" ;Entity: W S",
|
" ;Entity: W S",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -342,8 +340,8 @@ def test_hook_renders_template():
|
||||||
assert lines == [
|
assert lines == [
|
||||||
"",
|
"",
|
||||||
"2015-03-14 BB",
|
"2015-03-14 BB",
|
||||||
" Accrued:Accounts Receivable $0.99",
|
" Accrued:Accounts Receivable 0.99 USD",
|
||||||
" Income:Donations -$0.99",
|
" Income:Donations -0.99 USD",
|
||||||
]
|
]
|
||||||
|
|
||||||
def test_hook_handles_empty_template():
|
def test_hook_handles_empty_template():
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import importlib
|
||||||
import itertools
|
import itertools
|
||||||
import pathlib
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import re
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import yaml
|
import yaml
|
||||||
|
|
@ -14,14 +13,23 @@ from import2ledger import importers, strparse
|
||||||
|
|
||||||
from . import DATA_DIR
|
from . import DATA_DIR
|
||||||
|
|
||||||
try:
|
|
||||||
load_yaml = yaml.full_load
|
def decimal_constructor(loader, node):
|
||||||
except AttributeError:
|
value = loader.construct_scalar(node)
|
||||||
load_yaml = yaml.load
|
return decimal.Decimal(value)
|
||||||
|
|
||||||
|
|
||||||
|
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 = load_yaml(yaml_file)
|
test_data = yaml.load(yaml_file, Loader=Loader)
|
||||||
for test in test_data:
|
for test in test_data:
|
||||||
test['source'] = DATA_DIR / test['source']
|
test['source'] = DATA_DIR / test['source']
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue