Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
67.86% covered (warning)
67.86%
38 / 56
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
RolePlayReportController
67.86% covered (warning)
67.86%
38 / 56
33.33% covered (danger)
33.33%
2 / 6
15.02
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 availableCharts
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 chart
66.67% covered (warning)
66.67%
6 / 9
0.00% covered (danger)
0.00%
0 / 1
2.15
 data
66.67% covered (warning)
66.67%
6 / 9
0.00% covered (danger)
0.00%
0 / 1
2.15
 spotlight
66.67% covered (warning)
66.67%
6 / 9
0.00% covered (danger)
0.00%
0 / 1
2.15
 export
59.09% covered (warning)
59.09%
13 / 22
0.00% covered (danger)
0.00%
0 / 1
3.62
1<?php
2
3namespace App\Http\Controllers\v2\Company;
4
5use App\Http\Controllers\Controller;
6use App\Http\Models\Auth\Role;
7use App\Http\Models\RolePlayConversations;
8use App\Http\Requests\v2\Reports\GetReportRequest;
9use App\Http\Services\CsvExportService;
10use App\Http\Services\Reports\RolePlayReportService;
11use App\Traits\ReportFilterTrait;
12use Carbon\Carbon;
13use Illuminate\Http\JsonResponse;
14use Illuminate\Http\Request;
15use Illuminate\Support\Facades\Log;
16use Symfony\Component\HttpFoundation\StreamedResponse;
17
18/**
19 * Controller for Roleplay (Sales Training) analytics reports.
20 *
21 * Provides chart data, summary statistics, spotlight KPIs, and CSV export
22 * for the admin-fe and cmc-fe reporting panels.
23 */
24class RolePlayReportController extends Controller
25{
26    use ReportFilterTrait;
27
28    public function __construct(
29        private RolePlayReportService $reportService,
30        private CsvExportService $csvExportService
31    ) {}
32
33    /**
34     * Return the list of available chart types for the Sales Training tab.
35     *
36     * @response 200 {
37     *   "data": [
38     *     {"value": "sessions_completed", "label": "Sessions Completed"},
39     *     {"value": "practice_time", "label": "Practice Time (hrs)"}
40     *   ],
41     *   "success": true
42     * }
43     */
44    public function availableCharts(Request $request): JsonResponse
45    {
46        $user = $request->user();
47        $isCmc = in_array(Role::VENGRESO_ADMIN, $user->roles());
48
49        return response()->json([
50            'data' => $this->reportService->availableCharts($isCmc),
51            'success' => true,
52        ]);
53    }
54
55    /**
56     * Return time-series chart data for a given sales training chart type.
57     *
58     * @param  GetReportRequest  $request  Validated request with optional date/company/group filters
59     * @param  string  $type  Chart type identifier (sessions_completed, practice_time, etc.)
60     * @return JsonResponse
61     *
62     * @response 200 {
63     *   "data": {
64     *     "chart": [{"period": "Jan 2026", "value": 45}]
65     *   },
66     *   "success": true
67     * }
68     */
69    public function chart(GetReportRequest $request, string $type): JsonResponse
70    {
71        try {
72            $baseMatch = $this->buildBaseMatchQuery($request);
73            $userIds = $this->resolveUserIds($baseMatch);
74            [$startDate, $endDate] = $this->getDateRange($request, [], RolePlayConversations::class);
75
76            $callType = $request->input('call_type');
77            $data = $this->reportService->getChartData($type, $userIds, $startDate, $endDate, $callType);
78
79            return response()->json(['data' => $data, 'success' => true]);
80        } catch (\Exception $e) {
81            Log::error('RolePlay report chart error: '.$e->getMessage());
82
83            return response()->json(['success' => false, 'error' => $e->getMessage()], 400);
84        }
85    }
86
87    /**
88     * Return summary data (total, average, top 5 users) for a chart type.
89     *
90     * @param  GetReportRequest  $request  Validated request with optional filters
91     * @param  string  $type  Chart type identifier
92     * @return JsonResponse
93     *
94     * @response 200 {
95     *   "data": {
96     *     "label": "Sessions Completed",
97     *     "title": "Sessions Completed",
98     *     "tooltip": "...",
99     *     "total": 1234,
100     *     "average": 12.5,
101     *     "top": [{"name": "John Doe", "avatar": "...", "value": 100}]
102     *   },
103     *   "success": true
104     * }
105     */
106    public function data(GetReportRequest $request, string $type): JsonResponse
107    {
108        try {
109            $baseMatch = $this->buildBaseMatchQuery($request);
110            $userIds = $this->resolveUserIds($baseMatch);
111            [$startDate, $endDate] = $this->getDateRange($request, [], RolePlayConversations::class);
112
113            $callType = $request->input('call_type');
114            $data = $this->reportService->getSummaryData($type, $userIds, $startDate, $endDate, $callType);
115
116            return response()->json(['data' => $data, 'success' => true]);
117        } catch (\Exception $e) {
118            Log::error('RolePlay report data error: '.$e->getMessage());
119
120            return response()->json(['success' => false, 'error' => $e->getMessage()], 400);
121        }
122    }
123
124    /**
125     * Return spotlight KPI cards for the Sales Training dashboard.
126     *
127     * @param  GetReportRequest  $request  Validated request with optional filters
128     * @return JsonResponse
129     *
130     * @response 200 {
131     *   "data": [
132     *     {"title": "Total Sessions", "subtitle": "Completed Sessions", "tooltip": "...", "amount": 1234, "average": {"value": 12.5, "label": "Average per User"}}
133     *   ],
134     *   "success": true
135     * }
136     */
137    public function spotlight(GetReportRequest $request): JsonResponse
138    {
139        try {
140            $baseMatch = $this->buildBaseMatchQuery($request);
141            $userIds = $this->resolveUserIds($baseMatch);
142            [$startDate, $endDate] = $this->getDateRange($request, [], RolePlayConversations::class);
143
144            $callType = $request->input('call_type');
145            $data = $this->reportService->getSpotlight($userIds, $startDate, $endDate, $callType);
146
147            return response()->json(['data' => $data, 'success' => true]);
148        } catch (\Exception $e) {
149            Log::error('RolePlay report spotlight error: '.$e->getMessage());
150
151            return response()->json(['success' => false, 'error' => $e->getMessage()], 400);
152        }
153    }
154
155    /**
156     * Export roleplay analytics data as CSV.
157     *
158     * @param  GetReportRequest  $request  Validated request with optional filters
159     * @return StreamedResponse|JsonResponse
160     */
161    public function export(GetReportRequest $request): StreamedResponse|JsonResponse
162    {
163        try {
164            $baseMatch = $this->buildBaseMatchQuery($request);
165            $userIds = $this->resolveUserIds($baseMatch);
166            [$startDate, $endDate] = $this->getDateRange($request, [], RolePlayConversations::class);
167
168            $callType = $request->input('call_type');
169            $exportData = $this->reportService->getExportData($userIds, $startDate, $endDate, $callType);
170
171            $delimiter = $this->csvExportService->resolveDelimiter($request->user());
172            $fileName = 'report_sales_training_'.now()->format('Y-m-d').'.csv';
173
174            $callback = function () use ($exportData, $delimiter) {
175                $file = fopen('php://output', 'w');
176                fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF)); // BOM for Excel
177
178                fputcsv($file, $exportData['headers'], $delimiter);
179                foreach ($exportData['rows'] as $row) {
180                    fputcsv($file, $row, $delimiter);
181                }
182                fclose($file);
183            };
184
185            return new StreamedResponse($callback, 200, [
186                'Content-Type' => 'text/csv',
187                'Content-Disposition' => 'attachment; filename="'.$fileName.'"',
188            ]);
189        } catch (\Exception $e) {
190            Log::error('RolePlay report export error: '.$e->getMessage());
191
192            return response()->json(['success' => false, 'error' => $e->getMessage()], 400);
193        }
194    }
195}