Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -39,12 +39,14 @@ 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 => $public !== '' && $secret !== '',
|
||||
self::PROVIDER_HUBTEL => $public !== '' && $secret !== '',
|
||||
default => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ namespace App\Services\Payments;
|
||||
|
||||
use App\Models\PaymentGatewaySetting;
|
||||
use App\Models\User;
|
||||
use App\Services\Pay\PayClient;
|
||||
use App\Services\Pos\SubscriptionService;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use RuntimeException;
|
||||
|
||||
class MerchantGatewayService
|
||||
{
|
||||
public function __construct(private readonly PayClient $pay) {}
|
||||
|
||||
public function settingFor(User|string $owner): ?PaymentGatewaySetting
|
||||
{
|
||||
$ownerRef = $owner instanceof User ? (string) $owner->public_id : $owner;
|
||||
@@ -19,11 +22,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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,15 +44,25 @@ class MerchantGatewayService
|
||||
string $reference,
|
||||
array $metadata = [],
|
||||
): array {
|
||||
$setting = $this->requireConfigured($owner);
|
||||
$currency = strtoupper($currency ?: 'GHS');
|
||||
$email = (string) config('pay.mini_checkout_email', 'pay@ladill.com');
|
||||
|
||||
return match ($setting->provider) {
|
||||
PaymentGatewaySetting::PROVIDER_PAYSTACK => $this->paystackInitialize($setting, $amountMinor, $currency, $email, $callbackUrl, $reference, $metadata),
|
||||
PaymentGatewaySetting::PROVIDER_FLUTTERWAVE => $this->flutterwaveInitialize($setting, $amountMinor, $currency, $email, $callbackUrl, $reference, $metadata),
|
||||
PaymentGatewaySetting::PROVIDER_HUBTEL => $this->hubtelInitialize($setting, $amountMinor, $currency, $email, $callbackUrl, $reference, $metadata),
|
||||
default => throw new RuntimeException('Unsupported payment provider.'),
|
||||
};
|
||||
if (! $this->shouldUseOwnerGateway($owner)) {
|
||||
return $this->ladillPayInitialize($owner, $amountMinor, $email, $callbackUrl, $reference, $metadata);
|
||||
}
|
||||
|
||||
$setting = $this->requireConfigured($owner);
|
||||
|
||||
try {
|
||||
return match ($setting->provider) {
|
||||
PaymentGatewaySetting::PROVIDER_PAYSTACK => $this->paystackInitialize($setting, $amountMinor, $currency, $email, $callbackUrl, $reference, $metadata),
|
||||
PaymentGatewaySetting::PROVIDER_FLUTTERWAVE => $this->flutterwaveInitialize($setting, $amountMinor, $currency, $email, $callbackUrl, $reference, $metadata),
|
||||
PaymentGatewaySetting::PROVIDER_HUBTEL => $this->hubtelInitialize($setting, $amountMinor, $currency, $email, $callbackUrl, $reference, $metadata),
|
||||
default => throw new RuntimeException('Unsupported payment provider.'),
|
||||
};
|
||||
} catch (\Throwable) {
|
||||
return $this->ladillPayInitialize($owner, $amountMinor, $email, $callbackUrl, $reference, $metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +70,24 @@ class MerchantGatewayService
|
||||
*/
|
||||
public function verify(User|string $owner, string $reference): array
|
||||
{
|
||||
$setting = $this->requireConfigured($owner);
|
||||
if (str_starts_with($reference, 'LP-')) {
|
||||
$result = $this->pay->verify($reference);
|
||||
|
||||
return [
|
||||
'paid' => in_array(strtolower((string) ($result['status'] ?? '')), ['paid', 'success'], true),
|
||||
'amount_minor' => (int) ($result['amount_minor'] ?? 0),
|
||||
'reference' => (string) ($result['reference'] ?? $reference),
|
||||
'provider' => 'ladill_pay',
|
||||
'raw' => $result,
|
||||
];
|
||||
}
|
||||
|
||||
// Verification intentionally ignores current plan state so payments
|
||||
// initiated before a downgrade can still complete safely.
|
||||
$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),
|
||||
@@ -79,6 +111,32 @@ class MerchantGatewayService
|
||||
return $setting;
|
||||
}
|
||||
|
||||
/** @return array{checkout_url:string,reference:string,provider:string} */
|
||||
private function ladillPayInitialize(User|string $owner, int $amountMinor, string $email, string $callbackUrl, string $reference, array $metadata): array
|
||||
{
|
||||
$ownerRef = $owner instanceof User ? (string) $owner->public_id : (string) $owner;
|
||||
$checkout = $this->pay->createCheckout([
|
||||
'merchant' => $ownerRef,
|
||||
'fee_tier' => 'sales',
|
||||
'source_service' => 'pos',
|
||||
'source_ref' => (string) ($metadata['pos_sale_id'] ?? $metadata['pos_payment_id'] ?? $reference),
|
||||
'callback_url' => $callbackUrl,
|
||||
'customer_email' => $email,
|
||||
'line_items' => [[
|
||||
'name' => (string) ($metadata['title'] ?? 'POS payment'),
|
||||
'unit_price_minor' => $amountMinor,
|
||||
'quantity' => 1,
|
||||
]],
|
||||
'metadata' => $metadata,
|
||||
]);
|
||||
|
||||
return [
|
||||
'checkout_url' => (string) $checkout['checkout_url'],
|
||||
'reference' => (string) $checkout['reference'],
|
||||
'provider' => 'ladill_pay',
|
||||
];
|
||||
}
|
||||
|
||||
protected function ownerMayUseGateway(User|string $owner): bool
|
||||
{
|
||||
$user = $owner instanceof User
|
||||
|
||||
Reference in New Issue
Block a user