accrual: Generate an aging report in more cases.
Default to generating an aging report unless the user searched for a specific RT ticket or invoice.
This commit is contained in:
parent
d7e2ab34b9
commit
0caf78436f
2 changed files with 26 additions and 24 deletions
|
@ -6,8 +6,7 @@ Liabilities:Payable) for errors and metadata consistency, and reports any
|
|||
problems on stderr. Then it writes a report about the status of those
|
||||
accruals.
|
||||
|
||||
If you run it with no arguments, it will generate an aging report in ODS format
|
||||
in the current directory.
|
||||
If you run it with no arguments, it will generate an aging report in ODS format.
|
||||
|
||||
Otherwise, the typical way to run it is to pass an RT ticket number or
|
||||
invoice link as an argument, to report about accruals that match those
|
||||
|
@ -38,17 +37,19 @@ You can pass any number of search terms. For example::
|
|||
accrual-report 1230 entity=Doe-Jane
|
||||
|
||||
accrual-report will automatically decide what kind of report to generate
|
||||
from the search terms you provide and the results they return. If you pass
|
||||
no search terms, it generates an aging report. If your search terms match a
|
||||
single outstanding payable, it writes an outgoing approval report.
|
||||
Otherwise, it writes a basic balance report. You can specify what report
|
||||
from the search terms you provide and the results they return. If you
|
||||
searched on an RT ticket or invoice that returned a single outstanding
|
||||
payable, it writes an outgoing approval report. If you searched on RT ticket
|
||||
or invoice that returned other results, it writes a balance
|
||||
report. Otherwise, it writes an aging report. You can specify what report
|
||||
type you want with the ``--report-type`` option::
|
||||
|
||||
# Write an outgoing approval report for all outstanding accruals for
|
||||
# Write an outgoing approval report for all outstanding payables for
|
||||
# Jane Doe, even if there's more than one
|
||||
accrual-report --report-type outgoing entity=Doe-Jane
|
||||
# Write an aging report for a specific project
|
||||
accrual-report --report-type aging project=ProjectName
|
||||
# Write an aging report for a single RT invoice (this can be helpful when
|
||||
# one invoice covers multiple parties)
|
||||
accrual-report --report-type aging 12/345
|
||||
"""
|
||||
# Copyright © 2020 Brett Smith
|
||||
#
|
||||
|
@ -627,7 +628,10 @@ metadata to match. A single ticket number is a shortcut for
|
|||
`TIK/ATT` format, is a shortcut for `invoice=LINK`.
|
||||
""")
|
||||
args = parser.parse_args(arglist)
|
||||
if args.report_type is None and not args.search_terms:
|
||||
if args.report_type is None and not any(
|
||||
term.meta_key == 'invoice' or term.meta_key == 'rt-id'
|
||||
for term in args.search_terms
|
||||
):
|
||||
args.report_type = ReportType.AGING
|
||||
return args
|
||||
|
||||
|
|
|
@ -577,15 +577,19 @@ def test_aging_report_does_not_include_too_recent_postings(accrual_postings):
|
|||
project='Development Grant'),
|
||||
], [])
|
||||
|
||||
def run_main(arglist, config=None):
|
||||
def run_main(arglist, config=None, out_type=io.StringIO):
|
||||
if config is None:
|
||||
config = testutil.TestConfig(
|
||||
books_path=testutil.test_path('books/accruals.beancount'),
|
||||
rt_client=RTClient(),
|
||||
)
|
||||
output = io.StringIO()
|
||||
if out_type is io.BytesIO:
|
||||
arglist.insert(0, '--output-file=-')
|
||||
output = out_type()
|
||||
errors = io.StringIO()
|
||||
retcode = accrual.main(arglist, output, errors, config)
|
||||
output.seek(0)
|
||||
errors.seek(0)
|
||||
return retcode, output, errors
|
||||
|
||||
def check_main_fails(arglist, config, error_flags):
|
||||
|
@ -593,7 +597,6 @@ def check_main_fails(arglist, config, error_flags):
|
|||
assert retcode > 16
|
||||
assert (retcode - 16) & error_flags
|
||||
assert not output.getvalue()
|
||||
errors.seek(0)
|
||||
return errors
|
||||
|
||||
@pytest.mark.parametrize('arglist', [
|
||||
|
@ -624,7 +627,7 @@ def test_output_payments_when_only_match(arglist, expect_invoice):
|
|||
@pytest.mark.parametrize('arglist,expect_amount', [
|
||||
(['310'], 420),
|
||||
(['310/3120'], 220),
|
||||
(['entity=Vendor'], 420),
|
||||
(['-t', 'out', 'entity=Vendor'], 420),
|
||||
])
|
||||
def test_main_outgoing_report(arglist, expect_amount):
|
||||
retcode, output, errors = run_main(arglist)
|
||||
|
@ -643,7 +646,6 @@ def test_main_outgoing_report(arglist, expect_amount):
|
|||
@pytest.mark.parametrize('arglist', [
|
||||
['-t', 'balance'],
|
||||
['515/5150'],
|
||||
['entity=MatchingProgram'],
|
||||
])
|
||||
def test_main_balance_report(arglist):
|
||||
retcode, output, errors = run_main(arglist)
|
||||
|
@ -666,23 +668,19 @@ def test_main_balance_report_because_no_rt_id():
|
|||
|
||||
@pytest.mark.parametrize('arglist', [
|
||||
[],
|
||||
['-t', 'aging', 'entity=Lawyer'],
|
||||
['entity=Lawyer'],
|
||||
])
|
||||
def test_main_aging_report(tmp_path, arglist):
|
||||
def test_main_aging_report(arglist):
|
||||
if arglist:
|
||||
recv_rows = [row for row in AGING_AR if 'Lawyer' in row.entity]
|
||||
pay_rows = [row for row in AGING_AP if 'Lawyer' in row.entity]
|
||||
else:
|
||||
recv_rows = AGING_AR
|
||||
pay_rows = AGING_AP
|
||||
output_path = tmp_path / 'AgingReport.ods'
|
||||
arglist.insert(0, f'--output-file={output_path}')
|
||||
retcode, output, errors = run_main(arglist)
|
||||
retcode, output, errors = run_main(arglist, out_type=io.BytesIO)
|
||||
assert not errors.getvalue()
|
||||
assert retcode == 0
|
||||
assert not output.getvalue()
|
||||
with output_path.open('rb') as ods_file:
|
||||
check_aging_ods(ods_file, None, recv_rows, pay_rows)
|
||||
check_aging_ods(output, None, recv_rows, pay_rows)
|
||||
|
||||
def test_main_no_books():
|
||||
errors = check_main_fails([], testutil.TestConfig(), 1 | 8)
|
||||
|
@ -693,7 +691,7 @@ def test_main_no_books():
|
|||
@pytest.mark.parametrize('arglist', [
|
||||
['499'],
|
||||
['505/99999'],
|
||||
['entity=NonExistent'],
|
||||
['-t', 'balance', 'entity=NonExistent'],
|
||||
])
|
||||
def test_main_no_matches(arglist, caplog):
|
||||
check_main_fails(arglist, None, 8)
|
||||
|
|
Loading…
Reference in a new issue