test: add tests

This commit is contained in:
Pratik
2026-01-14 14:10:11 +00:00
parent c2b55a67e1
commit fbe2b45939
12 changed files with 734 additions and 150 deletions
+24 -4
View File
@@ -152,10 +152,26 @@ import { computed, provide, ref } from "vue";
import ChartItem from "./components/ChartItem.vue";
import { __ } from "@/translation";
type LayoutItem = {
chart: string;
data: Record<string, unknown>;
layout: {
x: number;
y: number;
w: number;
h: number;
i: string;
minW?: number;
minH?: number;
maxW?: number;
maxH?: number;
};
};
const { userName, userId } = storeToRefs(useAuthStore());
const editing = ref(false);
const layout = ref([]);
const oldLayout = ref([]);
const layout = ref<LayoutItem[]>([]);
const oldLayout = ref<LayoutItem[]>([]);
const isDirty = computed(() => {
return JSON.stringify(layout.value) !== JSON.stringify(oldLayout.value);
@@ -167,9 +183,13 @@ const isLoading = computed(() => {
});
const agentDashboard = createResource({
url: "helpdesk.api.agent_dashboard.get_dashboard",
url: "helpdesk.api.agent_home.agent_home.get_dashboard",
auto: true,
onSuccess(data) {
onSuccess(data: {
layout: LayoutItem[];
default_layout: string;
dashboard_id?: string;
}) {
layout.value = data.layout;
},
});
@@ -58,7 +58,7 @@ const chartConfig = computed(() => {
});
const getAgentTicketsResource = createResource({
url: "helpdesk.api.agent_dashboard.get_agent_tickets",
url: "helpdesk.api.agent_home.agent_home.get_agent_tickets",
type: "GET",
makeParams: () => {
return {
@@ -58,7 +58,7 @@ const chartConfig = computed(() => {
});
const getAvgFirstResponseTimeResource = createResource({
url: "helpdesk.api.agent_dashboard.get_avg_first_response_time",
url: "helpdesk.api.agent_home.agent_home.get_avg_first_response_time",
type: "GET",
makeParams: () => {
return {
@@ -57,7 +57,7 @@ const chartConfig = computed(() => {
});
const getAvgResolutionTimeResource = createResource({
url: "helpdesk.api.agent_dashboard.get_avg_resolution_time",
url: "helpdesk.api.agent_home.agent_home.get_avg_resolution_time",
type: "GET",
makeParams: () => {
return {
@@ -67,7 +67,7 @@
</template>
<script setup lang="ts">
import { computed, h, markRaw, onMounted, ref } from "vue";
import { computed, onMounted, ref } from "vue";
import EChart from "./EChart.vue";
import { EChartsOption } from "echarts";
import { createResource, TabButtons } from "frappe-ui";
@@ -84,7 +84,7 @@ const props = defineProps({
const currentDuration = ref("6m");
const getAvgTimeMetricsResource = createResource({
url: "helpdesk.api.agent_dashboard.get_avg_time_metrics",
url: "helpdesk.api.agent_home.agent_home.get_avg_time_metrics",
type: "GET",
makeParams: () => {
return {
@@ -132,8 +132,12 @@ const chartConfig = computed<EChartsOption>(() => {
color: "#000",
},
formatter: (params) => {
const [category, firstResponse, resolution] = params.data;
if (params.seriesIndex === 0) {
const p = params as unknown as {
data: [string, number, number];
seriesIndex: number;
};
const [category, firstResponse, resolution] = p.data;
if (p.seriesIndex === 0) {
return `<span>${category}</span><br/>${__(
"Avg. First Response"
)}: <b>${formatTime(firstResponse, {
@@ -162,7 +166,7 @@ const chartConfig = computed<EChartsOption>(() => {
},
yAxis: {
axisLabel: {
formatter: (value) => {
formatter: (value: number) => {
if (value < 3600) {
return (value / 60).toFixed(0) + "m";
} else if (value < 86400) {
@@ -163,7 +163,7 @@ const chartConfig = computed(() => {
});
const getPendingTicketsResource = createResource({
url: "helpdesk.api.agent_dashboard.get_pending_tickets",
url: "helpdesk.api.agent_home.agent_home.get_pending_tickets",
});
function getPriorityBadgeColor(integerValue: number) {
@@ -412,7 +412,7 @@ const getRatingColor = (rating: number) => {
};
const getRecentFeedbackResource = createResource({
url: "helpdesk.api.agent_dashboard.get_recent_feedback",
url: "helpdesk.api.agent_home.agent_home.get_recent_feedback",
makeParams: () => ({
period: currentPeriod.value,
sort_order: currentSort.value,
@@ -119,7 +119,7 @@ const goToAllTickets = () => {
};
const getRecentlyAssignedTickets = createResource({
url: "helpdesk.api.agent_dashboard.get_recently_assigned_tickets",
url: "helpdesk.api.agent_home.agent_home.get_recently_assigned_tickets",
type: "GET",
});
@@ -222,17 +222,44 @@ import { computed, onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router";
import TimerIcon from "~icons/lucide/timer";
const props = defineProps({
data: {
type: Object,
required: true,
},
});
interface SlaTicket {
name: string;
subject: string;
status: string;
priority: string;
integer_value: number;
agent_group: string;
first_responded_on: string | null;
response_by: string;
resolution_date: string | null;
resolution_by: string;
}
interface SlaViolationsData {
total_sla_violations_count: number;
upcoming_sla_violations: SlaTicket[];
min_priority: number;
max_priority: number;
}
interface SortByFieldname {
label: string;
value: string;
}
interface SortBy {
direction: "asc" | "desc";
fieldname: SortByFieldname;
}
const props = defineProps<{
data: SlaViolationsData;
}>();
const { getStatus } = useTicketStatusStore();
const router = useRouter();
const priorityFilter = ref("");
const sortBy = ref({
const sortBy = ref<SortBy>({
direction: "asc",
fieldname: {
label: __("First Response"),
@@ -245,7 +272,7 @@ const getPriorityListResource = createListResource({
doctype: "HD Ticket Priority",
fields: ["name"],
auto: true,
transform(data) {
transform(data: { name: string }[]) {
return data.map((d) => d.name);
},
});
@@ -302,7 +329,7 @@ const sortDropdownOptions = computed(() => {
});
const upcomingSlaViolations = createResource({
url: "helpdesk.api.agent_dashboard.get_upcoming_sla_violations",
url: "helpdesk.api.agent_home.agent_home.get_upcoming_sla_violations",
});
function getPriorityBadgeColor(integerValue: number) {
@@ -317,7 +344,7 @@ function getPriorityBadgeColor(integerValue: number) {
return "gray";
}
const goToTicket = (ticket: any) => {
const goToTicket = (ticket: SlaTicket) => {
router.push({
name: "TicketAgent",
params: { ticketId: ticket.name },
@@ -47,9 +47,9 @@ def get_dashboard(reset_layout=False):
for chart in layout:
method_name = f"get_{chart['chart']}"
if hasattr(frappe.get_attr("helpdesk.api.agent_dashboard"), method_name):
if hasattr(frappe.get_attr("helpdesk.api.agent_home.agent_home"), method_name):
method = getattr(
frappe.get_attr("helpdesk.api.agent_dashboard"), method_name
frappe.get_attr("helpdesk.api.agent_home.agent_home"), method_name
)
chart["data"] = method()
else:
@@ -232,79 +232,6 @@ def get_avg_resolution_time(period="last month"):
return _get_avg_time_metric(period, "resolution_time")
@frappe.whitelist()
@agent_only
def get_unresolved_tickets():
allowed_statuses = frappe.get_all(
"HD Ticket Status", filters={"category": ["!=", "Resolved"]}, pluck="name"
)
count = frappe.db.count(
"HD Ticket",
filters=[
["_assign", "like", f"%{frappe.session.user}%"],
["status", "in", allowed_statuses],
],
)
return {"total": count}
@frappe.whitelist()
@agent_only
def get_recently_assigned_tickets():
one_week_ago = frappe.utils.add_days(frappe.utils.nowdate(), -7)
todo = DocType("ToDo")
assigned_tickets = (
frappe.qb.from_(todo)
.select(todo.reference_name)
.distinct()
.where(todo.reference_type == "HD Ticket")
.where(todo.allocated_to == frappe.session.user)
.where(todo.creation >= one_week_ago)
.where(todo.status == "Open")
.run(as_dict=False)
)
ticket_names = [row[0] for row in assigned_tickets]
if not ticket_names:
return {"count": 0, "tickets": []}
allowed_statuses = frappe.get_all(
"HD Ticket Status", filters={"category": ["!=", "Resolved"]}, pluck="name"
)
# Count tickets assigned in past week that are still assigned and not resolved
count = frappe.db.count(
"HD Ticket",
filters=[
["name", "in", ticket_names],
["_assign", "like", f"%{frappe.session.user}%"],
["status", "in", allowed_statuses],
],
)
tickets = frappe.get_list(
"HD Ticket",
fields=[
"name",
"subject",
"status",
"priority",
"modified",
"creation",
],
filters=[
["name", "in", ticket_names],
["_assign", "like", f"%{frappe.session.user}%"],
["status", "in", allowed_statuses],
],
order_by="modified desc",
limit=5,
)
return {"count": count, "tickets": tickets}
@frappe.whitelist()
@agent_only
def get_recent_feedback(period="all_time", sort_order="positive_first"):
@@ -776,53 +703,3 @@ def get_pending_tickets(ticket_type="all"):
"min_priority": min_priority,
"max_priority": max_priority,
}
@frappe.whitelist()
@agent_only
def get_upcoming_sla_violations(priority=None, order_by="response_by asc"):
filters = [
["sla", "!=", ""],
["agreement_status", "in", ["First Response Due", "Resolution Due"]],
["status_category", "!=", "Closed"],
["_assign", "like", f"%{frappe.session.user}%"],
["resolution_by", ">", frappe.utils.now()],
["response_by", ">", frappe.utils.now()],
]
if priority:
filters.append(["priority", "=", priority])
# Get total count of tickets about to breach SLA
total_sla_violations_count = frappe.db.count("HD Ticket", filters=filters)
upcoming_sla_violations = frappe.get_list(
"HD Ticket",
fields=[
"name",
"subject",
"status",
"priority",
"priority.integer_value",
"agent_group",
"response_by",
"resolution_by",
"resolution_date",
"agreement_status",
"status_category",
"first_responded_on",
],
filters=filters,
order_by=order_by,
limit=5,
)
priorities = frappe.get_all("HD Ticket Priority", fields="integer_value")
min_priority = min(priorities, key=lambda x: x["integer_value"])["integer_value"]
max_priority = max(priorities, key=lambda x: x["integer_value"])["integer_value"]
return {
"upcoming_sla_violations": upcoming_sla_violations,
"total_sla_violations_count": total_sla_violations_count,
"min_priority": min_priority,
"max_priority": max_priority,
}
+638
View File
@@ -0,0 +1,638 @@
# Copyright (c) 2024, Frappe Technologies and Contributors
# See license.txt
import json
import frappe
from frappe.tests import IntegrationTestCase
from helpdesk.api.agent_home.agent_home import (
get_agent_tickets,
get_avg_first_response_time,
get_avg_resolution_time,
get_avg_time_metrics,
get_dashboard,
get_default_agent_dashboard,
get_pending_tickets,
get_recent_feedback,
)
from helpdesk.test_utils import make_agent, make_sla, make_ticket
agent_email = "[email protected]"
def set_ticket_timestamps(
ticket_name: str,
creation=None,
modified=None,
first_response_time=None,
resolution_time=None,
):
"""
Updates ticket timestamps directly in the database.
Useful for creating test tickets with specific dates.
"""
if creation:
frappe.db.set_value("HD Ticket", ticket_name, "creation", creation)
if modified:
frappe.db.sql(
"UPDATE `tabHD Ticket` SET modified=%s WHERE name=%s",
(modified, ticket_name),
)
if first_response_time:
frappe.db.set_value(
"HD Ticket", ticket_name, "first_response_time", first_response_time
)
if resolution_time:
frappe.db.set_value(
"HD Ticket", ticket_name, "resolution_time", resolution_time
)
def create_ticket_with_agent(
agent: str = None,
creation=None,
modified=None,
first_response_time=None,
resolution_time=None,
**kwargs,
):
"""
Creates a ticket with flexible options including agent assignment and timestamps.
Combines make_ticket functionality with agent assignment and timestamp setting.
"""
ticket = make_ticket(**kwargs)
if agent:
ticket.assign_agent(agent)
if creation or modified or first_response_time or resolution_time:
set_ticket_timestamps(
ticket.name,
creation=creation,
modified=modified,
first_response_time=first_response_time,
resolution_time=resolution_time,
)
return ticket
class TestAgentHome(IntegrationTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
make_agent(agent_email, "Test Agent")
frappe.set_user(agent_email)
@classmethod
def tearDownClass(cls):
frappe.set_user("Administrator")
super().tearDownClass()
def setUp(self):
frappe.set_user(agent_email)
# Clean up tickets before each test
frappe.db.delete("HD Ticket")
frappe.db.delete("HD Field Layout", {"user": agent_email})
frappe.db.commit()
def _create_ticket(
self,
agent=None,
creation=None,
modified=None,
first_response_time=None,
resolution_time=None,
**kwargs,
):
"""Helper to create a ticket with flexible options"""
if agent is None:
agent = agent_email
# Use default values if not provided in kwargs
if "subject" not in kwargs:
kwargs["subject"] = "Test Ticket"
if "description" not in kwargs:
kwargs["description"] = "Test Description"
return create_ticket_with_agent(
agent=agent,
creation=creation,
modified=modified,
first_response_time=first_response_time,
resolution_time=resolution_time,
**kwargs,
)
def test_returns_valid_json(self):
"""Test that default dashboard returns valid JSON string"""
result = get_default_agent_dashboard()
self.assertIsInstance(result, str)
# Should be parseable as JSON
parsed = json.loads(result)
self.assertIsInstance(parsed, list)
def test_get_dashboard_with_existing_layout(self):
"""Test dashboard retrieval when layout exists"""
# Create a layout for the user
layout_doc = frappe.get_doc(
{
"doctype": "HD Field Layout",
"user": agent_email,
"layout": get_default_agent_dashboard(),
}
).insert(ignore_permissions=True)
result = get_dashboard()
self.assertEqual(result["dashboard_id"], layout_doc.name)
def test_reset_layout(self):
"""Test dashboard reset functionality"""
# Create a custom layout
custom_layout = json.dumps([{"chart": "custom_chart", "layout": {}}])
frappe.get_doc(
{
"doctype": "HD Field Layout",
"user": agent_email,
"layout": custom_layout,
}
).insert(ignore_permissions=True)
result = get_dashboard(reset_layout=True)
# Should return default layout structure
default_layout = json.loads(get_default_agent_dashboard())
self.assertEqual(len(result["layout"]), len(default_layout))
def test_get_agent_tickets_different_periods(self):
"""Test different period options"""
now = frappe.utils.nowdate()
# T1: 2 days ago (matches all periods: week, month, 3 months)
self._create_ticket(
creation=frappe.utils.add_days(now, -2),
subject="Ticket 2 days ago",
)
# T2: 10 days ago (matches: month, 3 months)
self._create_ticket(
creation=frappe.utils.add_days(now, -10),
subject="Ticket 10 days ago",
)
# T3: 40 days ago (matches: 3 months only)
self._create_ticket(
creation=frappe.utils.add_days(now, -40),
subject="Ticket 40 days ago",
)
# Test last week (7 days) - Should see 1 ticket (T1)
result = get_agent_tickets(period="last week")
self.assertIn("data", result)
self.assertIn("total", result)
self.assertIn("percentage_change", result)
self.assertEqual(result["total"], 1)
# Verify data is a list with date entries
self.assertIsInstance(result["data"], list)
self.assertEqual(len(result["data"]), 7) # 7 days of data
# Test last month (30 days) - Should see 2 tickets (T1, T2)
result = get_agent_tickets(period="last month")
self.assertEqual(result["total"], 2)
self.assertEqual(len(result["data"]), 30) # 30 days of data
# Test last 3 months (90 days) - Should see 3 tickets (T1, T2, T3)
result = get_agent_tickets(period="last 3 months")
self.assertEqual(result["total"], 3)
self.assertEqual(len(result["data"]), 90) # 90 days of data
def test_get_agent_tickets_count_per_agent(self):
"""Test that ticket count is retrieved correctly for each agent"""
# Create a second agent
second_agent_email = "[email protected]"
make_agent(second_agent_email, "Test Agent 2")
# Create 2 tickets assigned to the first agent ([email protected])
self._create_ticket()
self._create_ticket()
# Create 3 tickets assigned to the second agent
for _ in range(3):
self._create_ticket(
agent=second_agent_email,
subject="Test Ticket for Agent 2",
)
# Verify first agent sees only their 2 tickets
frappe.set_user(agent_email)
result = get_agent_tickets()
self.assertEqual(result["total"], 2)
# Verify second agent sees only their 3 tickets
frappe.set_user(second_agent_email)
result = get_agent_tickets()
self.assertEqual(result["total"], 3)
# Switch back to original agent
frappe.set_user(agent_email)
def _test_avg_metric(self, method, field_name):
"""Helper to test average time metric calculations"""
# Create tickets for "Current" period (Last 30 days)
# Using 2 days ago
current_date_1 = frappe.utils.add_days(frappe.utils.nowdate(), -2)
self._create_ticket(
creation=current_date_1, **{field_name: 30}
) # 30 mins/hours
self._create_ticket(
creation=current_date_1, **{field_name: 60}
) # 60 mins/hours
# Current Avg = (30 + 60) / 2 = 45
# Create tickets for "Previous" period (30-60 days ago)
# Using 35 days ago
previous_date_1 = frappe.utils.add_days(frappe.utils.nowdate(), -35)
self._create_ticket(
creation=previous_date_1, **{field_name: 20}
) # 20 mins/hours
self._create_ticket(
creation=previous_date_1, **{field_name: 40}
) # 40 mins/hours
# Previous Avg = (20 + 40) / 2 = 30
# Calculate Expected Percentage Change
# ((Current - Previous) / Previous) * 100
# ((45 - 30) / 30) * 100 = (15 / 30) * 100 = 50.0
result = method(period="last month")
self.assertEqual(result["average"], 45.0)
self.assertEqual(result["percentage_change"], 50.0)
def test_get_avg_first_response_time(self):
"""Test average first response time calculation"""
self._test_avg_metric(get_avg_first_response_time, "first_response_time")
def test_get_avg_resolution_time(self):
"""Test average resolution time calculation"""
self._test_avg_metric(get_avg_resolution_time, "resolution_time")
def test_get_recent_feedback_rating_distribution(self):
"""Test average and distribution calculations with multiple feedbacks"""
# Create multiple tickets with different ratings
self._create_ticket(feedback_rating=1.0) # 5 stars
self._create_ticket(feedback_rating=0.6) # 3 stars
self._create_ticket(feedback_rating=0.2) # 1 star
# Avg = (5 + 3 + 1) / 3 = 3.0
result = get_recent_feedback()
self.assertEqual(result["total_feedbacks"], 3)
self.assertEqual(result["average_rating"], 3.0)
dist = result["rating_distribution"]
self.assertEqual(dist[5], 1)
self.assertEqual(dist[3], 1)
self.assertEqual(dist[1], 1)
self.assertEqual(dist[2], 0)
self.assertEqual(dist[4], 0)
def test_get_recent_feedback_different_periods(self):
"""Test different period options"""
# Create tickets with different ages
now = frappe.utils.now_datetime()
# T1: Today (matches all periods)
self._create_ticket(feedback_rating=1.0, modified=now)
# T2: 10 days ago (matches last month, last 3 months, all time)
self._create_ticket(
feedback_rating=0.8, modified=frappe.utils.add_days(now, -10)
)
# T3: 40 days ago (matches last 3 months, all time)
self._create_ticket(
feedback_rating=0.6, modified=frappe.utils.add_days(now, -40)
)
# T4: 100 days ago (only matches all time)
self._create_ticket(
feedback_rating=0.4, modified=frappe.utils.add_days(now, -100)
)
# Test last_week (7 days) - Should see 1 ticket
result = get_recent_feedback(period="last_week")
self.assertEqual(result["total_feedbacks"], 1)
self.assertEqual(result["average_rating"], 5.0)
# Test last_month (30 days) - Should see 2 tickets (T1, T2)
result = get_recent_feedback(period="last_month")
self.assertEqual(result["total_feedbacks"], 2)
# Avg = (5 + 4) / 2 = 4.5
self.assertEqual(result["average_rating"], 4.5)
# Test last_3_months (90 days) - Should see 3 tickets (T1, T2, T3)
result = get_recent_feedback(period="last_3_months")
self.assertEqual(result["total_feedbacks"], 3)
# Avg = (5 + 4 + 3) / 3 = 4.0
self.assertEqual(result["average_rating"], 4.0)
# Test all_time - Should see 4 tickets
result = get_recent_feedback(period="all_time")
self.assertEqual(result["total_feedbacks"], 4)
# Avg = (5 + 4 + 3 + 2) / 4 = 3.5
self.assertEqual(result["average_rating"], 3.5)
def test_get_recent_feedback_sort_order(self):
"""Test sort order options"""
# Create tickets with different ratings
self._create_ticket(feedback_rating=1.0) # 5 stars
self._create_ticket(feedback_rating=0.6) # 3 stars
self._create_ticket(feedback_rating=0.2) # 1 star
# Test positive_first (Descending)
result = get_recent_feedback(sort_order="positive_first")
feedbacks = result["recent_feedbacks"]
self.assertEqual(len(feedbacks), 3)
self.assertEqual(feedbacks[0]["feedback_rating"], 1.0)
self.assertEqual(feedbacks[1]["feedback_rating"], 0.6)
self.assertEqual(feedbacks[2]["feedback_rating"], 0.2)
# Test negative_first (Ascending)
result = get_recent_feedback(sort_order="negative_first")
feedbacks = result["recent_feedbacks"]
self.assertEqual(len(feedbacks), 3)
self.assertEqual(feedbacks[0]["feedback_rating"], 0.2)
self.assertEqual(feedbacks[1]["feedback_rating"], 0.6)
self.assertEqual(feedbacks[2]["feedback_rating"], 1.0)
def test_get_avg_time_metrics_different_periods(self):
"""Test different period options with actual data verification"""
now = frappe.utils.now_datetime()
# Create tickets spread across the last year
# T1: 1 month ago (matches 3m, 6m, 1y)
self._create_ticket(
creation=frappe.utils.add_months(now, -1),
first_response_time=10,
resolution_time=20,
)
# T2: 4 months ago (matches 6m, 1y)
self._create_ticket(
creation=frappe.utils.add_months(now, -4),
first_response_time=20,
resolution_time=40,
)
# T3: 8 months ago (matches 1y)
self._create_ticket(
creation=frappe.utils.add_months(now, -8),
first_response_time=30,
resolution_time=60,
)
# Test 3m period (Should see T1 only)
# Avg First = 10, Avg Res = 20
result = get_avg_time_metrics(period="3m")
self.assertEqual(result["averages"]["first_response"], 10.0)
self.assertEqual(result["averages"]["resolution"], 20.0)
# Verify data points exist for the months
month_labels = [row[0] for row in result["data"]]
t1_month = frappe.utils.add_months(now, -1).strftime("%b")
self.assertIn(t1_month, month_labels)
# Test 6m period (Should see T1, T2)
# Avg First = (10 + 20) / 2 = 15
# Avg Res = (20 + 40) / 2 = 30
result = get_avg_time_metrics(period="6m")
self.assertEqual(result["averages"]["first_response"], 15.0)
self.assertEqual(result["averages"]["resolution"], 30.0)
# Test 1y period (Should see T1, T2, T3)
# Avg First = (10 + 20 + 30) / 3 = 20
# Avg Res = (20 + 40 + 60) / 3 = 40
result = get_avg_time_metrics(period="1y")
self.assertEqual(result["averages"]["first_response"], 20.0)
self.assertEqual(result["averages"]["resolution"], 40.0)
def _create_ticket_with_sla(self, priority="High", agent=None):
"""Helper to create a ticket with SLA"""
# Create SLA with condition for the priority
condition = f"doc.priority == '{priority}'"
sla = make_sla(f"Test SLA {priority}", condition)
# Configure SLA with priority settings
sla.reload()
# Clear and set support days to avoid duplicate workday validation errors
sla.support_and_resolution = []
for day in ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]:
sla.append(
"support_and_resolution",
{
"workday": day,
"start_time": "10:00:00",
"end_time": "18:00:00",
},
)
sla.priorities = []
sla.append(
"priorities",
{
"priority": priority,
"default_priority": 1,
"response_time": 60 * 60, # 1 hour
"resolution_time": 60 * 60 * 4, # 4 hours
},
)
sla.save()
# Create ticket with the specified priority
ticket = self._create_ticket(
subject="SLA Test Ticket", priority=priority, agent=agent
)
# Ensure SLA fields are set for upcoming_sla tests
ticket.reload()
return ticket
def test_get_pending_tickets_upcoming_sla_type(self):
"""Test getting upcoming SLA violation tickets"""
# Create a second agent for non-matching tickets
other_agent_email = "[email protected]"
make_agent(other_agent_email, "Other Agent SLA")
# Create SLA ticket for current agent
ticket = self._create_ticket_with_sla(priority="High")
# Create SLA ticket for OTHER agent (should NOT be returned)
other_ticket = self._create_ticket_with_sla(
priority="High", agent=other_agent_email
)
result = get_pending_tickets(ticket_type="upcoming_sla")
# Verify our SLA ticket is in the result
ticket_names = [t["name"] for t in result["tickets"]]
self.assertIn(ticket.name, ticket_names)
# Other agent's ticket should NOT be in the result
self.assertNotIn(other_ticket.name, ticket_names)
def test_get_pending_tickets_new_tickets_type(self):
"""Test getting newly assigned tickets"""
# Create a second agent for non-matching tickets
other_agent_email = "[email protected]"
make_agent(other_agent_email, "Other Agent New")
# Create new tickets for current agent
ticket1 = self._create_ticket(subject="New Test Ticket 1")
ticket2 = self._create_ticket(subject="New Test Ticket 2")
ticket3 = self._create_ticket(subject="New Test Ticket 3")
# Create tickets assigned to OTHER agent (should NOT be returned)
self._create_ticket(agent=other_agent_email, subject="Other Agent New Ticket 1")
self._create_ticket(agent=other_agent_email, subject="Other Agent New Ticket 2")
result = get_pending_tickets(ticket_type="new_tickets")
self.assertIn("tickets", result)
self.assertIn("total_pending_tickets", result)
# Only current agent's new tickets should be returned
self.assertEqual(result["total_pending_tickets"], 3)
# Verify all new tickets are in the result
ticket_names = [t["name"] for t in result["tickets"]]
self.assertIn(ticket1.name, ticket_names)
self.assertIn(ticket2.name, ticket_names)
self.assertIn(ticket3.name, ticket_names)
# Verify reason format
for t in result["tickets"]:
self.assertEqual(t["reason"]["type"], "new_tickets")
self.assertEqual(t["reason"]["text"], "Recently assigned")
def test_get_pending_tickets_pending_type(self):
"""Test getting tickets pending response"""
# Create a second agent for non-matching tickets
other_agent_email = "[email protected]"
make_agent(other_agent_email, "Other Agent Pending")
# Create tickets pending response for current agent
ticket1 = self._create_ticket(subject="Pending Response Ticket 1")
frappe.get_doc(
{
"doctype": "Communication",
"communication_type": "Communication",
"reference_doctype": "HD Ticket",
"reference_name": ticket1.name,
"sent_or_received": "Received",
"content": "Customer message 1",
}
).insert(ignore_permissions=True)
ticket2 = self._create_ticket(subject="Pending Response Ticket 2")
frappe.get_doc(
{
"doctype": "Communication",
"communication_type": "Communication",
"reference_doctype": "HD Ticket",
"reference_name": ticket2.name,
"sent_or_received": "Received",
"content": "Customer message 2",
}
).insert(ignore_permissions=True)
# Create ticket for OTHER agent with communication (should NOT be returned)
other_ticket = self._create_ticket(
agent=other_agent_email, subject="Other Agent Pending Ticket"
)
frappe.get_doc(
{
"doctype": "Communication",
"communication_type": "Communication",
"reference_doctype": "HD Ticket",
"reference_name": other_ticket.name,
"sent_or_received": "Received",
"content": "Other agent customer message",
}
).insert(ignore_permissions=True)
result = get_pending_tickets(ticket_type="pending")
# Verify current agent's pending tickets are returned
self.assertGreaterEqual(result["total_pending_tickets"], 2)
# Verify pending tickets are in the result
ticket_names = [t["name"] for t in result["tickets"]]
self.assertIn(ticket1.name, ticket_names)
self.assertIn(ticket2.name, ticket_names)
# Verify reason format
for t in result["tickets"]:
self.assertEqual(t["reason"]["type"], "pending")
self.assertIn("Pending for", t["reason"]["text"])
def test_get_pending_tickets_all_combines_types(self):
"""Test that 'all' type combines different ticket types without duplicates"""
# Create a second agent for non-matching tickets
other_agent_email = "[email protected]"
make_agent(other_agent_email, "Other Agent Combined")
# Create tickets of different types for current agent
new_ticket1 = self._create_ticket(subject="New Test Ticket 1")
new_ticket2 = self._create_ticket(subject="New Test Ticket 2")
pending_ticket = self._create_ticket(subject="Pending Response Ticket")
frappe.get_doc(
{
"doctype": "Communication",
"communication_type": "Communication",
"reference_doctype": "HD Ticket",
"reference_name": pending_ticket.name,
"sent_or_received": "Received",
"content": "Customer message",
}
).insert(ignore_permissions=True)
# Create tickets for OTHER agent (should NOT be returned)
self._create_ticket(agent=other_agent_email, subject="Other Agent New Ticket")
other_pending = self._create_ticket(
agent=other_agent_email, subject="Other Agent Pending Ticket"
)
frappe.get_doc(
{
"doctype": "Communication",
"communication_type": "Communication",
"reference_doctype": "HD Ticket",
"reference_name": other_pending.name,
"sent_or_received": "Received",
"content": "Other agent customer message",
}
).insert(ignore_permissions=True)
result = get_pending_tickets(ticket_type="all")
# Get ticket names from results
ticket_names = [t["name"] for t in result["tickets"]]
# Verify no duplicates
self.assertEqual(len(ticket_names), len(set(ticket_names)))
# Verify only current agent's tickets are returned
self.assertIn(new_ticket1.name, ticket_names)
self.assertIn(new_ticket2.name, ticket_names)
self.assertIn(pending_ticket.name, ticket_names)
# Verify total count is correct for current agent
self.assertGreaterEqual(result["total_pending_tickets"], 3)
+18
View File
@@ -207,3 +207,21 @@ def make_status(name: str = "Test Status", category: str = "Open"):
}
)
return doc.insert(ignore_if_duplicate=True)
def make_agent(email: str, first_name: str = "Test Agent"):
"""
Creates a test user and HD Agent if they don't exist.
Returns the user email.
"""
if not frappe.db.exists("User", email):
frappe.get_doc(
{"doctype": "User", "first_name": first_name, "email": email}
).insert(ignore_permissions=True)
if not frappe.db.exists("HD Agent", {"user": email}):
frappe.get_doc({"doctype": "HD Agent", "user": email}).insert(
ignore_permissions=True
)
return email