Add _current_outstanding_in_scope helper + 3 tests
Hero KPI card 2 needs 'Outstanding NOW' scoped to the report's selected projects/teams. This helper wraps _compute_outstanding, reshapes the by_project dict into a sorted list, and exposes the net total for direct rendering. Tests cover unfiltered total, project-scoped total, and team-scoped total (including the worker__teams subquery path for adjustments). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e74f48f050
commit
82594faad7
@ -534,3 +534,58 @@ class CompanyCostVelocityTests(TestCase):
|
||||
log.workers.add(w1, w2)
|
||||
result = _company_cost_velocity()
|
||||
self.assertEqual(result['working_days'], 1) # not 2
|
||||
|
||||
|
||||
class CurrentOutstandingInScopeTests(TestCase):
|
||||
"""Hero card 2 — 'Outstanding NOW' with optional filter scope."""
|
||||
|
||||
def setUp(self):
|
||||
self.admin = User.objects.create_user(username='a-out', is_staff=True)
|
||||
self.p1 = Project.objects.create(name='ProjA')
|
||||
self.p2 = Project.objects.create(name='ProjB')
|
||||
self.t1 = Team.objects.create(name='TeamA', supervisor=self.admin)
|
||||
self.w = Worker.objects.create(
|
||||
name='Wkr', id_number='W1', monthly_salary=Decimal('4000')
|
||||
)
|
||||
self.t1.workers.add(self.w)
|
||||
# Unpaid log on project 1
|
||||
log1 = WorkLog.objects.create(
|
||||
date=datetime.date(2026, 3, 1),
|
||||
project=self.p1, team=self.t1, supervisor=self.admin,
|
||||
)
|
||||
log1.workers.add(self.w)
|
||||
# Unpaid log on project 2
|
||||
log2 = WorkLog.objects.create(
|
||||
date=datetime.date(2026, 3, 2),
|
||||
project=self.p2, team=self.t1, supervisor=self.admin,
|
||||
)
|
||||
log2.workers.add(self.w)
|
||||
|
||||
def test_no_filters_includes_all_projects(self):
|
||||
from core.views import _current_outstanding_in_scope
|
||||
result = _current_outstanding_in_scope()
|
||||
# daily_rate = 4000/20 = 200; 2 unpaid logs * 200 = 400
|
||||
self.assertEqual(result['total'], Decimal('400.00'))
|
||||
self.assertEqual(len(result['by_project']), 2)
|
||||
|
||||
def test_project_filter_scopes_total(self):
|
||||
from core.views import _current_outstanding_in_scope
|
||||
result = _current_outstanding_in_scope(project_ids=[self.p1.id])
|
||||
self.assertEqual(result['total'], Decimal('200.00'))
|
||||
self.assertEqual(len(result['by_project']), 1)
|
||||
self.assertEqual(result['by_project'][0]['name'], 'ProjA')
|
||||
|
||||
def test_team_filter_scopes_total(self):
|
||||
"""Team filter on work logs + worker__teams on adjustments."""
|
||||
from core.views import _current_outstanding_in_scope
|
||||
# Adjustment on a worker not in t1
|
||||
other_worker = Worker.objects.create(
|
||||
name='Other', id_number='O1', monthly_salary=Decimal('4000')
|
||||
)
|
||||
PayrollAdjustment.objects.create(
|
||||
worker=other_worker, project=self.p1, type='Bonus',
|
||||
amount=Decimal('500.00'), date=datetime.date(2026, 3, 3),
|
||||
)
|
||||
# With team filter, only self.w's logs appear — R 400 total
|
||||
result = _current_outstanding_in_scope(team_ids=[self.t1.id])
|
||||
self.assertEqual(result['total'], Decimal('400.00'))
|
||||
|
||||
@ -252,6 +252,32 @@ def _company_cost_velocity():
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === CURRENT OUTSTANDING — SCOPED FOR THE REPORT ===
|
||||
# Thin wrapper around _compute_outstanding that shapes the output for
|
||||
# the executive report's hero card 2. Includes a 'by_project' list
|
||||
# sorted by amount desc, ready for direct template rendering.
|
||||
# =============================================================================
|
||||
|
||||
def _current_outstanding_in_scope(project_ids=None, team_ids=None):
|
||||
"""Return current outstanding payments, optionally scoped by project/team.
|
||||
|
||||
Calls _compute_outstanding and reshapes the by_project dict into a
|
||||
list sorted by amount descending (for display). The 'total' field
|
||||
is the net outstanding (unpaid wages + additive adjustments minus
|
||||
deductive adjustments), matching the home dashboard card.
|
||||
"""
|
||||
raw = _compute_outstanding(project_ids=project_ids, team_ids=team_ids)
|
||||
by_project_list = sorted(
|
||||
[{'name': name, 'amount': amt} for name, amt in raw['outstanding_by_project'].items()],
|
||||
key=lambda r: -r['amount'],
|
||||
)
|
||||
return {
|
||||
'total': raw['outstanding_payments'],
|
||||
'by_project': by_project_list,
|
||||
}
|
||||
|
||||
|
||||
# === HOME DASHBOARD ===
|
||||
# The main page users see after logging in. Shows different content
|
||||
# depending on whether the user is an admin or supervisor.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user