6
0
Fork 0
jiqu-library-server/app/Endpoint/Api/Http/Controllers/Account/WalletController.php

346 lines
11 KiB
PHP

<?php
namespace App\Endpoint\Api\Http\Controllers\Account;
use App\Endpoint\Api\Http\Controllers\Controller;
use App\Endpoint\Api\Http\Resources\BalanceLogResource;
use App\Endpoint\Api\Http\Resources\DistributionPreIncomeResource;
use App\Endpoint\Api\Http\Resources\WalletLogResource;
use App\Endpoint\Api\Http\Resources\WalletToBankLogResource;
use App\Exceptions\BalanceFrozenException;
use App\Exceptions\BizException;
use App\Exceptions\InvalidPaySerialNumberException;
use App\Exceptions\PayPasswordIncorrectException;
use App\Exceptions\WalletFrozenException;
use App\Exceptions\WalletNotEnoughException;
use App\Helpers\Paginator as PaginatorHelper;
use App\Models\BalanceLog;
use App\Models\Order;
use App\Models\PayLog;
use App\Models\User;
use App\Models\WalletLog;
use App\Models\WalletToBankLog;
use App\Rules\PhoneNumber;
use App\Services\BalanceService;
use App\Services\PayService;
use App\Services\WalletService;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Throwable;
class WalletController extends Controller
{
/**
* 账户明细
*
* @param Request $request
* @return void
*/
public function index(Request $request)
{
return response()->json([
'distribution_pre' => $request->user()->distributionPreIncomes()->pending()->sum('total_revenue'),
'wallet_balance'=> $request->user()->wallet?->balance_format ?? 0,
]);
}
/**
* 预收益明细
*
* @param Request $request
* @return void
*/
public function distributionLogs(Request $request)
{
$perPage = PaginatorHelper::resolvePerPage('per_page', 20, 50);
$distributionLogs = $request->user()->distributionPreIncomes()
->with('logs')
->pending()
->latest('id')
->simplePaginate($perPage);
return DistributionPreIncomeResource::collection($distributionLogs);
}
/**
* 可提明细
*
* @param Request $request
* @return void
*/
public function walletLogs(Request $request)
{
$perPage = PaginatorHelper::resolvePerPage('per_page', 20, 50);
$walletLogs = $request->user()->walletLogs()->filter($request->all())
->latest('id')
->simplePaginate($perPage);
return WalletLogResource::collection($walletLogs);
}
/**
* 余额明细
*
* @return void
*/
public function balanceLogs(Request $request)
{
$perPage = PaginatorHelper::resolvePerPage('per_page', 20, 50);
$walletLogs = $request->user()->balanceLogs()->filter($request->all())
->latest('id')
->simplePaginate($perPage);
return BalanceLogResource::collection($walletLogs);
}
/**
* 钱包付款
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*
* @throws \App\Exceptions\BizException
*/
public function pay(Request $request)
{
$validated = $request->validate([
'pay_sn' => ['bail', 'required'],
'pay_way' => ['bail', 'required', Rule::in([PayLog::PAY_WAY_WALLET, PayLog::PAY_WAY_BALANCE])],
'pay_password' => ['bail', 'required'],
]);
$user = $request->user();
if (! $user->wallet?->verifyPassword($validated['pay_password'])) {
throw new PayPasswordIncorrectException();
}
try {
DB::transaction(function () use ($user, $validated) {
$payLog = PayLog::where('pay_sn', $validated['pay_sn'])
->where('pay_way', $validated['pay_way'])
->lockForUpdate()
->first();
if ($payLog === null) {
throw new InvalidPaySerialNumberException();
}
$payable = $payLog->payable;
if ($payable instanceof Order) {
if ($payLog->isWallet()) {
(new WalletService())->changeBalance($user, -$payable->total_amount, WalletLog::ACTION_ORDER_PAID, '订单-支付', $payable);
} else {
(new BalanceService())->changeBalance($user, -$payable->total_amount, BalanceLog::ACTION_ORDER_PAID, '订单-支付', $payable);
}
}
(new PayService())->handleSuccess($payLog);
});
} catch (InvalidPaySerialNumberException $e) {
throw $e;
} catch (Throwable $e) {
try {
(new PayService())->handleFailedByPaySerialNumber($validated['pay_sn'], [
'failed_reason' => $e->getMessage(),
]);
} catch (Throwable $e) {
report($e);
}
throw $e;
}
return response()->noContent();
}
/**
* 提现到银行
*
* @return void
*/
public function walletToBank(Request $request, WalletService $walletService)
{
$input = $request->validate([
'amount' => ['bail', 'required', 'int', 'min:1'],
'wallet_password' => ['bail', 'required', 'filled', 'string', 'size:6'],
]);
$user = $request->user();
$amount = Arr::get($input, 'amount', 0);
if (is_null($user->bank)) {
throw new BizException('请先绑定设置银行卡');
}
//校验是否冻结
if ($user->wallet->is_frozen) {
throw new WalletFrozenException();
}
//校验是否关闭提现
if (!$user->wallet->withdrawable) {
throw new BizException('可提账户已被限制提现');
}
// todo-校验提现门槛
if (bcdiv($amount, 100, 2) < app_settings('withdraw.threshold_amount', 0)) {
throw new BizException('提现金额需大于'.app_settings('withdraw.threshold_amount', 0).'元');
}
//校验安全密码
if (! $user->wallet?->verifyPassword($input['wallet_password'])) {
throw new PayPasswordIncorrectException();
}
try {
DB::beginTransaction();
$rate = app_settings('withdraw.rate', '0.00');//手续费率
//计算手续费(四舍五入)
$serviceAmount = round($rate*$amount);
//生成提现记录
$log = WalletToBankLog::create([
'user_id' =>$user->id,
'bank_name' => $user->bank->bank_name,
'bank_number' => $user->bank->bank_number,
'bank_description' => $user->bank->bank_description,
'username' => $user->bank->real_name,
'amount'=> $amount,
'rate' => $rate,
'service_amount' => $serviceAmount,
'account_amount' => $amount-$serviceAmount,
]);
//减去用户可提金额
$walletService->changeBalance($user, -$amount, WalletLog::ACTION_WITHDRAW_BANK, '提现-银行卡', $log);
DB::commit();
} catch (WalletNotEnoughException $th) {
DB::rollBack();
throw new BizException('可提金额不足');
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('系统繁忙,请稍后再试');
}
return response()->noContent();
}
/**
* 提现到银行的记录
*
* @return void
*/
public function walletToBankLogs(Request $request)
{
$perPage = PaginatorHelper::resolvePerPage('per_page', 20, 50);
$logs = $request->user()->walletToBankLogs()
->latest('id')
->simplePaginate($perPage);
return WalletToBankLogResource::collection($logs);
}
/**
* 提现到余额
*
* @param Request $request
* @return void
*/
public function walletToBalance(Request $request, WalletService $walletService, BalanceService $balanceService)
{
$input = $request->validate([
'amount' => ['bail', 'required', 'int', 'min:1'],
'wallet_password' => ['bail', 'required', 'filled', 'string', 'size:6'],
]);
$user = $request->user();
//校验是否冻结
if ($user->wallet->is_frozen) {
throw new WalletFrozenException();
}
//校验是否关闭提现
if (!$user->wallet->withdrawable) {
throw new BizException('可提账户已被限制提现');
}
//校验安全密码
if (! $user->wallet?->verifyPassword($input['wallet_password'])) {
throw new PayPasswordIncorrectException();
}
try {
DB::beginTransaction();
//余额添加
$log = $balanceService->changeBalance($user, Arr::get($input, 'amount', 0), BalanceLog::ACTION_WALLET_IN, '可提-转入');
//减去用户可提金额
$walletService->changeBalance($user, -Arr::get($input, 'amount', 0), WalletLog::ACTION_WITHDRAW_BALACNE, '提现-余额', $log);
DB::commit();
} catch (WalletNotEnoughException $th) {
DB::rollBack();
throw new BizException('可提金额不足');
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException('系统繁忙,请稍后再试');
}
return response()->noContent();
}
/**
* 余额转账
*
* @return void
*/
public function balanceTransfer(Request $request, BalanceService $balanceService)
{
$input = $request->validate([
'phone' => ['bail', 'required', new PhoneNumber()],
'amount' => ['bail', 'required', 'int', 'min:1'],
'wallet_password' => ['bail', 'required', 'filled', 'string', 'size:6'],
]);
$user = $request->user();
//校验是否冻结
if ($user->balance->is_frozen) {
throw new BalanceFrozenException();
}
//校验是否关闭转账
if (!$user->balance->transferable) {
throw new BizException('余额账户已被限制转账');
}
//判断转账对象是否存在
$toUser = User::where('phone', '=', $input['phone'])->first();
if (is_null($toUser)) {
throw new BizException('转账对象不存在');
}
//校验安全密码
if (! $user->wallet?->verifyPassword($input['wallet_password'])) {
throw new PayPasswordIncorrectException();
}
try {
DB::beginTransaction();
//转出对象
$log = $balanceService->changeBalance($user, -Arr::get($input, 'amount', 0), BalanceLog::ACTION_TRANSFER_OUT, '转出-'.$toUser->phone);
//转入对象
$balanceService->changeBalance($toUser, Arr::get($input, 'amount', 0), BalanceLog::ACTION_TRANSFER_IN, $toUser->phone.'-转入', $log);
DB::commit();
} catch (Throwable $th) {
DB::rollBack();
report($th);
}
return response()->noContent();
}
}