hooks.ledger_entry: Clean up whitespace in strings.
The hook now ensures it does not output whitespace that could be significant to Ledger, either because it's a newline or an account-amount separator.
This commit is contained in:
parent
cc2b397801
commit
89378cbf90
3 changed files with 44 additions and 6 deletions
|
@ -222,9 +222,10 @@ class AccountSplitter:
|
||||||
|
|
||||||
|
|
||||||
class Template:
|
class Template:
|
||||||
ACCOUNT_SPLIT_RE = re.compile(r'(?:\t| )\s*')
|
ACCOUNT_SPLIT_RE = re.compile(r'(?: ?\t| )[ \t]*')
|
||||||
DATE_FMT = '%Y/%m/%d'
|
DATE_FMT = '%Y/%m/%d'
|
||||||
PAYEE_LINE_RE = re.compile(r'^\{(\w*_)*date\}\s')
|
PAYEE_LINE_RE = re.compile(r'^\{(\w*_)*date\}\s')
|
||||||
|
NEWLINE_RE = re.compile(r'[\f\n\r\v\u0085\u2028\u2029]')
|
||||||
SIGNED_CURRENCY_FMT = '¤#,##0.###;¤-#,##0.###'
|
SIGNED_CURRENCY_FMT = '¤#,##0.###;¤-#,##0.###'
|
||||||
UNSIGNED_CURRENCY_FMT = '#,##0.### ¤¤'
|
UNSIGNED_CURRENCY_FMT = '#,##0.### ¤¤'
|
||||||
|
|
||||||
|
@ -301,12 +302,17 @@ class Template:
|
||||||
"entry needs {} field but that's not set by the importer".format(
|
"entry needs {} field but that's not set by the importer".format(
|
||||||
self.date_field,
|
self.date_field,
|
||||||
), self.splitter.template_name)
|
), self.splitter.template_name)
|
||||||
render_vars = {
|
render_vars = {}
|
||||||
'amount': strparse.currency_decimal(template_vars['amount']),
|
|
||||||
}
|
|
||||||
for key, value in template_vars.items():
|
for key, value in template_vars.items():
|
||||||
if value is not None and (key == 'date' or key.endswith('_date')):
|
if value is None:
|
||||||
|
pass
|
||||||
|
elif key == 'date' or key.endswith('_date'):
|
||||||
render_vars[key] = value.strftime(self.date_fmt)
|
render_vars[key] = value.strftime(self.date_fmt)
|
||||||
|
elif isinstance(value, str):
|
||||||
|
value = self.NEWLINE_RE.sub(' ', value)
|
||||||
|
value = self.ACCOUNT_SPLIT_RE.sub(' ', value)
|
||||||
|
render_vars[key] = value
|
||||||
|
render_vars['amount'] = strparse.currency_decimal(template_vars['amount'])
|
||||||
all_vars = collections.ChainMap(render_vars, template_vars)
|
all_vars = collections.ChainMap(render_vars, template_vars)
|
||||||
return ''.join(f(all_vars) for f in self.format_funcs)
|
return ''.join(f(all_vars) for f in self.format_funcs)
|
||||||
|
|
||||||
|
|
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='0.11.0',
|
version='0.11.1',
|
||||||
author='Brett Smith',
|
author='Brett Smith',
|
||||||
author_email='brettcsmith@brettcsmith.org',
|
author_email='brettcsmith@brettcsmith.org',
|
||||||
license='GNU AGPLv3+',
|
license='GNU AGPLv3+',
|
||||||
|
|
|
@ -92,6 +92,38 @@ def test_complex_template():
|
||||||
" ;Entity: T-T",
|
" ;Entity: T-T",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def test_variable_whitespace_cleaned():
|
||||||
|
# There are two critical parts of this to avoid making malformed Ledger
|
||||||
|
# entries:
|
||||||
|
# * Ensure newlines become non-newline whitespace so we don't write
|
||||||
|
# malformed lines.
|
||||||
|
# * Collapse multiple spaces into one so variables in account names
|
||||||
|
# can't make malformed account lines by having a premature split
|
||||||
|
# between the account name and amount.
|
||||||
|
render_vars = template_vars('W\t\tS', '125.50', other_vars={
|
||||||
|
'entity': 'W\fS',
|
||||||
|
'program': 'Spectrum\r\nDefense',
|
||||||
|
'txid': 'ABC\v\tDEF',
|
||||||
|
})
|
||||||
|
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",
|
||||||
|
" ;Entity: Supplier",
|
||||||
|
" Income:Donations:Spectrum Defense $-119.85",
|
||||||
|
" ;Program: Spectrum Defense",
|
||||||
|
" ;Entity: W S",
|
||||||
|
" Income:Donations:General $-5.65",
|
||||||
|
" ;Entity: W S",
|
||||||
|
]
|
||||||
|
|
||||||
def test_balancing():
|
def test_balancing():
|
||||||
lines = render_lines(template_vars('FF', '1.01'), 'FiftyFifty')
|
lines = render_lines(template_vars('FF', '1.01'), 'FiftyFifty')
|
||||||
assert lines == [
|
assert lines == [
|
||||||
|
|
Loading…
Reference in a new issue