改进 现有的支付

This commit is contained in:
iVampireSP.com 2022-11-06 22:57:01 +08:00
parent ff3f51c90d
commit 5dc942ea1c
No known key found for this signature in database
GPG Key ID: 2F7B001CA27A8132
32 changed files with 241 additions and 306 deletions

View File

@ -1,51 +0,0 @@
<?php
namespace App\Console\Commands\System;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
class Down extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'down';
/**
* The console command description.
*
* @var string
*/
protected $description = '启动维护模式。';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
//
// 记录到缓存(维护最长 2 小时)
Cache::put('system_down', true, now()->addHours(2));
$this->info('API 已进入维护模式,将在 2 小时后自动关闭。');
$this->warn('请注意,维护模式只会拦截用户的请求,不会影响模块通信。');
}
}

View File

@ -1,49 +0,0 @@
<?php
namespace App\Console\Commands\System;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
class Up extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'up';
/**
* The console command description.
*
* @var string
*/
protected $description = '关闭维护模式。';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
//
Cache::delete('system_down');
$this->info('维护模式已关闭。');
// maintenance_mode(false);
}
}

View File

@ -37,8 +37,8 @@ public function __construct($user_id, $type, $message)
// if (Auth::check()) {
if (Auth::guard('remote')->check()) {
$this->module = Auth::guard('remote')->user();
if (Auth::guard('module')->check()) {
$this->module = Auth::guard('module')->user();
} else {
$this->module = null;
}

View File

@ -5,17 +5,17 @@
trait ApiResponse
{
// RESTful API response
public function apiResponse($data, $status = 200)
public function apiResponse($data = [], $status = 200)
{
// if data is paginated, return paginated data
if ($data instanceof \Illuminate\Pagination\Paginator) {
$data = $data->toArray();
$data['data'] = $data['data'];
$data['data'] = $data['data'] ?? [];
$data['meta'] = [
'per_page' => $data['per_page'],
'current_page' => $data['current_page'],
'from' => $data['from'],
'to' => $data['to'],
'per_page' => $data['per_page'] ?? 0,
'current_page' => $data['current_page'] ?? 0,
'from' => $data['from'] ?? 0,
'to' => $data['to'] ?? 0,
];
$data['paginate'] = 1;
} else {

View File

@ -49,16 +49,6 @@ public function store(Request $request)
'payment' => 'alipay',
];
$pay = Pay::alipay()->web([
'out_trade_no' => 'lae-' . time(),
'total_amount' => $request->amount,
'subject' => '在莱云上充值 ' . $request->amount . ' 元',
]);
return $pay;
// if local
// if (env('APP_ENV') == 'local') {
// $data['payment'] = null;
@ -68,13 +58,6 @@ public function store(Request $request)
$balance = $balance->create($data);
// if (env('APP_ENV') == 'local') {
// $user->increment('balance', $request->amount);
// return $this->success($balance);
// }
// 生成 18 位订单号
$order_id = date('YmdHis') . $balance->id . rand(1000, 9999);
$balance->order_id = $order_id;
@ -88,64 +71,47 @@ public function store(Request $request)
}
public function show(Request $request, Balance $balance)
public function show(Balance $balance)
{
if ($balance->paid_at !== null) {
return $this->error('订单已支付');
}
if (now()->diffInDays($balance->created_at) > 1) {
return $this->error('订单已失效');
}
try {
return;
// if ($responseChecker->success($result)) {
// $html = $result->body;
// return view('pay', compact('html'));
// }
} catch (Exception $e) {
Log::error($e);
echo "调用失败," . $e->getMessage() . PHP_EOL;;
}
return $this->success($balance);
}
public function return(Request $request)
{
$this->validate($request, [
'out_trade_no' => 'required',
$pay = Pay::alipay()->web([
'out_trade_no' => $balance->order_id,
'total_amount' => 10,
'subject' => config('app.display_name') . ' 充值',
]);
$alipay = Pay::alipay();
return $pay;
$data = $alipay->callback();
Log::debug($data);
dd($data);
return;
// 检测订单是否存在
// $balance = Balance::where('order_id', $request->out_trade_no)->with('user')->first();
// if (!$balance) {
// return $this->notFound('balance not found');
// $result = false;
// try {
// $result = $this->checkAndCharge($balance, true);
// // if ($responseChecker->success($result)) {
// // $html = $result->body;
// // return view('pay', compact('html'));
// // }
// } catch (Exception $e) {
// Log::error($e);
// return $this->error($e->getMessage());
// }
// 检测订单是否已支付
if ($balance->paid_at !== null) {
return $this->success('订单已支付');
}
// if ($result) {
if ($this->checkAndCharge($balance)) {
return view('pay_success');
} else {
return view('pay_error');
}
// return response($pay);
// } else {
// return $this->error('支付失败');
// }
// return $this->success($balance);
}
public function notify(Request $request)
@ -157,12 +123,29 @@ 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');
return $this->notFound('找不到对应的订单');
}
// 检测订单是否已支付
if ($balance->paid_at !== null) {
return $this->success('订单已支付');
// return $this->success('订单已支付');
return view('pay_success');
}
$data = Pay::alipay()->callback();
// 检测 out_trade_no 是否为商户系统中创建的订单号
if ($data->out_trade_no != $balance->order_id) {
return $this->error('订单号不一致');
}
if ((int) $data->total_amount != (int) $balance->amount) {
throw new ChargeException('金额不一致');
}
// 验证 商户
if ($data['app_id'] != config('pay.alipay.default.app_id')) {
throw new ChargeException('商户不匹配');
}
if ($this->checkAndCharge($balance)) {
@ -184,48 +167,27 @@ public function checkAndCharge(Balance $balance, $check = false)
}
try {
// 请自行对 trade_status 进行判断及其它逻辑进行判断,在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
// 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
// 2、判断total_amount是否确实为该订单的实际金额即商户订单创建时的金额
// 3、校验通知中的seller_id或者seller_email) 是否为out_trade_no这笔单据的对应的操作方有的时候一个商户可能有多个seller_id/seller_email
// 4、验证app_id是否为该商户本身。
// 5、其它业务逻辑情况
// 验证 商户
// if ($data['app_id'] != config('pay.alipay.app_id')) {
// throw new ChargeException('商户不匹配');
// }
// if ((int) $data->total_amount != (int) $balance->amount) {
// throw new ChargeException('金额不一致');
// }
(new Transaction)->addAmount($balance->user_id, 'alipay', $balance->amount);
$balance->update([
'paid_at' => now()
]);
(new Transaction)->addAmount($balance->user_id, 'alipay', $data->totalAmount);
} catch (InvalidResponseException) {
return $this->error('无法验证支付结果');
}
return $alipay->success();
return view('pay_success');
}
// // 转换为 drops
// public function transfer($amount = 1)
// {
// $balance = auth()->user();
// $balance->decrement('amount', $request->amount);
// return $this->success($balance);
// }
/**
* 获取交易记录
*
* @param mixed $request
* @return void
*/
public function transactions(Request $request)
{
$transactions = Transaction::thisUser();
$transactions = Transaction::where('user_id', auth()->id());
if ($request->has('type')) {
$transactions = $transactions->where('type', $request->type);
@ -240,54 +202,20 @@ public function transactions(Request $request)
return $this->success($transactions);
}
/**
* 获取 Drops
*
* @return void
*/
public function drops()
{
// $month = now()->month;
$user_id = auth()->id();
// $cache_key = 'user_' . $user_id . '_month_' . $month . '_drops';
$transactions = new Transaction();
$resp = [
'drops' => $transactions->getDrops($user_id),
// 'monthly_usages' => (double) Cache::get($cache_key, 0),
'drops' => (new Transaction())->getDrops($user_id),
'rate' => config('drops.rate'),
];
return $this->success($resp);
}
// private function alipayOptions()
// {
// $options = new AlipayConfig();
// $options->protocol = 'https';
// // if local
// if (app()->environment() == 'local') {
// $options->gatewayHost = 'openapi.alipaydev.com';
// } else {
// $options->gatewayHost = 'openapi.alipay.com';
// }
// $options->signType = 'RSA2';
// $options->appId = config('payment.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->notifyUrl = route('balances.notify');
// return $options;
// }
}

View File

@ -52,8 +52,9 @@ public function store(Request $request)
'name' => $name,
'status' => $request->status,
'price' => $request->price,
'managed_price' => $request->managed_price ?? 0,
'user_id' => $user->id,
'module_id' => auth('remote')->id()
'module_id' => auth('module')->id()
];
$host = Host::create($data);

View File

@ -12,7 +12,7 @@ class ModuleController extends Controller
{
public function index()
{
$module = auth('remote')->user();
$module = auth('module')->user();
$calc = $this->calcModule($module);

View File

@ -69,7 +69,7 @@ public function reduce(Request $request, User $user)
'description' => 'required|string',
]);
$module = auth('remote')->user();
$module = auth('module')->user();
$transaction = new Transaction();

View File

@ -42,7 +42,6 @@ class Kernel extends HttpKernel
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\ForceJsonResponse::class,
\App\Http\Middleware\AllowCors::class,
],
];

View File

@ -1,23 +0,0 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ForceJsonResponse
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
return $next($request);
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Requests;
use Illuminate\Http\Request;
class BaseRequest extends Request
{
public function expectsJson()
{
return true;
}
public function wantsJson()
{
return true;
}
}

View File

@ -16,7 +16,7 @@ public function authorize(): bool
{
$server = $this->route('server');
return $server->query()->where('module_id', auth('remote')->id())->exists();
return $server->query()->where('module_id', auth('module')->id())->exists();
}
/**

View File

@ -23,7 +23,7 @@ public function authorize(): bool
$work_order_id = $work_order;
}
return WorkOrder::where('id', $work_order_id)->where('module_id', auth('remote')->id())->exists();
return WorkOrder::where('id', $work_order_id)->where('module_id', auth('module')->id())->exists();
}
/**

View File

@ -5,7 +5,7 @@
use Illuminate\Foundation\Http\FormRequest;
use App\Models\WorkOrder\WorkOrder;
class WorkOrderReques extends FormRequest
class WorkOrderRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.

View File

@ -38,14 +38,6 @@ public function handle()
}
});
// 删除所有未付款并且大于两天的订单
Balance::where('paid_at', null)->where('created_at', '<', now()->subDays(2))->delete();
// Balance::chunk(100, function ($balances) use ($bc) {
// foreach ($balances as $balance) {
// $bc->checkAndCharge($balance);
// }
// });
}
}

View File

@ -192,7 +192,6 @@ protected static function boot()
static::created(function ($model) {
broadcast(new UserEvent($model->user_id, 'hosts.created', $model));
Cache::forget('user_tasks_' . $model->user_id);
});
static::updating(function ($model) {
@ -201,8 +200,6 @@ protected static function boot()
} else if ($model->status == 'running') {
$model->suspended_at = null;
}
Cache::forget('user_tasks_' . $model->user_id);
broadcast(new UserEvent($model->user_id, 'hosts.updating', $model));
});

View File

@ -2,14 +2,17 @@
namespace App\Models;
use GuzzleHttp\Exception\ConnectException;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Exception\ConnectException;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Module extends Authenticatable
{
use Cachable;
protected $table = 'modules';
// primary key
@ -89,7 +92,7 @@ public function remoteRequest($method, $path, $requests)
public function moduleRequest($method, $path, $requests)
{
$module_id = auth('remote')->id();
$module_id = auth('module')->id();
$http = Http::remote($this->api_token, $this->url)
->accept('application/json');

View File

@ -59,7 +59,7 @@ protected static function boot()
$model->workOrder->status = 'user_replied';
}
if (auth('remote')->check()) {
if (auth('module')->check()) {
$model->user_id = null;
$model->workOrder->status = 'replied';
@ -70,7 +70,7 @@ protected static function boot()
});
static::created(function ($model) {
if (auth('remote')->check()) {
if (auth('module')->check()) {
$model->workOrder->status = 'replied';
$model->workOrder->save();
}

View File

@ -51,7 +51,7 @@ public function module(): \Illuminate\Database\Eloquent\Relations\BelongsTo
// scope
public function scopeThisModule($query)
{
return $query->where('module_id', auth('remote')->id());
return $query->where('module_id', auth('module')->id());
}
public function scopeThisUser($query)

View File

@ -33,6 +33,10 @@ public function boot()
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware(['api', 'auth:module'])
->prefix('remote')
->group(base_path('routes/remote.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
});

View File

@ -23,6 +23,7 @@
"fakerphp/faker": "^1.9.1",
"laravel/pint": "^1.0",
"laravel/sail": "^1.0.1",
"laravel/telescope": "^4.9",
"mockery/mockery": "^1.4.4",
"nunomaduro/collision": "^6.1",
"phpunit/phpunit": "^9.5.10",

76
composer.lock generated
View File

@ -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": "9f709e18793a5010b075e0233cbb8825",
"content-hash": "1e4e33f5e2b62096d5b1a31033e45d31",
"packages": [
{
"name": "brick/math",
@ -7293,6 +7293,80 @@
},
"time": "2022-09-26T13:53:59+00:00"
},
{
"name": "laravel/telescope",
"version": "v4.9.4",
"source": {
"type": "git",
"url": "https://github.com/laravel/telescope.git",
"reference": "ca8bec380ecef80d00ce6daecac2dc17c7e35ccd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/telescope/zipball/ca8bec380ecef80d00ce6daecac2dc17c7e35ccd",
"reference": "ca8bec380ecef80d00ce6daecac2dc17c7e35ccd",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-json": "*",
"laravel/framework": "^8.37|^9.0",
"php": "^7.3|^8.0",
"symfony/var-dumper": "^5.0|^6.0"
},
"require-dev": {
"ext-gd": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"orchestra/testbench": "^6.0|^7.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Telescope\\TelescopeServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Telescope\\": "src/",
"Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Mohamed Said",
"email": "mohamed@laravel.com"
}
],
"description": "An elegant debug assistant for the Laravel framework.",
"keywords": [
"debugging",
"laravel",
"monitoring"
],
"support": {
"issues": "https://github.com/laravel/telescope/issues",
"source": "https://github.com/laravel/telescope/tree/v4.9.4"
},
"time": "2022-10-03T14:55:50+00:00"
},
{
"name": "mockery/mockery",
"version": "1.5.1",

View File

@ -1,12 +0,0 @@
<?php
return [
'alipay' => [
'app_id' => env('ALIPAY_APP_ID'),
],
'wepay' => [
'mch_id' => env('WECHAT_MENCENT_ID'),
'v2_secret_key' => env('WECHAT_V2_API_KEY'),
'v3_secret_key' => env('WECHAT_V3_API_KEY'),
]
];

View File

@ -1,7 +1,8 @@
<?php
use App\Http\Requests\BaseRequest;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
// use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
@ -49,7 +50,8 @@
$kernel = $app->make(Kernel::class);
$response = $kernel->handle(
$request = Request::capture()
// $request = Request::capture()
$request = BaseRequest::capture()
)->send();
$kernel->terminate($request, $response);

7
public/vendor/telescope/app-dark.css vendored Normal file

File diff suppressed because one or more lines are too long

7
public/vendor/telescope/app.css vendored Normal file

File diff suppressed because one or more lines are too long

2
public/vendor/telescope/app.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
public/vendor/telescope/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,5 @@
{
"/app.js": "/app.js?id=7328e77177db89b6ec830fb908e3df6c",
"/app-dark.css": "/app-dark.css?id=3ae28ef5f7b987d68dc611118c646308",
"/app.css": "/app.css?id=7c970f699ed9cf60d80b273b4ad2ad61"
}

View File

@ -27,7 +27,7 @@
Route::get('balances/transactions', [BalanceController::class, 'transactions']);
Route::get('balances/drops', [BalanceController::class, 'drops']);
Route::resource('work-orders', WorkOrderController::class)->only(['index', 'store', 'show']);
Route::resource('work-orders', WorkOrderController::class)->only(['index', 'store', 'show', 'update']);
Route::resource('work-orders.replies', ReplyController::class)->only(['index', 'store']);

32
routes/remote.php Normal file
View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Remote\UserController;
use App\Http\Controllers\Remote\ModuleController;
use App\Http\Controllers\Remote\BroadcastController;
use App\Http\Controllers\Remote\Host\HostController;
use App\Http\Controllers\Remote\Host\TaskController;
use App\Http\Controllers\Remote\WorkOrder\ReplyController;
use App\Http\Controllers\Remote\WorkOrder\WorkOrderController;
Route::get('modules', [ModuleController::class, 'index']);
Route::resource('hosts', HostController::class);
Route::resource('tasks', TaskController::class);
Route::resource('work-orders', WorkOrderController::class);
Route::resource('work-orders.replies', ReplyController::class);
// 用户信息
Route::get('users', [UserController::class, 'index']);
Route::get('users/{user}', [UserController::class, 'show']);
Route::post('users/{user}/reduce', [UserController::class, 'reduce']);
Route::get('users/{user}/hosts', [UserController::class, 'hosts']);
Route::post('broadcast/users/{user}', [BroadcastController::class, 'broadcast_to_user']);
Route::post('broadcast/users/{user}', [BroadcastController::class, 'broadcast_to_host']);
// 模块间调用
Route::any('modules/{module}/{path?}', [ModuleController::class, 'exportCall'])
->where('path', '.*');

View File

@ -24,8 +24,7 @@
Route::get('/balance/{balance}', [BalanceController::class, 'show'])->name('balances.pay.show');
Route::get('/pay/return', [BalanceController::class, 'return'])->name('balances.alipay.return');
Route::get('/pay/notify', [BalanceController::class, 'notify'])->name('balances.alipay.notify');
Route::get('/pay/alipay/notify', [BalanceController::class, 'notify'])->name('balances.alipay.notify');
Route::get('/pay', function () {