accrual: Aging report filters out too-recent accruals. RT#11600.
This commit is contained in:
parent
948d3a2d14
commit
6e9a612bb7
3 changed files with 50 additions and 6 deletions
|
@ -507,11 +507,29 @@ class AgingReport(BaseReport):
|
||||||
self.ods = AgingODS(rt_client, date, self.logger)
|
self.ods = AgingODS(rt_client, date, self.logger)
|
||||||
|
|
||||||
def run(self, groups: PostGroups) -> None:
|
def run(self, groups: PostGroups) -> None:
|
||||||
rows = list(
|
rows: List[AccrualPostings] = []
|
||||||
group.since_last_nonzero()
|
for group in groups.values():
|
||||||
for group in groups.values()
|
if group.is_zero():
|
||||||
if not group.is_zero()
|
# Cheap optimization: don't slice and dice groups we're not
|
||||||
)
|
# going to report anyway.
|
||||||
|
continue
|
||||||
|
elif group.accrual_type is None:
|
||||||
|
group = group.since_last_nonzero()
|
||||||
|
else:
|
||||||
|
# Filter out new accruals after the report date.
|
||||||
|
# e.g., cover the case that the same invoices has multiple
|
||||||
|
# postings over time, and we don't want to report too-recent
|
||||||
|
# ones.
|
||||||
|
cutoff_date = self.ods.date - datetime.timedelta(
|
||||||
|
days=group.accrual_type.value.aging_thresholds[-1],
|
||||||
|
)
|
||||||
|
group = AccrualPostings(
|
||||||
|
post for post in group.since_last_nonzero()
|
||||||
|
if post.meta.date <= cutoff_date
|
||||||
|
or group.accrual_type.normalize_amount(post.units.number) < 0
|
||||||
|
)
|
||||||
|
if group and not group.is_zero():
|
||||||
|
rows.append(group)
|
||||||
rows.sort(key=lambda related: (
|
rows.sort(key=lambda related: (
|
||||||
related.account,
|
related.account,
|
||||||
related[0].meta.date,
|
related[0].meta.date,
|
||||||
|
|
|
@ -151,3 +151,10 @@
|
||||||
project: "Development Grant"
|
project: "Development Grant"
|
||||||
Assets:Receivable:Accounts 5500 USD
|
Assets:Receivable:Accounts 5500 USD
|
||||||
Income:Donations -5500 USD
|
Income:Donations -5500 USD
|
||||||
|
|
||||||
|
2010-09-15 * "GrantCo" "2010Q3 grant"
|
||||||
|
rt-id: "rt:470"
|
||||||
|
invoice: "rt:470/4700"
|
||||||
|
project: "Development Grant"
|
||||||
|
Assets:Receivable:Accounts 6000 USD
|
||||||
|
Income:Donations -6000 USD
|
||||||
|
|
|
@ -121,7 +121,7 @@ AGING_AR = [
|
||||||
AgingRow.make_simple('2010-03-05', 'EarlyBird', -500, 'rt:40/400'),
|
AgingRow.make_simple('2010-03-05', 'EarlyBird', -500, 'rt:40/400'),
|
||||||
AgingRow.make_simple('2010-05-15', 'MatchingProgram', 1500,
|
AgingRow.make_simple('2010-05-15', 'MatchingProgram', 1500,
|
||||||
'rt://ticket/515/attachments/5150'),
|
'rt://ticket/515/attachments/5150'),
|
||||||
AgingRow.make_simple('2010-06-15', 'GrantCo', 5500, 'rt:470/4700',
|
AgingRow.make_simple('2010-06-15', 'GrantCo', 11500, 'rt:470/4700',
|
||||||
project='Development Grant'),
|
project='Development Grant'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -630,6 +630,11 @@ def test_aging_report(accrual_postings):
|
||||||
def test_aging_report_date_cutoffs(accrual_postings, date, recv_end, pay_end):
|
def test_aging_report_date_cutoffs(accrual_postings, date, recv_end, pay_end):
|
||||||
expect_recv = AGING_AR[:recv_end]
|
expect_recv = AGING_AR[:recv_end]
|
||||||
expect_pay = AGING_AP[:pay_end]
|
expect_pay = AGING_AP[:pay_end]
|
||||||
|
if 10 <= date.day < 12:
|
||||||
|
# Take the 60 USD posting out of the invoice 510/6100 payable.
|
||||||
|
expect_pay[-1] = expect_pay[-1]._replace(
|
||||||
|
at_cost=testutil.Amount(expect_pay[-1].at_cost.number - 60),
|
||||||
|
)
|
||||||
output = run_aging_report(accrual_postings, date)
|
output = run_aging_report(accrual_postings, date)
|
||||||
check_aging_ods(output, date, expect_recv, expect_pay)
|
check_aging_ods(output, date, expect_recv, expect_pay)
|
||||||
|
|
||||||
|
@ -644,6 +649,20 @@ def test_aging_report_entity_consistency(accrual_postings):
|
||||||
AgingRow.make_simple('2010-04-15', 'MultiPartyB', 125, 'rt:480/4800'),
|
AgingRow.make_simple('2010-04-15', 'MultiPartyB', 125, 'rt:480/4800'),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
def test_aging_report_does_not_include_too_recent_postings(accrual_postings):
|
||||||
|
# This date is after the Q3 posting, but too soon after for that to be
|
||||||
|
# included in the aging report.
|
||||||
|
date = datetime.date(2010, 10, 1)
|
||||||
|
output = run_aging_report((
|
||||||
|
post for post in accrual_postings
|
||||||
|
if post.meta.get('rt-id') == 'rt:470'
|
||||||
|
), date)
|
||||||
|
# Date+amount are both from the Q2 posting only.
|
||||||
|
check_aging_ods(output, date, [
|
||||||
|
AgingRow.make_simple('2010-06-15', 'GrantCo', 5500, 'rt:470/4700',
|
||||||
|
project='Development Grant'),
|
||||||
|
], [])
|
||||||
|
|
||||||
def run_main(arglist, config=None):
|
def run_main(arglist, config=None):
|
||||||
if config is None:
|
if config is None:
|
||||||
config = testutil.TestConfig(
|
config = testutil.TestConfig(
|
||||||
|
|
Loading…
Reference in a new issue