from datetime import datetime from io import BytesIO from unittest.mock import MagicMock, patch from uuid import uuid4 from openpyxl import load_workbook from rest_framework import status from rest_framework.test import APITestCase from utils.clients.gooyal_advertising_client.models.ticket_state_enum import TicketStateEnum class GenerateReportTests(APITestCase): def _build_ticket(self, user_uuid=None): ticket = MagicMock() ticket.uuid = uuid4() ticket.user = user_uuid or uuid4() ticket.title = "Login issue" ticket.description = "Cannot login" ticket.state = TicketStateEnum(10) ticket.created_at = datetime(2026, 5, 20, 10, 0) ticket.updated_at = datetime(2026, 5, 21, 10, 0) return ticket def _build_user(self, user_uuid): user = MagicMock() user.uuid = user_uuid user.username = "alice" user.first_name = "Alice" user.last_name = "Doe" user.email = "alice@example.com" user.phone_number = "09120000000" return user @patch("apps.reports.services.data_sources.ReportDataSources.fetch_user_metrics") @patch("apps.reports.services.data_sources.ReportDataSources.fetch_users") def test_generate_user_report_is_public_and_returns_excel( self, mock_fetch_users, mock_fetch_user_metrics, ): user = self._build_user(uuid4()) mock_fetch_users.return_value = [user] mock_fetch_user_metrics.return_value = {str(user.uuid): {"ticket_count": 3}} response = self.client.post( "/api/reports/generate/", { "report_type": "user", "filters": {"status": "active"}, }, format="json", ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( response["Content-Type"], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ) self.assertEqual( response["Content-Disposition"], 'attachment; filename="user-report.xlsx"', ) workbook = load_workbook(BytesIO(response.content)) worksheet = workbook.active self.assertEqual(worksheet["A1"].value, "User Report") self.assertEqual( [cell.value for cell in worksheet[2]], [ "User UUID", "Username", "First Name", "Last Name", "Email", "Phone Number", "Ticket Count", ], ) self.assertEqual( [cell.value for cell in worksheet[3]], [ str(user.uuid), "alice", "Alice", "Doe", "alice@example.com", "09120000000", 3, ], ) mock_fetch_users.assert_called_once_with({"status": "active"}) @patch("apps.reports.services.data_sources.ReportDataSources.fetch_ticket_metrics") @patch("apps.reports.services.data_sources.ReportDataSources.fetch_tickets") def test_generate_tickets_report_uses_static_columns( self, mock_fetch_tickets, mock_fetch_ticket_metrics, ): ticket = self._build_ticket() mock_fetch_tickets.return_value = [ticket] mock_fetch_ticket_metrics.return_value = {} response = self.client.post( "/api/reports/generate/", {"report_type": "tickets"}, format="json", ) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual( response["Content-Disposition"], 'attachment; filename="tickets-report.xlsx"', ) workbook = load_workbook(BytesIO(response.content)) worksheet = workbook.active self.assertEqual(worksheet["A1"].value, "Tickets Report") self.assertEqual( [cell.value for cell in worksheet[2]], [ "Ticket UUID", "User UUID", "Title", "Description", "State", "Created At", "Updated At", ], ) self.assertEqual( [cell.value for cell in worksheet[3]], [ str(ticket.uuid), str(ticket.user), "Login issue", "Cannot login", "CLOSED", "2026-05-20 10:00:00", "2026-05-21 10:00:00", ], ) def test_unknown_report_type_returns_validation_error(self): response = self.client.post( "/api/reports/generate/", {"report_type": "unknown"}, format="json", ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)