소스 검색

Add Payment Method, Cryptomus

Bug Fixed
BrettonYe 4 달 전
부모
커밋
fe59d9c98f

+ 2 - 2
app/Http/Controllers/Admin/NodeController.php

@@ -263,10 +263,10 @@ class NodeController extends Controller
         $ret = false;
         if ($id) {
             $node = Node::findOrFail($id);
-            $ret = reloadNode::dispatchSync($node);
+            $ret = (new reloadNode($node))->handle();
         } else {
             foreach (Node::whereStatus(1)->whereType(4)->get() as $node) {
-                $result = reloadNode::dispatchSync($node);
+                $result = (new reloadNode($node))->handle();
                 if ($result && ! $ret) {
                     $ret = true;
                 }

+ 2 - 0
app/Services/ProxyService.php

@@ -100,6 +100,8 @@ class ProxyService
         $config = [
             'id' => $node->id,
             'name' => $node->name,
+            'country' => $node->country_code,
+            'labels' => $node->labels->pluck('name')->toArray(),
             'area' => $node->country->name,
             'host' => $node->host,
             'group' => sysConfig('website_name'),

+ 1 - 0
app/Utils/Clients/Clash.php

@@ -1,4 +1,5 @@
 <?php
+
 /*
  * Developed based on
  * https://clash.wiki/configuration/configuration-reference.html

+ 1 - 0
app/Utils/Clients/Quantumult.php

@@ -1,4 +1,5 @@
 <?php
+
 /*
  * Developed based on
  * https://github.com/crossutility/Quantumult/blob/master/quantumult-uri-scheme.md

+ 1 - 0
app/Utils/Clients/Surge.php

@@ -1,4 +1,5 @@
 <?php
+
 /*
  * Developed based on
  * https://wiki.surge.community/modules

+ 1 - 0
app/Utils/Library/AlipayF2F.php

@@ -1,4 +1,5 @@
 <?php
+
 /*
  * 作者:BrettonYe
  * 功能:ProxyPanel 支付宝面对面【收单线下交易预创建】【收单交易查询】接口实现库

+ 1 - 1
app/Utils/NetworkDetection.php

@@ -40,7 +40,7 @@ class NetworkDetection
 
     private function networkCheck(string $ip, int $port): ?array
     { // 通过众多API进行节点阻断检测.
-        $checkers = ['toolsdaquan', 'vps234', 'flyzy2005', 'idcoffer', 'ip112', 'upx8', 'rss', 'gd', 'vps1352', 'akile'];
+        $checkers = ['flyzy2005', 'toolsdaquan', 'vps234', 'idcoffer', 'ip112', 'upx8', 'rss', 'gd', 'vps1352', 'akile'];
         self::$basicRequest = Http::timeout(15)->retry(2)->withOptions(['http_errors' => false])->withoutVerifying()->withUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36');
 
         foreach ($checkers as $checker) {

+ 109 - 0
app/Utils/Payments/Cryptomus.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace App\Utils\Payments;
+
+use App\Utils\Library\PaymentHelper;
+use App\Utils\Library\Templates\Gateway;
+use Http;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Log;
+use Response;
+
+class Cryptomus implements Gateway
+{
+    private const API_URL = 'https://api.cryptomus.com/';
+
+    public static array $methodDetails = [
+        'key' => 'cryptomus',
+        'settings' => ['cryptomus_merchant_uuid', 'cryptomus_key'],
+    ];
+
+    private string $apiKey;
+
+    private string $mid;
+
+    public function __construct()
+    {
+        $this->mid = sysConfig('cryptomus_merchant_uuid');
+        $this->apiKey = sysConfig('cryptomus_api_key');
+    }
+
+    public function purchase(Request $request): JsonResponse
+    {
+        $payment = PaymentHelper::createPayment(auth()->id(), $request->input('id'), $request->input('amount'));
+
+        $result = $this->createOrder([
+            'amount' => $payment->amount,
+            'currency' => sysConfig('standard_currency'),
+            'order_id' => $payment->trade_no,
+            'lifetime' => 900,
+            // 'network' => '',
+            'is_payment_multiple' => false,
+            'url_return' => route('shop.index'),
+            'url_success' => route('invoice.index'),
+            'url_callback' => route('payment.notify', ['method' => 'cryptomus']),
+        ]);
+
+        if (isset($result['state'], $result['result']['url']) && $result['state'] === 0) {
+            $payment->update(['url' => $result['result']['url']]);
+
+            return Response::json(['status' => 'success', 'url' => $result['result']['url'], 'message' => trans('user.payment.order_creation.success')]);
+        }
+
+        $payment->failed();
+        if (isset($result['message'])) {
+            Log::alert('【Cryptomus】创建订单错误:'.$result['message']);
+
+            return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
+        }
+
+        if (! isset($result['result']['url'])) {
+            Log::alert('【Cryptomus】创建订单错误:未获取到支付链接'.var_export($result, true));
+        }
+
+        return Response::json(['status' => 'fail', 'message' => trans('user.payment.order_creation.failed')]);
+    }
+
+    private function createOrder(array $params): array
+    {
+        $response = Http::withHeaders(['merchant' => $this->mid, 'sign' => $this->sign($params)])->asJson()->post(self::API_URL.'v1/payment', $params);
+
+        if ($response->ok()) {
+            return $response->json();
+        }
+
+        Log::alert('【Cryptomus】创建订单失败:'.var_export($response->json(), true));
+
+        return ['status' => 'fail', 'message' => '获取失败!请检查配置信息'];
+    }
+
+    private function sign(array|string $data): string
+    {
+        if (isset($params['sign'])) {
+            unset($params['sign']);
+        }
+
+        return md5(base64_encode(json_encode($data, JSON_UNESCAPED_UNICODE)).$this->apiKey);
+    }
+
+    public function notify(Request $request): void
+    {
+        if (! $this->verify($request->post())) {
+            exit(400);
+        }
+
+        if ($request->has(['is_final', 'status', 'order_id']) && in_array($request->input('status'), ['paid', 'paid_over'], true) && PaymentHelper::paymentReceived($request->input(['order_id']))) {
+            exit(200);
+        }
+
+        Log::error('【Cryptomus】交易失败:'.var_export($request->all(), true));
+
+        exit(500);
+    }
+
+    private function verify(array $params): bool
+    {
+        return hash_equals($params['sign'], $this->sign($params));
+    }
+}

+ 1 - 15
app/Utils/Payments/PayPal.php

@@ -47,21 +47,7 @@ class PayPal implements Gateway
 
         $data = $this->getCheckoutData($payment->trade_no, $payment->amount);
 
-        $response = self::$provider->createOrder([
-            'intent' => 'CAPTURE',
-            'application_context' => [
-                'return_url' => route('payment.notify', ['method' => 'paypal']),
-                'cancel_url' => route('invoice.index'),
-            ],
-            'purchase_units' => [
-                0 => [
-                    'amount' => [
-                        'currency_code' => 'USD',
-                        'value' => '100.00',
-                    ],
-                ],
-            ],
-        ]);
+        $response = self::$provider->createOrder($data);
         if (isset($response['id']) && $response['id'] != null) {
             Log::error('【Paypal】处理错误:'.var_export($response, true));
 

+ 1 - 0
config/common.php

@@ -13,6 +13,7 @@ return [
             'payjs' => 'PayJs',
             'paypal' => 'PayPal',
             'stripe' => 'Stripe',
+            'cryptomus' => 'Cryptomus',
             'theadpay' => '平头哥支付',
             'youzan' => '有赞云',
         ],

+ 25 - 0
database/migrations/2025_04_21_215352_add_cryptomus.php

@@ -0,0 +1,25 @@
+<?php
+
+use App\Models\Config;
+use Illuminate\Database\Migrations\Migration;
+
+return new class extends Migration
+{
+    private static array $configs = ['cryptomus_merchant_uuid', 'cryptomus_api_key'];
+
+    public function up(): void
+    {
+        if (Config::exists()) {
+            foreach (self::$configs as $config) {
+                Config::insert(['name' => $config]);
+            }
+        }
+    }
+
+    public function down(): void
+    {
+        foreach (self::$configs as $config) {
+            Config::destroy(['name' => $config]);
+        }
+    }
+};

+ 2 - 0
database/seeders/ConfigSeeder.php

@@ -23,6 +23,8 @@ class ConfigSeeder extends Seeder
         'codepay_id',
         'codepay_key',
         'codepay_url',
+        'cryptomus_api_key',
+        'cryptomus_merchant_uuid',
         'data_anomaly_notification',
         'data_exhaust_notification',
         'ddns_key',

+ 1 - 1
install.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 # 设置工作目录为脚本所在的目录
-cd "$(dirname "$0")" || exit
+cd "$(dirname "$0")" || exit 1
 
 # 引入依赖脚本
 source scripts/lib.sh

+ 1 - 1
package.json

@@ -9,7 +9,7 @@
         "@shufo/prettier-plugin-blade": "^1.14.1",
         "axios": "^1.1.2",
         "laravel-vite-plugin": "^0.7.5",
-        "prettier": "^3.3.2",
+        "prettier": "^3.3.3",
         "vite": "^4.0.0"
     }
 }

+ 4 - 0
resources/lang/zh_CN/admin.php

@@ -664,6 +664,7 @@ return [
                 'paypal' => 'PayPal',
                 'stripe' => 'Stripe',
                 'theadpay' => '平头哥支付',
+                'cryptomus' => 'Cryptomus',
             ],
             'hint' => [
                 'alipay' => '本功能需要从<a href="https://open.alipay.com/platform/appManage.htm?#/create/" target="_blank">蚂蚁金服开放平台</a>申请权限及应用',
@@ -673,6 +674,7 @@ return [
                 'payjs' => '请到<a href="https://payjs.cn/ref/zgxjnb" target="_blank">PayJs</a> 申请账号',
                 'paypal' => '使用商家账号登录<a href="https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty" target="_blank">API凭证申请页</a>,同意并获取设置信息',
                 'theadpay' => '请到<a href="https://theadpay.com/" target="_blank">平头哥支付 THeadPay</a>申请账号',
+                'cryptomus' => '请到<a href="https://app.cryptomus.com/signup" target="_blank">Cryptomus</a>申请账号,并按照<a href="https://doc.cryptomus.com/business/general/getting-api-keys" target="_blank">教程</a>获取必要信息',
             ],
         ],
         'payment_confirm_notification' => '人工支付确认通知',
@@ -717,6 +719,8 @@ return [
         'stripe_public_key' => 'Public Key',
         'stripe_secret_key' => 'Secret Key',
         'stripe_signing_secret' => 'WebHook Signing secret',
+        'cryptomus_merchant_uuid' => 'Merchant ID',
+        'cryptomus_api_key' => 'API key',
         'subject_name' => '自定义商品名称',
         'subscribe_ban_times' => '订阅请求阈值',
         'subscribe_domain' => '节点订阅地址',

+ 17 - 0
resources/views/admin/config/system.blade.php

@@ -395,6 +395,7 @@
                                     <x-system.select code="is_otherPay" multiple="1" :list="[
                                         trans('admin.system.payment.channel.paypal') => 'paypal',
                                         trans('admin.system.payment.channel.stripe') => 'stripe',
+                                        trans('admin.system.payment.channel.cryptomus') => 'cryptomus',
                                     ]" />
                                     <x-system.input code="subject_name" :value="$subject_name" />
                                     <x-system.input type="url" code="website_callback_url" :value="$website_callback_url" :holder="trans('admin.system.placeholder.default_url', ['url' => $website_url])" />
@@ -484,6 +485,16 @@
                                     <x-system.input code="theadpay_mchid" :value="$theadpay_mchid" />
                                     <x-system.input code="theadpay_key" :value="$theadpay_key" />
                                 </x-system.tab-pane>
+                                <x-system.tab-pane id="Cryptomus">
+                                    <div class="form-group col-lg-6 d-flex">
+                                        <label class="col-md-3 col-form-label">{{ trans('admin.system.payment.channel.cryptomus') }}</label>
+                                        <div class="col-md-7">
+                                            {!! trans('admin.system.payment.hint.cryptomus') !!}
+                                        </div>
+                                    </div>
+                                    <x-system.input code="cryptomus_merchant_uuid" :value="$cryptomus_merchant_uuid" />
+                                    <x-system.input code="cryptomus_api_key" :value="$cryptomus_api_key" />
+                                </x-system.tab-pane>
                                 <x-system.tab-pane id="Manual">
                                     <div class="form-group col-lg-12 d-flex">
                                         <label class="col-md-3 col-form-label">{{ trans('admin.system.payment.channel.manual') }}</label>
@@ -537,6 +548,10 @@
                                     <a class="nav-link" data-toggle="tab" href="#Stripe" role="tab"
                                        aria-controls="Stripe">{{ trans('admin.system.payment.channel.stripe') }}</a>
                                 </li>
+                                <li class="nav-item">
+                                    <a class="nav-link" data-toggle="tab" href="#Cryptomus" role="tab"
+                                       aria-controls="Cryptomus">{{ trans('admin.system.payment.channel.cryptomus') }}</a>
+                                </li>
                                 <li class="nav-item">
                                     <a class="nav-link" data-toggle="tab" href="#PayBeaver" role="tab"
                                        aria-controls="PayBeaver">{{ trans('admin.system.payment.channel.paybeaver') }}</a>
@@ -567,6 +582,8 @@
                                            aria-controls="PayPal">{{ trans('admin.system.payment.channel.paypal') }}</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#Stripe" role="tab"
                                            aria-controls="Stripe">{{ trans('admin.system.payment.channel.stripe') }}</a>
+                                        <a class="dropdown-item" data-toggle="tab" href="#Cryptomus" role="tab"
+                                           aria-controls="Cryptomus">{{ trans('admin.system.payment.channel.cryptomus') }}</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#PayBeaver" role="tab"
                                            aria-controls="PayBeaver">{{ trans('admin.system.payment.channel.paybeaver') }}</a>
                                         <a class="dropdown-item" data-toggle="tab" href="#THeadPay" role="tab"

+ 5 - 0
resources/views/user/components/purchase.blade.php

@@ -19,6 +19,11 @@
             <img src="/assets/images/payment/btc.svg" alt="{{ trans('common.payment.crypto') }}" height="36px" />
             <span class="font-size-24 black"> {{ trans('common.payment.crypto') }} </span>
         </button>
+    @elseif(str_contains(sysConfig('is_otherPay'), 'cryptomus'))
+        <button class="btn btn-round btn-outline-default mt-2" onclick="pay('cryptomus','4')">
+            <img src="/assets/images/payment/btc.svg" alt="{{ trans('common.payment.crypto') }}" height="36px" />
+            <span class="font-size-24 black"> {{ trans('common.payment.crypto') }} </span>
+        </button>
     @endif
     @if (str_contains(sysConfig('is_otherPay'), 'paypal'))
         <button class="btn btn-round btn-outline-default mt-2" onclick="pay('paypal','5')">

+ 3 - 1
scripts/lib.sh

@@ -143,7 +143,9 @@ redirect_stderr=true
 stdout_logfile=$PWD/storage/logs/horizon.log
 stopwaitsecs=3600
 EOF
-    sudo supervisorctl restart horizon
+    sudo supervisorctl reread
+    sudo supervisorctl update
+    sudo supervisorctl start horizon
     echo -e "\e[32mHorizon configuration completed! | Horizon 配置完成!\e[0m"
   else
     echo -e "\e[36mHorizon already configured! | Horizon 已配置!\e[0m"

+ 1 - 1
update.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 # 设置工作目录为脚本所在的目录
-cd "$(dirname "$0")" || exit
+cd "$(dirname "$0")" || exit 1
 
 # 引入依赖脚本
 source scripts/lib.sh