HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/Refactor/Admin/PlanController.php
<?php

namespace App\Http\Controllers\Refactor\Admin;

use App\Http\Controllers\Controller;
use App\Library\RateLimit;
use App\Model\EmailVerificationServer;
use App\Model\Plan;
use App\Model\SendingServer;
use App\Services\Plans\Credits\CreditKey;
use App\Services\Plans\Entitlements\EntitlementKey;
use App\Services\Plans\Entitlements\EntitlementsService;
use App\Services\Plans\PlansService;
use App\Services\Plans\Quotas\QuotaKey;
use App\Services\Plans\RateLimits\RateLimitKey;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class PlanController extends Controller
{
    public function index(Request $request)
    {
        if (Gate::denies('read', Plan::newDefaultPlan())) {
            return $this->notAuthorized();
        }

        // Admin sees ALL plans (active + inactive) of type=general only
        $allPlans = Plan::query();

        $stats = [
            'total' => (clone $allPlans)->count(),
            'active' => (clone $allPlans)->where('plans.status', 'active')->count(),
            'visible' => (clone $allPlans)->where('plans.visible', true)->count(),
            'subscriptions' => \App\Model\Subscription::count(),
        ];

        return view('refactor.pages.admin.plans.index', compact('stats'));
    }

    public function listing(Request $request)
    {
        if (Gate::denies('read', Plan::newDefaultPlan())) {
            return response('Unauthorized', 403);
        }

        // Admin sees ALL plans of type=general (verification plans live under
        // /admin/plan-verifications). Without this filter, /plans/{uid}/general
        // can be reached for a verification UID and crash with BadMethodCallException.
        $query = Plan::query();

        // Search
        if ($keyword = $request->keyword) {
            $query = $query->where(function ($q) use ($keyword) {
                $q->where('plans.name', 'like', "%{$keyword}%")
                  ->orWhere('plans.description', 'like', "%{$keyword}%");
            });
        }

        // Status filter
        if ($request->status && $request->status !== 'all') {
            $query = $query->where('plans.status', $request->status);
        }

        // Sort
        $sortBy = $request->sort_by ?? 'plans.created_at';
        $sortDir = $request->sort_direction ?? 'desc';
        $query = $query->orderBy($sortBy, $sortDir);

        $plans = $query->paginate($request->per_page ?? 15);

        return view('refactor.pages.admin.plans._list', compact('plans'));
    }

    public function create(Request $request)
    {
        if (Gate::denies('create', Plan::newDefaultPlan())) {
            return $this->notAuthorized();
        }

        $plan = Plan::newDefaultPlan();

        return view('refactor.pages.admin.plans.create', compact('plan'));
    }

    public function store(Request $request)
    {
        if (Gate::denies('create', Plan::newDefaultPlan())) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $validator = \Validator::make($request->all(), [
            'plan.general.name'             => 'required|string|max:255',
            'plan.general.price'            => 'required|numeric|min:0',
            'plan.general.currency_id'      => 'required|exists:currencies,id',
            'plan.general.frequency_amount' => 'required|integer|min:1',
            'plan.general.frequency_unit'   => 'required|in:day,week,month,year',
            'plan.general.trial_amount'     => 'nullable|integer|min:0',
            'plan.general.trial_unit'       => 'nullable|in:day,week,month,year',
        ]);
        if ($validator->fails()) {
            return response()->json([
                'errors' => $validator->errors()->toArray(),
            ], 422);
        }

        $data = $request->input('plan.general', []);
        $plan = app(PlansService::class)->create([
            'name'             => $data['name'],
            'description'      => $data['description'] ?? '',
            'price'            => $data['price'],
            'currency_id'      => $data['currency_id'],
            'frequency_amount' => $data['frequency_amount'],
            'frequency_unit'   => $data['frequency_unit'],
            'trial_amount'     => $data['trial_amount'] ?? 0,
            'trial_unit'       => $data['trial_unit'] ?? 'day',
        ]);
        $plan->checkStatus();

        return response()->json([
            'message' => trans('refactor/admin_plans.flash.created'),
            'redirect' => route('refactor.admin.plans.general', $plan->uid),
        ]);
    }

    public function general(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return $this->notAuthorized();
        }

        return view('refactor.pages.admin.plans.general', compact('plan'));
    }

    // Legacy `quota` / `security` tabs removed — replaced by plan_quotas / plan_rate_limits tabs.

    /**
     * Toggle the plan between "system" and "own" sending-server mode.
     * Internally this writes only the HAS_OWN_SENDING_SERVER entitlement — kept
     * as a dedicated endpoint (instead of asking admins to dig into the generic
     * Entitlements tab) because this toggle has outsized behavioral impact.
     */
    public function setSendingServerMode(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return $this->notAuthorized();
        }

        $mode = $request->input('mode') === 'own' ? 'own' : 'system';
        $service = app(PlansService::class);

        // Preserve unrelated entitlements; we only touch HAS_OWN_SENDING_SERVER
        // + sending_providers (ALLOW_SENDING_*).
        $byKey = app(EntitlementsService::class)->entitlementsOfPlan($plan);

        $byKey[EntitlementKey::HAS_OWN_SENDING_SERVER->value] = ($mode === 'own');

        // In "own" mode read per-provider toggles from the form; in "system" mode
        // force them all off (they're irrelevant — customer uses system servers).
        foreach (EntitlementKey::cases() as $key) {
            if ($key->group() !== 'sending_providers') continue;
            if ($mode === 'own') {
                $byKey[$key->value] = (bool) $request->input("providers.{$key->value}", false);
            } else {
                $byKey[$key->value] = false;
            }
        }

        $service->setEntitlements($plan, $byKey);

        // MAX_SENDING_SERVERS quota — preserve every other quota; only touch this key.
        $quotaByKey = app(\App\Services\Plans\Quotas\QuotasService::class)->quotasOfPlan($plan);
        if ($mode === 'own') {
            $unlimited = (string) $request->input('max_sending_servers_unlimited') === '1';
            $raw       = $request->input('max_sending_servers');
            if (!$unlimited && (!is_numeric($raw) || (int) $raw < 1)) {
                return redirect()->back()
                    ->with('error', trans('refactor/admin_plans.sending_servers.max_servers_validation_error'))
                    ->withInput();
            }
            $quotaByKey[QuotaKey::MAX_SENDING_SERVERS->value] = $unlimited
                ? null
                : (int) $raw;
        } else {
            // system mode: customer can't bring any own server
            $quotaByKey[QuotaKey::MAX_SENDING_SERVERS->value] = 0;
        }
        $service->setQuotas($plan, $quotaByKey);

        return redirect()->route('refactor.admin.plans.sending_servers', $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    public function sendingServers(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return $this->notAuthorized();
        }

        // System sending servers already assigned
        $planSendingServers = $plan->plansSendingServers()->with('sendingServer')->get();

        // Available system servers for adding — system (admin-owned) only.
        // Customer-owned servers can't be plan-bound because a plan applies
        // to all customers subscribed to it.
        $existingIds = $planSendingServers->pluck('sending_server_id')->toArray();
        $availableServers = SendingServer::system()
            ->where('status', 'active')
            ->whereNotIn('id', $existingIds)
            ->get();

        // ALLOW_SENDING_* entitlements (only meaningful when HAS_OWN_SENDING_SERVER)
        $providerKeys = array_values(array_filter(
            EntitlementKey::cases(),
            fn ($k) => $k->group() === 'sending_providers'
        ));
        $providerState = app(EntitlementsService::class)->entitlementsOfPlan($plan);

        // MAX_SENDING_SERVERS quota (only meaningful in own mode). limitForPlan
        // returns false when row absent; legacy view treats null=unlimited / 0=not-configured
        // — normalize false→null since "no row" here is conceptually "not yet configured"
        // (own-mode form lets admin set it next). View distinguishes null vs int correctly.
        $maxServersRaw = app(\App\Services\Plans\Quotas\QuotasService::class)
            ->limitForPlan($plan, QuotaKey::MAX_SENDING_SERVERS);
        $maxServersLimit = $maxServersRaw === false ? null : $maxServersRaw;

        return view('refactor.pages.admin.plans.sending_servers', compact(
            'plan', 'planSendingServers', 'availableServers', 'providerKeys', 'providerState', 'maxServersLimit'
        ));
    }

    public function addSendingServer(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        if ($request->isMethod('get')) {
            $existingIds = $plan->plansSendingServers()->pluck('sending_server_id')->toArray();
            // System (admin-owned) servers only — customer-owned servers can't
            // be plan-bound because plans apply to all customers of the plan.
            $availableServers = SendingServer::system()
                ->where('status', 'active')
                ->whereNotIn('id', $existingIds)
                ->get();

            return view('refactor.pages.admin.plans.add_sending_server', compact('plan', 'availableServers'));
        }

        $server = SendingServer::findByUid($request->sending_server_uid);
        if (!$server) {
            return response()->json(['error' => 'Server not found'], 404);
        }

        // Check duplicate
        $exists = $plan->plansSendingServers()
            ->where('sending_server_id', $server->id)
            ->exists();

        if ($exists) {
            return response()->json(['error' => trans('refactor/admin_plans.sending_servers.already_added')], 422);
        }

        $plan->addSendingServerByUid($server->uid);
        $plan->checkStatus();

        return response()->json([
            'message' => trans('refactor/admin_plans.sending_servers.flash.added'),
            'redirect' => route('refactor.admin.plans.sending_servers', $plan->uid),
        ]);
    }

    public function removeSendingServer(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $plan->removeSendingServerByUid($request->sending_server_uid);
        $plan->checkStatus();

        return response()->json([
            'message' => trans('refactor/admin_plans.sending_servers.flash.removed'),
            'redirect' => route('refactor.admin.plans.sending_servers', $plan->uid),
        ]);
    }

    public function setPrimarySendingServer(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $plan->setPrimarySendingServer($request->sending_server_uid);
        $plan->checkStatus();

        return response()->json([
            'message' => trans('refactor/admin_plans.sending_servers.flash.primary_set'),
            'redirect' => route('refactor.admin.plans.sending_servers', $plan->uid),
        ]);
    }

    public function fitness(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        if ($request->isMethod('post')) {
            $plan->updateFitnesses($request->sending_servers);
            $plan->checkStatus();

            return response()->json([
                'message' => trans('refactor/admin_plans.sending_servers.flash.fitness_saved'),
                'redirect' => route('refactor.admin.plans.sending_servers', $plan->uid),
            ]);
        }

        $planSendingServers = $plan->plansSendingServers()->with('sendingServer')->get();

        return view('refactor.pages.admin.plans.fitness', compact('plan', 'planSendingServers'));
    }

    // Legacy `sendingServerOption` / `saveSendingServerOwn` tabs removed — replaced by
    // plan_entitlements (HAS_OWN_SENDING_SERVER + ALLOW_SENDING_* per provider) tab.

    public function pieChart(Request $request)
    {
        if (Gate::denies('read', Plan::newDefaultPlan())) {
            return response()->json([], 403);
        }

        $admin = $request->user()->admin;
        $result = ['data' => []];

        foreach (Plan::active()->get() as $plan) {
            $count = $admin->getAllSubscriptionsByPlan($plan)->count();
            if ($count) {
                $result['data'][] = ['value' => $count, 'name' => $plan->name];
            }
        }

        usort($result['data'], function ($a, $b) {
            return $b['value'] - $a['value'];
        });

        return response()->json($result);
    }

    // Legacy `emailFooter` / `emailVerification` tabs removed — footer text lives on
    // plans.footer_html/footer_text columns (gated by HAS_CUSTOM_FOOTER entitlement),
    // and email-verification server plan settings moved to plan_entitlements
    // (HAS_OWN_EMAIL_VERIFICATION_SERVER + HAS_ALL_EMAIL_VERIFICATION_SERVERS).

    public function tos(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return $this->notAuthorized();
        }

        return view('refactor.pages.admin.plans.tos', compact('plan'));
    }

    // ===== New 4-concept plan management tabs =====

    public function planCredits(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        $credits = app(\App\Services\Plans\Credits\CreditsService::class)->creditsOfPlan($plan);
        return view('refactor.pages.admin.plans.plan_credits', [
            'plan'    => $plan,
            'credits' => $credits,
            'keys'    => CreditKey::cases(),
        ]);
    }

    public function savePlanCredits(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        $errors = [];
        $byKey = [];
        foreach (CreditKey::cases() as $key) {
            $enabled = (string) $request->input("credits_enabled.{$key->value}") === '1';
            if (! $enabled) {
                continue; // key absent → setCredits() deletes the plan_credits row
            }

            $unlimited = (string) $request->input("credits_unlimited.{$key->value}") === '1';
            if ($unlimited) {
                $byKey[$key->value] = null;
                continue;
            }

            $raw = $request->input("credits.{$key->value}");
            if ($raw === null || $raw === '') {
                $errors["credits.{$key->value}"] = [trans('refactor/admin_plans.credit.validation.required')];
                continue;
            }

            if (!is_numeric($raw) || (int) $raw < 0 || (string) (int) $raw !== (string) $raw) {
                $errors["credits.{$key->value}"] = [trans('refactor/admin_plans.credit.validation.invalid')];
                continue;
            }

            $byKey[$key->value] = (int) $raw;
        }

        if ($errors) {
            throw \Illuminate\Validation\ValidationException::withMessages($errors);
        }

        app(PlansService::class)->setCredits($plan, $byKey);

        return redirect()->route('refactor.admin.plans.plan_credits', $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    public function planQuotas(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        $quotaByKey   = app(\App\Services\Plans\Quotas\QuotasService::class)->quotasOfPlan($plan);
        $requiresTd   = (bool) \App\Model\PlanEntitlement::where('plan_id', $plan->id)
            ->where('entitlement_key', EntitlementKey::REQUIRES_TRACKING_DOMAIN->value)
            ->value('enabled');

        return view('refactor.pages.admin.plans.plan_quotas', [
            'plan'      => $plan,
            'quotaByKey' => $quotaByKey,
            'keys'      => QuotaKey::cases(),
            'requiresTrackingDomain' => $requiresTd,
        ]);
    }

    public function savePlanQuotas(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        // Preserve MAX_SENDING_SERVERS — it's managed in the Sending Servers tab
        // (depends on HAS_OWN_SENDING_SERVER entitlement) and isn't exposed here.
        $preserved = app(\App\Services\Plans\Quotas\QuotasService::class)->quotasOfPlan($plan);

        $errors = [];
        $byKey = [];
        foreach (QuotaKey::cases() as $key) {
            if ($key === QuotaKey::MAX_SENDING_SERVERS) {
                if (array_key_exists($key->value, $preserved)) {
                    $byKey[$key->value] = $preserved[$key->value];
                }
                continue;
            }
            $enabled = (string) $request->input("quotas_enabled.{$key->value}") === '1';
            if (! $enabled) {
                continue; // key absent → setQuotas() deletes the plan_quotas row
            }
            $unlimited = (string) $request->input("quotas_unlimited.{$key->value}") === '1';
            if ($unlimited) {
                $byKey[$key->value] = null;
                continue;
            }
            $raw = $request->input("quotas.{$key->value}");
            if ($raw === null || $raw === '') {
                $errors["quotas.{$key->value}"] = [trans('refactor/admin_plans.quota.validation.required')];
                continue;
            }
            if (!is_numeric($raw) || (int) $raw < 0 || (string) (int) $raw !== (string) $raw) {
                $errors["quotas.{$key->value}"] = [trans('refactor/admin_plans.quota.validation.invalid')];
                continue;
            }
            $byKey[$key->value] = (int) $raw;
        }

        if ($errors) {
            throw \Illuminate\Validation\ValidationException::withMessages($errors);
        }

        try {
            app(PlansService::class)->setQuotas($plan, $byKey);
        } catch (\InvalidArgumentException $e) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'quotas.' . QuotaKey::MAX_TRACKING_DOMAINS->value => [$e->getMessage()],
            ]);
        }

        return redirect()->route('refactor.admin.plans.plan_quotas', $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    public function planEntitlements(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        // Ensure full catalog seeded
        app(EntitlementsService::class)->seedCatalogForPlan($plan->id);

        $entitlements = app(EntitlementsService::class)->entitlementsOfPlan($plan);
        $trackingDomainQuota = app(\App\Services\Plans\Quotas\QuotasService::class)->limitForPlan($plan, QuotaKey::MAX_TRACKING_DOMAINS);

        return view('refactor.pages.admin.plans.plan_entitlements', [
            'plan'         => $plan,
            'entitlements' => $entitlements,
            'keys'         => EntitlementKey::cases(),
            'trackingDomainQuota' => $trackingDomainQuota,
        ]);
    }

    public function savePlanEntitlements(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        // Preserve sending_providers (ALLOW_SENDING_*) entitlements — those are
        // managed exclusively in the Sending Servers tab; this form doesn't expose them.
        $preserved = app(EntitlementsService::class)->entitlementsOfPlan($plan);

        $byKey = [];
        foreach (EntitlementKey::cases() as $key) {
            if ($key->group() === 'sending_providers') {
                $byKey[$key->value] = $preserved[$key->value] ?? false;
                continue;
            }
            $byKey[$key->value] = (bool) $request->input("entitlements.{$key->value}", false);
        }

        try {
            app(PlansService::class)->setEntitlements($plan, $byKey);
        } catch (\InvalidArgumentException $e) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'entitlements.' . EntitlementKey::REQUIRES_TRACKING_DOMAIN->value => [$e->getMessage()],
            ]);
        }

        return redirect()->route('refactor.admin.plans.plan_entitlements', $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    public function planRateLimits(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        $rates = app(\App\Services\Plans\RateLimits\RateLimitsService::class)->configsOfPlan($plan);
        return view('refactor.pages.admin.plans.plan_rate_limits', [
            'plan'  => $plan,
            'rates' => $rates,
            'keys'  => RateLimitKey::cases(),
        ]);
    }

    public function savePlanRateLimits(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if (Gate::denies('update', $plan)) return $this->notAuthorized();

        $service = app(PlansService::class);
        foreach (RateLimitKey::cases() as $key) {
            $limit  = $request->input("rates.{$key->value}.limit");
            $amount = $request->input("rates.{$key->value}.amount");
            $unit   = $request->input("rates.{$key->value}.unit");

            if ($limit === null || $limit === '' || (int) $limit <= 0) {
                $service->setRateLimit($plan, $key, null);
                continue;
            }

            $service->setRateLimit($plan, $key, new RateLimit(
                (int) $limit,
                (int) ($amount ?: 1),
                in_array($unit, ['second', 'minute', 'hour', 'day'], true) ? $unit : 'minute',
            ));
        }

        return redirect()->route('refactor.admin.plans.plan_rate_limits', $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    // ===== End new 4-concept tabs =====

    /**
     * Save general plan attributes (name/price/frequency/currency/trial). The old
     * options-based saveAll pipeline is gone; each 4-concept tab saves via its own
     * controller method.
     */
    public function save(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return $this->notAuthorized();
        }

        app(PlansService::class)->updateBase($plan, $request->input('plan.general', []));

        $redirectTab = $request->input('_redirect_tab', 'general');
        return redirect()->route('refactor.admin.plans.' . $redirectTab, $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    public function saveTos(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (Gate::denies('update', $plan)) {
            return $this->notAuthorized();
        }

        $validator = $plan->updateTos($request->all());

        if ($validator->fails()) {
            return redirect()->back()->withErrors($validator)->withInput();
        }

        return redirect()->route('refactor.admin.plans.tos', $plan->uid)
            ->with('success', trans('refactor/admin_plans.flash.saved'));
    }

    public function enable(Request $request)
    {
        $service = app(PlansService::class);
        $uids = is_array($request->uids) ? $request->uids : [$request->uids];

        foreach ($uids as $uid) {
            $plan = Plan::findByUid($uid);
            if ($plan) {
                $service->enable($plan);
            }
        }

        return response()->json([
            'message' => trans('refactor/admin_plans.flash.enabled'),
        ]);
    }

    public function disable(Request $request)
    {
        $service = app(PlansService::class);
        $uids = is_array($request->uids) ? $request->uids : [$request->uids];

        foreach ($uids as $uid) {
            $plan = Plan::findByUid($uid);
            if ($plan) {
                $service->disable($plan);
            }
        }

        return response()->json([
            'message' => trans('refactor/admin_plans.flash.disabled'),
        ]);
    }

    public function delete(Request $request)
    {
        $uids = is_array($request->uids) ? $request->uids : [$request->uids];

        foreach ($uids as $uid) {
            $plan = Plan::findByUid($uid);
            if ($plan && Gate::allows('delete', $plan)) {
                $plan->delete();
            }
        }

        return response()->json([
            'message' => trans('refactor/admin_plans.flash.deleted'),
        ]);
    }

    public function visibleOn(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if ($plan) {
            if ($plan->useSystemSendingServer() && !$plan->hasPrimarySendingServer()) {
                return response()->json(['error' => trans('refactor/admin_plans.warning.cannot_show_no_server')], 422);
            }
            $plan->visible = true;
            $plan->save();
        }

        return response()->json(['message' => trans('refactor/admin_plans.flash.visible_on')]);
    }

    public function visibleOff(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);
        if ($plan) {
            $plan->visible = false;
            $plan->save();
        }

        return response()->json(['message' => trans('refactor/admin_plans.flash.visible_off')]);
    }

    public function copy(Request $request, $uid)
    {
        $plan = Plan::findByUid($uid);

        if (!$plan) {
            return response()->json(['error' => 'Plan not found'], 404);
        }

        $newPlan = $plan->replicate();
        $newPlan->name = $plan->name . ' (Copy)';
        $newPlan->uid = uniqid();
        $newPlan->save();

        return response()->json([
            'message' => trans('refactor/admin_plans.flash.copied'),
        ]);
    }

    public function payment(Request $request, $uid)
    {
        $plan = \App\Model\Plan::findByUid($uid);

        if (!$plan || \Gate::denies('update', $plan)) {
            return redirect()->route('refactor.admin.plans.general', $uid);
        }

        // View never existed in old codebase — redirect to general settings
        return redirect()->route('refactor.admin.plans.general', $uid);
    }

}