PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.4.5
Fluent Support – Helpdesk & Customer Support Ticket System v2.4.5
2.4.5 2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 All 69 releases
fluent-support / app / Http / Controllers / ReportingController.php

ReportingController.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.4.5, at app/Http/Controllers/ReportingController.php

250 lines 8.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Http\Controllers;
4
5 use FluentSupport\App\Modules\Reporting\Reporting;
6 use FluentSupport\App\Modules\StatModule;
7 use FluentSupport\App\Services\Helper;
8 use FluentSupport\Framework\Http\Request\Request;
9 use FluentSupport\App\Models\Ticket;
10 use FluentSupport\App\Services\Tickets\AgentTicketAccess;
11 use FluentSupport\App\Models\Conversation;
12 use FluentSupport\App\Models\TagPivot;
13
14 /**
15 * Report endpoints.
16 */
17 class ReportingController extends Controller
18 {
19 public static function getSanitizedDateRange(Request $request)
20 {
21 $dateRange = $request->get('date_range', []);
22
23 if (is_array($dateRange) && count($dateRange) >= 2) {
24 return [
25 sanitize_text_field($dateRange[0] ?? ''),
26 sanitize_text_field($dateRange[1] ?? '')
27 ];
28 }
29
30 if (is_string($dateRange)) {
31 $parts = array_map('trim', explode(',', $dateRange));
32 return [
33 sanitize_text_field($parts[0] ?? ''),
34 sanitize_text_field($parts[1] ?? '')
35 ];
36 }
37
38 return ['', ''];
39 }
40
41 public static function getAgentIdsForGroup(Request $request)
42 {
43 $groupId = $request->getSafe('agent_group_id', 'intval');
44 if (!$groupId) {
45 return null;
46 }
47
48 return TagPivot::where('source_type', 'agent_group')
49 ->where('tag_id', $groupId)
50 ->pluck('source_id')
51 ->toArray();
52 }
53
54 /**
55 * Stats for the logged-in agent.
56 *
57 * @param Request $request
58 * @return array
59 */
60 public function getAgentOverallReports(Request $request): array
61 {
62 $agent = Helper::getAgentByUserId(get_current_user_id());
63
64 return [
65 'overall_reports' => StatModule::getAgentOverallStats($agent->id),
66 'today_reports' => StatModule::getTodayStats($agent->id)
67 ];
68 }
69
70 /**
71 * @param Request $request
72 * @param Reporting $reporting
73 * @return array
74 */
75 public function getAgentResolveChart(Request $request, Reporting $reporting)
76 {
77 $agent = Helper::getAgentByUserId(get_current_user_id());
78 list($from, $to) = self::getSanitizedDateRange($request);
79
80 return [
81 'stats' => $reporting->getTicketResolveGrowth($from, $to, ['agent_id' => $agent->id])
82 ];
83 }
84
85 /**
86 * @param Request $request
87 * @param Reporting $reporting
88 * @return array
89 */
90 public function getAgentResponseChart(Request $request, Reporting $reporting)
91 {
92 $agent = Helper::getAgentByUserId(get_current_user_id());
93 list($from, $to) = self::getSanitizedDateRange($request);
94
95 return [
96 'stats' => $reporting->getResponseGrowth($from, $to, ['person_id' => $agent->id])
97 ];
98 }
99
100 /**
101 * Closed/open ticket and response counts for the logged-in agent in a date range.
102 *
103 * @param Reporting $reporting
104 * @param Request $request
105 * @return array
106 */
107 public function getPersonalSummary(Reporting $reporting, Request $request)
108 {
109 $agent = Helper::getAgentByUserId(get_current_user_id());
110
111 return [
112 'summary' => $reporting->agentSummary($request->getSafe('from', 'sanitize_text_field'), $request->getSafe('to', 'sanitize_text_field'), $agent->id)
113 ];
114 }
115
116 /**
117 * Overview counts filtered by date_range, mailbox_id (or business_box), product_id,
118 * agent_id, agent_group_id and customer_id. With agent_id, active_tickets is
119 * replaced by the agent's total_replies.
120 *
121 * @param Request $request
122 * @return array
123 */
124 public function getStats(Request $request)
125 {
126 list($from, $to) = self::getSanitizedDateRange($request);
127
128 $filters = [
129 'mailbox_id' => $request->getSafe('mailbox_id', 'intval') ?: $request->getSafe('business_box', 'intval'),
130 'product_id' => $request->getSafe('product_id', 'intval'),
131 'agent_id' => $request->getSafe('agent_id', 'intval'),
132 'customer_id' => $request->getSafe('customer_id', 'intval'),
133 ];
134
135 $agentIds = self::getAgentIdsForGroup($request);
136
137 $access = new AgentTicketAccess();
138
139 // Bound first: a caller-supplied mailbox_id below is not proof of access.
140 $baseQuery = $access->applyMailboxRestrictionScope(Ticket::query());
141
142 foreach ($filters as $field => $value) {
143 if ($value) {
144 $baseQuery->where($field, $value);
145 }
146 }
147
148 if ($agentIds !== null) {
149 $baseQuery->whereIn('agent_id', $agentIds);
150 }
151
152 $applyDateRange = function($query, $dateField = 'created_at') use ($from, $to) {
153 if ($from && $to) {
154 $query->whereBetween($dateField, ["$from 00:00:00", "$to 23:59:59"]);
155 } elseif ($from) {
156 $query->where($dateField, '>=', "$from 00:00:00");
157 } elseif ($to) {
158 $query->where($dateField, '<=', "$to 23:59:59");
159 }
160 };
161
162 $countTickets = function($status, $dateField = 'created_at') use ($baseQuery, $applyDateRange) {
163 $query = clone $baseQuery;
164 $query->where('status', $status);
165 $applyDateRange($query, $dateField);
166 return $query->count();
167 };
168
169 $newTickets = $countTickets('new');
170 $closedTickets = $countTickets('closed', 'resolved_at');
171
172 $openQuery = clone $baseQuery;
173 $openQuery->where('status', '!=', 'closed');
174 $applyDateRange($openQuery);
175 $openTickets = $openQuery->count();
176
177 $agentId = $filters['agent_id'];
178
179 $responsesQuery = $access->applyMailboxRestrictionScopeViaTicket(
180 Conversation::query()->where('conversation_type', 'response')
181 );
182
183 // For a single agent, count the replies they wrote, not every reply on tickets assigned to them.
184 $ticketFilters = $filters;
185 if ($agentId) {
186 $responsesQuery->where('person_id', $agentId);
187 unset($ticketFilters['agent_id']);
188 }
189
190 if (array_filter($ticketFilters) || $agentIds !== null) {
191 $responsesQuery->whereHas('ticket', function ($q) use ($ticketFilters, $agentIds) {
192 foreach ($ticketFilters as $field => $value) {
193 if ($value) {
194 $q->where($field, $value);
195 }
196 }
197 if ($agentIds !== null) {
198 $q->whereIn('agent_id', $agentIds);
199 }
200 });
201 }
202
203 $applyDateRange($responsesQuery, 'created_at');
204 $responses = $responsesQuery->count();
205
206 if ($agentId) {
207 $stats = [
208 'new_tickets' => $newTickets,
209 'closed_tickets' => $closedTickets,
210 'responses' => $responses,
211 'open_tickets' => $openTickets,
212 ];
213 } else {
214 $activeTickets = $countTickets('active');
215
216 $stats = [
217 'new_tickets' => $newTickets,
218 'active_tickets' => $activeTickets,
219 'closed_tickets' => $closedTickets,
220 'responses' => $responses,
221 'open_tickets' => $openTickets,
222 ];
223 }
224
225 $labels = [
226 'new_tickets' => __('New Tickets', 'fluent-support'),
227 'active_tickets' => __('Active Tickets', 'fluent-support'),
228 'closed_tickets' => __('Closed Tickets', 'fluent-support'),
229 'responses' => __('Responses', 'fluent-support'),
230 'open_tickets' => __('Open Tickets', 'fluent-support'),
231 ];
232
233 if ($agentId) {
234 $labels['responses'] = __('Total Responses', 'fluent-support');
235 }
236
237 $overallReports = [];
238 foreach ($stats as $key => $count) {
239 $overallReports[$key] = [
240 'title' => $labels[$key] ?? ucwords(str_replace('_', ' ', (string) $key)),
241 'key' => $key,
242 'count' => $count,
243 ];
244 }
245
246 return ['overall_reports' => $overallReports];
247 }
248
249 }
250