feat(reports): add uncategorized dual-share exports
This commit is contained in:
@@ -147,9 +147,130 @@ class ReportViewTests(APITestCase):
|
||||
self.assertEqual(owner_summary["project_percentages"][0]["percentage"], "100")
|
||||
self.assertEqual(owner_summary["client_percentages"][0]["percentage"], "100")
|
||||
self.assertEqual(owner_summary["tag_percentages"][0]["percentage"], "100")
|
||||
self.assertEqual(member_summary["project_percentages"], [])
|
||||
self.assertEqual(member_summary["client_percentages"], [])
|
||||
self.assertEqual(member_summary["tag_percentages"], [])
|
||||
self.assertEqual(member_summary["project_percentages"][0]["percentage"], "0")
|
||||
self.assertEqual(member_summary["client_percentages"][0]["percentage"], "0")
|
||||
self.assertEqual(member_summary["tag_percentages"][0]["percentage"], "0")
|
||||
|
||||
def test_specific_user_report_includes_uncategorized_rows_and_balanced_percentages(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
|
||||
TimeEntry.objects.create(
|
||||
workspace=self.workspace,
|
||||
user=self.owner,
|
||||
project=None,
|
||||
description="Uncategorized billable",
|
||||
start_time="2026-04-12T10:00:00+03:30",
|
||||
end_time="2026-04-12T11:00:00+03:30",
|
||||
duration=timedelta(hours=1),
|
||||
is_billable=True,
|
||||
hourly_rate=Decimal("10.00"),
|
||||
currency="USD",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"apps.reports.services.aggregation.timezone.localdate",
|
||||
return_value=date(2026, 4, 20),
|
||||
):
|
||||
response = self.client.get(
|
||||
"/api/reports/table/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"period": "this_month",
|
||||
"user": str(self.owner.id),
|
||||
"language": "en",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
summary = response.data["user_summary"]
|
||||
self.assertEqual(
|
||||
sum(int(row["percentage"]) for row in summary["project_percentages"]),
|
||||
100,
|
||||
)
|
||||
self.assertEqual(
|
||||
sum(int(row["percentage"]) for row in summary["client_percentages"]),
|
||||
100,
|
||||
)
|
||||
self.assertEqual(
|
||||
sum(int(row["percentage"]) for row in summary["tag_percentages"]),
|
||||
100,
|
||||
)
|
||||
self.assertEqual(
|
||||
{row["name"] for row in summary["project_percentages"]},
|
||||
{"Website", "No project"},
|
||||
)
|
||||
self.assertEqual(
|
||||
{row["name"] for row in summary["client_percentages"]},
|
||||
{"Acme", "No client"},
|
||||
)
|
||||
self.assertEqual(
|
||||
{row["name"] for row in summary["tag_percentages"]},
|
||||
{"Design", "No tag"},
|
||||
)
|
||||
self.assertEqual(
|
||||
{row["name"] for row in response.data["projects"]},
|
||||
{"Website", "No project"},
|
||||
)
|
||||
self.assertEqual(
|
||||
{row["name"] for row in response.data["clients"]},
|
||||
{"Acme", "No client"},
|
||||
)
|
||||
self.assertEqual(
|
||||
{row["name"] for row in response.data["tags"]},
|
||||
{"Design", "No tag"},
|
||||
)
|
||||
self.assertEqual(
|
||||
sum(int(row["percentage"]) for row in summary["project_income_percentages"]),
|
||||
100,
|
||||
)
|
||||
self.assertEqual(
|
||||
sum(int(row["percentage"]) for row in summary["client_income_percentages"]),
|
||||
100,
|
||||
)
|
||||
self.assertEqual(
|
||||
sum(int(row["percentage"]) for row in summary["tag_income_percentages"]),
|
||||
100,
|
||||
)
|
||||
|
||||
def test_income_percentages_are_hidden_for_mixed_currency_breakdowns(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
second_project = Project.objects.create(
|
||||
workspace=self.workspace,
|
||||
name="Mobile App",
|
||||
client=self.client_obj,
|
||||
)
|
||||
|
||||
TimeEntry.objects.create(
|
||||
workspace=self.workspace,
|
||||
user=self.owner,
|
||||
project=second_project,
|
||||
description="EUR work",
|
||||
start_time="2026-04-13T10:00:00+03:30",
|
||||
end_time="2026-04-13T11:00:00+03:30",
|
||||
duration=timedelta(hours=1),
|
||||
is_billable=True,
|
||||
hourly_rate=Decimal("20.00"),
|
||||
currency="EUR",
|
||||
)
|
||||
|
||||
with patch(
|
||||
"apps.reports.services.aggregation.timezone.localdate",
|
||||
return_value=date(2026, 4, 20),
|
||||
):
|
||||
response = self.client.get(
|
||||
"/api/reports/table/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"period": "this_month",
|
||||
"user": str(self.owner.id),
|
||||
"language": "en",
|
||||
},
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
summary = response.data["user_summary"]
|
||||
self.assertEqual(summary["project_income_percentages"], [])
|
||||
self.assertEqual(summary["client_income_percentages"], [])
|
||||
|
||||
def test_daily_rate_uses_latest_billable_entry_snapshot(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
|
||||
Reference in New Issue
Block a user