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)
|
||||
|
||||
def run(self, groups: PostGroups) -> None:
|
||||
rows = list(
|
||||
group.since_last_nonzero()
|
||||
for group in groups.values()
|
||||
if not group.is_zero()
|
||||
)
|
||||
rows: List[AccrualPostings] = []
|
||||
for group in groups.values():
|
||||
if 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: (
|
||||
related.account,
|
||||
related[0].meta.date,
|
||||
|
|
|
@ -151,3 +151,10 @@
|
|||
project: "Development Grant"
|
||||
Assets:Receivable:Accounts 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-05-15', 'MatchingProgram', 1500,
|
||||
'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'),
|
||||
]
|
||||
|
||||
|
@ -630,6 +630,11 @@ def test_aging_report(accrual_postings):
|
|||
def test_aging_report_date_cutoffs(accrual_postings, date, recv_end, pay_end):
|
||||
expect_recv = AGING_AR[:recv_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)
|
||||
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'),
|
||||
])
|
||||
|
||||
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):
|
||||
if config is None:
|
||||
config = testutil.TestConfig(
|
||||
|
|
Loading…
Reference in a new issue