diff --git a/app/Http/Controllers/Qr/AccountController.php b/app/Http/Controllers/Qr/AccountController.php index b71be3b..88c4d32 100644 --- a/app/Http/Controllers/Qr/AccountController.php +++ b/app/Http/Controllers/Qr/AccountController.php @@ -6,6 +6,7 @@ use App\Http\Controllers\Controller; use App\Models\PaymentGatewaySetting; use App\Models\QrSetting; use App\Services\Billing\BillingClient; +use App\Services\Events\SubscriptionService; use App\Services\Payments\MerchantGatewayService; use App\Support\AccountBranding; use App\Support\Qr\QrCornerStyleCatalog; @@ -21,6 +22,7 @@ class AccountController extends Controller public function __construct( private BillingClient $billing, private MerchantGatewayService $gateway, + private SubscriptionService $subscriptions, ) {} private function topupUrl(): string @@ -83,6 +85,7 @@ class AccountController extends Controller 'cornerInnerStyles' => QrCornerStyleCatalog::innerStyles(), 'frameStyles' => QrFrameStyleCatalog::visible(), 'gateway' => $this->gateway->settingFor($account), + 'canUsePaymentGateway' => $this->subscriptions->canUsePaymentGateway($account), ]); } @@ -164,7 +167,7 @@ class AccountController extends Controller ); $provider = (string) ($data['gateway_provider'] ?? ''); - if ($provider !== '') { + if ($provider !== '' && $this->subscriptions->canUsePaymentGateway($account)) { $existing = PaymentGatewaySetting::query()->firstOrNew([ 'owner_ref' => $account->public_id, ]); diff --git a/app/Services/Events/SubscriptionService.php b/app/Services/Events/SubscriptionService.php index 9866fb3..0b92f44 100644 --- a/app/Services/Events/SubscriptionService.php +++ b/app/Services/Events/SubscriptionService.php @@ -74,6 +74,12 @@ class SubscriptionService return $this->hasPaidPlan($user); } + /** Own payment gateway (Paystack / Flutterwave / Hubtel) requires Pro or Business. */ + public function canUsePaymentGateway(User $user): bool + { + return $this->hasPaidPlan($user); + } + public function liveEventCount(User $user): int { return QrCode::query() diff --git a/app/Services/Payments/MerchantGatewayService.php b/app/Services/Payments/MerchantGatewayService.php index f41c599..14da68a 100644 --- a/app/Services/Payments/MerchantGatewayService.php +++ b/app/Services/Payments/MerchantGatewayService.php @@ -4,6 +4,7 @@ namespace App\Services\Payments; use App\Models\PaymentGatewaySetting; use App\Models\User; +use App\Services\Events\SubscriptionService; use Illuminate\Support\Facades\Http; use RuntimeException; @@ -18,6 +19,10 @@ class MerchantGatewayService public function isConfigured(User|string $owner): bool { + if (! $this->ownerMayUseGateway($owner)) { + return false; + } + return (bool) $this->settingFor($owner)?->isConfigured(); } @@ -62,6 +67,10 @@ class MerchantGatewayService protected function requireConfigured(User|string $owner): PaymentGatewaySetting { + if (! $this->ownerMayUseGateway($owner)) { + throw new RuntimeException('Connecting your own payment gateway requires a paid plan. Upgrade to Pro or Business.'); + } + $setting = $this->settingFor($owner); if (! $setting?->isConfigured()) { throw new RuntimeException('Connect Paystack, Flutterwave, or Hubtel in Settings before accepting online payments.'); @@ -70,6 +79,19 @@ class MerchantGatewayService return $setting; } + protected function ownerMayUseGateway(User|string $owner): bool + { + $user = $owner instanceof User + ? $owner + : User::query()->where('public_id', (string) $owner)->first(); + + if (! $user) { + return false; + } + + return app(SubscriptionService::class)->canUsePaymentGateway($user); + } + /** * @param array $metadata * @return array{checkout_url: string, reference: string, provider: string} diff --git a/resources/views/qr/account/settings.blade.php b/resources/views/qr/account/settings.blade.php index 574f152..5c1c016 100644 --- a/resources/views/qr/account/settings.blade.php +++ b/resources/views/qr/account/settings.blade.php @@ -272,40 +272,48 @@

Payment gateway

-

Connect Paystack, Flutterwave, or Hubtel. Ticket and contribution payments go 100% to you — 0% Ladill platform fee.

+

Connect Paystack, Flutterwave, or Hubtel. Ticket and contribution payments go 100% to you — 0% Ladill platform fee. Pro & Business only.

-
- - -
-
+ @if ($canUsePaymentGateway ?? false)
- - + + +
+
+
+ + +
+
+ + +
- - + +
-
-
- - -
- - @if ($gateway?->isConfigured()) -

Gateway connected ({{ ucfirst($gateway->provider) }}).

+ + @if ($gateway?->isConfigured()) +

Gateway connected ({{ ucfirst($gateway->provider) }}).

+ @else +

Paid checkouts stay disabled until a gateway is connected.

+ @endif @else -

Paid checkouts stay disabled until a gateway is connected.

+
+

Your own payment gateway is a Pro feature

+

Upgrade to Pro or Business to connect Paystack, Flutterwave, or Hubtel for paid tickets and contributions with 0% Ladill fee.

+ View plans → +
@endif
diff --git a/tests/Feature/EventsProTest.php b/tests/Feature/EventsProTest.php index ce997a3..a81602e 100644 --- a/tests/Feature/EventsProTest.php +++ b/tests/Feature/EventsProTest.php @@ -75,4 +75,32 @@ class EventsProTest extends TestCase $this->assertTrue($svc->canCreateEvent($user)); $this->assertSame(0, $svc->liveEventCount($user)); } + + public function test_free_user_cannot_use_payment_gateway(): void + { + $user = $this->user(); + $svc = app(SubscriptionService::class); + + $this->assertFalse($svc->canUsePaymentGateway($user)); + $this->assertFalse(app(\App\Services\Payments\MerchantGatewayService::class)->isConfigured($user)); + } + + public function test_pro_user_can_use_payment_gateway_when_configured(): void + { + Http::fake(['*/debit' => Http::response(['id' => 1], 201)]); + $user = $this->user(); + $svc = app(SubscriptionService::class); + $svc->subscribe($user); + + \App\Models\PaymentGatewaySetting::create([ + 'owner_ref' => $user->public_id, + 'provider' => \App\Models\PaymentGatewaySetting::PROVIDER_PAYSTACK, + 'public_key' => 'pk_test', + 'secret_key' => 'sk_test', + 'is_active' => true, + ]); + + $this->assertTrue($svc->canUsePaymentGateway($user)); + $this->assertTrue(app(\App\Services\Payments\MerchantGatewayService::class)->isConfigured($user)); + } }