Require Ladill Pay only for Merchant checkouts.
Deploy Ladill Merchant / deploy (push) Successful in 51s

Remove custom/owner payment gateway option and always route customer payments through Ladill Pay with platform fees.
This commit is contained in:
isaacclad
2026-07-24 14:15:39 +00:00
parent ce41c1ece7
commit 0a3e142f47
3 changed files with 10 additions and 44 deletions
@@ -22,6 +22,8 @@ class PlanEntitlementService
public function canUseCustomPaymentGateway(User $owner): bool public function canUseCustomPaymentGateway(User $owner): bool
{ {
return $this->has($owner, self::CUSTOM_PAYMENT_GATEWAY); // Custom / owner payment gateways are retired. All checkouts use Ladill Pay
// with platform fees (see config/pay.php fee_tiers on the platform).
return false;
} }
} }
+2 -20
View File
@@ -59,27 +59,9 @@
<div class="rounded-2xl border border-slate-200 bg-white p-5 space-y-4"> <div class="rounded-2xl border border-slate-200 bg-white p-5 space-y-4">
<div> <div>
<h2 class="text-sm font-semibold text-slate-900">Customer payment engine</h2> <h2 class="text-sm font-semibold text-slate-900">Customer payment engine</h2>
<p class="mt-1 text-xs text-slate-500">Ladill Pay is recommended, zero-config, and selected by default.</p> <p class="mt-1 text-xs text-slate-500">All customer checkouts use Ladill Pay zero-config, no owner API keys.</p>
</div> </div>
<p class="rounded-lg bg-emerald-50 px-3 py-2 text-sm text-emerald-800">Ladill Pay remains the safe fallback and requires no owner keys.</p> <p class="rounded-lg bg-emerald-50 px-3 py-2 text-sm text-emerald-800">Ladill Pay is the only payment option. Standard platform fees apply on paid orders and settle to your Ladill wallet.</p>
@if ($canUsePaymentGateway ?? false)
<select name="gateway_provider" class="w-full rounded-lg border-slate-200 text-sm">
<option value="">Ladill Pay (recommended)</option>
<option value="paystack" @selected(old('gateway_provider', $gateway?->is_active ? $gateway?->provider : '') === 'paystack')>My Paystack account</option>
</select>
<div class="grid gap-3 sm:grid-cols-2">
<input name="gateway_public_key" placeholder="{{ $gateway?->public_key ? 'Public key saved — leave blank to keep' : 'pk_live_…' }}" class="rounded-lg border-slate-200 text-sm">
<input type="password" name="gateway_secret_key" autocomplete="new-password" placeholder="{{ $gateway?->secret_key ? 'Secret saved — leave blank to keep' : 'sk_live_…' }}" class="rounded-lg border-slate-200 text-sm">
</div>
<label class="flex items-center gap-2 text-sm text-slate-700">
<input type="hidden" name="gateway_is_active" value="0">
<input type="checkbox" name="gateway_is_active" value="1" @checked(old('gateway_is_active', $gateway?->is_active ?? false)) class="rounded border-slate-300 text-indigo-600">
Use my Paystack account
</label>
<p class="text-xs text-slate-500">Optional. Invalid or incomplete keys automatically fall back to Ladill Pay.</p>
@else
<p class="rounded-lg bg-indigo-50 px-3 py-2 text-sm text-indigo-800">Free uses Ladill Pay only. Pro and higher plans may optionally connect owner Paystack.</p>
@endif
</div> </div>
<button type="submit" class="btn-primary"> <button type="submit" class="btn-primary">
+5 -23
View File
@@ -4,6 +4,7 @@ namespace Tests\Feature;
use App\Models\PaymentGatewaySetting; use App\Models\PaymentGatewaySetting;
use App\Models\User; use App\Models\User;
use App\Services\Billing\PlanEntitlementService;
use App\Services\Payments\MerchantGatewayService; use App\Services\Payments\MerchantGatewayService;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
@@ -13,39 +14,20 @@ class PaymentGatewayPolicyTest extends TestCase
{ {
use RefreshDatabase; use RefreshDatabase;
public function test_free_cannot_activate_saved_owner_gateway_but_pro_can(): void public function test_owner_gateway_is_never_used_even_with_saved_keys(): void
{ {
config(['billing.api_url' => 'https://ladill.com/api/billing', 'billing.api_key' => 'merchant-test']); config(['billing.api_url' => 'https://ladill.com/api/billing', 'billing.api_key' => 'merchant-test']);
$owner = User::factory()->create(['public_id' => 'usr_merchant_policy']); $owner = User::factory()->create(['public_id' => 'usr_merchant_policy']);
$setting = PaymentGatewaySetting::create([ PaymentGatewaySetting::create([
'owner_ref' => $owner->public_id, 'provider' => 'paystack', 'owner_ref' => $owner->public_id, 'provider' => 'paystack',
'public_key' => 'pk_test_saved', 'secret_key' => 'sk_test_saved', 'is_active' => true, 'public_key' => 'pk_test_saved', 'secret_key' => 'sk_test_saved', 'is_active' => true,
]); ]);
Http::fakeSequence()
->push(['data' => ['effective_plan' => 'free', 'features' => []]])
->push(['data' => ['effective_plan' => 'pro', 'features' => ['custom_payment_gateway']]])
->push(['data' => ['effective_plan' => 'pro', 'features' => ['custom_payment_gateway']]]);
$this->assertFalse(app(MerchantGatewayService::class)->shouldUseOwnerGateway($owner));
$setting->update(['is_active' => false]);
$this->assertFalse(app(MerchantGatewayService::class)->shouldUseOwnerGateway($owner));
$setting->update(['is_active' => true]);
$this->assertTrue(app(MerchantGatewayService::class)->shouldUseOwnerGateway($owner));
}
public function test_invalid_pro_credentials_fall_back_to_ladill_pay(): void
{
config(['billing.api_url' => 'https://ladill.com/api/billing', 'billing.api_key' => 'merchant-test']);
Http::fake(['*/suite-entitlements*' => Http::response(['data' => [ Http::fake(['*/suite-entitlements*' => Http::response(['data' => [
'effective_plan' => 'business', 'features' => ['custom_payment_gateway'], 'effective_plan' => 'enterprise', 'features' => ['custom_payment_gateway'],
]])]); ]])]);
$owner = User::factory()->create(['public_id' => 'usr_merchant_invalid']);
PaymentGatewaySetting::create([
'owner_ref' => $owner->public_id, 'provider' => 'paystack',
'public_key' => 'invalid', 'secret_key' => 'invalid', 'is_active' => true,
]);
$this->assertFalse(app(PlanEntitlementService::class)->canUseCustomPaymentGateway($owner));
$this->assertFalse(app(MerchantGatewayService::class)->shouldUseOwnerGateway($owner)); $this->assertFalse(app(MerchantGatewayService::class)->shouldUseOwnerGateway($owner));
} }
} }