Passed
Push — master ( 5d0f2f...49b4e9 )
by Darko
10:54
created

AdminPromotionController::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace App\Http\Controllers\Admin;
4
5
use App\Http\Controllers\BasePageController;
6
use App\Models\RolePromotion;
7
use App\Models\RolePromotionStat;
8
use Illuminate\Http\RedirectResponse;
9
use Illuminate\Http\Request;
10
use Illuminate\Support\Carbon;
11
use Illuminate\Support\Facades\Validator;
12
use Illuminate\View\View;
13
use Spatie\Permission\Models\Role;
14
15
class AdminPromotionController extends BasePageController
16
{
17
    /**
18
     * Display a listing of promotions.
19
     */
20
    public function index(): View
21
    {
22
        $promotions = RolePromotion::orderBy('is_active', 'desc')
23
            ->orderBy('created_at', 'desc')
0 ignored issues
show
Bug introduced by
'created_at' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

23
            ->orderBy(/** @scrutinizer ignore-type */ 'created_at', 'desc')
Loading history...
24
            ->get();
25
26
        return view('admin.promotions.index', [
27
            'promotions' => $promotions,
28
        ]);
29
    }
30
31
    /**
32
     * Show the form for creating a new promotion.
33
     */
34
    public function create(): View
35
    {
36
        $customRoles = RolePromotion::getCustomRoles();
37
38
        return view('admin.promotions.create', [
39
            'customRoles' => $customRoles,
40
        ]);
41
    }
42
43
    /**
44
     * Store a newly created promotion in storage.
45
     */
46
    public function store(Request $request): RedirectResponse
47
    {
48
        $validator = Validator::make($request->all(), [
49
            'name' => 'required|string|max:255',
50
            'description' => 'nullable|string',
51
            'applicable_roles' => 'nullable|array',
52
            'applicable_roles.*' => 'exists:roles,id',
53
            'additional_days' => 'required|integer|min:0',
54
            'start_date' => 'nullable|date',
55
            'end_date' => 'nullable|date|after_or_equal:start_date',
56
            'is_active' => 'boolean',
57
        ]);
58
59
        if ($validator->fails()) {
60
            return redirect()->back()
61
                ->withErrors($validator)
62
                ->withInput();
63
        }
64
65
        RolePromotion::create([
66
            'name' => $request->input('name'),
67
            'description' => $request->input('description'),
68
            'applicable_roles' => $request->input('applicable_roles', []),
69
            'additional_days' => $request->input('additional_days'),
70
            'start_date' => $request->input('start_date'),
71
            'end_date' => $request->input('end_date'),
72
            'is_active' => $request->has('is_active'),
73
        ]);
74
75
        return redirect()->route('admin.promotions.index')
76
            ->with('success', 'Promotion created successfully.');
77
    }
78
79
    /**
80
     * Show the form for editing the specified promotion.
81
     */
82
    public function edit(int $id): View
83
    {
84
        $promotion = RolePromotion::findOrFail($id);
85
        $customRoles = RolePromotion::getCustomRoles();
86
87
        return view('admin.promotions.edit', [
88
            'promotion' => $promotion,
89
            'customRoles' => $customRoles,
90
        ]);
91
    }
92
93
    /**
94
     * Update the specified promotion in storage.
95
     */
96
    public function update(Request $request, int $id): RedirectResponse
97
    {
98
        $promotion = RolePromotion::findOrFail($id);
99
100
        $validator = Validator::make($request->all(), [
101
            'name' => 'required|string|max:255',
102
            'description' => 'nullable|string',
103
            'applicable_roles' => 'nullable|array',
104
            'applicable_roles.*' => 'exists:roles,id',
105
            'additional_days' => 'required|integer|min:0',
106
            'start_date' => 'nullable|date',
107
            'end_date' => 'nullable|date|after_or_equal:start_date',
108
            'is_active' => 'boolean',
109
        ]);
110
111
        if ($validator->fails()) {
112
            return redirect()->back()
113
                ->withErrors($validator)
114
                ->withInput();
115
        }
116
117
        $promotion->update([
118
            'name' => $request->input('name'),
119
            'description' => $request->input('description'),
120
            'applicable_roles' => $request->input('applicable_roles', []),
121
            'additional_days' => $request->input('additional_days'),
122
            'start_date' => $request->input('start_date'),
123
            'end_date' => $request->input('end_date'),
124
            'is_active' => $request->has('is_active'),
125
        ]);
126
127
        return redirect()->route('admin.promotions.index')
128
            ->with('success', 'Promotion updated successfully.');
129
    }
130
131
    /**
132
     * Remove the specified promotion from storage.
133
     */
134
    public function destroy(int $id): RedirectResponse
135
    {
136
        $promotion = RolePromotion::findOrFail($id);
137
        $promotion->delete();
138
139
        return redirect()->route('admin.promotions.index')
140
            ->with('success', 'Promotion deleted successfully.');
141
    }
142
143
    /**
144
     * Toggle the active status of the specified promotion.
145
     */
146
    public function toggle(int $id): RedirectResponse
147
    {
148
        $promotion = RolePromotion::findOrFail($id);
149
        $promotion->update(['is_active' => !$promotion->is_active]);
0 ignored issues
show
Bug introduced by
The property is_active does not seem to exist on Illuminate\Database\Eloq...gHasThroughRelationship.
Loading history...
150
151
        $status = $promotion->is_active ? 'activated' : 'deactivated';
152
153
        return redirect()->route('admin.promotions.index')
154
            ->with('success', "Promotion {$status} successfully.");
155
    }
156
157
    /**
158
     * Display overall promotion statistics.
159
     */
160
    public function statistics(Request $request): View
161
    {
162
        // Get date range filter (default to last 30 days)
163
        $endDate = Carbon::now();
164
        $startDate = Carbon::now()->subDays(30);
165
166
        if ($request->has('start_date') && $request->has('end_date')) {
167
            $startDate = Carbon::parse($request->input('start_date'));
168
            $endDate = Carbon::parse($request->input('end_date'));
169
        } elseif ($request->has('period')) {
170
            switch ($request->input('period')) {
171
                case '7days':
172
                    $startDate = Carbon::now()->subDays(7);
173
                    break;
174
                case '30days':
175
                    $startDate = Carbon::now()->subDays(30);
176
                    break;
177
                case '90days':
178
                    $startDate = Carbon::now()->subDays(90);
179
                    break;
180
                case 'year':
181
                    $startDate = Carbon::now()->subYear();
182
                    break;
183
                case 'all':
184
                    $startDate = null;
185
                    break;
186
            }
187
        }
188
189
        // Get all promotions with their statistics
190
        $promotions = RolePromotion::withCount(['statistics' => function ($query) use ($startDate, $endDate) {
191
            if ($startDate) {
192
                $query->whereBetween('applied_at', [$startDate, $endDate]);
193
            }
194
        }])
195
            ->with(['statistics' => function ($query) use ($startDate, $endDate) {
196
                if ($startDate) {
197
                    $query->whereBetween('applied_at', [$startDate, $endDate]);
198
                }
199
                $query->with(['user', 'role']);
200
            }])
201
            ->get();
202
203
        // Calculate overall statistics
204
        $overallStats = [
205
            'total_promotions' => $promotions->count(),
206
            'active_promotions' => $promotions->where('is_active', true)->count(),
207
            'total_applications' => $promotions->sum('statistics_count'),
208
            'unique_users' => RolePromotionStat::query()
209
                ->when($startDate, fn($q) => $q->whereBetween('applied_at', [$startDate, $endDate]))
210
                ->distinct('user_id')
211
                ->count('user_id'),
212
            'total_days_added' => RolePromotionStat::query()
213
                ->when($startDate, fn($q) => $q->whereBetween('applied_at', [$startDate, $endDate]))
214
                ->sum('days_added'),
215
        ];
216
217
        // Get top promotions by usage
218
        $topPromotions = $promotions->sortByDesc('statistics_count')->take(5);
219
220
        // Get recent activity
221
        $recentActivity = RolePromotionStat::with(['user', 'promotion', 'role'])
222
            ->when($startDate, fn($q) => $q->whereBetween('applied_at', [$startDate, $endDate]))
223
            ->latest('applied_at')
224
            ->limit(10)
225
            ->get();
226
227
        // Get statistics by role
228
        $statsByRole = RolePromotionStat::query()
229
            ->selectRaw('role_id, COUNT(*) as total_upgrades, SUM(days_added) as total_days, COUNT(DISTINCT user_id) as unique_users')
230
            ->when($startDate, fn($q) => $q->whereBetween('applied_at', [$startDate, $endDate]))
231
            ->groupBy('role_id')
232
            ->with('role')
233
            ->get();
234
235
        return view('admin.promotions.statistics', [
236
            'promotions' => $promotions,
237
            'overallStats' => $overallStats,
238
            'topPromotions' => $topPromotions,
239
            'recentActivity' => $recentActivity,
240
            'statsByRole' => $statsByRole,
241
            'startDate' => $startDate,
242
            'endDate' => $endDate,
243
            'selectedPeriod' => $request->input('period', '30days'),
244
        ]);
245
    }
246
247
    /**
248
     * Display statistics for a specific promotion.
249
     */
250
    public function showStatistics(int $id, Request $request): View
251
    {
252
        $promotion = RolePromotion::findOrFail($id);
253
254
        // Get date range filter
255
        $endDate = Carbon::now();
256
        $startDate = Carbon::now()->subDays(30);
257
258
        if ($request->has('start_date') && $request->has('end_date')) {
259
            $startDate = Carbon::parse($request->input('start_date'));
260
            $endDate = Carbon::parse($request->input('end_date'));
261
        } elseif ($request->has('period')) {
262
            switch ($request->input('period')) {
263
                case '7days':
264
                    $startDate = Carbon::now()->subDays(7);
265
                    break;
266
                case '30days':
267
                    $startDate = Carbon::now()->subDays(30);
268
                    break;
269
                case '90days':
270
                    $startDate = Carbon::now()->subDays(90);
271
                    break;
272
                case 'year':
273
                    $startDate = Carbon::now()->subYear();
274
                    break;
275
                case 'all':
276
                    $startDate = null;
277
                    break;
278
            }
279
        }
280
281
        // Get promotion statistics
282
        $stats = $promotion->getStatisticsForPeriod($startDate ?? Carbon::createFromTimestamp(0), $endDate);
283
        $statsByRole = $promotion->getStatisticsByRole();
284
285
        // Get applications with users
286
        $applications = RolePromotionStat::forPromotion($id)
287
            ->when($startDate, fn($q) => $q->whereBetween('applied_at', [$startDate, $endDate]))
288
            ->with(['user', 'role'])
289
            ->latest('applied_at')
290
            ->paginate(20);
291
292
        // Get daily statistics for chart
293
        $dailyStats = RolePromotionStat::forPromotion($id)
294
            ->when($startDate, fn($q) => $q->whereBetween('applied_at', [$startDate, $endDate]))
295
            ->selectRaw('DATE(applied_at) as date, COUNT(*) as count, SUM(days_added) as days')
296
            ->groupBy('date')
297
            ->orderBy('date')
0 ignored issues
show
Bug introduced by
'date' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

297
            ->orderBy(/** @scrutinizer ignore-type */ 'date')
Loading history...
298
            ->get();
299
300
        return view('admin.promotions.show-statistics', [
301
            'promotion' => $promotion,
302
            'stats' => $stats,
303
            'statsByRole' => $statsByRole,
304
            'applications' => $applications,
305
            'dailyStats' => $dailyStats,
306
            'startDate' => $startDate,
307
            'endDate' => $endDate,
308
            'selectedPeriod' => $request->input('period', '30days'),
309
        ]);
310
    }
311
}
312
313