6
0
Fork 0
release
李静 2022-04-12 14:38:31 +08:00
parent 7cebf43fdf
commit e17a2b9357
13 changed files with 339 additions and 13 deletions

View File

@ -51,7 +51,7 @@ class WalletToBankLogController extends AdminController
$grid->model()->orderBy('created_at', 'desc');
$grid->actions(function (Grid\Displayers\Actions $actions) {
if ($actions->row->status == WalletToBankLogStatus::Pending && Admin::user()->can('dcat.admin.wallet_to_bank_logs.verify')) {
if (in_array($actions->row->status, [WalletToBankLogStatus::Pending, WalletToBankLogStatus::Failed]) && Admin::user()->can('dcat.admin.wallet_to_bank_logs.verify')) {
$actions->append(new WalletToBankLogVerify());
}
});

View File

@ -2,6 +2,9 @@
namespace App\Admin\Forms;
use App\Enums\WalletToBankLogPayWay;
use App\Enums\WalletToBankLogStatus;
use App\Exceptions\BizException;
use App\Models\WalletLog;
use App\Models\WalletToBankLog;
use App\Services\WalletService;
@ -34,15 +37,37 @@ class WalletToBankLogVerify extends Form implements LazyRenderable
*/
public function handle(array $input)
{
$id = $this->payload['id'] ?? 0;
$log = WalletToBankLog::findOrFail($id);
try {
DB::beginTransaction();
$log->update($input);
//如果拒绝,重新添加对应可提金额
if ($log->status == 2) {
$walletService = new WalletService();
$walletService->changeBalance($log->user, $log->amount, WalletLog::ACTION_WITHDRAW_FAILED, '提现-失败', $log);
$log = WalletToBankLog::lockForUpdate()->findOrFail($this->payload['id']);
if (! in_array($log->status, [WalletToBankLogStatus::Pending, WalletToBankLogStatus::Failed])) {
throw new BizException('提现记录状态异常');
}
if ($input['status'] == 1) {
$log->pay_way = $input['pay_way'];
if ($log->pay_way === WalletToBankLogPayWay::Offline) {
$log->status = WalletToBankLogStatus::Success;
$log->pay_at = now();
} else {
$log->pay_sn = serial_number();
$log->status = WalletToBankLogStatus::Passed;
}
$log->failed_reason = null;
} else {
$log->status = WalletToBankLogStatus::Refused;
}
$log->remarks = $input['remarks'];
$log->save();
// 如果拒绝,退换扣除金额
if ($log->status === WalletToBankLogStatus::Refused) {
(new WalletService())->changeBalance($log->user, $log->amount, WalletLog::ACTION_WITHDRAW_FAILED, '提现-失败', $log);
}
DB::commit();
@ -65,7 +90,6 @@ class WalletToBankLogVerify extends Form implements LazyRenderable
$id = $this->payload['id'] ?? 0;
$log = WalletToBankLog::findOrFail($id);
$this->text('bank_name')->value($log->bank_name)->disable();
$this->text('bank_number')->value($log->bank_number)->disable();
$this->text('username')->value($log->username)->disable();
@ -75,11 +99,19 @@ class WalletToBankLogVerify extends Form implements LazyRenderable
$this->currency('service_amount')->symbol('¥')->value(bcdiv($log->service_amount, 100, 2))->disable();
$this->currency('account_amount')->symbol('¥')->value(bcdiv($log->account_amount, 100, 2))->disable();
$this->radio('status')->options([
1 => '通过',
2 => '拒绝',
])->default(1);
if ($log->status === WalletToBankLogStatus::Failed) {
$this->textarea('failed_reason')->value($log->failed_reason ?: '')->disable();
}
$this->radio('status')
->options([
1 => '通过',
2 => '拒绝',
])
->default(1);
$this->select('pay_way')
->options(WalletToBankLogPayWay::texts())
->rules('required_if:status,1', ['required_if'=>'请选择支付方式']);
$this->text('remarks')->rules('required_if:status,2', ['required_if'=>'拒绝时需要填写备注']);
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace App\Console\Commands;
use App\Enums\Bank;
use App\Enums\WalletToBankLogStatus;
use App\Exceptions\YeePayException;
use App\Models\WalletToBankLog;
use App\Services\YeePayService;
use Illuminate\Console\Command;
use Throwable;
class WalletToBankCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'wallet-to-bank';
/**
* The console command description.
*
* @var string
*/
protected $description = '可提提现';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$yeePayService = new YeePayService(config('services.yeepay'));
while (true) {
WalletToBankLog::where('status', WalletToBankLogStatus::Passed)->chunkById(1, function ($logs) use ($yeePayService) {
foreach ($logs as $log) {
try {
$result = $yeePayService->request('accountpay.behalf.Pay', [
'payerOutUserId' => '21102510220227100003' ?: config('services.yeepay.partner_id'),
'merchOrderNo' => $log->pay_sn,
'tradeName' => '余额提现',
'payeeUserName' => $log->username,
'bankCardNo' => $log->bank_number,
'bankCode' => Bank::tryFromBankName($log->bank_name)?->name,
'bankCardType' => 'DEBIT_CARD',
'amount' => bcdiv($log->account_amount, 100, 2),
'feeRole' => 'PAYER',
'tradeMemo' => '商城余额提现',
]);
if ($result['orderStatus'] === 'SUCCESS') {
$log->update([
'status' => WalletToBankLogStatus::Success,
'pay_at' => now(),
'failed_reason' => null,
]);
} elseif ($result['orderStatus'] === 'FAIL') {
$log->update([
'status' => WalletToBankLogStatus::Failed,
'failed_reason' => '交易失败',
]);
} else {
$log->update([
'status' => WalletToBankLogStatus::Paying,
'failed_reason' => null,
]);
}
} catch (YeePayException $e) {
$log->update([
'status' => WalletToBankLogStatus::Failed,
'failed_reason' => $e->getMessage(),
]);
} catch (Throwable $e) {
throw $e;
}
}
});
sleep(60);
}
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Endpoint\Callback\Http\Controllers;
use Illuminate\Http\Request;
class YeePayNotifyController extends Controller
{
public function __invoke(Request $request)
{
logger()->debug('yeepay notify', $request->input());
}
}

View File

@ -3,6 +3,7 @@
use App\Endpoint\Callback\Http\Controllers\AlipayController;
use App\Endpoint\Callback\Http\Controllers\Kuaidi100Controller;
use App\Endpoint\Callback\Http\Controllers\WxpayController;
use App\Endpoint\Callback\Http\Controllers\YeePayNotifyController;
use Illuminate\Support\Facades\Route;
//快递100物流推送
@ -13,3 +14,5 @@ Route::post('wxpay/{payment}/paid-notify', [WxpayController::class, 'paidNotify'
Route::post('wxpay/{payment}/order-refund-notify', [WxpayController::class, 'orderRefundedNotify'])->name('wxpay.order_refund_notify');
Route::post('alipay', AlipayController::class)->name('alipay.notify');
Route::post('yeepay-notify', YeePayNotifyController::class)->name('yeepay.notify');

View File

@ -0,0 +1,38 @@
<?php
namespace App\Enums;
enum WalletToBankLogPayWay: int {
case Offline = 1;
case Behalf = 2;
/**
* @return string
*/
public function color(): string
{
return match ($this) {
static::Offline => '#5b69bc',
static::Behalf => '#21b978',
};
}
/**
* @return string
*/
public function text(): string
{
return static::texts()[$this->value];
}
/**
* @return array
*/
public static function texts(): array
{
return [
static::Offline->value => '线下',
static::Behalf->value => '代付',
];
}
}

View File

@ -6,6 +6,9 @@ enum WalletToBankLogStatus: int {
case Pending = 0;
case Success = 1;
case Refused = 2;
case Passed = 3; // 审核通过 - 等待付款
case Paying = 4; // 审核通过 - 付款中
case Failed = 9;
/**
* @return string
@ -14,7 +17,10 @@ enum WalletToBankLogStatus: int {
{
return match ($this) {
static::Pending => '#5b69bc',
static::Passed => '#dda451',
static::Paying => '#3085d6',
static::Success => '#21b978',
static::Failed => '#ea5455',
static::Refused => '#b3b9bf',
};
}
@ -34,7 +40,10 @@ enum WalletToBankLogStatus: int {
{
return [
static::Pending->value => '待处理',
static::Passed->value => '待付款',
static::Paying->value => '付款中',
static::Success->value => '成功',
static::Failed->value => '失败',
static::Refused->value => '拒绝',
];
}

View File

@ -0,0 +1,9 @@
<?php
namespace App\Exceptions;
use Exception;
class YeePayException extends Exception
{
}

View File

@ -2,6 +2,7 @@
namespace App\Models;
use App\Enums\WalletToBankLogPayWay;
use App\Enums\WalletToBankLogStatus;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@ -14,6 +15,8 @@ class WalletToBankLog extends Model
protected $casts = [
'status' => WalletToBankLogStatus::class,
'pay_way' => WalletToBankLogPayWay::class,
'pay_at' => 'datetime',
];
/**
@ -31,6 +34,10 @@ class WalletToBankLog extends Model
'rate',
'service_amount',
'account_amount',
'pay_sn',
'pay_way',
'pay_at',
'failed_reason',
];
/**

View File

@ -0,0 +1,82 @@
<?php
namespace App\Services;
use App\Exceptions\YeePayException;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
class YeePayService
{
public function __construct(
protected array $config,
) {
}
/**
* @param string $service
* @param array $data
* @return array
*/
public function request(string $service, array $data = []): array
{
$data = array_merge([
'requestNo' => Str::uuid()->getHex()->toString(),
'service' => $service,
'partnerId' => $this->config['partner_id'],
'signType' => 'MD5',
'notifyUrl' => route('yeepay.notify'),
], $data);
$data['sign'] = $this->sign($data);
$response = Http::asForm()->post($this->config['gateway_url'], $data);
$response->throw();
$result = $response->json();
if ($result['success'] && in_array($result['resultCode'], ['EXECUTE_SUCCESS', 'EXECUTE_PROCESSING'])) {
return $result;
}
$message = $result['resultDetail'] ?? $result['resultMessage'];
throw new YeePayException($message);
}
/**
* 生成签名
*
* @param array $params
* @return string
*/
protected function sign(array $params): string
{
unset($params['sign']);
ksort($params);
$str = '';
foreach ($params as $key => $value) {
if (blank($value)) {
continue;
}
if ($str !== '') {
$str .= '&';
}
if (is_array($value)) {
$value = json_encode($value);
}
$str .= "{$key}={$value}";
}
$str .= $this->config['secret_key'];
return md5($str);
}
}

View File

@ -30,4 +30,10 @@ return [
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'yeepay' => [
'partner_id' => env('YEEPAY_PARTNER_ID'),
'secret_key' => env('YEEPAY_SECRET_KEY'),
'gateway_url' => env('YEEPAY_GATEWAY_URL'),
],
];

View File

@ -0,0 +1,38 @@
<?php
use App\Enums\WalletToBankLogPayWay;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPayColumnsToWalletToBankLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('wallet_to_bank_logs', function (Blueprint $table) {
$table->string('pay_sn')->nullable()->comment('支付单号');
$table->tinyInteger('pay_way')->default(WalletToBankLogPayWay::Offline->value)->comment('支付方式: 1 线下, 2 代付');
$table->timestamp('pay_at')->nullable()->comment('支付时间');
$table->text('failed_reason')->nullable()->comment('失败原因');
$table->unique('pay_sn');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('wallet_to_bank_logs', function (Blueprint $table) {
$table->dropColumn(['pay_sn', 'pay_way', 'failed_reason', 'pay_at']);
});
}
}

View File

@ -17,6 +17,9 @@ return [
'status' => '状态',
'remarks' => '备注',
'created_at'=> '申请时间',
'pay_way' => '支付方式',
'pay_at' => '支付时间',
'failed_reason' => '失败原因',
'user'=>[
'phone' => '申请人',
],