Make Events payment routing plan-aware.
Deploy Ladill Events / deploy (push) Successful in 51s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-21 19:47:10 +00:00
co-authored by Cursor
parent 837c249634
commit 1bcbdbfdb1
6 changed files with 119 additions and 37 deletions
@@ -174,12 +174,17 @@ class AccountController extends Controller
);
$provider = (string) ($data['gateway_provider'] ?? '');
if ($provider !== '' && $this->subscriptions->canUsePaymentGateway($account)) {
if ($this->subscriptions->canUsePaymentGateway($account)) {
$existing = PaymentGatewaySetting::query()->firstOrNew([
'owner_ref' => $account->public_id,
]);
$existing->provider = $provider;
$existing->is_active = $request->boolean('gateway_is_active', true);
if ($provider === '' && ! $existing->exists) {
return redirect()->route('account.settings')->with('success', 'Settings saved.');
}
if ($provider !== '') {
$existing->provider = $provider;
}
$existing->is_active = $provider !== '' && $request->boolean('gateway_is_active');
if (filled($data['gateway_public_key'] ?? null)) {
$existing->public_key = $data['gateway_public_key'];
}
+6 -5
View File
@@ -39,12 +39,13 @@ class PaymentGatewaySetting extends Model
return false;
}
$public = trim((string) $this->public_key);
$secret = trim((string) $this->secret_key);
return $secret !== '' && in_array($this->provider, [
self::PROVIDER_PAYSTACK,
self::PROVIDER_FLUTTERWAVE,
self::PROVIDER_HUBTEL,
], true);
return match ($this->provider) {
self::PROVIDER_PAYSTACK => str_starts_with($public, 'pk_') && str_starts_with($secret, 'sk_'),
self::PROVIDER_FLUTTERWAVE, self::PROVIDER_HUBTEL => $public !== '' && $secret !== '',
default => false,
};
}
}
@@ -133,30 +133,54 @@ class EventRegistrationService
$feeTier = $mode === 'contributions' ? 'donations' : 'sales';
$callbackUrl = LadillLink::path($qrCode->short_code, 'register/callback');
$payOrder = $this->pay->createCheckout([
'merchant' => $qrCode->user->public_id,
'fee_tier' => $feeTier,
'source_service' => 'events',
'source_ref' => (string) $qrCode->id,
'callback_url' => $callbackUrl,
'customer_name' => $name,
'customer_email' => $email,
'customer_phone' => $registration->attendee_phone,
'line_items' => [
[
$usesOwnerGateway = $this->gateway->shouldUseOwnerGateway($qrCode->user);
$payOrder = null;
if ($usesOwnerGateway) {
try {
$payOrder = $this->gateway->initializeCheckout(
$qrCode->user,
$amountMinor,
(string) ($content['currency'] ?? 'GHS'),
(string) config('pay.mini_checkout_email', 'pay@ladill.com'),
$callbackUrl,
'EVTP-'.strtoupper(Str::random(16)),
[
'title' => $lineName,
'registration_id' => $registration->id,
'registration_reference' => $registration->reference,
'qr_code_id' => $qrCode->id,
'mode' => $mode,
'attendee_email' => $email,
],
);
} catch (\Throwable) {
$usesOwnerGateway = false;
}
}
if (! $usesOwnerGateway) {
$payOrder = $this->pay->createCheckout([
'merchant' => $qrCode->user->public_id,
'fee_tier' => $feeTier,
'source_service' => 'events',
'source_ref' => (string) $qrCode->id,
'callback_url' => $callbackUrl,
'customer_name' => $name,
'customer_email' => $email,
'customer_phone' => $registration->attendee_phone,
'line_items' => [[
'name' => $lineName,
'unit_price_minor' => $amountMinor,
'quantity' => 1,
]],
'metadata' => [
'registration_id' => $registration->id,
'registration_reference' => $registration->reference,
'qr_code_id' => $qrCode->id,
'mode' => $mode,
'attendee_email' => $email,
],
],
'metadata' => [
'registration_id' => $registration->id,
'registration_reference' => $registration->reference,
'qr_code_id' => $qrCode->id,
'mode' => $mode,
'attendee_email' => $email,
],
]);
]);
}
$checkoutUrl = (string) ($payOrder['checkout_url'] ?? '');
if ($checkoutUrl === '') {
@@ -164,10 +188,11 @@ class EventRegistrationService
}
$registration->update([
'pay_order_id' => $payOrder['id'] ?? null,
'pay_order_id' => $usesOwnerGateway ? null : ($payOrder['id'] ?? null),
'payment_reference' => $payOrder['reference'],
'metadata' => array_merge((array) $registration->metadata, [
'ladill_pay_init' => [
($usesOwnerGateway ? 'merchant_gateway_init' : 'ladill_pay_init') => [
'provider' => $payOrder['provider'] ?? 'ladill_pay',
'platform_fee_minor' => $payOrder['platform_fee_minor'] ?? null,
'merchant_amount_minor' => $payOrder['merchant_amount_minor'] ?? null,
],
@@ -19,11 +19,13 @@ class MerchantGatewayService
public function isConfigured(User|string $owner): bool
{
if (! $this->ownerMayUseGateway($owner)) {
return false;
}
return $this->shouldUseOwnerGateway($owner);
}
return (bool) $this->settingFor($owner)?->isConfigured();
public function shouldUseOwnerGateway(User|string $owner): bool
{
return $this->ownerMayUseGateway($owner)
&& (bool) $this->settingFor($owner)?->isConfigured();
}
/**
@@ -55,7 +57,12 @@ class MerchantGatewayService
*/
public function verify(User|string $owner, string $reference): array
{
$setting = $this->requireConfigured($owner);
// Do not re-check the current plan here: an owner-gateway payment
// initiated before a downgrade must remain verifiable.
$setting = $this->settingFor($owner);
if (! $setting?->isConfigured()) {
throw new RuntimeException('The payment gateway used for this transaction is no longer configured.');
}
return match ($setting->provider) {
PaymentGatewaySetting::PROVIDER_PAYSTACK => $this->paystackVerify($setting, $reference),