button force anoncecall
This commit is contained in:
1 parent
c7993aae44
commit
9af91941d9
15 files changed
+294
-23
No files matched your search
+106
-1
@@ -4,6 +4,7 @@ from unittest.mock import Mock, patch
|
||||
import pytest
|
||||
import requests
|
||||
from django.core.management import call_command
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.accounts.models import User
|
||||
@@ -12,7 +13,7 @@ from apps.core.models import VoipConfiguration
|
||||
from apps.messaging.models import MessageReadReceipt
|
||||
from apps.notifications.models import AnnouncementJob
|
||||
from apps.staff.models import OrganizationalUnit
|
||||
from apps.tickets.models import TicketCategory
|
||||
from apps.tickets.models import TicketAccessGrant, TicketCategory
|
||||
from apps.tickets.services import create_ticket, reply_ticket
|
||||
|
||||
|
||||
@@ -222,3 +223,107 @@ def test_staff_ticket_shows_call_history_without_claiming_connection(client, ann
|
||||
assert "پذیرش درخواست، بهتنهایی برقرار شدن" in content
|
||||
assert configuration.announcement_url not in content
|
||||
assert configuration.announcement_api_key not in content
|
||||
|
||||
|
||||
def test_staff_can_queue_immediate_call_and_see_it_in_ticket(client, announcement_data):
|
||||
category, staff, customer, configuration = announcement_data
|
||||
ticket = create_ticket(customer=customer, created_by=staff, category=category, subject="تماس فوری", body="پیام نخست")
|
||||
automatic = AnnouncementJob.objects.get(message__ticket=ticket)
|
||||
MessageReadReceipt.objects.create(message=automatic.message, user=customer)
|
||||
detail_url = reverse("staff_tickets:detail", args=[ticket.public_id])
|
||||
call_url = reverse("staff_tickets:announcement_now", args=[ticket.public_id])
|
||||
client.force_login(staff)
|
||||
detail = client.get(detail_url).content.decode()
|
||||
assert call_url in detail
|
||||
assert "اطلاعرسانی تلفنی فوری" in detail
|
||||
assert "پیام اطلاعرسانی از پیش ضبطشده" in detail
|
||||
assert client.get(call_url).status_code == 405
|
||||
|
||||
response = client.post(call_url, follow=True)
|
||||
assert response.status_code == 200
|
||||
assert "درخواست اطلاعرسانی تلفنی فوری در صف قرار گرفت." in response.content.decode()
|
||||
job = AnnouncementJob.objects.get(ticket=ticket, source=AnnouncementJob.Source.MANUAL)
|
||||
assert job.message is None and job.requested_by == staff
|
||||
assert job.next_attempt_at <= timezone.now()
|
||||
assert "درخواست فوری" in response.content.decode()
|
||||
assert AnnouncementJob.objects.get(pk=automatic.pk).status == AnnouncementJob.Status.PENDING
|
||||
|
||||
provider_response = Mock(content=b"{}")
|
||||
provider_response.json.return_value = {}
|
||||
with patch("apps.integrations.announcements.requests.post", return_value=provider_response) as post:
|
||||
call_command("process_notifications", once=True)
|
||||
job.refresh_from_db()
|
||||
automatic.refresh_from_db()
|
||||
assert job.status == AnnouncementJob.Status.SENT
|
||||
assert automatic.status == AnnouncementJob.Status.PENDING
|
||||
assert post.call_args.kwargs["json"] == {"customer_number": customer.local_mobile, "announcement_id": configuration.announcement_id}
|
||||
assert post.call_args.kwargs["headers"]["Idempotency-Key"] == job.idempotency_key
|
||||
|
||||
|
||||
def test_immediate_call_coalesces_repeated_clicks(client, announcement_data):
|
||||
category, staff, customer, _ = announcement_data
|
||||
ticket = create_ticket(customer=customer, category=category, subject="تماس فوری", body="پیام مشتری")
|
||||
url = reverse("staff_tickets:announcement_now", args=[ticket.public_id])
|
||||
client.force_login(staff)
|
||||
assert client.post(url).status_code == 302
|
||||
second = client.post(url, follow=True)
|
||||
assert "در دقیقهٔ گذشته ثبت شده است" in second.content.decode()
|
||||
assert AnnouncementJob.objects.filter(ticket=ticket, source=AnnouncementJob.Source.MANUAL).count() == 1
|
||||
|
||||
|
||||
def test_immediate_call_requires_staff_reply_access_and_configuration(client, announcement_data):
|
||||
category, staff, customer, configuration = announcement_data
|
||||
ticket = create_ticket(customer=customer, category=category, subject="تماس فوری", body="پیام مشتری")
|
||||
url = reverse("staff_tickets:announcement_now", args=[ticket.public_id])
|
||||
outsider = User.objects.create_user(username="announcement-viewer", account_type="STAFF")
|
||||
TicketAccessGrant.objects.create(ticket=ticket, user=outsider, granted_by=staff, permission_level=TicketAccessGrant.Level.VIEW_ONLY)
|
||||
client.force_login(outsider)
|
||||
assert url not in client.get(reverse("staff_tickets:detail", args=[ticket.public_id])).content.decode()
|
||||
assert client.post(url).status_code == 403
|
||||
client.force_login(customer)
|
||||
assert client.post(url).status_code == 403
|
||||
assert not AnnouncementJob.objects.filter(ticket=ticket).exists()
|
||||
|
||||
client.force_login(staff)
|
||||
configuration.announcement_url = ""
|
||||
configuration.save()
|
||||
page = client.get(reverse("staff_tickets:detail", args=[ticket.public_id])).content.decode()
|
||||
assert "اطلاعرسانی تلفنی فوری" in page and "disabled" in page
|
||||
result = client.post(url, follow=True)
|
||||
assert "تنظیمات اطلاعرسانی تلفنی کامل نیست." in result.content.decode()
|
||||
assert not AnnouncementJob.objects.filter(ticket=ticket).exists()
|
||||
|
||||
|
||||
def test_immediate_call_is_processed_before_older_scheduled_calls(client, announcement_data):
|
||||
category, staff, customer, _ = announcement_data
|
||||
ticket = create_ticket(customer=customer, created_by=staff, category=category, subject="تماس فوری", body="پیام نخست")
|
||||
for message in ticket.ticket_messages.all():
|
||||
due(AnnouncementJob.objects.get(message=message))
|
||||
client.force_login(staff)
|
||||
client.post(reverse("staff_tickets:announcement_now", args=[ticket.public_id]))
|
||||
immediate = AnnouncementJob.objects.get(ticket=ticket, source=AnnouncementJob.Source.MANUAL)
|
||||
with patch("apps.integrations.announcements.requests.post", return_value=Mock(content=b"")) as post:
|
||||
call_command("process_notifications", once=True)
|
||||
assert post.call_args_list[0].kwargs["headers"]["Idempotency-Key"] == immediate.idempotency_key
|
||||
|
||||
|
||||
def test_immediate_call_retries_provider_outage_without_breaking_ticket(client, announcement_data):
|
||||
category, staff, customer, _ = announcement_data
|
||||
ticket = create_ticket(customer=customer, category=category, subject="تماس فوری", body="پیام مشتری")
|
||||
url = reverse("staff_tickets:announcement_now", args=[ticket.public_id])
|
||||
client.force_login(staff)
|
||||
client.post(url)
|
||||
job = AnnouncementJob.objects.get(ticket=ticket, source=AnnouncementJob.Source.MANUAL)
|
||||
with patch("apps.integrations.announcements.requests.post", side_effect=requests.ConnectionError("provider secret")) as post:
|
||||
call_command("process_notifications", once=True)
|
||||
job.refresh_from_db()
|
||||
assert job.status == AnnouncementJob.Status.PENDING
|
||||
assert job.last_error == "service_unreachable" and job.attempts == 1
|
||||
assert post.call_args.kwargs["headers"]["Idempotency-Key"] == job.idempotency_key
|
||||
assert client.get(reverse("staff_tickets:detail", args=[ticket.public_id])).status_code == 200
|
||||
due(job)
|
||||
with patch("apps.integrations.announcements.requests.post", return_value=Mock(content=b"")) as retry:
|
||||
call_command("process_notifications", once=True)
|
||||
job.refresh_from_db()
|
||||
assert job.status == AnnouncementJob.Status.SENT
|
||||
assert retry.call_args.kwargs["headers"]["Idempotency-Key"] == job.idempotency_key
|
||||
Reference in new issue
Block a user