File "SessionYearMigrationService.php"

Full Path: /home/trinadezambia/public_html/admin_panel/app/Services/SessionYearMigrationService.php
File size: 10.05 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace App\Services;

use App\Models\ClassSubject;
use App\Models\ClassTeacher;
use App\Models\ElectiveSubjectGroup;
use App\Models\Fee;
use App\Models\FeesClassType;
use App\Models\FeesInstallment;
use App\Models\LeaveMaster;
use App\Models\Semester;
use App\Models\SubjectTeacher;
use App\Models\SessionYear;
use App\Models\Timetable;
use Illuminate\Support\Facades\DB;
use Throwable;

class SessionYearMigrationService
{
    /**
     * Migrate data from one session year to another.
     *
     * @param int $fromSessionYearId
     * @param int $toSessionYearId
     * @param array $options
     * @param int $schoolId
     * @param array|null $semesterData
     * @return void
     * @throws Throwable
     */
    public function migrate(int $fromSessionYearId, int $toSessionYearId, array $options, int $schoolId, ?array $semesterData = null): void
    {
        DB::beginTransaction();
        try {
            $semesterMapping = [];
            $classSubjectMapping = [];
            $subjectTeacherMapping = [];

            // 1. Semesters (if selected)
            if (in_array('semesters', $options)) {
                $semesterMapping = $this->migrateSemesters($fromSessionYearId, $toSessionYearId, $schoolId, $semesterData);
            }

            // 2. Class Subjects (and Elective Groups)
            if (in_array('class_subjects', $options)) {
                $classSubjectMapping = $this->migrateClassSubjects($fromSessionYearId, $toSessionYearId, $schoolId, $semesterMapping);
            }

            // 3. Teachers (Class & Subject)
            if (in_array('teachers', $options)) {
                $subjectTeacherMapping = $this->migrateTeachers($fromSessionYearId, $toSessionYearId, $schoolId, $classSubjectMapping);
            }

            // 4. Timetables
            if (in_array('class_timetables', $options)) {
                $this->migrateTimetables($fromSessionYearId, $toSessionYearId, $schoolId, $subjectTeacherMapping, $semesterMapping);
            }

            // 5. Fees
            if (in_array('fees', $options)) {
                $this->migrateFees($fromSessionYearId, $toSessionYearId, $schoolId);
            }

            // 6. Leave Settings
            if (in_array('leave_settings', $options)) {
                $this->migrateLeaveSettings($fromSessionYearId, $toSessionYearId, $schoolId);
            }

            DB::commit();
        } catch (Throwable $e) {
            DB::rollBack();
            throw $e;
        }
    }

    private function migrateSemesters(int $fromId, int $toId, int $schoolId, ?array $semesterData): array
    {
        $mapping = [];
        $oldSemesters = Semester::where('session_year_id', $fromId)->where('school_id', $schoolId)->get();
        foreach ($oldSemesters as $oldSemester) {
            $newSemester = $oldSemester->replicate();
            $newSemester->session_year_id = $toId;

            if ($semesterData && isset($semesterData[$oldSemester->id])) {
                $newSemester->start_date = \Carbon\Carbon::createFromFormat('d-m-Y', $semesterData[$oldSemester->id]['start_date'])->format('Y-m-d');
                $newSemester->end_date = \Carbon\Carbon::createFromFormat('d-m-Y', $semesterData[$oldSemester->id]['end_date'])->format('Y-m-d');
            }

            $newSemester->save();
            $mapping[$oldSemester->id] = $newSemester->id;
        }
        return $mapping;
    }

    private function migrateClassSubjects(int $fromId, int $toId, int $schoolId, array $semesterMapping): array
    {
        $classSubjectMapping = [];

        // 1. Migrate Elective Subject Groups first
        $electiveGroupMapping = [];
        ElectiveSubjectGroup::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldGroups) use ($toId, $semesterMapping, &$electiveGroupMapping) {
            foreach ($oldGroups as $oldGroup) {
                $newGroup = $oldGroup->replicate();
                $newGroup->session_year_id = $toId;
                // Map semester_id if it exists
                if ($oldGroup->semester_id && isset($semesterMapping[$oldGroup->semester_id])) {
                    $newGroup->semester_id = $semesterMapping[$oldGroup->semester_id];
                }
                $newGroup->save();
                $electiveGroupMapping[$oldGroup->id] = $newGroup->id;
            }
        });

        // 2. Migrate Class Subjects
        ClassSubject::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldClassSubjects) use ($toId, $semesterMapping, $electiveGroupMapping, &$classSubjectMapping) {
            foreach ($oldClassSubjects as $oldCS) {
                $newCS = $oldCS->replicate(['virtual_semester_id']);
                $newCS->session_year_id = $toId;

                // Map semester_id if it was migrated
                if ($oldCS->semester_id && isset($semesterMapping[$oldCS->semester_id])) {
                    $newCS->semester_id = $semesterMapping[$oldCS->semester_id];
                }

                // $newCS->virtual_semester_id = $newCS->semester_id ?? 0;

                // Map elective_subject_group_id if it was migrated
                if ($oldCS->elective_subject_group_id && isset($electiveGroupMapping[$oldCS->elective_subject_group_id])) {
                    $newCS->elective_subject_group_id = $electiveGroupMapping[$oldCS->elective_subject_group_id];
                }

                $newCS->save();
                $classSubjectMapping[$oldCS->id] = $newCS->id;
            }
        });

        return $classSubjectMapping;
    }

    private function migrateTeachers(int $fromId, int $toId, int $schoolId, array $classSubjectMapping): array
    {
        $subjectTeacherMapping = [];

        // 1. Migrate Class Teachers
        ClassTeacher::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldClassTeachers) use ($toId) {
            foreach ($oldClassTeachers as $oldCT) {
                $newCT = $oldCT->replicate();
                $newCT->session_year_id = $toId;
                $newCT->save();
            }
        });

        // 2. Migrate Subject Teachers
        SubjectTeacher::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldSubjectTeachers) use ($toId, $classSubjectMapping, &$subjectTeacherMapping) {
            foreach ($oldSubjectTeachers as $oldST) {
                // Only migrate if the class subject was migrated
                if (isset($classSubjectMapping[$oldST->class_subject_id])) {
                    $newST = $oldST->replicate();
                    $newST->session_year_id = $toId;
                    $newST->class_subject_id = $classSubjectMapping[$oldST->class_subject_id];
                    $newST->save();
                    $subjectTeacherMapping[$oldST->id] = $newST->id;
                }
            }
        });

        return $subjectTeacherMapping;
    }

    private function migrateTimetables(int $fromId, int $toId, int $schoolId, array $subjectTeacherMapping, array $semesterMapping): void
    {
        Timetable::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldTimetables) use ($toId, $subjectTeacherMapping, $semesterMapping) {
            foreach ($oldTimetables as $oldTT) {
                $newTT = $oldTT->replicate();
                $newTT->session_year_id = $toId;

                // Map Semester ID
                if ($oldTT->semester_id && isset($semesterMapping[$oldTT->semester_id])) {
                    $newTT->semester_id = $semesterMapping[$oldTT->semester_id];
                }

                // Handle Lectures
                if ($oldTT->type == 'Lecture') {
                    // Map subject_teacher_id if the teacher assignment was migrated
                    if ($oldTT->subject_teacher_id && isset($subjectTeacherMapping[$oldTT->subject_teacher_id])) {
                        $newTT->subject_teacher_id = $subjectTeacherMapping[$oldTT->subject_teacher_id];
                    }
                    // subject_id is session-neutral, stays the same
                    // class_section_id is session-neutral, stays the same
                }

                $newTT->save();
            }
        });
    }

    private function migrateFees(int $fromId, int $toId, int $schoolId): void
    {
        $toSessionYear = SessionYear::findOrFail($toId);
        $newDueDate = $toSessionYear->getRawOriginal('end_date');

        // 1. Migrate Fees (Main records)
        Fee::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldFees) use ($toId, $newDueDate) {
            foreach ($oldFees as $oldFee) {
                $newFee = $oldFee->replicate();
                $newFee->session_year_id = $toId;
                $newFee->due_date = $newDueDate; // Reset to session end date
                $newFee->save();

                // 2. Migrate FeesClassType (Links to this specific fee)
                $oldClassTypes = FeesClassType::where('fees_id', $oldFee->id)->get();
                foreach ($oldClassTypes as $oldCT) {
                    $newCT = $oldCT->replicate();
                    $newCT->fees_id = $newFee->id;
                    $newCT->save();
                }

                // 3. Migrate FeesInstallment (Links to this specific fee)
                $oldInstallments = FeesInstallment::where('fees_id', $oldFee->id)->get();
                foreach ($oldInstallments as $oldInst) {
                    $newInst = $oldInst->replicate();
                    $newInst->session_year_id = $toId;
                    $newInst->fees_id = $newFee->id;
                    $newInst->due_date = $newDueDate; // Reset to session end date
                    $newInst->save();
                }
            }
        });
    }

    private function migrateLeaveSettings(int $fromId, int $toId, int $schoolId): void
    {
        LeaveMaster::where('session_year_id', $fromId)->where('school_id', $schoolId)->chunk(100, function ($oldLeaves) use ($toId) {
            foreach ($oldLeaves as $oldL) {
                $newL = $oldL->replicate();
                $newL->session_year_id = $toId;
                $newL->save();
            }
        });
    }
}