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…
	
	Add table
		
		Reference in a new issue