6
0
Fork 0

钱包(可提现)付款

release
李静 2021-12-27 21:32:49 +08:00
parent 2b215a615c
commit 2724be081a
14 changed files with 188 additions and 30 deletions

View File

@ -5,8 +5,16 @@ namespace App\Endpoint\Api\Http\Controllers\Account;
use App\Endpoint\Api\Http\Controllers\Controller;
use App\Endpoint\Api\Http\Resources\DistributionPreIncomeResource;
use App\Endpoint\Api\Http\Resources\WalletLogResource;
use App\Exceptions\BizException;
use App\Helpers\Paginator as PaginatorHelper;
use App\Models\Order;
use App\Models\PayLog;
use App\Models\WalletLog;
use App\Services\PayService;
use App\Services\WalletService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
class WalletController extends Controller
{
@ -51,14 +59,10 @@ class WalletController extends Controller
public function walletLogs(Request $request)
{
$perPage = PaginatorHelper::resolvePerPage('per_page', 20, 50);
$walletLogs = $request->user()->wallet?->logs()
$walletLogs = $request->user()->walletLogs()
->latest('id')
->simplePaginate($perPage);
if (is_null($walletLogs)) {
return response()->json([
'data'=>[],
]);
}
return WalletLogResource::collection($walletLogs);
}
@ -71,4 +75,53 @@ class WalletController extends Controller
public function balanceLogs(Request $request)
{
}
/**
* 钱包付款
*
* @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'],
]);
$user = $request->user();
try {
DB::transaction(function () use ($user, $validated) {
$payLog = PayLog::where('pay_sn', $validated['pay_sn'])->lockForUpdate()->firstOrFail();
$payable = $payLog->payable;
switch (get_class($payable)) {
case Order::class:
(new WalletService())->changeBalance($user, -$payable->total_amount, WalletLog::ACTION_ORDER_PAY, '订单支付扣款', $payable);
break;
default:
throw new BizException('非法操作');
break;
}
(new PayService())->handleSuccess($payLog);
});
} catch (Throwable $e) {
try {
(new PayService())->handleFailedByPaySerialNumber($validated['pay_sn'], [
'failed_reason' => $e->getMessage(),
]);
} catch (Throwable $e) {
report($e);
}
throw $e;
}
return response()->noContent();
}
}

View File

@ -15,9 +15,9 @@ class WalletLogResource extends JsonResource
public function toArray($request)
{
return [
'remarks' => $this->remarks,
'created_at' => $this->created_at->toDateTimeString(),
'fee' => $this->fee_format,
'remarks' => $this->remarks,
'created_at' => $this->created_at->toDateTimeString(),
'change_balance' => $this->change_balance,
];
}
}

View File

@ -91,6 +91,7 @@ Route::group([
Route::get('wallet', [WalletController::class, 'index']);
Route::get('wallet/distribution-logs', [WalletController::class, 'distributionLogs']);
Route::get('wallet/wallet-logs', [WalletController::class, 'walletLogs']);
Route::post('wallet/pay', [WalletController::class, 'pay']);
//银行卡
Route::get('user-bank', [UserBankController::class, 'show']);

View File

@ -17,6 +17,7 @@ class PayLog extends Model
public const PAY_WAY_WXPAY_JSAPI = 'wxpay_jsapi'; // 微信支付 - JSAPI 支付
public const PAY_WAY_WXPAY_MINI = 'wxpay_mini'; // 微信支付 - 小程序支付
public const PAY_WAY_WXPAY_H5 = 'wxpay_h5'; // 微信支付 - H5 支付
public const PAY_WAY_WALLET = 'wallet'; // 钱包付款(可提现)
public const PAY_WAY_BALANCE = 'balance'; // 余额支付
public const PAY_WAY_OFFLINE = 'offline'; // 线下支付
@ -86,4 +87,14 @@ class PayLog extends Model
{
return $this->pay_way === static::PAY_WAY_OFFLINE;
}
/**
* 确认支付方式是否是钱包付款
*
* @return bool
*/
public function isWallet(): bool
{
return $this->pay_way === static::PAY_WAY_WALLET;
}
}

View File

@ -188,6 +188,14 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac
return $this->hasOne(Wallet::class, 'user_id');
}
/**
* 用户的钱包日志
*/
public function walletLogs()
{
return $this->hasMany(WalletLog::class, 'user_id');
}
/**
* 用户的预收益
*/
@ -270,6 +278,22 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac
];
}
/**
* 获取此用户的钱包并加行锁
*
* @return \App\Models\Wallet
*/
public function lockWallet(): Wallet
{
if ($wallet = $this->wallet()->lockForUpdate()->first()) {
return $wallet;
}
$this->wallet()->create();
return $this->wallet()->lockForUpdate()->first();
}
/**
* 创建用户
*
@ -290,8 +314,8 @@ class User extends Model implements AuthorizableContract, AuthenticatableContrac
'inviter_id' => null,
'depth' => 1,
'path' => '/',
])
;
]
);
return $user;
}

View File

@ -20,6 +20,9 @@ class Wallet extends Model
* @var array
*/
protected $attributes = [
'balance' => 0,
'total_revenue' => 0,
'total_expenses' => 0,
'withdrawable' => true,
];
@ -42,15 +45,6 @@ class Wallet extends Model
'withdrawable' => 'bool',
];
/**
* 资产日志
*
*/
public function logs()
{
return $this->hasMany(WalletLog::class, 'wallet_id');
}
/**
* 设置此用户的安全密码
*

View File

@ -7,13 +7,28 @@ use Illuminate\Database\Eloquent\Model;
class WalletLog extends Model
{
public const ACTION_ORDER_PAY = 1;
/**
* @var array
*/
protected $fillable = [
'user_id',
'loggable_id',
'loggable_type',
'action',
'before_balance',
'change_balance',
'remarks',
];
/**
* 获取变动金额
*
* @return string
*/
public function getFeeFormatAttribute()
public function getChangeBalanceFormatAttribute()
{
return Numeric::trimTrailingZero(bcdiv($this->attributes['fee'], 100, 2));
return Numeric::trimTrailingZero(bcdiv($this->attributes['change_balance'], 100, 2));
}
}

View File

@ -185,8 +185,6 @@ class OrderService
$totalAmount += $shippingFee;
$totalAmount=0;
do {
// 如果订单号重复,则直接重试
try {
@ -783,6 +781,11 @@ class OrderService
'trade_type' => WeChatPayService::$tradeTypes[$payLog->pay_way],
]);
}
return [
'pay_sn' => $payLog->pay_sn,
'pay_way' => $payLog->pay_way,
];
}
/**

View File

@ -37,7 +37,7 @@ class PayService
public function handleSuccess(PayLog $payLog, array $params = []): PayLog
{
if (! $payLog->isPending()) {
throw new BizException('支付记录状态异常');
throw new BizException('支付异常');
}
$payLog->update([
@ -109,7 +109,7 @@ class PayService
public function handleFailed(PayLog $payLog, array $params = []): PayLog
{
if (! $payLog->isPending()) {
throw new BizException('支付记录状态异常');
throw new BizException('支付异常');
}
$payLog->update([

View File

@ -0,0 +1,57 @@
<?php
namespace App\Services;
use App\Exceptions\BizException;
use App\Models\User;
use Illuminate\Support\Facades\DB;
class WalletService
{
/**
* 变更钱包余额
*
* @param \App\Models\User $user
* @param int $changeBalance
* @param int $action
* @param string|null $remarks
* @param mixed $loggable
* @return void
*/
public function changeBalance(User $user, int $changeBalance, int $action, ?string $remarks = null, $loggable = null)
{
$wallet = $user->lockWallet();
// 变更前余额
$beforeBalance = $wallet->balance;
$_balance = abs($changeBalance);
if ($changeBalance > 0) {
// 收入
$user->wallet()->update([
'balance' => DB::raw("balance + {$_balance}"),
'total_revenue' => DB::raw("total_revenue + {$_balance}"),
]);
} else {
// 支出
if ($wallet->balance < $_balance) {
throw new BizException('可提现金额不足');
}
$user->wallet()->update([
'balance' => DB::raw("balance - {$_balance}"),
'total_expenses' => DB::raw("total_expenses + {$_balance}"),
]);
}
$user->walletLogs()->create([
'loggable_id' => $loggable?->id,
'loggable_type' => $loggable?->getMorphClass(),
'before_balance' => $beforeBalance,
'change_balance' => $changeBalance,
'action' => $action,
'remarks' => $remarks,
]);
}
}

View File

@ -21,7 +21,7 @@ class CreateOrderRefundLogsTable extends Migration
$table->unsignedBigInteger('amount')->comment('退款金额');
$table->tinyInteger('status')->default(0)->comment('状态');
$table->string('reason')->nullable()->comment('退款原因');
$table->string('failed_reason')->nullable()->comment('失败原因');
$table->text('failed_reason')->nullable()->comment('失败原因');
$table->timestamps();
$table->unique(['order_id', 'after_sale_id']);

View File

@ -18,7 +18,7 @@ class CreateDistributionPreIncomeJobsTable extends Migration
$table->morphs('jobable');
$table->tinyInteger('status')->default(0)->comment('状态');
$table->string('remarks')->nullable()->comment('备注');
$table->string('failed_reason')->nullable()->comment('失败原因');
$table->text('failed_reason')->nullable()->comment('失败原因');
$table->timestamps();
});
}

View File

@ -19,7 +19,7 @@ class CreateWalletLogsTable extends Migration
$table->nullableMorphs('loggable');
$table->tinyInteger('action')->comment('操作类型');
$table->unsignedBigInteger('before_balance')->default(0)->comment('变更前的余额');
$table->bigInteger('fee')->default(0)->comment('变动额(分)');
$table->bigInteger('change_balance')->default(0)->comment('变动额(分)');
$table->string('remarks')->nullable()->comment('备注');
$table->timestamps();

View File

@ -21,7 +21,7 @@ class CreatePayLogsTable extends Migration
$table->string('out_trade_no')->nullable()->comment('外部交易单号');
$table->timestamp('pay_at')->nullable()->comment('支付时间');
$table->tinyInteger('status')->comment('状态: 0 待付款, 1 支付成功, 2 支付失败');
$table->string('failed_reason')->nullable()->comment('失败原因');
$table->text('failed_reason')->nullable()->comment('失败原因');
$table->timestamps();
});
}