浏览代码

优化/重构 支付相关代码

1. 优化支付文件框架为后续大改做准备;
2. 重构了支付宝面对面支付;
   - 本次重构解决了PHP版本>7.3 导致该支付无法使用的问题;
   - 自行开发的接入方式,简化&快捷化了代码;
3. 修正 Stripe 汇率API 查询的代码 & 部分报错代码;

TODO:
1. 汇率查询API 应该集中统一化(Paypal & Stripe 都需要汇率转换);
2. 简化支付对接成本(单文件自动对接);
BrettonYe 2 年之前
父节点
当前提交
1b004e1c57

+ 1 - 1
app/Channels/Components/WeChat.php → app/Channels/Library/WeChat.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace App\Channels\Components;
+namespace App\Channels\Library;
 
 use DOMDocument;
 use Exception;

+ 1 - 1
app/Channels/WeChatChannel.php

@@ -2,7 +2,7 @@
 
 namespace App\Channels;
 
-use App\Channels\Components\WeChat;
+use App\Channels\Library\WeChat;
 use Cache;
 use Helpers;
 use Http;

+ 0 - 99
app/Http/Controllers/Gateway/F2Fpay.php

@@ -1,99 +0,0 @@
-<?php
-
-namespace App\Http\Controllers\Gateway;
-
-use Auth;
-use Exception;
-use Illuminate\Http\JsonResponse;
-use InvalidArgumentException;
-use Log;
-use Payment\Client;
-use Payment\Exceptions\ClassNotFoundException;
-use Response;
-
-class F2Fpay extends AbstractPayment
-{
-    private static $aliConfig;
-
-    public function __construct()
-    {
-        self::$aliConfig = [
-            'use_sandbox'     => false,
-            'app_id'          => sysConfig('f2fpay_app_id'),
-            'sign_type'       => 'RSA2',
-            'ali_public_key'  => sysConfig('f2fpay_public_key'),
-            'rsa_private_key' => sysConfig('f2fpay_private_key'),
-            'limit_pay'       => [],
-            'notify_url'      => route('payment.notify', ['method' => 'f2fpay']),
-            'return_url'      => route('invoice'),
-            'fee_type'        => 'CNY',
-        ];
-    }
-
-    public function purchase($request): JsonResponse
-    {
-        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
-
-        $data = [
-            'body'        => '',
-            'subject'     => sysConfig('subject_name') ?: sysConfig('website_name'),
-            'trade_no'    => $payment->trade_no,
-            'time_expire' => time() + 900, // 必须 15分钟 内付款
-            'amount'      => $payment->amount,
-        ];
-
-        try {
-            $result = (new Client(Client::ALIPAY, self::$aliConfig))->pay(Client::ALI_CHANNEL_QR, $data);
-        } catch (InvalidArgumentException $e) {
-            Log::alert('【支付宝当面付】输入信息错误:'.$e->getMessage());
-            exit;
-        } catch (ClassNotFoundException $e) {
-            Log::alert('【支付宝当面付】未知类型:'.$e->getMessage());
-            exit;
-        } catch (Exception $e) {
-            Log::alert('【支付宝当面付】错误:'.$e->getMessage());
-            exit;
-        }
-
-        $payment->update(['qr_code' => 1, 'url' => $result['qr_code']]);
-
-        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
-    }
-
-    public function notify($request): void
-    {
-        $data = [
-            'trade_no'       => $request->input('out_trade_no'),
-            'transaction_id' => $request->input('trade_no'),
-        ];
-
-        try {
-            $result = (new Client(Client::ALIPAY, self::$aliConfig))->tradeQuery($data);
-            Log::notice('【支付宝当面付】回调验证查询:'.var_export($result, true));
-        } catch (InvalidArgumentException $e) {
-            Log::alert('【支付宝当面付】回调信息错误: '.$e->getMessage());
-            exit;
-        } catch (ClassNotFoundException $e) {
-            Log::alert('【支付宝当面付】未知类型: '.$e->getMessage());
-            exit;
-        } catch (Exception $e) {
-            Log::alert('【支付宝当面付】错误: '.$e->getMessage());
-            exit;
-        }
-
-        if ($result['code'] == 10000 && $result['msg'] === 'Success') {
-            if ($request->has('out_trade_no') && in_array($request->input('trade_status'), ['TRADE_FINISHED', 'TRADE_SUCCESS'])) {
-                if ($this->paymentReceived($request->input('out_trade_no'))) {
-                    exit('success');
-                }
-            } else {
-                Log::error('【支付宝当面付】交易失败:'.var_export($request->all(), true));
-            }
-        } else {
-            Log::error('【支付宝当面付】验证失败:'.var_export($result, true));
-        }
-
-        // 返回验证结果
-        exit('fail');
-    }
-}

+ 10 - 13
app/Http/Controllers/PaymentController.php

@@ -3,21 +3,20 @@
 namespace App\Http\Controllers;
 
 use App\Components\Helpers;
-use App\Http\Controllers\Gateway\BitpayX;
-use App\Http\Controllers\Gateway\CodePay;
-use App\Http\Controllers\Gateway\EPay;
-use App\Http\Controllers\Gateway\F2Fpay;
-use App\Http\Controllers\Gateway\Local;
-use App\Http\Controllers\Gateway\Manual;
-use App\Http\Controllers\Gateway\PayBeaver;
-use App\Http\Controllers\Gateway\PayJs;
-use App\Http\Controllers\Gateway\PayPal;
-use App\Http\Controllers\Gateway\Stripe;
-use App\Http\Controllers\Gateway\THeadPay;
 use App\Models\Coupon;
 use App\Models\Goods;
 use App\Models\Order;
 use App\Models\Payment;
+use App\Payments\CodePay;
+use App\Payments\EPay;
+use App\Payments\F2Fpay;
+use App\Payments\Local;
+use App\Payments\Manual;
+use App\Payments\PayBeaver;
+use App\Payments\PayJs;
+use App\Payments\PayPal;
+use App\Payments\Stripe;
+use App\Payments\THeadPay;
 use App\Services\CouponService;
 use Auth;
 use Exception;
@@ -50,8 +49,6 @@ class PaymentController extends Controller
                 return new Codepay();
             case 'payjs':
                 return new PayJs();
-            case 'bitpayx':
-                return new BitpayX();
             case 'paypal':
                 return new PayPal();
             case 'epay':

+ 3 - 2
app/Http/Controllers/Gateway/CodePay.php → app/Payments/CodePay.php

@@ -1,13 +1,14 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
+use App\Payments\Library\Gateway;
 use Auth;
 use Illuminate\Http\JsonResponse;
 use Log;
 use Response;
 
-class CodePay extends AbstractPayment
+class CodePay extends Gateway
 {
     public function purchase($request): JsonResponse
     {

+ 3 - 2
app/Http/Controllers/Gateway/EPay.php → app/Payments/EPay.php

@@ -1,7 +1,8 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
+use App\Payments\Library\Gateway;
 use Auth;
 use Http;
 use Illuminate\Http\JsonResponse;
@@ -9,7 +10,7 @@ use Illuminate\Http\Request;
 use Log;
 use Response;
 
-class EPay extends AbstractPayment
+class EPay extends Gateway
 {
     public function purchase(Request $request): JsonResponse
     {

+ 75 - 0
app/Payments/F2Fpay.php

@@ -0,0 +1,75 @@
+<?php
+
+namespace App\Payments;
+
+use App\Payments\Library\AlipayF2F;
+use App\Payments\Library\Gateway;
+use Auth;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Log;
+use Response;
+
+class F2Fpay extends Gateway
+{
+    private static $aliConfig;
+
+    public function __construct()
+    {
+        self::$aliConfig = [
+            'app_id'          => sysConfig('f2fpay_app_id'),
+            'ali_public_key'  => sysConfig('f2fpay_public_key'),
+            'rsa_private_key' => sysConfig('f2fpay_private_key'),
+            'notify_url'      => route('payment.notify', ['method' => 'f2fpay']),
+        ];
+    }
+
+    public function purchase($request): JsonResponse
+    {
+        $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
+
+        $data = [
+            'subject'      => sysConfig('subject_name') ?: sysConfig('website_name'),
+            'out_trade_no' => $payment->trade_no,
+            'total_amount' => $payment->amount,
+        ];
+
+        try {
+            $gateWay = new AlipayF2F(self::$aliConfig);
+            $result = $gateWay->qrCharge($data);
+            $payment->update(['qr_code' => 1, 'url' => $result['qr_code']]);
+        } catch (Exception $e) {
+            $payment->delete();
+            Log::alert('【支付宝当面付】支付错误: '.$e->getMessage());
+            exit;
+        }
+
+        return Response::json(['status' => 'success', 'data' => $payment->trade_no, 'message' => '创建订单成功!']);
+    }
+
+    public function notify($request): void
+    {
+        try {
+            $result = (new AlipayF2F(self::$aliConfig))->tradeQuery($request->only('out_trade_no', 'trade_no'));
+            Log::notice('【支付宝当面付】回调验证查询:'.var_export($result, true));
+        } catch (Exception $e) {
+            Log::alert('【支付宝当面付】回调信息错误: '.$e->getMessage());
+            exit;
+        }
+
+        if ($result['code'] === 10000 && $result['msg'] === 'Success') {
+            if ($request->has('out_trade_no') && in_array($request->input('trade_status'), ['TRADE_FINISHED', 'TRADE_SUCCESS'])) {
+                if ($this->paymentReceived($request->input('out_trade_no'))) {
+                    exit('success');
+                }
+            } else {
+                Log::error('【支付宝当面付】交易失败:'.var_export($request->all(), true));
+            }
+        } else {
+            Log::error('【支付宝当面付】验证失败:'.var_export($result, true));
+        }
+
+        // 返回验证结果
+        exit('fail');
+    }
+}

+ 193 - 0
app/Payments/Library/AlipayF2F.php

@@ -0,0 +1,193 @@
+<?php
+/*
+ * 作者:BrettonYe
+ * 功能:ProxyPanel 支付宝面对面 【收单线下交易预创建】 【收单交易查询】 接口实现库
+ * 时间:2022/12/28
+ * 参考资料:https://opendocs.alipay.com/open/02ekfg?scene=19 riverslei/payment
+ */
+
+namespace App\Payments\Library;
+
+use Illuminate\Support\Facades\Http;
+use RuntimeException;
+
+class AlipayF2F
+{
+    private static $gatewayUrl = 'https://openapi.alipay.com/gateway.do';
+    private $config;
+
+    public function __construct(array $rawConfig = [])
+    {
+        $config = [
+            'app_id'      => $rawConfig['app_id'],
+            'public_key'  => '',
+            'private_key' => '',
+            'notify_url'  => $rawConfig['notify_url'],
+        ];
+
+        if ($rawConfig['ali_public_key']) {
+            $config['public_key'] = self::getRsaKeyValue($rawConfig['ali_public_key'], false);
+        }
+        if (empty($config['public_key'])) {
+            throw new RuntimeException('please set ali public key');
+        }
+
+        // 初始 RSA私钥文件 需要检查该文件是否存在
+        if ($rawConfig['rsa_private_key']) {
+            $config['private_key'] = self::getRsaKeyValue($rawConfig['rsa_private_key']);
+        }
+        if (empty($config['private_key'])) {
+            throw new RuntimeException('please set ali private key');
+        }
+
+        $this->config = $config;
+    }
+
+    /**
+     * 获取rsa密钥内容.
+     *
+     * @param  string  $key  传入的密钥信息, 可能是文件或者字符串
+     * @param  bool  $is_private  私钥/公钥
+     * @return string
+     */
+    public static function getRsaKeyValue($key, $is_private = true)
+    {
+        $keyStr = is_file($key) ? @file_get_contents($key) : $key;
+        if (empty($keyStr)) {
+            return null;
+        }
+
+        $keyStr = str_replace('\n', '', $keyStr);
+        // 为了解决用户传入的密钥格式,这里进行统一处理
+        if ($is_private) {
+            $beginStr = "-----BEGIN RSA PRIVATE KEY-----\n";
+            $endStr = "\n-----END RSA PRIVATE KEY-----";
+        } else {
+            $beginStr = "-----BEGIN PUBLIC KEY-----\n";
+            $endStr = "\n-----END PUBLIC KEY-----";
+        }
+
+        return $beginStr.wordwrap($keyStr, 64, "\n", true).$endStr;
+    }
+
+    public function tradeQuery($content)
+    {
+        $this->setMethod('alipay.trade.query');
+        $this->setContent($content);
+
+        return $this->send();
+    }
+
+    /**
+     * RSA2验签.
+     *
+     * @param  array  $data  待签名数据
+     * @param $sign
+     * @return bool
+     *
+     * @throws RuntimeException
+     */
+    public function rsaVerify($data, $sign): bool
+    {
+        unset($data['sign'], $data['sign_type']);
+        $publicKey = openssl_pkey_get_public($this->config['public_key']);
+        if (empty($publicKey)) {
+            throw new RuntimeException('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
+        }
+
+        $result = ! openssl_verify(json_encode($data, JSON_UNESCAPED_UNICODE), base64_decode($sign), $publicKey, OPENSSL_ALGO_SHA256);
+        if (PHP_VERSION_ID < 80000) {
+            openssl_free_key($publicKey);
+        }
+
+        return $result;
+    }
+
+    public function qrCharge($content)
+    {
+        $this->setMethod('alipay.trade.precreate');
+        $this->setContent($content);
+
+        return $this->send();
+    }
+
+    private function setMethod($method)
+    {
+        $this->config['method'] = $method;
+    }
+
+    private function setContent($content)
+    {
+        $content = array_filter($content);
+        ksort($content);
+        $this->config['biz_content'] = json_encode($content);
+    }
+
+    private function send()
+    {
+        $response = Http::get(self::$gatewayUrl, $this->buildParams())->json();
+        $resKey = str_replace('.', '_', $this->config['method']).'_response';
+        if (! isset($response[$resKey])) {
+            throw new RuntimeException('【支付宝当面付】请求错误:看起来是请求失败');
+        }
+
+        if (! $this->rsaVerify($response[$resKey], $response['sign'])) {
+            throw new RuntimeException('【支付宝当面付】请求错误:'.$response[$resKey]['msg'].' | '.$response[$resKey]['sub_msg']);
+        }
+
+        $response = $response[$resKey];
+        if ($response['msg'] !== 'Success') {
+            throw new RuntimeException($response['sub_msg']);
+        }
+
+        return $response;
+    }
+
+    private function buildParams(): array
+    {
+        $params = [
+            'app_id'      => $this->config['app_id'] ?? '',
+            'method'      => $this->config['method'] ?? '',
+            'charset'     => 'utf-8',
+            'sign_type'   => 'RSA2',
+            'timestamp'   => date('Y-m-d H:m:s'),
+            'biz_content' => $this->config['biz_content'] ?? [],
+            'version'     => '1.0',
+            'notify_url'  => $this->config['notify_url'] ?? '',
+        ];
+        $params = array_filter($params);
+        $params['sign'] = $this->encrypt($this->buildQuery($params));
+
+        return $params;
+    }
+
+    /**
+     * RSA2签名.
+     *
+     * @param  string  $data  签名的数组
+     * @return string
+     *
+     * @throws RuntimeException
+     */
+    private function encrypt(string $data): string
+    {
+        $privateKey = openssl_pkey_get_private($this->config['private_key']); // 私钥
+        if (empty($privateKey)) {
+            throw new RuntimeException('您使用的私钥格式错误,请检查RSA私钥配置');
+        }
+
+        openssl_sign($data, $sign, $privateKey, OPENSSL_ALGO_SHA256);
+        if (PHP_VERSION_ID < 80000) {
+            openssl_free_key($privateKey);
+        }
+
+        return base64_encode($sign); // base64编码
+    }
+
+    private function buildQuery(array $params): string
+    {
+        ksort($params); // 排序
+
+        return urldecode(http_build_query($params)); // 组合
+    }
+}

+ 2 - 2
app/Http/Controllers/Gateway/AbstractPayment.php → app/Payments/Library/Gateway.php

@@ -1,6 +1,6 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments\Library;
 
 use App\Models\Payment;
 use App\Models\PaymentCallback;
@@ -9,7 +9,7 @@ use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Str;
 
-abstract class AbstractPayment
+abstract class Gateway
 {
     abstract public function purchase(Request $request): JsonResponse;
 

+ 3 - 2
app/Http/Controllers/Gateway/Local.php → app/Payments/Local.php

@@ -1,15 +1,16 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
 use App\Components\Helpers;
 use App\Models\Goods;
 use App\Models\Order;
+use App\Payments\Library\Gateway;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Response;
 
-class Local extends AbstractPayment
+class Local extends Gateway
 {
     public function purchase($request): JsonResponse
     {

+ 3 - 2
app/Http/Controllers/Gateway/Manual.php → app/Payments/Manual.php

@@ -1,14 +1,15 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
 use App\Models\Payment;
+use App\Payments\Library\Gateway;
 use Auth;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Request;
 use Response;
 
-class Manual extends AbstractPayment
+class Manual extends Gateway
 {
     public function purchase(Request $request): JsonResponse
     {

+ 3 - 2
app/Http/Controllers/Gateway/PayBeaver.php → app/Payments/PayBeaver.php

@@ -5,15 +5,16 @@
  * Version: 2020-12-06.
  */
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
+use App\Payments\Library\Gateway;
 use Auth;
 use Http;
 use Illuminate\Http\JsonResponse;
 use Log;
 use Response;
 
-class PayBeaver extends AbstractPayment
+class PayBeaver extends Gateway
 {
     private $appId;
     private $appSecret;

+ 3 - 2
app/Http/Controllers/Gateway/PayJs.php → app/Payments/PayJs.php

@@ -1,14 +1,15 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
+use App\Payments\Library\Gateway;
 use Auth;
 use Illuminate\Http\JsonResponse;
 use Log;
 use Response;
 use Xhat\Payjs\Payjs as Pay;
 
-class PayJs extends AbstractPayment
+class PayJs extends Gateway
 {
     private static $config;
 

+ 3 - 2
app/Http/Controllers/Gateway/PayPal.php → app/Payments/PayPal.php

@@ -1,8 +1,9 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
 use App\Models\Payment;
+use App\Payments\Library\Gateway;
 use Auth;
 use Exception;
 use Http;
@@ -12,7 +13,7 @@ use Log;
 use Response;
 use Srmklive\PayPal\Services\ExpressCheckout;
 
-class PayPal extends AbstractPayment
+class PayPal extends Gateway
 {
     protected $provider;
     protected $exChange;

+ 48 - 48
app/Http/Controllers/Gateway/Stripe.php → app/Payments/Stripe.php

@@ -1,10 +1,12 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
 use App\Models\Payment;
+use App\Payments\Library\Gateway;
 use Auth;
 use Exception;
+use Http;
 use Illuminate\Http\JsonResponse;
 use Log;
 use Response;
@@ -14,7 +16,7 @@ use Stripe\Source;
 use Stripe\Webhook;
 use UnexpectedValueException;
 
-class Stripe extends AbstractPayment
+class Stripe extends Gateway
 {
     public function __construct()
     {
@@ -28,25 +30,26 @@ class Stripe extends AbstractPayment
 
         if ($type == 1 || $type == 3) {
             $stripe_currency = sysConfig('stripe_currency');
-            $ch = curl_init();
-            $url = 'https://api.exchangerate-api.com/v4/latest/'.strtoupper($stripe_currency);
-            curl_setopt($ch, CURLOPT_URL, $url);
-            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-            curl_setopt($ch, CURLOPT_HEADER, 0);
-            $currency = json_decode(curl_exec($ch));
-            curl_close($ch);
-            $price_exchanged = bcdiv((float) $payment->amount, $currency->rates->CNY, 10);
+            $response = Http::get('https://api.exchangerate-api.com/v4/latest/'.strtoupper($stripe_currency));
+            if (! $response->ok()) {
+                Log::warning('【Stripe】错误: 获取汇率失败!');
+                $payment->delete();
+
+                return Response::json(['status' => 'fail', 'message' => '获取汇率失败!']);
+            }
+            $response = $response->json();
+            $price_exchanged = bcdiv((float) $payment->amount, $response['rates']['CNY'], 10);
             $source = Source::create([
-                'amount' => floor($price_exchanged * 100),
-                'currency' => $stripe_currency,
-                'type' => $type == 1 ? 'alipay' : 'wechat',
+                'amount'               => floor($price_exchanged * 100),
+                'currency'             => $stripe_currency,
+                'type'                 => $type == 1 ? 'alipay' : 'wechat',
                 'statement_descriptor' => $payment->trade_no,
-                'metadata' => [
-                    'user_id' => $payment->user_id,
+                'metadata'             => [
+                    'user_id'      => $payment->user_id,
                     'out_trade_no' => $payment->trade_no,
-                    'identifier' => '',
+                    'identifier'   => '',
                 ],
-                'redirect' => [
+                'redirect'             => [
                     'return_url' => route('invoice'),
                 ],
             ]);
@@ -55,7 +58,7 @@ class Stripe extends AbstractPayment
                     Log::warning('创建订单错误:未知错误');
                     $payment->delete();
 
-                    return response()->json(['code' => 0, 'msg' => '创建订单失败:未知错误']);
+                    return Response::json(['status' => 'fail', 'message' => '创建订单失败:未知错误']);
                 }
                 $payment->update(['qr_code' => 1, 'url' => $source['wechat']['qr_code_url']]);
 
@@ -88,39 +91,13 @@ class Stripe extends AbstractPayment
         }
     }
 
-    protected function getCheckoutSessionData(string $tradeNo, int $amount, int $type): array
-    {
-        $unitAmount = $amount * 100;
-
-        return [
-            'payment_method_types' => ['card'],
-            'line_items'           => [
-                [
-                    'price_data' => [
-                        'currency'     => 'usd',
-                        'product_data' => ['name' => sysConfig('subject_name') ?: sysConfig('website_name')],
-                        'unit_amount'  => $unitAmount,
-                    ],
-                    'quantity'   => 1,
-                ],
-            ],
-            'mode'                 => 'payment',
-            'success_url'          => route('invoice'),
-            'cancel_url'           => route('invoice'),
-            'client_reference_id'  => $tradeNo,
-            'customer_email'       => Auth::getUser()->email,
-        ];
-    }
-
-    // redirect to Stripe Payment url
     public function redirectPage($session_id)
-    {
+    { // redirect to Stripe Payment url
         return view('user.components.payment.stripe', ['session_id' => $session_id]);
     }
 
-    // url = '/callback/notify?method=stripe'
     public function notify($request): void
-    {
+    { // url = '/callback/notify?method=stripe'
         $sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'];
         $endpointSecret = sysConfig('stripe_signing_secret');
         $payload = @file_get_contents('php://input');
@@ -170,12 +147,35 @@ class Stripe extends AbstractPayment
         exit();
     }
 
-    // 未支付成功则关闭订单
     public function failedPayment(Session $session)
-    {
+    { // 未支付成功则关闭订单
         $payment = Payment::whereTradeNo($session->client_reference_id)->first();
         if ($payment) {
             $payment->order->close();
         }
     }
+
+    protected function getCheckoutSessionData(string $tradeNo, int $amount, int $type): array
+    {
+        $unitAmount = $amount * 100;
+
+        return [
+            'payment_method_types' => ['card'],
+            'line_items'           => [
+                [
+                    'price_data' => [
+                        'currency'     => 'usd',
+                        'product_data' => ['name' => sysConfig('subject_name') ?: sysConfig('website_name')],
+                        'unit_amount'  => $unitAmount,
+                    ],
+                    'quantity'   => 1,
+                ],
+            ],
+            'mode'                 => 'payment',
+            'success_url'          => route('invoice'),
+            'cancel_url'           => route('invoice'),
+            'client_reference_id'  => $tradeNo,
+            'customer_email'       => Auth::getUser()->email,
+        ];
+    }
 }

+ 3 - 2
app/Http/Controllers/Gateway/THeadPay.php → app/Payments/THeadPay.php

@@ -1,14 +1,15 @@
 <?php
 
-namespace App\Http\Controllers\Gateway;
+namespace App\Payments;
 
+use App\Payments\Library\Gateway;
 use Auth;
 use Http;
 use Illuminate\Http\JsonResponse;
 use Log;
 use Response;
 
-class THeadPay extends AbstractPayment
+class THeadPay extends Gateway
 {
     public function purchase($request): JsonResponse
     {

+ 0 - 1
composer.json

@@ -35,7 +35,6 @@
     "mews/purifier": "^3.3",
     "overtrue/laravel-lang": "~5.0",
     "phpoffice/phpspreadsheet": "^1.16",
-    "riverslei/payment": "^5.1",
     "socialiteproviders/telegram": "^4.1",
     "spatie/laravel-permission": "^4.0",
     "srmklive/paypal": "^1.8",

+ 1 - 68
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "09b412ee2134272c0a2bd14284ed9728",
+    "content-hash": "81d07bf2521fca879f12a57bb5ba3257",
     "packages": [
         {
             "name": "arcanedev/log-viewer",
@@ -5217,73 +5217,6 @@
             ],
             "time": "2021-09-25T23:10:38+00:00"
         },
-        {
-            "name": "riverslei/payment",
-            "version": "v5.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/helei112g/payment.git",
-                "reference": "77f671b68b0285a6af77dc7c5afa36eabcae35aa"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/helei112g/payment/zipball/77f671b68b0285a6af77dc7c5afa36eabcae35aa",
-                "reference": "77f671b68b0285a6af77dc7c5afa36eabcae35aa",
-                "shasum": "",
-                "mirrors": [
-                    {
-                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
-                        "preferred": true
-                    }
-                ]
-            },
-            "require": {
-                "ext-bcmath": "*",
-                "ext-json": "*",
-                "ext-mbstring": "*",
-                "ext-openssl": "*",
-                "ext-simplexml": "*",
-                "ext-xml": "*",
-                "guzzlehttp/guzzle": "~6.0",
-                "php": ">=7.0"
-            },
-            "require-dev": {
-                "codeception/codeception": "*"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Payment\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Leo",
-                    "email": "[email protected]",
-                    "homepage": "https://dayutalk.cn"
-                }
-            ],
-            "description": "支付宝支付、微信支付、招商一网通支付php SDK。方便快速接入,最完整的开源支付 php sdk",
-            "homepage": "http://helei112g.github.io/payment",
-            "keywords": [
-                "alipay",
-                "weixin",
-                "一网通",
-                "微信支付",
-                "招商一网通",
-                "支付宝支付",
-                "集成支付接口SDK"
-            ],
-            "support": {
-                "issues": "https://github.com/helei112g/payment/issues",
-                "source": "https://github.com/helei112g/payment/tree/v5.x"
-            },
-            "time": "2020-05-04T03:07:17+00:00"
-        },
         {
             "name": "socialiteproviders/manager",
             "version": "v4.1.0",