增加 支付宝支付网关
This commit is contained in:
parent
c8fcc8c9ed
commit
27e756156f
@ -56,3 +56,5 @@ VITE_PUSHER_HOST="${PUSHER_HOST}"
|
|||||||
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
VITE_PUSHER_PORT="${PUSHER_PORT}"
|
||||||
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
|
||||||
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
|
|
||||||
|
ALIPAY_APP_ID=
|
||||||
|
10
app/Exceptions/PaymentException.php
Normal file
10
app/Exceptions/PaymentException.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class PaymentException extends Exception
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
@ -2,8 +2,13 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\User;
|
namespace App\Http\Controllers\User;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use Exception;
|
||||||
|
use App\Models\User\Balance;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Alipay\EasySDK\Kernel\Util\ResponseChecker;
|
||||||
|
use Alipay\EasySDK\Kernel\Factory as AlipayFactory;
|
||||||
|
|
||||||
class BalanceController extends Controller
|
class BalanceController extends Controller
|
||||||
{
|
{
|
||||||
@ -18,28 +23,102 @@ public function index(Request $request)
|
|||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
// 充值
|
// 充值
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'amount' => 'required|numeric',
|
'amount' => 'required|numeric',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$balance = $request->user();
|
$user = $request->user();
|
||||||
|
|
||||||
// 启用事物
|
$balance = new Balance();
|
||||||
\DB::beginTransaction();
|
|
||||||
try {
|
|
||||||
$balance->increment('amount', $request->amount);
|
$balance = $balance->create([
|
||||||
\DB::commit();
|
'user_id' => $user->id,
|
||||||
} catch (\Exception $e) {
|
'amount' => $request->amount,
|
||||||
\DB::rollBack();
|
'payment' => 'alipay',
|
||||||
return $this->error($e->getMessage());
|
]);
|
||||||
}
|
|
||||||
|
// 生成 18 位订单号
|
||||||
|
$order_id = date('YmdHis') . $balance->id . rand(1000, 9999);
|
||||||
|
$balance->order_id = $order_id;
|
||||||
|
|
||||||
|
$balance->save();
|
||||||
|
|
||||||
|
$balance = $balance->toArray();
|
||||||
|
$balance['pay_url'] = route('balances.pay.show', ['balance' => $balance['order_id']]);
|
||||||
|
|
||||||
return $this->success($balance);
|
return $this->success($balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function show(Request $request, Balance $balance)
|
||||||
|
{
|
||||||
|
// dd(AlipayFactory::payment()->common()->query('20220901070430102316'));
|
||||||
|
// dd(route(''));
|
||||||
|
if ($balance->paid_at !== null) {
|
||||||
|
return $this->error('订单已支付');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = AlipayFactory::payment()->page()->pay("支付", $balance->order_id, $balance->amount, 'http://rcrmqishil.sharedwithexpose.com/api/pay/return');
|
||||||
|
|
||||||
|
$responseChecker = new ResponseChecker();
|
||||||
|
|
||||||
|
// dd($result);
|
||||||
|
|
||||||
|
if ($responseChecker->success($result)) {
|
||||||
|
$html = $result->body;
|
||||||
|
return view('pay', compact('html'));
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
dd($e->getMessage());
|
||||||
|
echo "调用失败," . $e->getMessage() . PHP_EOL;;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $this->success($balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notify(Request $request)
|
||||||
|
{
|
||||||
|
// 检测订单是否存在
|
||||||
|
$balance = Balance::where('order_id', $request->out_trade_no)->with('user')->first();
|
||||||
|
if (!$balance) {
|
||||||
|
return $this->notFound('balance not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测订单是否已支付
|
||||||
|
if ($balance->paid_at !== null) {
|
||||||
|
return $this->success('订单已支付');
|
||||||
|
}
|
||||||
|
|
||||||
|
$trade = AlipayFactory::payment()->common()->query($request->out_trade_no);
|
||||||
|
|
||||||
|
if ($trade->code == "10000" && $trade->tradeStatus == "TRADE_SUCCESS") {
|
||||||
|
$balance->paid_at = now();
|
||||||
|
$balance->save();
|
||||||
|
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
try {
|
||||||
|
$balance->user->increment('balance', $trade->totalAmount);
|
||||||
|
DB::commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
DB::rollBack();
|
||||||
|
AlipayFactory::payment()->common()->refund($request->out_trade_no, $trade->totalAmount);
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->success('订单支付成功');
|
||||||
|
} else {
|
||||||
|
return $this->error('订单支付失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// // 转换为 drops
|
// // 转换为 drops
|
||||||
// public function transfer($amount = 1)
|
// public function transfer($amount = 1)
|
||||||
// {
|
// {
|
||||||
@ -49,6 +128,4 @@ public function store(Request $request)
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
32
app/Models/User/Balance.php
Normal file
32
app/Models/User/Balance.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\User;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
|
||||||
|
class Balance extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'order_id',
|
||||||
|
'payment',
|
||||||
|
'amount',
|
||||||
|
'user_id',
|
||||||
|
'paid_at',
|
||||||
|
'trade_id'
|
||||||
|
];
|
||||||
|
|
||||||
|
// route key
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'order_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use Alipay\EasySDK\Kernel\Config as AlipayConfig;
|
||||||
|
use Alipay\EasySDK\Kernel\Factory as AlipayFactory;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
@ -34,5 +37,33 @@ public function boot()
|
|||||||
])->baseUrl($url);
|
])->baseUrl($url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AlipayFactory::setOptions($this->alipayOptions());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function alipayOptions()
|
||||||
|
{
|
||||||
|
$options = new AlipayConfig();
|
||||||
|
$options->protocol = 'https';
|
||||||
|
$options->gatewayHost = 'openapi.alipaydev.com';
|
||||||
|
$options->signType = 'RSA2';
|
||||||
|
|
||||||
|
$options->appId = config('alipay.app_id');
|
||||||
|
|
||||||
|
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
|
||||||
|
$options->merchantPrivateKey = trim(Storage::get('alipayAppPriv.key'));
|
||||||
|
|
||||||
|
$options->alipayCertPath = storage_path('app/alipayCertPublicKey_RSA2.crt');
|
||||||
|
$options->alipayRootCertPath = storage_path('app/alipayRootCert.crt');
|
||||||
|
$options->merchantCertPath = storage_path('app/appCertPublicKey.crt');
|
||||||
|
|
||||||
|
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
|
||||||
|
// $options->alipayPublicKey = Storage::get('alipayCertPublicKey_RSA2.crt');
|
||||||
|
|
||||||
|
//可设置异步通知接收服务地址(可选)
|
||||||
|
$options->notifyUrl = "http://rcrmqishil.sharedwithexpose.com/api/pay/notify";
|
||||||
|
|
||||||
|
|
||||||
|
return $options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.0.2",
|
"php": "^8.0.2",
|
||||||
|
"alipaysdk/easysdk": "^2.0",
|
||||||
"doctrine/dbal": "^3.3",
|
"doctrine/dbal": "^3.3",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"laravel/framework": "^9.19",
|
"laravel/framework": "^9.19",
|
||||||
@ -13,7 +14,8 @@
|
|||||||
"laravel/octane": "^1.2",
|
"laravel/octane": "^1.2",
|
||||||
"laravel/sanctum": "^2.14.1",
|
"laravel/sanctum": "^2.14.1",
|
||||||
"laravel/telescope": "^4.9",
|
"laravel/telescope": "^4.9",
|
||||||
"laravel/tinker": "^2.7"
|
"laravel/tinker": "^2.7",
|
||||||
|
"league/omnipay": "^3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
|
988
composer.lock
generated
988
composer.lock
generated
File diff suppressed because it is too large
Load Diff
5
config/alipay.php
Normal file
5
config/alipay.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'app_id' => env('ALIPAY_APP_ID'),
|
||||||
|
];
|
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('balances', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
// order id
|
||||||
|
$table->string('order_id')->nullable()->index();
|
||||||
|
|
||||||
|
// trade id
|
||||||
|
$table->string('trade_id')->nullable()->index();
|
||||||
|
|
||||||
|
// payment
|
||||||
|
$table->string('payment')->nullable()->index();
|
||||||
|
|
||||||
|
// amount
|
||||||
|
$table->decimal('amount', 10, 2)->default(0);
|
||||||
|
|
||||||
|
// paid_at
|
||||||
|
$table->timestamp('paid_at')->nullable();
|
||||||
|
|
||||||
|
// user id
|
||||||
|
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||||
|
$table->foreign('user_id')->references('id')->on('users');
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('balances');
|
||||||
|
}
|
||||||
|
};
|
13
resources/views/pay.blade.php
Normal file
13
resources/views/pay.blade.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>支付订单</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{!! $html !!}
|
||||||
|
{{--{{ $html }}--}}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\User\DropController;
|
|
||||||
use App\Http\Controllers\User\TaskController;
|
use App\Http\Controllers\User\TaskController;
|
||||||
use App\Http\Controllers\Remote\ModuleController;
|
use App\Http\Controllers\Remote\ModuleController;
|
||||||
use App\Http\Controllers\ServerController;
|
use App\Http\Controllers\ServerController;
|
||||||
|
use App\Http\Controllers\User\BalanceController;
|
||||||
use App\Http\Controllers\UserController;
|
use App\Http\Controllers\UserController;
|
||||||
use App\Http\Controllers\User\WorkOrder\ReplyController;
|
use App\Http\Controllers\User\WorkOrder\ReplyController;
|
||||||
use App\Http\Controllers\User\WorkOrder\WorkOrderController;
|
use App\Http\Controllers\User\WorkOrder\WorkOrderController;
|
||||||
@ -14,7 +14,8 @@
|
|||||||
Route::get('servers', ServerController::class);
|
Route::get('servers', ServerController::class);
|
||||||
|
|
||||||
|
|
||||||
Route::apiResource('drops', DropController::class);
|
Route::apiResource('balances', BalanceController::class)->only(['index', 'store']);
|
||||||
|
// Route::apiResource('drops', DropController::class);
|
||||||
|
|
||||||
Route::get('tasks', TaskController::class);
|
Route::get('tasks', TaskController::class);
|
||||||
|
|
||||||
@ -23,5 +24,8 @@
|
|||||||
|
|
||||||
// 调用远程 API
|
// 调用远程 API
|
||||||
Route::any('/modules/{module}', [ModuleController::class, 'call'])->name('module.call');
|
Route::any('/modules/{module}', [ModuleController::class, 'call'])->name('module.call');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Route::get('/pay/return', [BalanceController::class, 'notify'])->name('balances.return');
|
||||||
|
Route::get('/pay/notify', [BalanceController::class, 'notify'])->name('balances.notify');
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// Route::apiResource('users', Remote\UserController::class)->only(['show']);
|
// Route::apiResource('users', Remote\UserController::class)->only(['show']);
|
||||||
|
|
||||||
Route::apiResource('modules', Remote\ModuleController::class)->only(['index']);
|
Route::apiResource('modules', Remote\ModuleController::class)->only(['index']);
|
||||||
Route::apiResource('servers', Remote\ServerController::class);
|
Route::apiResource('servers', \App\Http\Controllers\ServerController::class);
|
||||||
Route::apiResource('hosts', Remote\Host\HostController::class);
|
Route::apiResource('hosts', Remote\Host\HostController::class);
|
||||||
// Route::patch('hosts/{host}', [Remote\Host\DropController::class, 'update']);
|
// Route::patch('hosts/{host}', [Remote\Host\DropController::class, 'update']);
|
||||||
// Route::patch('tasks', Remote\Host\TaskController::class);
|
// Route::patch('tasks', Remote\Host\TaskController::class);
|
||||||
|
@ -25,3 +25,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/', [Controllers\AuthController::class, 'index'])->name('index');
|
Route::get('/', [Controllers\AuthController::class, 'index'])->name('index');
|
||||||
|
|
||||||
|
Route::get('/balances/{balance}', [Controllers\User\BalanceController::class, 'show'])->name('balances.pay.show');
|
||||||
|
|
||||||
|
|
||||||
|
BIN
storage/.DS_Store
vendored
Normal file
BIN
storage/.DS_Store
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user