File "AssignElectiveSubjectController.php"

Full Path: /home/trinadezambia/public_html/admin_panel/app/Http/Controllers/AssignElectiveSubjectController.php
File size: 19.53 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace App\Http\Controllers;

use App\Models\PaymentConfiguration;
use App\Repositories\Addon\AddonInterface;
use App\Repositories\AddonSubscription\AddonSubscriptionInterface;
use App\Repositories\Feature\FeatureInterface;
use App\Repositories\PaymentTransaction\PaymentTransactionInterface;
use App\Repositories\Subscription\SubscriptionInterface;
use App\Services\BootstrapTableService;
use App\Services\CachingService;
use App\Services\FeaturesService;
use App\Services\ResponseService;
use App\Services\SubscriptionService;
use Auth;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Throwable;

use Stripe\Stripe;
use Stripe\StripeClient;
use Stripe\Checkout\Session as StripeSession;

use App\Repositories\ClassSection\ClassSectionInterface;
use App\Repositories\Subject\SubjectInterface;
use App\Repositories\StudentSubject\StudentSubjectInterface;
use App\Repositories\Student\StudentInterface;
use App\Repositories\User\UserInterface;
use App\Repositories\SessionYear\SessionYearInterface;
use App\Repositories\ClassSchool\ClassSchoolInterface;
use App\Repositories\ClassSubject\ClassSubjectInterface;
use App\Models\ElectiveSubjectGroup;
use App\Models\ClassSection;

class AssignElectiveSubjectController extends Controller
{

    private ClassSectionInterface $classSection;
    private SubjectInterface $subject;
    private StudentSubjectInterface $studentSubject;
    private StudentInterface $student;
    private UserInterface $user;
    private ClassSchoolInterface $class;
    private SessionYearInterface $sessionYear;
    private ClassSubjectInterface $classSubject;
    private CachingService $cache;
    public function __construct(
        ClassSectionInterface $classSection,
        SubjectInterface $subject,
        StudentSubjectInterface $studentSubject,
        StudentInterface $student,
        UserInterface $user,
        ClassSchoolInterface $class,
        SessionYearInterface $sessionYear,
        ClassSubjectInterface $classSubject,
        CachingService $cache
    ) {
        $this->classSection = $classSection;
        $this->subject = $subject;
        $this->studentSubject = $studentSubject;
        $this->classSubject = $classSubject;
        $this->student = $student;
        $this->user = $user;
        $this->sessionYear = $sessionYear;
        $this->class = $class;
        $this->cache = $cache;
    }

    public function index()
    {
        ResponseService::noPermissionThenRedirect('assign-elective-subject-list');
        try {
            $class_sections = $this->classSection->all(['*'], ['class', 'class.stream', 'class.shift', 'section', 'medium']);
            $subjects = $this->subject->builder()->where('type', 'Elective')->get();
            $sessionYearId = $this->cache->getSessionYear()->id;

            // Get elective subject groups with proper data structure
            // Load the same way as show() function - load groups and then load subjects for each group
            $electiveSubjectGroups = $this->class->builder()
                ->with(['elective_subject_groups'])
                ->where('school_id', Auth::user()->school_id)
                ->get()
                ->map(function ($class) {
                    // Load subjects for each group (same relationship as defined in model)
                    if ($class->elective_subject_groups) {
                        $class->elective_subject_groups->each(function ($group) {
                            // Load subjects using the model's relationship definition
                            $group->load('subjects');
                        });
                    }
                    return $class;
                });

            $session_years = $this->sessionYear->all();

            return view('assign-elective-subject.index', compact('class_sections', 'session_years', 'electiveSubjectGroups', 'sessionYearId'));
        } catch (\Exception $e) {
            return ResponseService::logErrorResponse($e, 'AssignElectiveSubjectController -> index method');
        }
    }

    public function store(Request $request)
    {
        ResponseService::noAnyPermissionThenSendJson(['assign-elective-subject-create']);

        try {

            $classSubjectIds = $request->class_subject_ids ?? [];

            // -------------------- VALIDATION --------------------
            $validator = Validator::make($request->all(), [
                'student_ids' => 'required|not_in:0',
                'class_section_id' => 'required',
                'session_year_id' => 'required',
                'class_subject_ids' => 'required|array|min:1',
                'class_subject_ids.*' => 'required|numeric'
            ], [
                'student_ids.required' => 'Please select at least one student.',
                'class_subject_ids.required' => 'Please select at least one subject.',
                'class_subject_ids.min' => 'Please select at least one subject.',
            ]);

            if ($validator->fails()) {
                return ResponseService::errorResponse($validator->errors()->first());
            }

            $studentIds = explode(",", $request->student_ids);
            $schoolId = Auth::user()->school_id;

            DB::beginTransaction();

            $electiveSubjects = $this->classSubject->builder()
                ->whereIn('id', $classSubjectIds)
                ->where('type', 'Elective')
                ->get();

            if ($electiveSubjects->count() !== count($classSubjectIds)) {
                return ResponseService::errorResponse('One or more invalid elective subjects selected.');
            }

            $electiveGroupIds = $electiveSubjects->pluck('elective_subject_group_id')->filter()->unique()->toArray();

            $selectableCount = ElectiveSubjectGroup::whereIn('id', $electiveGroupIds)
                ->pluck('total_selectable_subjects')
                ->toArray();

            if (count($classSubjectIds) > $selectableCount[0]) {
                return ResponseService::errorResponse('You can select maximum ' . $selectableCount[0] . ' subjects.');
            } elseif (count($classSubjectIds) < $selectableCount[0]) {
                return ResponseService::errorResponse('You must select ' . $selectableCount[0] . ' subjects.');
            }
            $oldClassSubjectIds = $this->classSubject->builder()
                ->whereIn('elective_subject_group_id', $electiveGroupIds)
                ->where('type', 'Elective')
                ->pluck('id')
                ->toArray();

            foreach ($studentIds as $studentId) {
                // Get the student record to access user_id
                $student = $this->student->builder()->where('id', $studentId)->first();

                if (!$student) {
                    continue; // Skip if student not found
                }

                $userId = $student->user_id; // student_id in student_subjects table is actually user_id

                // Remove old subjects from all groups that the new subjects belong to
                if (!empty($oldClassSubjectIds)) {
                    $this->studentSubject->builder()
                        ->where('student_id', $userId)
                        ->whereIn('class_subject_id', $oldClassSubjectIds)
                        ->where('class_section_id', $request->class_section_id)
                        ->where('session_year_id', $request->session_year_id)
                        ->where('school_id', $schoolId)
                        ->delete();
                }

                // Assign all new subjects
                foreach ($classSubjectIds as $classSubjectId) {
                    $this->studentSubject->create([
                        'student_id' => $userId, // Use user_id, not student table id
                        'class_subject_id' => $classSubjectId,
                        'class_section_id' => $request->class_section_id,
                        'session_year_id' => $request->session_year_id,
                        'school_id' => $schoolId
                    ]);
                }
            }

            DB::commit();

            ResponseService::successResponse("Elective Subjects Updated Successfully");
        } catch (\Exception $e) {
            DB::rollback();
            ResponseService::logErrorResponse($e, 'AssignElectiveSubjectController -> store');
            ResponseService::errorResponse();
        }
    }

    public function show()
    {
        ResponseService::noPermissionThenRedirect('assign-elective-subject-list');
        try {
            $offset = request('offset', 0);
            $limit = request('limit', 10);
            $sort = request('sort', 'id');
            $order = request('order', 'DESC');
            $search = request('search');
            $session_year_id = $this->cache->getSessionYear()->id;
            $class_section_id = request('class_section_id');
            $class_subject_id = request('class_subject_id');
            $status = request('status');
            $school_id = Auth::user()->school_id;

            $sql = $this->student->builder()
                ->where('session_year_id', $session_year_id)
                ->where('application_status', 1)
                ->whereHas('class_section.class.elective_subject_groups')
                ->whereHas('user', function ($query) use ($school_id) {
                    $query->where('status', 1);
                })
                ->with([
                    'user:id,first_name,last_name,image,email',
                    'class_section.class.elective_subject_groups' => function ($query) use ($session_year_id) {
                        $query->where('session_year_id', $session_year_id)
                            ->with(['subjects' => function ($sub) {
                                $sub->select('subjects.id', 'subjects.name', 'subjects.code', 'subjects.type')
                                    ->withPivot('id as class_subject_id');
                            }]);
                    },
                    'class_section.class.stream',
                    'class_section.class.medium',
                    'class_section.class.shift',
                    'class_section.section',
                    'student_subjects' => function ($query) use ($school_id, $session_year_id) {
                        $query->where('school_id', $school_id)
                            ->where('session_year_id', $session_year_id)
                            ->with([
                                'class_subject' => function ($q) {
                                    $q->where('type', 'Elective')
                                        ->with(['subject', 'subjectGroup']);
                                }
                            ]);
                    },
                ]);

            // Search functionality
            if (!empty($search)) {
                $sql->where(function ($query) use ($search) {
                    $query->where('admission_no', 'LIKE', "%$search%")
                        ->orWhere('roll_number', 'LIKE', "%$search%")
                        ->orWhereHas('user', function ($q) use ($search) {
                            $q->where('first_name', 'LIKE', "%$search%")
                                ->orWhere('last_name', 'LIKE', "%$search%")
                                ->orWhereRaw("CONCAT(first_name, ' ', last_name) LIKE ?", ["%$search%"]);
                        });
                });
            }

            // Class section filter
            if ($class_section_id) {
                $sql->whereHas('class_section', function ($query) use ($class_section_id) {
                    $query->where('id', $class_section_id);
                });
            }

            // Elective subject filter (class_subject_id)
            if ($class_subject_id && $class_subject_id !== 'data-not-found') {
                $sql->whereHas('student_subjects', function ($query) use ($class_subject_id, $school_id, $session_year_id) {
                    $query->where('class_subject_id', $class_subject_id)
                        ->where('school_id', $school_id)
                        ->where('session_year_id', $session_year_id);
                });
            }

            // Get all results first to calculate status and apply status filter
            // Note: We need to get all results to calculate status correctly
            if ($sort === 'full_name') {
                $sql->orderByRaw("CONCAT((SELECT first_name FROM users WHERE users.id = students.user_id), ' ', (SELECT last_name FROM users WHERE users.id = students.user_id)) $order");
            } else {
                $sql->orderBy($sort, $order);
            }
            $res = $sql->get();

            $rows = [];
            $no = 1;
            foreach ($res as $row) {
                $tempRow = $row->toArray();
                $tempRow['user_id'] = $row->user_id;
                $tempRow['user_image'] = $row->user ? $row->user->image : null;
                // Get only elective subjects
                $electiveSubjects = $row->student_subjects->filter(function ($subject) {
                    return $subject->class_subject && $subject->class_subject->type === 'Elective';
                });

                $tempRow['elective_subjects'] = $electiveSubjects->map(function ($subject) {
                    return $subject->class_subject->subject->name . ' (' . $subject->class_subject->subject->type . ')' ?? '';
                })->filter()->implode(', ');

                // Store assigned class_subject_ids for modal pre-checking
                $tempRow['assigned_class_subject_ids'] = $electiveSubjects->pluck('class_subject_id')->toArray();

                // Calculate status: Not Assigned, Incomplete, or Complete
                // Check if student has elective groups that require selection
                $hasElectiveGroups = false;
                $totalRequired = 0;
                $totalSelected = 0;

                if ($row->class_section && $row->class_section->class && $row->class_section->class->elective_subject_groups) {
                    $hasElectiveGroups = $row->class_section->class->elective_subject_groups->count() > 0;

                    // Calculate total required and selected subjects
                    foreach ($row->class_section->class->elective_subject_groups as $group) {
                        $totalRequired += $group->total_selectable_subjects ?? 0;

                        // Count how many subjects from this group are assigned
                        $groupSubjectIds = [];
                        if ($group->subjects) {
                            foreach ($group->subjects as $groupSubject) {
                                $classSubjectId = null;
                                if ($groupSubject->pivot && isset($groupSubject->pivot->class_subject_id)) {
                                    $classSubjectId = $groupSubject->pivot->class_subject_id;
                                } elseif (isset($groupSubject->class_subject_id)) {
                                    $classSubjectId = $groupSubject->class_subject_id;
                                }
                                if ($classSubjectId) {
                                    $groupSubjectIds[] = $classSubjectId;
                                }
                            }
                        }

                        // Count assigned subjects from this group
                        $assignedFromGroup = $electiveSubjects->filter(function ($subject) use ($groupSubjectIds) {
                            return in_array($subject->class_subject_id, $groupSubjectIds);
                        })->count();

                        $totalSelected += min($assignedFromGroup, $group->total_selectable_subjects ?? 0);
                    }
                }

                // Determine status
                if ($electiveSubjects->count() == 0) {
                    $tempRow['status'] = 'not_assigned';
                } elseif ($hasElectiveGroups && $totalRequired > 0 && $totalSelected < $totalRequired) {
                    $tempRow['status'] = 'incomplete';
                } else {
                    $tempRow['status'] = 'complete';
                }

                // Apply status filter if provided
                if ($status && $tempRow['status'] !== $status) {
                    continue; // Skip this row if it doesn't match the status filter
                }

                $operate = BootstrapTableService::editButton(route('assign.elective.subject.update', $row->id));
                $tempRow['operate'] = $operate;

                $rows[] = $tempRow;
            }

            // Apply pagination after filtering
            $total = count($rows);
            if ($offset >= $total && $total > 0) {
                $lastPage = floor(($total - 1) / $limit) * $limit;
                $offset = $lastPage;
            }
            $paginatedRows = array_slice($rows, $offset, $limit);

            // Update row numbers for paginated results
            foreach ($paginatedRows as $index => $row) {
                $paginatedRows[$index]['no'] = $offset + $index + 1;
            }

            return response()->json([
                'total' => $total,
                'rows' => $paginatedRows
            ]);
        } catch (\Exception $e) {
            return ResponseService::logErrorResponse($e, 'AssignElectiveSubjectController -> show method');
        }
    }

    public function edit($id)
    {
        //
    }

    public function update(Request $request, $id)
    {
        ResponseService::noPermissionThenSendJson('assign-elective-subject-edit');
        ResponseService::successResponse('Data Updated Successfully');
    }

    public function destroy($id)
    {
        ResponseService::noPermissionThenSendJson('assign-elective-subject-delete');
        try {
            $studentSubject = $this->studentSubject->findOrFail($id);

            if ($studentSubject->school_id != Auth::user()->school_id) {
                throw new \Exception(__('Invalid Assignment'));
            }

            $studentSubject->delete();
            ResponseService::successResponse('Data Deleted Successfully');
        } catch (\Exception $e) {
            ResponseService::logErrorResponse($e, 'AssignElectiveSubjectController -> destroy method');
            ResponseService::errorResponse();
        }
    }

    public function restore($id)
    {
        ResponseService::noPermissionThenSendJson('assign-elective-subject-edit');
        ResponseService::successResponse('Data Restored Successfully');
    }

    public function status($id)
    {
        ResponseService::noAnyPermissionThenSendJson(['assign-elective-subject-create', 'assign-elective-subject-edit']);
        try {
            DB::beginTransaction();
            $addon = $this->addon->findById($id);
            $addon = ['status' => $addon->status == 1 ? 0 : 1];
            $this->addon->update($id, $addon);
            DB::commit();
            ResponseService::successResponse('Data Updated Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'AssignElectiveSubjectController -> status method');
            ResponseService::errorResponse();
        }
    }

    public function removeSubject(Request $request)
    {
        try {
            // dd($request->all());


            $studentSubject = $this->studentSubject->builder()->where('student_id', $request->student_id)->where('class_subject_id', $request->class_subject_id);

            $studentSubject->delete();
            ResponseService::successResponse('Data Deleted Successfully');
        } catch (\Exception $e) {
            ResponseService::logErrorResponse($e, 'AssignElectiveSubjectController -> removeSubject method');
            ResponseService::errorResponse();
        }
    }
}