voip click2calll

This commit is contained in:
javad committed 2026-09-26 12:51:12 +03:30
1 parent cb92abbb41
commit 38b1cf06df
18 files changed
+543 -26

No files matched your search

+23 -1
View File
@@ -45,7 +45,13 @@ def test_staff_operations_pages_are_authorized_and_visually_styled(live_server,
part = Q(content_type__app_label=app_label, codename__in=codenames)
query = part if query is None else query | part
unit.permissions.add(*Permission.objects.filter(query))
staff = User.objects.create_user(username="e2e-operations", password=PASSWORD, account_type=User.AccountType.STAFF)
staff = User.objects.create_user(
username="e2e-operations",
password=PASSWORD,
account_type=User.AccountType.STAFF,
voip_extension="300",
voip_mobile="09384999655",
)
StaffProfile.objects.create(user=staff, display_name="کارشناس عملیات", primary_unit=unit)
customer = User.objects.create_user(username="e2e-carrier", mobile="09120009121", account_type=User.AccountType.CUSTOMER)
profile = CustomerProfile.objects.create(user=customer, first_name="باربری", stakeholder_type=CustomerProfile.StakeholderType.CARRIER)
@@ -76,6 +82,22 @@ def test_staff_operations_pages_are_authorized_and_visually_styled(live_server,
assert page.evaluate("getComputedStyle(document.querySelector('.operations-page')).display") == "grid"
assert page.evaluate("document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1")
page.goto(f"{live_server.url}{reverse('staff_tickets:contacts')}", wait_until="domcontentloaded")
call_trigger = page.locator("[data-voip-call-trigger]").first
call_trigger.click()
call_menu = page.locator("body > .voip-call-menu:not([hidden])")
expect(call_menu).to_be_visible()
expect(call_menu.get_by_role("menuitem")).to_have_count(2)
assert call_menu.evaluate("menu => menu.parentElement === document.body")
assert int(call_menu.evaluate("menu => getComputedStyle(menu).zIndex")) > 100000
menu_box = call_menu.bounding_box()
assert menu_box is not None
assert menu_box["x"] >= 0 and menu_box["y"] >= 0
assert menu_box["x"] + menu_box["width"] <= page.viewport_size["width"]
assert menu_box["y"] + menu_box["height"] <= page.viewport_size["height"]
page.keyboard.press("Escape")
expect(call_menu).to_be_hidden()
page.goto(f"{live_server.url}{reverse('staff_tickets:dispatch_create')}", wait_until="domcontentloaded")
expect(page).to_have_title("ردیابی E2E")
expect(page.locator(".staff-brand-copy b")).to_have_text("مرکز عملیات E2E")
+134
View File
@@ -0,0 +1,134 @@
import json
from unittest.mock import Mock, patch
import pytest
import requests
from django.urls import reverse
from apps.accounts.models import User
from apps.core.models import VoipConfiguration
from apps.customers.models import ContactGroup, CustomerProfile
from apps.staff.models import OrganizationalUnit, StaffProfile
from apps.tickets.models import TicketCategory
from apps.tickets.services import create_ticket
@pytest.fixture
def voip_data(db):
unit = OrganizationalUnit.objects.create(name="فروش تماس", slug="voip-sales")
group = ContactGroup.objects.create(name="مخاطبان تماس", unit=unit)
existing_customer = User.objects.create_user(
username="existing-voip-mobile-customer",
mobile="09384999655",
account_type=User.AccountType.CUSTOMER,
)
agent = User.objects.create_superuser(
username="voip-agent",
password="safe-password",
mobile=None,
account_type=User.AccountType.STAFF,
voip_extension="300",
voip_mobile="09384999655",
)
StaffProfile.objects.create(user=agent, primary_unit=unit, display_name="کارشناس تماس")
customer = User.objects.create_user(
username="voip-customer",
mobile="09139591708",
account_type=User.AccountType.CUSTOMER,
)
profile = CustomerProfile.objects.create(user=customer, first_name="مخاطب", last_name="آزمایشی")
profile.groups.add(group)
category = TicketCategory.objects.create(unit=unit, title="تماس فروش", slug="voip-call")
ticket = create_ticket(customer=customer, category=category, subject="پیگیری تماس", body="شرح تماس")
VoipConfiguration.objects.create(voip_call_url="http://127.0.0.1:9000/v1/click2call")
assert agent.voip_mobile == existing_customer.mobile
return agent, customer, ticket
@pytest.mark.django_db
@pytest.mark.parametrize(
"case",
(
{"method": "ip_phone", "agent_field": "agent_extension", "agent_value": "300", "key_prefix": "internal-"},
{"method": "mobile", "agent_field": "agent_mobile", "agent_value": "09384999655", "key_prefix": "mobile-"},
),
)
def test_backend_sends_voip_call(client, voip_data, case):
agent, customer, _ = voip_data
method = case["method"]
client.force_login(agent)
response_mock = Mock(content=b"{}")
response_mock.json.return_value = {}
with patch("apps.integrations.voip.requests.post", return_value=response_mock) as post:
response = client.post(
reverse("staff_tickets:contact_call", args=[customer.public_id]),
data=json.dumps({"method": method}),
content_type="application/json",
)
assert response.status_code == 200
call = post.call_args
assert call.args == ("http://127.0.0.1:9000/v1/click2call",)
assert call.kwargs["json"] == {
"method": method,
case["agent_field"]: case["agent_value"],
"customer_number": "09139591708",
"metadata": {"agent_id": str(agent.public_id), "customer_id": str(customer.public_id)},
}
assert call.kwargs["headers"]["Idempotency-Key"].startswith(case["key_prefix"])
@pytest.mark.django_db
def test_call_pages_hide_provider_url(client, voip_data):
agent, customer, ticket = voip_data
client.force_login(agent)
for route in (
reverse("staff_tickets:contacts"),
reverse("staff_tickets:contact_edit", args=[customer.public_id]),
reverse("staff_tickets:detail", args=[ticket.public_id]),
):
content = client.get(route).content.decode()
assert 'data-voip-method="ip_phone"' in content
assert 'data-voip-method="mobile"' in content
assert reverse("staff_tickets:contact_call", args=[customer.public_id]) in content
assert "http://127.0.0.1:9000/v1/click2call" not in content
assert "voip-call.js" in content
@pytest.mark.django_db
def test_call_method_availability(client, voip_data):
agent, _, ticket = voip_data
agent.voip_mobile = ""
agent.save(update_fields=["voip_mobile"])
client.force_login(agent)
content = client.get(reverse("staff_tickets:detail", args=[ticket.public_id])).content.decode()
assert 'data-voip-method="ip_phone"' in content
assert 'data-voip-method="mobile"' not in content
agent.voip_call = False
agent.save(update_fields=["voip_call"])
content = client.get(reverse("staff_tickets:detail", args=[ticket.public_id])).content.decode()
assert "data-voip-call" not in content
@pytest.mark.django_db
def test_voip_error_is_minimal(client, voip_data):
agent, customer, _ = voip_data
client.force_login(agent)
with patch("apps.integrations.voip.requests.post", side_effect=requests.ConnectionError("provider detail")):
response = client.post(
reverse("staff_tickets:contact_call", args=[customer.public_id]),
data=json.dumps({"method": "mobile"}),
content_type="application/json",
)
assert response.status_code == 502
assert response.json() == {"success": False, "message": "برقراری تماس ناموفق بود."}
agent.voip_call = False
agent.save(update_fields=["voip_call"])
response = client.post(
reverse("staff_tickets:contact_call", args=[customer.public_id]),
data=json.dumps({"method": "mobile"}),
content_type="application/json",
)
assert response.status_code == 403