Issues (350)

app/Http/Controllers/EnrollmentController.php (9 issues)

1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Events\EnrollmentCourseUpdated;
6
use App\Http\Requests\StoreEnrollmentRequest;
7
use App\Interfaces\EnrollmentSheetInterface;
8
use App\Models\Attendance;
9
use App\Models\Book;
10
use App\Models\Config;
11
use App\Models\Course;
12
use App\Models\Discount;
13
use App\Models\Enrollment;
14
use App\Models\Fee;
15
use App\Models\InvoiceType;
16
use App\Models\Paymentmethod;
17
use App\Models\Student;
18
use App\Models\Tax;
19
use App\Services\AFSantiagoEnrollmentSheetService;
20
use App\Traits\PeriodSelection;
21
use Carbon\Carbon;
22
use Illuminate\Http\Request;
23
use Illuminate\Support\Facades\App;
24
use Illuminate\Support\Facades\Gate;
25
use Illuminate\Support\Facades\Log;
26
use Illuminate\Support\Facades\Redirect;
27
use Illuminate\Support\Facades\Storage;
28
use Illuminate\Support\Str;
29
use PhpOffice\PhpWord\IOFactory;
30
use PhpOffice\PhpWord\PhpWord;
31
use Prologue\Alerts\Facades\Alert;
32
33
class EnrollmentController extends Controller
34
{
35
    use PeriodSelection;
0 ignored issues
show
The trait App\Traits\PeriodSelection requires the property $id which is not provided by App\Http\Controllers\EnrollmentController.
Loading history...
36
37
    private EnrollmentSheetInterface $enrollmentSheetService;
38
39
    public function __construct()
40
    {
41
        parent::__construct();
42
43
        // these methods are reserved to administrators or staff members.
44
        // Only the store method can also be called by teachers to enroll students in their courses
45
        $this->middleware('permission:enrollments.edit', ['except' => 'store']);
46
        $this->enrollmentSheetService = new AFSantiagoEnrollmentSheetService($this);
0 ignored issues
show
The call to App\Services\AFSantiagoE...tService::__construct() has too many arguments starting with $this. ( Ignorable by Annotation )

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

46
        $this->enrollmentSheetService = /** @scrutinizer ignore-call */ new AFSantiagoEnrollmentSheetService($this);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
47
    }
48
49
    /**
50
     * Store the newly created enrollment.
51
     */
52
    public function store(StoreEnrollmentRequest $request)
53
    {
54
        $course = Course::findOrFail($request->input('course_id'));
55
56
        if (Gate::forUser(backpack_user())->denies('enroll-in-course', $course)) {
57
            abort(403);
58
        }
59
60
        $student = Student::findOrFail($request->input('student_id'));
61
        $enrollment_id = $student->enroll($course);
62
        Alert::success(__('Enrollment successfully created'))->flash();
0 ignored issues
show
It seems like __('Enrollment successfully created') can also be of type array and array; however, parameter $text of Prologue\Alerts\Facades\Alert::success() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

62
        Alert::success(/** @scrutinizer ignore-type */ __('Enrollment successfully created'))->flash();
Loading history...
63
64
        Log::info(backpack_user()->firstname.' generated a new enrollment for student '.$student->name);
0 ignored issues
show
Accessing firstname on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
65
66
        if (backpack_user()->can('enrollments.edit')) {
67
            return url("/enrollment/$enrollment_id/show");
68
        }
69
    }
70
71
    public function update(Enrollment $enrollment, Request $request)
72
    {
73
        $course = Course::findOrFail($request->input('course_id'));
74
        $previousCourse = $enrollment->course;
0 ignored issues
show
The assignment to $previousCourse is dead and can be removed.
Loading history...
75
76
        // if enrollment has children, delete them
77
        Enrollment::where('parent_id', $enrollment->id)->delete();
78
79
        // update enrollment with new course
80
        $enrollment->update([
81
            'course_id' => $course->id,
82
        ]);
83
84
        // if the new course has children, create an enrollment as well
85
        foreach ($course->children as $children_course) {
86
            $child_enrollment = Enrollment::firstOrNew([
87
                'student_id' => $enrollment->student_id,
88
                'course_id' => $children_course->id,
89
                'parent_id' => $enrollment->id,
90
            ]);
91
            $child_enrollment->responsible_id = backpack_user()->id ?? null;
0 ignored issues
show
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
92
            $child_enrollment->save();
93
        }
94
95
        // delete attendance
96
        foreach ($enrollment->course->events as $event) {
97
            Attendance::where('event_id', $event->id)->where('student_id', $enrollment->student_id)->delete();
98
        }
99
100
        foreach ($enrollment->course->children as $child) {
101
            foreach ($child->events as $event) {
102
                Attendance::where('event_id', $event->id)->where('student_id', $enrollment->student_id)->delete();
103
            }
104
        }
105
106
        // TODO delete grades and/or skills
107
108
        // Create attendance in new course.
109
        $events = $course->events->where('start', '<', (new Carbon())->toDateString());
110
        foreach ($events as $event) {
111
            $event->attendance()->create([
112
                'student_id' => $enrollment->student_id,
113
                'attendance_type_id' => 3,
114
            ]);
115
        }
116
117
        // display a confirmation message and redirect to enrollment details
118
        Alert::success(__('The enrollment has been updated'))->flash();
0 ignored issues
show
It seems like __('The enrollment has been updated') can also be of type array and array; however, parameter $text of Prologue\Alerts\Facades\Alert::success() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

118
        Alert::success(/** @scrutinizer ignore-type */ __('The enrollment has been updated'))->flash();
Loading history...
119
120
        return "enrollment/$enrollment->id/show";
121
    }
122
123
    /**
124
     * Create a new cart with the specified enrollment
125
     * and display the cart.
126
     */
127
    public function bill(Enrollment $enrollment)
128
    {
129
        Log::info('User # '.backpack_user()->id.' is generating a invoice');
0 ignored issues
show
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
130
131
        // build an array with products to include
132
        $products = [];
133
134
        foreach (Fee::where('default', 1)->get() as $fee) {
135
            // Set quantity to 1
136
137
            array_push($products, $fee);
138
        }
139
140
        if (config('invoicing.invoices_contain_enrollments_only')) {
141
            $enrollment->append('balance');
142
        }
143
144
        array_push($products, $enrollment);
145
146
        if ($enrollment->course->books->count() > 0 && config('invoicing.add_books_to_invoices')) {
147
            // Set quantity to 1
148
149
            foreach ($enrollment->course->books as $book) {
150
                array_push($products, $book);
151
            }
152
        }
153
154
        // build an array with all contact data
155
        $clients = [];
156
157
        array_push($clients, [
158
            'name' => $enrollment->student_name,
159
            'email' => $enrollment->student_email,
160
            'idnumber' => $enrollment->student->idnumber,
161
            'address' => $enrollment->student->address,
162
            'phone' => $enrollment->student->phone,
163
        ]);
164
165
        foreach ($enrollment->student->contacts as $client) {
166
            array_push($clients, $client);
167
        }
168
169
        $data = [
170
            'enrollment' => $enrollment,
171
            'products' => $products,
172
            'invoicetypes' => InvoiceType::all(),
173
            'clients' => $clients,
174
            'availableBooks' => Book::all(),
175
            'availableFees' => Fee::all(),
176
            'availableDiscounts' => Discount::all(),
177
            'availablePaymentMethods' => Paymentmethod::all(),
178
            'availableTaxes' => Tax::all(),
179
        ];
180
181
        if (config('invoicing.price_categories_enabled')) {
182
            $data = array_merge(
183
                $data,
184
                [
185
                    'priceCategories' => collect([
186
                        'price_a' => $enrollment->course->price,
187
                        'price_b' => $enrollment->course->price_b,
188
                        'price_c' => $enrollment->course->price_c,
189
                    ]),
190
                    'studentPriceCategory' => $enrollment->student?->price_category,
191
                ]
192
            );
193
        }
194
195
        return view('carts.show', $data);
196
    }
197
198
    public function markaspaid(Enrollment $enrollment)
199
    {
200
        $enrollment->markAsPaid();
201
202
        return redirect()->back();
203
    }
204
205
    public function markasunpaid(Enrollment $enrollment)
206
    {
207
        $enrollment->update(['status_id' => 1]);
208
209
        return redirect()->back();
210
    }
211
212
    public function savePrice(Enrollment $enrollment, Request $request)
213
    {
214
        $request->validate(['price' => 'required|numeric']);
215
216
        $enrollment->update(['total_price' => $request->price]);
217
218
        return $enrollment->fresh();
219
    }
220
221
    public function exportToWord(Enrollment $enrollment)
222
    {
223
        return $this->enrollmentSheetService->exportToWord($enrollment);
224
    }
225
226
    public function getBalance(Request $request)
227
    {
228
        if (! config('invoicing.invoices_contain_enrollments_only')) {
229
            abort(422, 'Configuration options forbid to access this value');
230
        }
231
232
        $periodId = $request->get('periodId');
233
        if ($periodId) {
234
            $pendingBalance = Enrollment::period($periodId)->pending()->sum('balance');
235
        } else {
236
            $pendingBalance = Enrollment::pending()->sum('balance');
237
        }
238
239
        return number_format($pendingBalance, 2);
0 ignored issues
show
It seems like $pendingBalance can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $num of number_format() does only seem to accept double, maybe add an additional type check? ( Ignorable by Annotation )

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

239
        return number_format(/** @scrutinizer ignore-type */ $pendingBalance, 2);
Loading history...
240
    }
241
}
242