Files
Xboard/app/Services/PaymentService.php
T
yinjianm 421844895e fix(payment): validate and filter unavailable methods
Filter user-visible payment methods to only include supported
providers and fail fast when a payment record or plugin cannot be
resolved.

This prevents invalid payment options from being returned by the
API and avoids constructing an undefined fallback payment class.
2026-03-19 20:29:26 +08:00

141 lines
4.2 KiB
PHP

<?php
namespace App\Services;
use App\Exceptions\ApiException;
use App\Models\Payment;
use App\Services\Plugin\PluginManager;
use App\Services\Plugin\HookManager;
class PaymentService
{
public $method;
protected $config;
protected $payment;
protected $pluginManager;
public function __construct($method, $id = NULL, $uuid = NULL)
{
$this->method = $method;
$this->pluginManager = app(PluginManager::class);
if ($method === 'temp') {
return;
}
$payment = null;
if ($id) {
$payment = Payment::find($id);
}
if (!$payment && $uuid) {
$payment = Payment::where('uuid', $uuid)->first();
}
if (($id || $uuid) && !$payment) {
throw new ApiException(__('Payment method is not available'));
}
$this->config = [];
if ($payment) {
$config = $payment->config;
$this->config = is_string($config) ? json_decode($config, true) : ($config ?? []);
if (!is_array($this->config)) {
$this->config = [];
}
$this->config['enable'] = $payment->enable;
$this->config['id'] = $payment->id;
$this->config['uuid'] = $payment->uuid;
$this->config['notify_domain'] = $payment->notify_domain ?? '';
}
$paymentMethods = $this->getAvailablePaymentMethods();
if (!isset($paymentMethods[$this->method])) {
throw new ApiException(__('Payment method is not available'));
}
$pluginCode = $paymentMethods[$this->method]['plugin_code'] ?? null;
if (!$pluginCode) {
throw new ApiException(__('Payment method is not available'));
}
$paymentPlugins = $this->pluginManager->getEnabledPaymentPlugins();
foreach ($paymentPlugins as $plugin) {
if ($plugin->getPluginCode() === $pluginCode) {
$plugin->setConfig($this->config);
$this->payment = $plugin;
return;
}
}
throw new ApiException(__('Payment method is not available'));
}
public function notify($params)
{
if (!$this->config['enable'])
throw new ApiException('gate is not enable');
return $this->payment->notify($params);
}
public function pay($order)
{
// custom notify domain name
$notifyUrl = url("/api/v1/guest/payment/notify/{$this->method}/{$this->config['uuid']}");
if ($this->config['notify_domain']) {
$parseUrl = parse_url($notifyUrl);
$notifyUrl = $this->config['notify_domain'] . $parseUrl['path'];
}
return $this->payment->pay([
'notify_url' => $notifyUrl,
'return_url' => source_base_url('/#/order/' . $order['trade_no']),
'trade_no' => $order['trade_no'],
'total_amount' => $order['total_amount'],
'user_id' => $order['user_id'],
'stripe_token' => $order['stripe_token']
]);
}
public function form()
{
$form = $this->payment->form();
$result = [];
foreach ($form as $key => $field) {
$result[$key] = [
'type' => $field['type'],
'label' => $field['label'] ?? '',
'placeholder' => $field['placeholder'] ?? '',
'description' => $field['description'] ?? '',
'value' => $this->config[$key] ?? $field['default'] ?? '',
'options' => $field['select_options'] ?? $field['options'] ?? []
];
}
return $result;
}
/**
* 获取所有可用的支付方式
*/
public function getAvailablePaymentMethods(): array
{
$methods = [];
$methods = HookManager::filter('available_payment_methods', $methods);
return $methods;
}
/**
* 获取所有支付方式名称列表(用于管理后台)
*/
public static function getAllPaymentMethodNames(): array
{
$pluginManager = app(PluginManager::class);
$pluginManager->initializeEnabledPlugins();
$instance = new self('temp');
$methods = $instance->getAvailablePaymentMethods();
return array_keys($methods);
}
}