fix button force anoncecall
This commit is contained in:
1 parent
9af91941d9
commit
4525ec3e6a
9 files changed
+99
-48
No files matched your search
@@ -11,12 +11,12 @@ class TicketConversationPage(BasePage):
|
||||
def request_immediate_announcement(self):
|
||||
card = self.page.get_by_role("region", name="اطلاعرسانی تلفنی فوری")
|
||||
expect(card).to_be_visible()
|
||||
expect(card).to_contain_text("پیام اطلاعرسانی از پیش ضبطشده")
|
||||
button = card.get_by_role("button", name="ارسال اطلاعرسانی تلفنی فوری")
|
||||
expect(card).to_contain_text("پیام صوتی از پیش ضبطشده")
|
||||
button = card.get_by_role("button", name="اطلاعرسانی تلفنی فوری")
|
||||
expect(button).to_be_enabled()
|
||||
with self.page.expect_navigation(wait_until="domcontentloaded"):
|
||||
button.click()
|
||||
expect(self.page.get_by_text("درخواست اطلاعرسانی تلفنی فوری در صف قرار گرفت.")).to_be_visible()
|
||||
expect(self.page.get_by_text("درخواست تماس توسط سرویس پذیرفته شد.")).to_be_visible()
|
||||
expect(self.page.get_by_role("region", name="وضعیت اطلاعرسانیهای تلفنی")).to_contain_text("درخواست فوری")
|
||||
|
||||
def send_reply(self, body):
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import base64
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
from django.contrib.auth.models import Permission
|
||||
@@ -41,7 +42,9 @@ def test_staff_can_request_immediate_announcement_from_ticket_sidebar(live_serve
|
||||
AuthenticationPage(page, live_server.url).login_staff(staff, PASSWORD)
|
||||
conversation = TicketConversationPage(page, live_server.url)
|
||||
conversation.goto(reverse("staff_tickets:detail", args=[ticket.public_id]))
|
||||
conversation.request_immediate_announcement()
|
||||
with patch("apps.integrations.announcements.requests.post", return_value=Mock(content=b"")) as post:
|
||||
conversation.request_immediate_announcement()
|
||||
post.assert_called_once()
|
||||
|
||||
|
||||
def test_staff_operations_pages_are_authorized_and_visually_styled(live_server, browser_page):
|
||||
|
||||
+56
-25
@@ -11,7 +11,7 @@ from apps.accounts.models import User
|
||||
from apps.core.admin import VoipConfigurationAdmin
|
||||
from apps.core.models import VoipConfiguration
|
||||
from apps.messaging.models import MessageReadReceipt
|
||||
from apps.notifications.models import AnnouncementJob
|
||||
from apps.notifications.models import AnnouncementJob, NotificationJob
|
||||
from apps.staff.models import OrganizationalUnit
|
||||
from apps.tickets.models import TicketAccessGrant, TicketCategory
|
||||
from apps.tickets.services import create_ticket, reply_ticket
|
||||
@@ -34,7 +34,7 @@ def announcement_people(db):
|
||||
@pytest.fixture
|
||||
def announcement_data(announcement_catalog, announcement_people):
|
||||
configuration = VoipConfiguration.objects.create(
|
||||
announcement_url="http://192.168.138.215:8000/v1/announcements",
|
||||
announcement_url="http://37.255.224.143:8009/v1/announcements",
|
||||
announcement_id="custom/fereshte1_G711",
|
||||
announcement_delay_minutes=90,
|
||||
)
|
||||
@@ -236,28 +236,26 @@ def test_staff_can_queue_immediate_call_and_see_it_in_ticket(client, announcemen
|
||||
detail = client.get(detail_url).content.decode()
|
||||
assert call_url in detail
|
||||
assert "اطلاعرسانی تلفنی فوری" in detail
|
||||
assert "پیام اطلاعرسانی از پیش ضبطشده" in detail
|
||||
assert "پیام صوتی از پیش ضبطشده" in detail
|
||||
assert detail.index("وضعیت پیامکهای مشتری") < detail.index('aria-label="اطلاعرسانی تلفنی فوری"')
|
||||
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()
|
||||
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.status == AnnouncementJob.Status.SENT
|
||||
assert automatic.status == AnnouncementJob.Status.PENDING
|
||||
assert "درخواست فوری" in response.content.decode()
|
||||
assert AnnouncementJob.objects.get(pk=automatic.pk).status == AnnouncementJob.Status.PENDING
|
||||
|
||||
post.assert_called_once()
|
||||
assert post.call_args.args == (configuration.announcement_url,)
|
||||
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
|
||||
assert post.call_args.kwargs["headers"] == {"Idempotency-Key": job.idempotency_key}
|
||||
|
||||
|
||||
def test_immediate_call_coalesces_repeated_clicks(client, announcement_data):
|
||||
@@ -265,10 +263,12 @@ def test_immediate_call_coalesces_repeated_clicks(client, 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)
|
||||
with patch("apps.integrations.announcements.requests.post", return_value=Mock(content=b"")) as post:
|
||||
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
|
||||
post.assert_called_once()
|
||||
|
||||
|
||||
def test_immediate_call_requires_staff_reply_access_and_configuration(client, announcement_data):
|
||||
@@ -300,11 +300,14 @@ def test_immediate_call_is_processed_before_older_scheduled_calls(client, announ
|
||||
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]))
|
||||
with patch("apps.integrations.announcements.requests.post", return_value=Mock(content=b"")) as immediate_post:
|
||||
client.post(reverse("staff_tickets:announcement_now", args=[ticket.public_id]))
|
||||
immediate = AnnouncementJob.objects.get(ticket=ticket, source=AnnouncementJob.Source.MANUAL)
|
||||
assert immediate.status == AnnouncementJob.Status.SENT
|
||||
immediate_post.assert_called_once()
|
||||
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
|
||||
assert all(call.kwargs["headers"]["Idempotency-Key"] != immediate.idempotency_key for call in post.call_args_list)
|
||||
|
||||
|
||||
def test_immediate_call_retries_provider_outage_without_breaking_ticket(client, announcement_data):
|
||||
@@ -312,11 +315,10 @@ def test_immediate_call_retries_provider_outage_without_breaking_ticket(client,
|
||||
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()
|
||||
result = client.post(url, follow=True)
|
||||
job = AnnouncementJob.objects.get(ticket=ticket, source=AnnouncementJob.Source.MANUAL)
|
||||
assert "تلاش مجدد در صف قرار گرفت" in result.content.decode()
|
||||
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
|
||||
@@ -327,3 +329,32 @@ def test_immediate_call_retries_provider_outage_without_breaking_ticket(client,
|
||||
job.refresh_from_db()
|
||||
assert job.status == AnnouncementJob.Status.SENT
|
||||
assert retry.call_args.kwargs["headers"]["Idempotency-Key"] == job.idempotency_key
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_worker_skips_sms_provider_when_no_delivery_check_is_due():
|
||||
with patch("apps.notifications.management.commands.process_notifications.get_sms_provider", side_effect=RuntimeError("SMS provider unavailable")) as sms_provider:
|
||||
call_command("process_notifications", once=True)
|
||||
sms_provider.assert_not_called()
|
||||
|
||||
|
||||
def test_sms_delivery_provider_error_does_not_stop_worker(announcement_data):
|
||||
category, staff, customer, _ = announcement_data
|
||||
ticket = create_ticket(customer=customer, created_by=staff, category=category, subject="تماس فوری", body="پیام")
|
||||
sms_job = NotificationJob.objects.create(
|
||||
channel=NotificationJob.Channel.SMS,
|
||||
event_type="CUSTOMER_TICKET_CREATED",
|
||||
ticket=ticket,
|
||||
customer=customer,
|
||||
status=NotificationJob.Status.SENT,
|
||||
next_attempt_at=timezone.now(),
|
||||
delivery_status=NotificationJob.DeliveryStatus.PENDING,
|
||||
delivery_next_check_at=timezone.now() - timedelta(seconds=1),
|
||||
provider_message_id="provider-id",
|
||||
dedupe_key="sms-delivery-failure-does-not-stop-worker",
|
||||
)
|
||||
with patch("apps.notifications.management.commands.process_notifications.get_sms_provider", side_effect=RuntimeError("provider unavailable")):
|
||||
call_command("process_notifications", once=True)
|
||||
sms_job.refresh_from_db()
|
||||
assert sms_job.delivery_status == NotificationJob.DeliveryStatus.PENDING
|
||||
assert sms_job.delivery_next_check_at > timezone.now()
|
||||
Reference in new issue
Block a user