2022-11-16 05:16:56 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Http\Controllers\Web;
|
|
|
|
|
|
|
|
use App\Http\Controllers\Controller;
|
|
|
|
use App\Models\Balance;
|
2022-11-16 10:06:51 +00:00
|
|
|
use App\Models\Module;
|
2022-11-16 05:16:56 +00:00
|
|
|
use App\Models\Transaction;
|
|
|
|
use Illuminate\Contracts\View\View;
|
|
|
|
use Illuminate\Http\JsonResponse;
|
2023-01-10 13:42:27 +00:00
|
|
|
use Illuminate\Http\RedirectResponse;
|
2022-11-16 05:16:56 +00:00
|
|
|
use Illuminate\Http\Request;
|
2022-12-27 16:24:41 +00:00
|
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
use Illuminate\Support\Facades\Log;
|
2022-11-16 05:16:56 +00:00
|
|
|
use Illuminate\Validation\ValidationException;
|
2022-12-27 16:24:41 +00:00
|
|
|
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
2022-11-16 05:16:56 +00:00
|
|
|
use Yansongda\LaravelPay\Facades\Pay;
|
|
|
|
|
|
|
|
class BalanceController extends Controller
|
|
|
|
{
|
|
|
|
public function index(Request $request): View
|
|
|
|
{
|
|
|
|
$balance = $request->user()->balance;
|
|
|
|
|
2023-01-10 13:42:27 +00:00
|
|
|
$balances = (new Balance)->thisUser()->latest()->paginate(100);
|
2022-11-16 10:06:51 +00:00
|
|
|
|
2022-11-19 14:42:47 +00:00
|
|
|
return view('balances.index', compact('balance', 'balances'));
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
|
|
|
|
2023-01-10 13:42:27 +00:00
|
|
|
public function store(Request $request): RedirectResponse
|
2022-11-16 05:16:56 +00:00
|
|
|
{
|
|
|
|
$this->validate($request, [
|
2022-12-18 03:16:27 +00:00
|
|
|
'amount' => 'required|integer|min:0.1|max:10000',
|
2022-12-27 16:24:41 +00:00
|
|
|
'payment' => 'required|in:wechat,alipay',
|
2022-11-16 05:16:56 +00:00
|
|
|
]);
|
|
|
|
|
2023-01-10 13:42:27 +00:00
|
|
|
$balance = (new Balance)->create([
|
2023-01-03 07:24:29 +00:00
|
|
|
'user_id' => auth('web')->id(),
|
2022-12-18 03:16:27 +00:00
|
|
|
'amount' => $request->input('amount'),
|
2022-12-27 16:24:41 +00:00
|
|
|
'payment' => $request->input('payment'),
|
2023-01-03 07:24:29 +00:00
|
|
|
]);
|
2022-11-16 05:16:56 +00:00
|
|
|
|
2022-12-27 16:24:41 +00:00
|
|
|
return redirect()->route('balances.show', compact('balance'));
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-12-27 16:24:41 +00:00
|
|
|
* 显示充值页面和状态(ajax)
|
2022-11-16 05:16:56 +00:00
|
|
|
*/
|
2023-01-10 13:42:27 +00:00
|
|
|
public function show(Request $request, Balance $balance): RedirectResponse|JsonResponse|View
|
2022-11-16 05:16:56 +00:00
|
|
|
{
|
2023-01-03 07:24:29 +00:00
|
|
|
if ($balance->isPaid()) {
|
2022-12-27 16:24:41 +00:00
|
|
|
if ($request->ajax()) {
|
|
|
|
return $this->success($balance);
|
|
|
|
}
|
|
|
|
|
|
|
|
return view('balances.process', compact('balance'));
|
|
|
|
} else {
|
|
|
|
if ($request->ajax()) {
|
|
|
|
return $this->success($balance);
|
|
|
|
}
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
|
|
|
|
2023-01-03 07:24:29 +00:00
|
|
|
if ($balance->isOverdue()) {
|
|
|
|
if (now()->diffInDays($balance->created_at) > 1) {
|
|
|
|
if ($request->ajax()) {
|
|
|
|
return $this->forbidden($balance);
|
|
|
|
}
|
2022-12-27 16:24:41 +00:00
|
|
|
|
2023-01-03 07:24:29 +00:00
|
|
|
return redirect()->route('index')->with('error', '订单已逾期。');
|
2022-12-27 16:24:41 +00:00
|
|
|
}
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
|
|
|
|
2022-12-27 16:24:41 +00:00
|
|
|
$balance->load('user');
|
|
|
|
|
|
|
|
$subject = config('app.display_name') . ' 充值';
|
|
|
|
|
|
|
|
$order = [
|
2022-11-16 05:16:56 +00:00
|
|
|
'out_trade_no' => $balance->order_id,
|
2022-12-27 16:24:41 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
$code = QrCode::size(150);
|
|
|
|
|
|
|
|
if ($balance->payment === 'wechat') {
|
|
|
|
$pay = $this->xunhu_wechat($balance, $subject);
|
|
|
|
|
|
|
|
$qr_code = $code->generate($pay['url']);
|
|
|
|
} else {
|
|
|
|
$order['subject'] = $subject;
|
|
|
|
$order['total_amount'] = $balance->amount;
|
|
|
|
|
2022-12-27 17:03:52 +00:00
|
|
|
$pay = Pay::alipay()->web($order);
|
2022-12-27 16:24:41 +00:00
|
|
|
|
2022-12-27 17:03:52 +00:00
|
|
|
return view('balances.alipay', ['html' => (string)$pay->getBody()]);
|
2022-12-27 16:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isset($qr_code)) {
|
2023-01-03 07:24:29 +00:00
|
|
|
return redirect()->route('index')->with('error', '支付方式错误。');
|
2022-12-27 16:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return view('balances.pay', compact('balance', 'qr_code'));
|
|
|
|
}
|
|
|
|
|
2023-01-03 07:24:29 +00:00
|
|
|
private
|
|
|
|
function xunhu_wechat(
|
|
|
|
Balance $balance, $subject = '支付'
|
|
|
|
) {
|
2022-12-27 16:24:41 +00:00
|
|
|
$data = [
|
|
|
|
'version' => '1.1',
|
|
|
|
'lang' => 'zh-cn',
|
|
|
|
'plugins' => config('app.name'),
|
|
|
|
'appid' => config('pay.xunhu.app_id'),
|
|
|
|
'trade_order_id' => $balance->order_id,
|
|
|
|
'payment' => 'wechat',
|
|
|
|
'type' => 'WAP',
|
|
|
|
'wap_url' => config('app.url'),
|
|
|
|
'wap_name' => config('app.display_name'),
|
|
|
|
'total_fee' => $balance->amount,
|
|
|
|
'title' => $subject,
|
|
|
|
'time' => time(),
|
|
|
|
'notify_url' => route('balances.notify', 'wechat'),
|
|
|
|
'return_url' => route('balances.notify', 'wechat'),
|
|
|
|
'callback_url' => route('balances.show', $balance),
|
|
|
|
'modal' => null,
|
|
|
|
'nonce_str' => str_shuffle(time()),
|
|
|
|
];
|
|
|
|
|
|
|
|
$data['hash'] = $this->xunhu_hash($data);
|
|
|
|
|
|
|
|
$response = Http::post(config('pay.xunhu.gateway'), $data);
|
|
|
|
|
|
|
|
if (!$response->successful()) {
|
2023-01-03 07:24:29 +00:00
|
|
|
return redirect()->route('index')->with('error', '支付网关错误。');
|
2022-12-27 16:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$response = $response->json();
|
|
|
|
|
|
|
|
$hash = $this->xunhu_hash($response);
|
2022-11-16 05:16:56 +00:00
|
|
|
|
2022-12-27 16:24:41 +00:00
|
|
|
if (!isset($response['hash']) || $response['hash'] !== $hash) {
|
2023-01-03 07:24:29 +00:00
|
|
|
return redirect()->route('index')->with('error', '无法校验支付网关返回数据。');
|
2022-12-27 16:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2023-01-03 07:24:29 +00:00
|
|
|
private
|
|
|
|
function xunhu_hash(
|
|
|
|
array $arr
|
2023-01-10 13:42:27 +00:00
|
|
|
): string {
|
2022-12-27 16:24:41 +00:00
|
|
|
ksort($arr);
|
|
|
|
|
|
|
|
$pre = [];
|
|
|
|
foreach ($arr as $key => $data) {
|
|
|
|
if (is_null($data) || $data === '') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($key == 'hash') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$pre[$key] = stripslashes($data);
|
|
|
|
}
|
|
|
|
|
|
|
|
$arg = '';
|
|
|
|
$qty = count($pre);
|
|
|
|
$index = 0;
|
|
|
|
|
|
|
|
foreach ($pre as $key => $val) {
|
|
|
|
$arg .= "$key=$val";
|
|
|
|
if ($index++ < ($qty - 1)) {
|
|
|
|
$arg .= "&";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return md5($arg . config('pay.xunhu.app_secret'));
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @throws ValidationException
|
|
|
|
*/
|
2023-01-03 07:24:29 +00:00
|
|
|
public
|
|
|
|
function notify(
|
|
|
|
Request $request, $payment
|
|
|
|
): View|JsonResponse {
|
2022-12-27 16:24:41 +00:00
|
|
|
$is_paid = false;
|
|
|
|
|
|
|
|
if ($payment === 'alipay') {
|
|
|
|
$out_trade_no = $request->input('out_trade_no');
|
|
|
|
} else if ($payment === 'wechat') {
|
|
|
|
$out_trade_no = $request->input('trade_order_id');
|
|
|
|
} else {
|
|
|
|
abort(400, '支付方式错误');
|
|
|
|
}
|
2022-11-16 05:16:56 +00:00
|
|
|
|
|
|
|
// 检测订单是否存在
|
2023-01-10 13:42:27 +00:00
|
|
|
$balance = (new Balance)->where('order_id', $out_trade_no)->with('user')->first();
|
2022-11-16 05:16:56 +00:00
|
|
|
if (!$balance) {
|
|
|
|
abort(404, '找不到订单。');
|
|
|
|
}
|
|
|
|
|
|
|
|
// 检测订单是否已支付
|
2022-12-27 16:24:41 +00:00
|
|
|
if ($balance->paid_at !== null) {
|
|
|
|
if ($request->ajax()) {
|
|
|
|
return $this->success($balance);
|
|
|
|
}
|
|
|
|
|
|
|
|
return view('balances.process', compact('balance'));
|
|
|
|
}
|
2022-11-17 06:43:18 +00:00
|
|
|
|
2022-12-27 16:24:41 +00:00
|
|
|
// 处理验证
|
2022-12-27 17:08:44 +00:00
|
|
|
if ($payment === 'wechat') {
|
2022-12-27 16:24:41 +00:00
|
|
|
if (!($request->filled('hash') || $request->filled('trade_order_id'))) {
|
|
|
|
return $this->error('参数错误。');
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($request->filled('plugins') && $request->input('plugins') != config('app.name')) {
|
|
|
|
return $this->error('插件不匹配。');
|
|
|
|
}
|
|
|
|
|
|
|
|
$hash = $this->xunhu_hash($request->toArray());
|
|
|
|
if ($request->input('hash') != $hash) {
|
|
|
|
Log::debug('hash error', $request->toArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($request->input('status') === 'OD') {
|
|
|
|
$is_paid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($is_paid) {
|
2023-01-16 20:36:43 +00:00
|
|
|
// $balance->user->charge($balance->amount, $balance->payment, $balance->order_id);
|
2023-01-10 13:42:27 +00:00
|
|
|
$balance->update([
|
|
|
|
'paid_at' => now()
|
|
|
|
]);
|
2022-12-27 16:24:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($request->ajax()) {
|
|
|
|
return $this->success($balance);
|
|
|
|
}
|
|
|
|
|
2022-11-17 06:43:18 +00:00
|
|
|
return view('balances.process', compact('balance'));
|
2022-11-16 05:16:56 +00:00
|
|
|
|
2022-11-16 10:06:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获取交易记录
|
|
|
|
*
|
|
|
|
* @param mixed $request
|
|
|
|
*
|
|
|
|
* @return View
|
|
|
|
*/
|
2022-12-27 17:08:44 +00:00
|
|
|
public
|
|
|
|
function transactions(
|
|
|
|
Request $request
|
|
|
|
): View {
|
2022-11-16 10:06:51 +00:00
|
|
|
|
|
|
|
$modules = Module::all();
|
|
|
|
|
2023-01-10 13:42:27 +00:00
|
|
|
$transactions = (new Transaction)->where('user_id', auth()->id());
|
2022-11-16 10:06:51 +00:00
|
|
|
|
|
|
|
if ($request->has('type')) {
|
|
|
|
$transactions = $transactions->where('type', $request->type);
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
2022-11-16 10:06:51 +00:00
|
|
|
|
|
|
|
if ($request->has('payment')) {
|
|
|
|
$transactions = $transactions->where('payment', $request->payment);
|
|
|
|
}
|
|
|
|
|
2022-11-17 00:22:18 +00:00
|
|
|
$transactions = $transactions->latest()->paginate(100)->withQueryString();
|
2022-11-16 10:06:51 +00:00
|
|
|
|
|
|
|
return view('balances.transactions', compact('transactions', 'modules'));
|
2022-11-16 05:16:56 +00:00
|
|
|
}
|
|
|
|
}
|