feat(reports): refine exports and restore project access
This commit is contained in:
@@ -46,15 +46,58 @@ def make_report_data(*, user_name="Owner User", mobile="09129990001", hourly_rat
|
||||
}
|
||||
|
||||
|
||||
def make_user_summary(*, name: str, mobile: str):
|
||||
return {
|
||||
"user": {"id": mobile, "name": name, "mobile": mobile},
|
||||
"hourly_rates": [{"amount": "15.00", "currency": "USD"}],
|
||||
"rate_periods": [
|
||||
{
|
||||
"amount": "15.00",
|
||||
"currency": "USD",
|
||||
"from_date": "2026-04-01",
|
||||
"to_date": "2026-04-30",
|
||||
}
|
||||
],
|
||||
"total_seconds": 7200,
|
||||
"total_duration": "02:00:00",
|
||||
"billable_seconds": 7200,
|
||||
"billable_duration": "02:00:00",
|
||||
"non_billable_seconds": 0,
|
||||
"non_billable_duration": "00:00:00",
|
||||
"income_totals": [{"amount": "30.00", "currency": "USD"}],
|
||||
"project_percentages": [{"id": "1", "name": "Website", "percentage": "100"}],
|
||||
"client_percentages": [{"id": "1", "name": "Acme", "percentage": "100"}],
|
||||
"tag_percentages": [{"id": "1", "name": "Design", "percentage": "100"}],
|
||||
}
|
||||
|
||||
|
||||
class ReportExporterTests(TestCase):
|
||||
def test_excel_export_adds_per_user_sheets_and_daily_rate_column(self):
|
||||
locale = build_export_locale("en")
|
||||
report_data = make_report_data(
|
||||
hourly_rate={"amount": "15.00", "currency": "USD"},
|
||||
)
|
||||
report_data["user_summaries"] = [
|
||||
make_user_summary(name="Owner User", mobile="09129990001"),
|
||||
make_user_summary(name="Team Mate", mobile="09129990002"),
|
||||
]
|
||||
per_user_reports = [
|
||||
make_report_data(user_name="Owner User", mobile="09129990001"),
|
||||
make_report_data(user_name="Team Mate", mobile="09129990002"),
|
||||
{
|
||||
**make_report_data(
|
||||
user_name="Owner User",
|
||||
mobile="09129990001",
|
||||
hourly_rate={"amount": "15.00", "currency": "USD"},
|
||||
),
|
||||
"user_summary": make_user_summary(name="Owner User", mobile="09129990001"),
|
||||
},
|
||||
{
|
||||
**make_report_data(
|
||||
user_name="Team Mate",
|
||||
mobile="09129990002",
|
||||
hourly_rate={"amount": "15.00", "currency": "USD"},
|
||||
),
|
||||
"user_summary": make_user_summary(name="Team Mate", mobile="09129990002"),
|
||||
},
|
||||
]
|
||||
|
||||
workbook = load_workbook(
|
||||
@@ -71,13 +114,38 @@ class ReportExporterTests(TestCase):
|
||||
self.assertIn("Owner User", workbook.sheetnames[1])
|
||||
self.assertIn("Team Mate", workbook.sheetnames[2])
|
||||
|
||||
worksheet = workbook.active
|
||||
values = list(worksheet.iter_rows(values_only=True))
|
||||
summary_sheet = workbook[workbook.sheetnames[0]]
|
||||
summary_values = list(summary_sheet.iter_rows(values_only=True))
|
||||
|
||||
self.assertTrue(any(row[:2] == ("User", "Owner User") for row in values if row))
|
||||
self.assertTrue(any(row[:2] == ("Mobile", "09129990001") for row in values if row))
|
||||
self.assertEqual(summary_sheet["A1"].value, "Workspace Report")
|
||||
self.assertEqual(summary_sheet["B1"].value, "Exports")
|
||||
self.assertEqual(summary_sheet["A15"].value, "Users Summary")
|
||||
self.assertIn("A15:M15", {str(item) for item in summary_sheet.merged_cells.ranges})
|
||||
self.assertEqual(
|
||||
tuple(summary_sheet.iter_rows(min_row=16, max_row=16, values_only=True))[0][:13],
|
||||
(
|
||||
"Name",
|
||||
"Mobile",
|
||||
"Working hours",
|
||||
"Non-working hours",
|
||||
"Income",
|
||||
"Hourly rate",
|
||||
"Period",
|
||||
"Clients",
|
||||
"Percentage",
|
||||
"Projects",
|
||||
"Percentage",
|
||||
"Tags",
|
||||
"Percentage",
|
||||
),
|
||||
)
|
||||
self.assertTrue(any(row and "Owner User" in row for row in summary_values))
|
||||
self.assertTrue(any(row and "09129990001" in row for row in summary_values))
|
||||
|
||||
daily_header = next(row[:6] for row in values if row and row[0] == "Date")
|
||||
user_sheet = workbook[workbook.sheetnames[1]]
|
||||
user_values = list(user_sheet.iter_rows(values_only=True))
|
||||
|
||||
daily_header = next(row[:6] for row in user_values if row and "Date" in row)
|
||||
self.assertEqual(
|
||||
daily_header,
|
||||
(
|
||||
@@ -90,7 +158,7 @@ class ReportExporterTests(TestCase):
|
||||
),
|
||||
)
|
||||
|
||||
daily_row = next(row[:6] for row in values if row and row[0] == "2026/04/12")
|
||||
daily_row = next(row[:6] for row in user_values if row and "2026/04/12" in row)
|
||||
self.assertEqual(daily_row[4], "15 USD")
|
||||
|
||||
def test_pdf_export_supports_persian_locale(self):
|
||||
@@ -98,7 +166,11 @@ class ReportExporterTests(TestCase):
|
||||
report_data = make_report_data(
|
||||
hourly_rate={"amount": "15.00", "currency": "USD"},
|
||||
)
|
||||
report_data["user_summaries"] = [make_user_summary(name="Owner User", mobile="09129990001")]
|
||||
per_user_reports = [
|
||||
{**make_report_data(user_name="Owner User", mobile="09129990001"), "user_summary": make_user_summary(name="Owner User", mobile="09129990001")}
|
||||
]
|
||||
|
||||
content = build_pdf_report(report_data=report_data, locale=locale)
|
||||
content = build_pdf_report(report_data=report_data, locale=locale, per_user_reports=per_user_reports)
|
||||
|
||||
self.assertEqual(content[:4], b"%PDF")
|
||||
|
||||
@@ -138,8 +138,18 @@ class ReportViewTests(APITestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.data["summary"]["total_duration"], "03:00:00")
|
||||
self.assertEqual(len(response.data["days"]), 2)
|
||||
self.assertEqual(len(response.data["user_summaries"]), 2)
|
||||
self.assertIsNone(response.data["days"][0]["latest_hourly_rate"])
|
||||
self.assertIsNone(response.data["days"][1]["latest_hourly_rate"])
|
||||
summaries = {item["user"]["id"]: item for item in response.data["user_summaries"]}
|
||||
owner_summary = summaries[str(self.owner.id)]
|
||||
member_summary = summaries[str(self.member.id)]
|
||||
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"], [])
|
||||
|
||||
def test_daily_rate_uses_latest_billable_entry_snapshot(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
|
||||
Reference in New Issue
Block a user