346 lines
11 KiB
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();
|
|
}
|
|
}
|