增加 支付宝支付网关
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_SCHEME="${PUSHER_SCHEME}"
|
||||
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;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Exception;
|
||||
use App\Models\User\Balance;
|
||||
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
|
||||
{
|
||||
@ -18,28 +23,102 @@ public function index(Request $request)
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
|
||||
|
||||
// 充值
|
||||
$request->validate([
|
||||
'amount' => 'required|numeric',
|
||||
]);
|
||||
|
||||
$balance = $request->user();
|
||||
$user = $request->user();
|
||||
|
||||
// 启用事物
|
||||
\DB::beginTransaction();
|
||||
try {
|
||||
$balance->increment('amount', $request->amount);
|
||||
\DB::commit();
|
||||
} catch (\Exception $e) {
|
||||
\DB::rollBack();
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
$balance = new Balance();
|
||||
|
||||
|
||||
$balance = $balance->create([
|
||||
'user_id' => $user->id,
|
||||
'amount' => $request->amount,
|
||||
'payment' => 'alipay',
|
||||
]);
|
||||
|
||||
// 生成 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);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
// 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;
|
||||
|
||||
use Alipay\EasySDK\Kernel\Config as AlipayConfig;
|
||||
use Alipay\EasySDK\Kernel\Factory as AlipayFactory;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
@ -34,5 +37,33 @@ public function boot()
|
||||
])->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",
|
||||
"require": {
|
||||
"php": "^8.0.2",
|
||||
"alipaysdk/easysdk": "^2.0",
|
||||
"doctrine/dbal": "^3.3",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"laravel/framework": "^9.19",
|
||||
@ -13,7 +14,8 @@
|
||||
"laravel/octane": "^1.2",
|
||||
"laravel/sanctum": "^2.14.1",
|
||||
"laravel/telescope": "^4.9",
|
||||
"laravel/tinker": "^2.7"
|
||||
"laravel/tinker": "^2.7",
|
||||
"league/omnipay": "^3"
|
||||
},
|
||||
"require-dev": {
|
||||
"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
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\User\DropController;
|
||||
use App\Http\Controllers\User\TaskController;
|
||||
use App\Http\Controllers\Remote\ModuleController;
|
||||
use App\Http\Controllers\ServerController;
|
||||
use App\Http\Controllers\User\BalanceController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\User\WorkOrder\ReplyController;
|
||||
use App\Http\Controllers\User\WorkOrder\WorkOrderController;
|
||||
@ -14,7 +14,8 @@
|
||||
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);
|
||||
|
||||
@ -23,5 +24,8 @@
|
||||
|
||||
// 调用远程 API
|
||||
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('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::patch('hosts/{host}', [Remote\Host\DropController::class, 'update']);
|
||||
// Route::patch('tasks', Remote\Host\TaskController::class);
|
||||
|
@ -25,3 +25,7 @@
|
||||
});
|
||||
|
||||
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