File: /home/xedaptot/be.naniguide.com/app/Http/Controllers/Refactor/Admin/PaymentGatewayController.php
<?php
namespace App\Http\Controllers\Refactor\Admin;
use App\Http\Controllers\Controller;
use App\Library\Facades\Billing;
use App\Model\PaymentGateway;
use App\Model\Setting;
use Illuminate\Http\Request;
class PaymentGatewayController extends Controller
{
public function index(Request $request)
{
if (!$request->user()->admin->can('read', new PaymentGateway())) {
return $this->notAuthorized();
}
$query = PaymentGateway::query()->global();
$stats = [
'total' => (clone $query)->count(),
'active' => (clone $query)->where('status', PaymentGateway::STATUS_ACTIVE)->count(),
'inactive' => (clone $query)->where('status', PaymentGateway::STATUS_INACTIVE)->count(),
];
// Category distribution by capability (remote-subscription vs direct charge).
// Plugins implementing RemoteSubscriptionGatewayInterface automatically bucket
// into "remote" — no type-string hardcoding here.
$globals = (clone $query)->get();
$remoteCount = $globals->filter(fn ($gw) => Billing::supportsRemoteSubscription($gw))->count();
$categoryDistribution = [
'direct' => $globals->count() - $remoteCount,
'remote' => $remoteCount,
];
return view('refactor.pages.admin.payment-gateways.index', compact('stats', 'categoryDistribution'));
}
public function listing(Request $request)
{
if (!$request->user()->admin->can('read', new PaymentGateway())) {
return response('Unauthorized', 403);
}
$query = PaymentGateway::query()->global();
if ($request->keyword) {
$keyword = '%' . strtolower(trim($request->keyword)) . '%';
$query->where(function ($q) use ($keyword) {
$q->whereRaw('LOWER(name) LIKE ?', [$keyword])
->orWhereRaw('LOWER(description) LIKE ?', [$keyword]);
});
}
// Type filter
if ($request->type && $request->type !== 'all') {
$query = $query->where('type', $request->type);
}
// Status filter
if ($request->status && $request->status !== 'all') {
$query = $query->where('status', $request->status);
}
$sortBy = $request->sort_by ?? 'payment_gateways.created_at';
$sortDir = $request->sort_direction ?? 'desc';
$query = $query->orderBy($sortBy, $sortDir);
$items = $query->paginate($request->per_page ?? 15);
return view('refactor.pages.admin.payment-gateways._list', compact('items'));
}
public function selectType(Request $request)
{
if (!$request->user()->admin->can('create', PaymentGateway::class)) {
return $this->notAuthorized();
}
$gatewayServices = Billing::getGateways();
return view('refactor.pages.admin.payment-gateways.select-type', compact('gatewayServices'));
}
public function create(Request $request, $type)
{
if (!$request->user()->admin->can('create', PaymentGateway::class)) {
return $this->notAuthorized();
}
$paymentGateway = PaymentGateway::newDefault($type);
$gatewayServices = Billing::getGateways();
$gatewayService = $gatewayServices[$type] ?? null;
if (!$gatewayService) {
abort(404);
}
return view('refactor.pages.admin.payment-gateways.create', compact('paymentGateway', 'gatewayService'));
}
public function store(Request $request, $type)
{
if (!$request->user()->admin->can('create', PaymentGateway::class)) {
return $this->notAuthorized();
}
$paymentGateway = PaymentGateway::newDefault($type);
$validator = $paymentGateway->savePaymentGateway(
$request->name,
$request->description,
$request->gateway_data
);
if ($validator->fails()) {
$gatewayServices = Billing::getGateways();
$gatewayService = $gatewayServices[$type];
return response()->view('refactor.pages.admin.payment-gateways.create', [
'paymentGateway' => $paymentGateway,
'gatewayService' => $gatewayService,
'errors' => $validator->errors(),
], 400);
}
$request->session()->flash('alert-success', trans('refactor/admin_payment_gateways.flash.created'));
return redirect()->route('refactor.admin.payment-gateways.index');
}
public function edit(Request $request, $uid)
{
$paymentGateway = PaymentGateway::global()->where('uid', $uid)->first();
if (!$paymentGateway) {
abort(404);
}
if (!$request->user()->admin->can('update', $paymentGateway)) {
return $this->notAuthorized();
}
$gatewayServices = Billing::getGateways();
$gatewayService = $gatewayServices[$paymentGateway->type] ?? null;
return view('refactor.pages.admin.payment-gateways.edit', compact('paymentGateway', 'gatewayService'));
}
public function update(Request $request, $uid)
{
$paymentGateway = PaymentGateway::global()->where('uid', $uid)->first();
if (!$paymentGateway) {
abort(404);
}
if (!$request->user()->admin->can('update', $paymentGateway)) {
return $this->notAuthorized();
}
$validator = $paymentGateway->savePaymentGateway(
$request->name,
$request->description,
$request->gateway_data
);
if ($validator->fails()) {
$gatewayServices = Billing::getGateways();
$gatewayService = $gatewayServices[$paymentGateway->type];
return response()->view('refactor.pages.admin.payment-gateways.edit', [
'paymentGateway' => $paymentGateway,
'gatewayService' => $gatewayService,
'errors' => $validator->errors(),
], 400);
}
$request->session()->flash('alert-success', trans('refactor/admin_payment_gateways.flash.updated'));
return redirect()->route('refactor.admin.payment-gateways.index');
}
public function enable(Request $request)
{
$items = PaymentGateway::global()->whereIn(
'uid',
is_array($request->uids) ? $request->uids : explode(',', $request->uids)
);
foreach ($items->get() as $item) {
if ($request->user()->admin->can('enable', $item)) {
$item->enable();
}
}
echo trans('refactor/admin_payment_gateways.flash.enabled');
}
public function disable(Request $request)
{
$items = PaymentGateway::global()->whereIn(
'uid',
is_array($request->uids) ? $request->uids : explode(',', $request->uids)
);
foreach ($items->get() as $item) {
if ($request->user()->admin->can('disable', $item)) {
$item->disable();
}
}
echo trans('refactor/admin_payment_gateways.flash.disabled');
}
public function delete(Request $request)
{
$items = PaymentGateway::global()->whereIn(
'uid',
is_array($request->uids) ? $request->uids : explode(',', $request->uids)
);
// Surface any persistence/business error verbatim instead of 500. The
// FK on payment_intents.payment_gateway_id used to be RESTRICT — a
// gateway with historical intents would throw SQL 1451 which Konstantin
// saw as a generic "server error". Migration 2026_05_14_140000 relaxed
// that to nullOnDelete; this catch covers any remaining FK on a child
// table we may have missed and keeps the response shape predictable.
try {
foreach ($items->get() as $item) {
if ($request->user()->admin->can('delete', $item)) {
$item->delete();
}
}
} catch (\Throwable $e) {
\Log::warning('admin.payment-gateways.delete failed', [
'admin_uid' => $request->user()->admin->uid ?? null,
'uids' => $request->uids,
'error' => $e->getMessage(),
]);
return response()->json([
'status' => 'error',
'message' => trans('refactor/admin_payment_gateways.flash.delete_failed', ['reason' => $e->getMessage()]),
], 422);
}
echo trans('refactor/admin_payment_gateways.flash.deleted');
}
public function testConnection(Request $request, $uid)
{
$paymentGateway = PaymentGateway::global()->where('uid', $uid)->first();
if (!$paymentGateway) {
abort(404);
}
try {
$service = Billing::resolveService($paymentGateway);
if ($service instanceof \App\Cashier\Contracts\RemoteSubscriptionGatewayInterface) {
$plans = app(\App\Services\Subscription\SubscriptionManagementService::class)
->fetchRemotePlans($paymentGateway);
return response()->json([
'status' => 'success',
'message' => trans('refactor/admin_payment_gateways.test_connection.success_remote', ['count' => count($plans)]),
]);
}
if (method_exists($service, 'isActive') && $service->isActive()) {
return response()->json([
'status' => 'success',
'message' => trans('refactor/admin_payment_gateways.test_connection.success'),
]);
}
return response()->json([
'status' => 'error',
'message' => trans('refactor/admin_payment_gateways.test_connection.not_active'),
], 400);
} catch (\Throwable $e) {
return response()->json([
'status' => 'error',
'message' => trans('refactor/admin_payment_gateways.test_connection.failed', ['error' => $e->getMessage()]),
], 400);
}
}
public function settings(Request $request)
{
if ($request->user()->admin->getPermission('setting_general') != 'yes') {
return $this->notAuthorized();
}
return view('refactor.pages.admin.payment-gateways.settings');
}
public function settingsSave(Request $request)
{
if ($request->user()->admin->getPermission('setting_general') != 'yes') {
return $this->notAuthorized();
}
$this->validate($request, [
'auto_billing_period' => 'required',
'grace_period' => 'required|integer|min:0',
]);
Setting::set('grace_period', $request->grace_period);
Setting::set('subscription.auto_billing_period', $request->auto_billing_period);
$request->session()->flash('alert-success', trans('refactor/admin_payment_gateways.flash.settings_updated'));
return redirect()->route('refactor.admin.payment-gateways.settings');
}
}