File "PackageController.php"

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

<?php

namespace App\Http\Controllers;

use App\Models\Feature;
use App\Models\SubscriptionFeature;
use App\Repositories\Feature\FeatureInterface;
use App\Repositories\Package\PackageInterface;
use App\Repositories\PackageFeature\PackageFeatureInterface;
use App\Repositories\Subscription\SubscriptionInterface;
use App\Repositories\SubscriptionFeature\SubscriptionFeatureInterface;
use App\Services\BootstrapTableService;
use App\Services\ResponseService;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Throwable;

class PackageController extends Controller
{

    private PackageInterface $package;
    private FeatureInterface $feature;
    private PackageFeatureInterface $packageFeature;
    private SubscriptionInterface $subscription;
    private SubscriptionFeatureInterface $subscriptionFeature;

    public function __construct(PackageInterface $package, FeatureInterface $feature, PackageFeatureInterface $packageFeature, SubscriptionInterface $subscription, SubscriptionFeatureInterface $subscriptionFeature)
    {
        $this->package = $package;
        $this->feature = $feature;
        $this->packageFeature = $packageFeature;
        $this->subscription = $subscription;
        $this->subscriptionFeature = $subscriptionFeature;
    }


    public function index()
    {
        ResponseService::noPermissionThenRedirect('package-list');
        return view('package.index');
    }


    public function create()
    {
        ResponseService::noPermissionThenRedirect('package-create');
        $features = $this->feature->builder()->activeFeatures()->orderBy('is_default', 'DESC')->orderBy('name', 'ASC')->get();
        $vps_features = $this->feature->builder()->where('required_vps', 1)->get();
        return view('package.create', compact('features', 'vps_features'));
    }


    public function store(Request $request)
    {
        ResponseService::noPermissionThenRedirect('package-create');
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'student_charge' => 'required_if:type,1|nullable|numeric|decimal:0,2',
            'staff_charge' => 'required_if:type,1|nullable|numeric|decimal:0,2',
            'feature_id' => 'required',
            'days' => 'required|numeric',
            'no_of_students' => 'required_if:type,0|nullable|numeric|decimal:0,2',
            'no_of_staffs' => 'required_if:type,0|nullable|numeric|decimal:0,2',
            'charges' => 'required_if:type,0|nullable|numeric|decimal:0,2',

        ], [
            'feature_id.required' => trans('please_select_at_least_one_feature')
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }

        $request['student_charge'] = $request->student_charge ?? 0;
        $request['staff_charge'] = $request->staff_charge ?? 0;

        $request['no_of_students'] = $request->no_of_students ?? 0;
        $request['no_of_staffs'] = $request->no_of_staffs ?? 0;
        $request['charges'] = $request->charges ?? 0;

        try {
            DB::beginTransaction();
            $packageData = [
                ...$request->all(),
                'highlight' => $request->highlight ?? 0,
            ];

            // Create package
            $package = $this->package->create($packageData);
            // Create package features
            $packageFeatures = [];
            foreach ($request->feature_id as $feature) {
                $packageFeatures[] = [
                    'package_id' => $package->id,
                    'feature_id' => $feature
                ];
            }
            $this->packageFeature->upsert($packageFeatures, ['package_id', 'feature_id'], ['package_id', 'feature_id']); // Store package features
            DB::commit();
            ResponseService::successResponse('Data Stored Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller -> Store method');
            ResponseService::errorResponse();
        }
    }


    public function show()
    {
        ResponseService::noPermissionThenRedirect('package-list');
        $offset = request('offset', 0);
        $limit = request('limit', 10);
        $sort = request('sort', 'rank');
        $order = request('order', 'ASC');
        $search = request('search');
        $showDeleted = request('show_deleted');
        $type = request('type');
        $today_date = Carbon::now()->format('Y-m-d');

        $sql = $this->package->builder()->with('package_feature.feature')->where('is_trial', 0)
            ->withCount([
                'subscription' => function ($q) use ($today_date) {
                    $q->whereDate('start_date', '<=', $today_date)->whereDate('end_date', '>=', $today_date);
                }
            ])
            ->where(function ($query) use ($search) {
                $query->when($search, function ($query) use ($search) {
                    $query->where(function ($query) use ($search) {
                        $query->where('name', 'LIKE', "%$search%")
                            ->orWhere('description', 'LIKE', "%$search%")
                            ->orWhere('tagline', 'LIKE', "%$search%");
                    });
                });
            })->when(!empty($showDeleted), function ($q) {
                $q->onlyTrashed();
            });

        if (isset($type)) {
            $sql->where('type', $type);
        }


        $total = $sql->count();
        if ($offset >= $total && $total > 0) {
            $lastPage = floor(($total - 1) / $limit) * $limit; // calculate last page offset
            $offset = $lastPage;
        }
        $sql->orderBy($sort, $order)->skip($offset)->take($limit);
        $res = $sql->get();

        $bulkData = array();
        $bulkData['total'] = $total;
        $rows = array();
        $no = 1;

        foreach ($res as $row) {
            $operate = '';
            if (empty($showDeleted)) {
                if ($row->status == 0) {
                    $operate .= BootstrapTableService::button('fa fa-check', '#', ['change-package-status', 'btn-gradient-success'], ['title' => trans("publish_package"), 'data-id' => $row->id]);
                } else {
                    $operate .= BootstrapTableService::button('fa fa-times', '#', ['change-package-status', 'btn-gradient-warning'], ['title' => trans("unpublished_package"), 'data-id' => $row->id]);
                }
                $operate .= BootstrapTableService::editButton(route('package.edit', $row->id), false);
                $operate .= BootstrapTableService::deleteButton(route('package.destroy', $row->id));
            } else {
                $operate .= BootstrapTableService::restoreButton(route('package.restore', $row->id));
                $operate .= BootstrapTableService::trashButton(route('package.trash', $row->id));
            }

            $tempRow = $row->toArray();
            $tempRow['no'] = $no++;
            $tempRow['used_by'] = $row->subscription_count;
            $tempRow['operate'] = $operate;
            $rows[] = $tempRow;
        }

        $bulkData['rows'] = $rows;
        return response()->json($bulkData);
    }


    public function edit($id)
    {
        ResponseService::noPermissionThenRedirect('package-edit');
        $package = $this->package->findById($id);
        $features = $this->feature->builder()->activeFeatures()->orderBy('is_default', 'DESC')->orderBy('name', 'ASC')->get();
        $vps_features = $this->feature->builder()->where('required_vps', 1)->get();
        return view('package.edit', compact('package', 'features', 'vps_features'));
    }

    public function update(Request $request, $id)
    {
        ResponseService::noPermissionThenSendJson('package-edit');
        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'student_charge' => 'required_if:type,1|nullable|numeric|decimal:0,2',
            'staff_charge' => 'required_if:type,1|nullable|numeric|decimal:0,2',
            'feature_id' => 'required',
            'days' => 'required|numeric',
            'no_of_students' => 'required_if:type,0|nullable|numeric|decimal:0,2',
            'no_of_staffs' => 'required_if:type,0|nullable|numeric|decimal:0,2',
            'charges' => 'required_if:type,0|nullable|numeric|decimal:0,2',
        ], [
            'feature_id.required' => trans('please_select_at_least_one_feature'),
        ]);



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

        try {
            DB::beginTransaction();

            // Instant effects features
            if ($request->instant_effects) {
                $today_date = Carbon::now()->format('Y-m-d');
                $subscriptions = $this->subscription->builder()->where('package_id',$id)->where('start_date','<=',$today_date)->where('end_date','>=',$today_date)->pluck('id');
            }

            // 0 => Prepaid, 1 => Postpaid
            if ($request->type == 1) {
                $request['student_charge'] = $request->student_charge ?? 0;
                $request['staff_charge'] = $request->staff_charge ?? 0;

                $request['no_of_students'] = 0;
                $request['no_of_staffs'] = 0;
                $request['charges'] = 0;
            } else {
                $request['student_charge'] = 0;
                $request['staff_charge'] = 0;

                $request['no_of_students'] = $request->no_of_students ?? 0;
                $request['no_of_staffs'] = $request->no_of_staffs ?? 0;
                $request['charges'] = $request->charges ?? 0;
            }

            $packageData = [
                ...$request->all(),
                'highlight' => $request->highlight ?? 0,
            ];

            $package = $this->package->update($id, $packageData);
            $package_features = $package->package_feature->pluck('feature_id')->toArray();
            $packageFeatures = [];
            $subscription_features = [];
            foreach ($request->feature_id as $feature) {
                $packageFeatures[] = [
                    'package_id' => $id,
                    'feature_id' => $feature
                ];

                // Remove package features
                $key = array_search($feature, $package_features);
                if ($key !== false) {
                    unset($package_features[$key]);
                }

                if ($request->instant_effects) {
                    foreach ($subscriptions as $key => $subscription) {
                        $subscription_features[] = [
                            'subscription_id' => $subscription,
                            'feature_id' => $feature
                        ];
                    }
                }
            }
            if ($request->instant_effects) {
                // Update features
                $this->subscriptionFeature->upsert($subscription_features, ['subscription_id', 'feature_id'], ['subscription_id', 'feature_id']);
                // Delete features
                $delete_subscription_features = $subscriptions;
                $this->subscriptionFeature->builder()->whereIn('subscription_id', $delete_subscription_features)->whereIn('feature_id', $package_features)->delete();
            }
            $this->packageFeature->upsert($packageFeatures, ['feature_id', 'package_id'], ['package_id', 'feature_id']);

            // Delete package features
            $this->packageFeature->builder()->whereIn('feature_id', $package_features)->where('package_id', $id)->delete();
            DB::commit();
            // Package update will affect all the schools that is why Cache::flush is used here.
            Cache::flush();
            ResponseService::successResponse('Data Updated Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller -> Update method');
            ResponseService::errorResponse();
        }
    }

    public function destroy($id)
    {
        //
        ResponseService::noPermissionThenSendJson('package-delete');
        try {
            DB::beginTransaction();
            $this->package->update($id, ['status' => 0]);
            $this->package->deleteById($id);
            DB::commit();
            ResponseService::successResponse('Data Deleted Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller -> Destroy method');
            ResponseService::errorResponse();
        }
    }


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


    public function restore($id)
    {
        ResponseService::noPermissionThenSendJson('package-edit');

        try {
            DB::beginTransaction();
            $this->package->restoreById($id);
            DB::commit();
            ResponseService::successResponse('Data Restored Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller -> Restore method');
            ResponseService::errorResponse();
        }
    }


    public function trash($id)
    {
        ResponseService::noPermissionThenSendJson('package-delete');
        try {
            DB::beginTransaction();
            // TODO:: Add condition this package cannot be subscribed to any school.
            $package = $this->package->findOnlyTrashedById($id);
            if (count($package->subscription)) {
                ResponseService::errorResponse('cannot_delete_because_data_is_associated_with_other_data');
            } else {
                $this->package->permanentlyDeleteById($id);
            }


            DB::commit();
            ResponseService::successResponse('Data Deleted Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller -> Trash method');
            ResponseService::errorResponse();
        }
    }

    public function change_rank(Request $request)
    {
        ResponseService::noPermissionThenRedirect('package-edit');

        $validator = Validator::make($request->all(), [
            'ids' => 'required',
        ], [
            'ids' => trans('No Package Data Found'),
        ]);
        if ($validator->fails()) {
            ResponseService::validationError($validator->errors()->first());
        }
        try {
            DB::beginTransaction();
            $ids = json_decode($request->ids, false, 512, JSON_THROW_ON_ERROR);
            $update = [];
            foreach ($ids as $key => $id) {
                $update[] = [
                    'id' => $id,
                    'rank' => ($key + 1)
                ];
            }
            $this->package->upsert($update, ['id'], ['rank']);
            DB::commit();
            ResponseService::successResponse('Rank Updated Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller -> Change Rank method');
            ResponseService::errorResponse();
        }
    }

    public function features_list()
    {
        if (!Auth::user()->hasRole('School Admin')) {
            ResponseService::noAnyPermissionThenRedirect(['addons-list', 'addons-create', 'addons-edit', 'addons-delete', 'package-list', 'package-create', 'package-edit', 'package-delete']);
        }
        return view('features');
    }

    public function features_show()
    {
        if (!Auth::user()->hasRole('School Admin')) {
            ResponseService::noAnyPermissionThenRedirect(['addons-list', 'addons-create', 'addons-edit', 'addons-delete', 'package-list', 'package-create', 'package-edit', 'package-delete']);
        }

        $offset = request('offset', 0);
        $limit = request('limit', 10);
        $sort = request('sort', 'id');
        $order = request('order', 'ASC');
        $search = request('search');

        $sql = Feature::activeFeatures()->orderBy($sort, $order);

        // Get all features as collection to handle array filtering in PHP
        $features = $sql->get();

        // Step 2: Filter features based on search term
        if ($search) {
            $features = $features->filter(function ($row) use ($search) {
                $matchesPermission = false;

                // Get permissions for each feature
                $permissions = $this->features_permission($row->name);

                // Search in feature name and permissions array
                if (stripos($row->name, $search) !== false) {
                    return true;
                }

                if (is_array($permissions)) {
                    foreach ($permissions as $permission) {
                        if (stripos($permission, $search) !== false) {
                            $matchesPermission = true;
                            break;
                        }
                    }
                }

                return $matchesPermission;
            });
        }

        // Step 3: Get the total number of filtered records
        $total = $features->count();
        if ($offset >= $total && $total > 0) {
            $lastPage = floor(($total - 1) / $limit) * $limit; // calculate last page offset
            $offset = $lastPage;
        }

        // Step 4: Paginate the filtered results
        $features = $features->slice($offset, $limit);

        $bulkData = array();
        $bulkData['total'] = $total;
        $rows = array();
        $no = $offset + 1;

        // Step 5: Prepare response data
        foreach ($features as $row) {
            $tempRow = $row->toArray();
            $tempRow['no'] = $no++;
            $tempRow['permission'] = $this->features_permission($row->name);
            $rows[] = $tempRow;
        }
        $bulkData['rows'] = $rows;
        // Step 6: Return JSON response
        return response()->json($bulkData);
    }

    public function features_enable(Request $request)
    {
        ResponseService::noAnyPermissionThenRedirect(['package-edit', 'package-create']);
        try {
            DB::beginTransaction();
            $update = [];
            foreach ($request->feature_id as $key => $value) {

                $update[] = [
                    'id' => $key,
                    'status' => $value
                ];
            }

            $this->feature->upsert($update, ['id'], ['status']);
            DB::commit();
            ResponseService::successResponse('Data Updated Successfully');
        } catch (Throwable $e) {
            DB::rollBack();
            ResponseService::logErrorResponse($e, 'Package Controller ->Enable Features method');
            ResponseService::errorResponse();
        }
    }

    public function features_permission($feature = null)
    {
        // TODO : Understand this code
        $permissions = array(
            "Student Management" => array(
                "Manage Student",
                "Manage Guardian",
                "Reset Password",
                "Manage Student Admission Custom Fields"
            ),
            "Academics Management" => array(
                "Manage Medium",
                "Manage Section",
                "Manage Subject",
                "Manage Semester",
                "Manage Stream",
                "Manage Shift",
                "Manage Class",
                "Manage Class Section",
                "Manage Class Teacher",
                "Promote Student"
            ),
            "Slider Management" => array(
                "Manage Slider for App & Web"
            ),
            "Teacher Management" => array(
                "Manage Teacher",
                "Bulk Upload"
            ),
            "Session Year Management" => array(
                "Manage Session Year"
            ),
            "Holiday Management" => array(
                "Manage Holiday"
            ),
            "Timetable Management" => array(
                "Manage Timetable",
                "Create Timetable Using Drag & Drop"
            ),
            "Attendance Management" => array(
                "Manage Attendance"
            ),
            // "Staff Attendance Management" => array(
            //     "Manage Staff Attendance"
            // ),
            "Exam Management" => array(
                "Manage Exam",
                "Manage Exam Timetable",
                "Manage Grade",
                "Manage Student Result",
                "Manage Online Exam",
                "Manage Online Exam Question",
                "Manage Online Result"
            ),
            "Lesson Management" => array(
                "Manage Lesson",
                "Manage Lesson Topic"
            ),
            "Announcement Management" => array(
                "Manage Announcement"
            ),
            "Staff Management" => array(
                "Manage Role",
                "Manage Staff",
                "Bulk Upload"
            ),
            "Assignment Management" => array(
                "Manage Assignment",
                "Manage Assignment Submission with Scores"
            ),
            "Expense Management" => array(
                "Manage Category",
                "Manage Expense",
                "Manage Staff Payroll",
                "Staff Allowances & Deductions",
            ),
            "Staff Leave Management" => array(
                "Manage Staff Leaves",
                "Manage Leave Allowances",
                "Manage LWP (Leave Without Pay)"
            ),
            "Fees Management" => array(
                "Manage Class Wise Fees",
                "Manage Payment [ Cash/Cheque, Online ]",
                "Manage Fees Receipt",
                "Partial Pay Fees with Receipt"
            ),
            "School Gallery Management" => array(
                "Manage School Gallery",
                "Upload Multiple Images & Youtube Links"
            ),
            "ID Card - Certificate Generation" => array(
                "Generate students - staff ID cards & certificates",
                "Drag-and-Drop Certificate Builder"
            ),
            "Website Management" => array(
                "Custom Domain",
                "Content Management System (CMS)",
                "User-Friendly Interface",
                "Dynamic Content Editing",
                "Online Student Admission",
                "Third-Patry API (Google Captcha)"
            ),
            "Chat Module" => array(
                "Parent - Teacher",
                "Student - Teacher",
                "Teacher - Staff",
            ),
            "Transportation Module" => array(
                "Manage Route",
                "Manage Pickup Points",
                "Manage Transportation Fees",
                "Manage Vehicle",
                "Manage Vehicle Schedule",
                "Manage Reports",
                "Manage Student Transportation"
            )
        );

        if ($feature) {
            return $permissions[$feature] ?? null;
        }
        return $permissions;
    }
}