You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

146 lines
6.1 KiB

from django.test import TestCase
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
from rest_framework import status
from apps.profiles.models import Institution
from apps.tickets.models import Ticket, TicketMessage, TicketStatus, TicketPriority, TicketCategory
User = get_user_model()
class Phase9TicketsAPITests(TestCase):
"""
Automated test suite for Phase 9: Official Ticketing
- Ticket Submission with Tracking Code Generation
- Ticket List & Filtering
- Ticket Detail & Message History
- User Reply & Official Astan Response Flow
- Ticket Closure & Satisfaction Rating
"""
def setUp(self):
self.client = APIClient()
self.user = User.objects.create_user(
email="[email protected]",
password="Password123!",
fullname="Sheikh Ali Ammar",
user_type=User.UserType.INSTITUTION_ADMIN,
)
self.staff_user = User.objects.create_user(
email="[email protected]",
password="AdminPassword123!",
fullname="Mohammad Hosseini",
user_type=User.UserType.SUPER_ADMIN,
is_staff=True,
)
self.institution = Institution.objects.create(
name="Imam Ali Cultural Center Beirut",
country="Lebanon",
city="Beirut",
type=Institution.InstitutionType.CULTURAL_CENTER,
)
def test_ticket_creation_and_auto_tracking_code(self):
self.client.force_authenticate(user=self.user)
payload = {
"subject": "Request for specialized cultural books and exhibition materials",
"category": TicketCategory.CULTURAL_AFFAIRS,
"priority": TicketPriority.HIGH,
"institution": self.institution.id,
"content": "We are organizing the annual Razavi Cultural Week in Beirut and request books in Arabic.",
}
response = self.client.post("/api/v1/tickets/", payload, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(response.data["tracking_code"].startswith("TK-RAZAVI-"))
self.assertEqual(response.data["status"], TicketStatus.OPEN)
self.assertEqual(len(response.data["messages"]), 1)
self.assertEqual(response.data["messages"][0]["content"], payload["content"])
def test_ticket_listing_and_filtering(self):
self.client.force_authenticate(user=self.user)
# Create two tickets
t1 = Ticket.objects.create(
user=self.user,
subject="Theological inquiry",
category=TicketCategory.RELIGIOUS_INQUIRY,
priority=TicketPriority.MEDIUM,
status=TicketStatus.OPEN,
)
t2 = Ticket.objects.create(
user=self.user,
subject="Financial grant clarification",
category=TicketCategory.FINANCIAL_LEGAL,
priority=TicketPriority.URGENT,
status=TicketStatus.IN_PROGRESS,
)
response = self.client.get("/api/v1/tickets/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2)
# Filter by priority
res_filter = self.client.get(f"/api/v1/tickets/?priority={TicketPriority.URGENT}")
self.assertEqual(res_filter.status_code, status.HTTP_200_OK)
self.assertEqual(len(res_filter.data), 1)
self.assertEqual(res_filter.data[0]["id"], t2.id)
def test_ticket_dialogue_reply_and_official_response(self):
ticket = Ticket.objects.create(
user=self.user,
subject="Cooperation Inquiry",
category=TicketCategory.INTER_CENTER_COOPERATION,
status=TicketStatus.OPEN,
)
# 1. Staff replies with official response
self.client.force_authenticate(user=self.staff_user)
reply_payload = {
"content": "Your request has been approved by the Department of International Cultural Affairs.",
"department_label": "International Cultural Affairs Desk",
}
response = self.client.post(f"/api/v1/tickets/{ticket.tracking_code}/reply/", reply_payload, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertTrue(response.data["is_official_response"])
self.assertEqual(response.data["department_label"], "International Cultural Affairs Desk")
# Ticket status should automatically transition to 'answered'
ticket.refresh_from_db()
self.assertEqual(ticket.status, TicketStatus.ANSWERED)
self.assertEqual(ticket.assigned_expert, self.staff_user)
# 2. User replies back
self.client.force_authenticate(user=self.user)
user_reply = {"content": "Thank you for the prompt official confirmation."}
res_user = self.client.post(f"/api/v1/tickets/{ticket.tracking_code}/reply/", user_reply, format="json")
self.assertEqual(res_user.status_code, status.HTTP_201_CREATED)
self.assertFalse(res_user.data["is_official_response"])
ticket.refresh_from_db()
self.assertEqual(ticket.status, TicketStatus.IN_PROGRESS)
def test_ticket_close_and_rating(self):
ticket = Ticket.objects.create(
user=self.user,
subject="General questions",
status=TicketStatus.ANSWERED,
)
self.client.force_authenticate(user=self.user)
# 1. Close ticket
close_res = self.client.post(f"/api/v1/tickets/{ticket.id}/close/")
self.assertEqual(close_res.status_code, status.HTTP_200_OK)
self.assertEqual(close_res.data["status"], TicketStatus.CLOSED)
self.assertIsNotNone(close_res.data["closed_at"])
# 2. Submit rating
rate_payload = {
"rating": 5,
"feedback": "Outstanding speed and support from Astan officers.",
}
rate_res = self.client.post(f"/api/v1/tickets/{ticket.id}/rate/", rate_payload, format="json")
self.assertEqual(rate_res.status_code, status.HTTP_200_OK)
self.assertEqual(rate_res.data["satisfaction_rating"], 5)
self.assertEqual(rate_res.data["feedback_comment"], rate_payload["feedback"])