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
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"])
|