Browse Source

商户提现申请

master
weigang 5 years ago
parent
commit
48dbda5349
  1. 16
      app/Constants/v3/ErrorCode.php
  2. 10
      app/Constants/v3/LogLabel.php
  3. 108
      app/Controller/v3/WithdrawController.php
  4. 48
      app/Service/v3/Implementations/PaymentService.php
  5. 1
      app/Service/v3/Interfaces/PaymentServiceInterface.php
  6. 7
      config/autoload/wechat.php
  7. 1
      config/routes.php

16
app/Constants/v3/ErrorCode.php

@ -251,4 +251,20 @@ class ErrorCode extends AbstractConstants
* @Message("优惠券使用失败")
*/
const COUPON_USE_FAILURE = 1202;
/************************************/
/* 提现相关 1251-1300 */
/************************************/
/**
* 提现失败
* @Message("提现失败")
*/
const STORE_WITHDRAW_FAIL = 1251;
/**
* 可提现余额不足
* @Message("可提现余额不足")
*/
const STORE_WITHDRAW_INSUFFICIENT_BALANCE = 1252;
}

10
app/Constants/v3/LogLabel.php

@ -82,4 +82,14 @@ class LogLabel extends AbstractConstants
*/
const COUPON_REFUND_LOG = 'coupon_refund_log';
/**
* @Message("提现失败")
*/
const STORE_WITHDRAW_FAIL_LOG = 'store_withdraw_fail_log';
/**
* @Message("付款到微信钱包失败")
*/
const PAY_TO_WX_FAIL_LOG = 'pay_to_wx_fail_log';
}

108
app/Controller/v3/WithdrawController.php

@ -2,26 +2,46 @@
namespace App\Controller\v3;
use App\Commons\Log;
use App\Constants\v3\ErrorCode;
use App\Constants\v3\LogLabel;
use App\Constants\v3\UserType;
use App\Controller\BaseController;
use App\Exception\ErrorCodeException;
use App\Model\v3\FinancialRecord;
use App\Model\v3\Store;
use App\Model\v3\StoreWithdrawal;
use App\Model\v3\User;
use App\Model\v3\UserBalance;
use App\Service\v3\Interfaces\FinancialRecordServiceInterface;
use App\Service\v3\Interfaces\PaymentServiceInterface;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Snowflake\IdGeneratorInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Validation\ValidationException;
class WithdrawController extends BaseController
{
/**
* @Inject
* @var Log
*/
protected $log;
/**
* @Inject
* @var FinancialRecordServiceInterface
*/
protected $financialService;
/**
* @Inject
* @var PaymentServiceInterface
*/
protected $paymentService;
/**
* 商户提现页数据
* 1、可提现金额
@ -44,8 +64,8 @@ class WithdrawController extends BaseController
throw new ValidationException($validator);
}
$userId = $this->request->input('user_id', 0);
$storeId = $this->request->input('store_id', 0);
$userId = $this->request->input('user_id');
$storeId = $this->request->input('store_id');
$store = Store::query()->where(['user_id' => $userId, 'id' => $storeId])->first();
if (empty($store)) {
throw new ErrorCodeException(ErrorCode::STORE_NOT_AVAILABLE);
@ -77,13 +97,95 @@ class WithdrawController extends BaseController
return $this->success($data);
}
/**
* 商户提现申请
* 1、商户提现参数校验
* 2、商户提现是否超过可提现金额
* 3、提现是否秒到账,秒到账则打款并且做流水,否则就打到后台审核
*/
public function applyByStore()
{
$isDirect = config('wechat.withdrawal.is_direct');
$min = config('wechat.withdrawal.min_amount');
$max = config('wechat.withdrawal.max_amount');
$validator = $this->validationFactory->make(
$this->request->all(),
[
'user_id' => 'required|nonempty'
'user_id' => 'required|nonempty|integer',
'store_id' => 'required|nonempty|integer',
'money' => "required|nonempty|numeric|between:{$min}, {$max}",
]
);
if ($validator->fails()) {
throw new ValidationException($validator);
}
$money = $this->request->input('money');
$userId = $this->request->input('user_id');
$storeId = $this->request->input('store_id');
$store = Store::query()->where(['user_id' => $userId, 'id' => $storeId])->first();
if (empty($store)) {
throw new ErrorCodeException(ErrorCode::STORE_NOT_AVAILABLE);
}
// 校验余额
$balance = UserBalance::query()
->where(['source_id' => $store->user_id, 'user_type' => UserType::STORE])
->first();
if ($money > $balance->balance) {
throw new ErrorCodeException(ErrorCode::STORE_WITHDRAW_INSUFFICIENT_BALANCE);
}
Db::beginTransaction();
try {
$storeUser = User::query()->find($store->user_id);
$currentTime = time();
// 获取分布式全局ID
$generator = ApplicationContext::getContainer()->get(IdGeneratorInterface::class);
$globalOrderId = $generator->generate();
// 记录提现申请记录
$withdraw = new StoreWithdrawal();
$withdraw->trade_no = $globalOrderId;
$withdraw->store_id = $store->id;
$withdraw->name = $storeUser->real_name ?? $storeUser->nick_name;
$withdraw->tel = $storeUser->tel;
$withdraw->apply_cash = $money;
$withdraw->save();
// 扣除余额
$balance->balance = bcsub($balance->balance, $money, 2);
$balance->save();
// 如果秒到账无需审核的话
if ($isDirect) {
// 打款
$res = $this->paymentService->payToWx(
bcmul($withdraw->apply_cash, 100 , 0),
$withdraw->trade_no,
$storeUser->openid,
$withdraw->name,
'商户提现打款'
);
// 更新打款金额,审核时间等
}
Db::commit();
return $this->success([]);
} catch (\Exception $e) {
Db::rollBack();
$this->log->event(LogLabel::STORE_WITHDRAW_FAIL_LOG, [
'exception' => $e->getMessage(),
'withdraw' => json_encode($withdraw),
'params' => json_encode(['balance' => $balance->balance, 'user_id' => $userId, 'store_id' => $storeId]),
]);
throw new ErrorCodeException(ErrorCode::STORE_WITHDRAW_FAIL, $e->getMessage());
}
}
}

48
app/Service/v3/Implementations/PaymentService.php

@ -12,6 +12,7 @@ use App\Model\v3\User;
use App\Service\v3\Interfaces\GoodsActivityServiceInterface;
use App\Service\v3\Interfaces\PaymentServiceInterface;
use EasyWeChat\Factory;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Guzzle\CoroutineHandler;
use Hyperf\Di\Annotation\Inject;
@ -97,6 +98,53 @@ class PaymentService implements PaymentServiceInterface
// TODO: Implement undo() method.
}
/**
* 企业付款到微信钱包
* @param $money
* @param $tradeNo
* @param $openId
* @param $userName
* @param string $desc
* @param string $checkName
* @throws GuzzleException
*/
public function payToWx($money, $tradeNo, $openId, $userName, $desc = '', $checkName = 'NO_CHECK')
{
$config = config('wxpay');
$app = Factory::payment($config);
$app['guzzle_handler'] = CoroutineHandler::class;
$result = $app->transfer->toBalance([
'partner_trade_no' => $tradeNo, // 商户订单号,需保持唯一性(只能是字母或者数字,不能包含有符号)
'openid' => $openId,
'check_name' => $checkName, // NO_CHECK:不校验真实姓名, FORCE_CHECK:强校验真实姓名
're_user_name' => $userName, // 如果 check_name 设置为FORCE_CHECK,则必填用户真实姓名
'amount' => $money, // 企业付款金额,单位为分
'desc' => $desc, // 企业付款操作说明信息
]);
if ($result['return_code'] != 'SUCCESS') {
$this->log->event(LogLabel::PAY_TO_WX_FAIL_LOG, [
'exception_payToWx' => $result['return_msg'],
'result' => json_encode($result),
'desc' => $desc
]);
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, $result['return_msg']);
}
if ($result['result_code'] != 'SUCCESS') {
$this->log->event(LogLabel::PAY_TO_WX_FAIL_LOG, [
'exception_payToWx' => $result['err_code_des'],
'result' => json_encode($result),
'desc' => $desc
]);
throw new ErrorCodeException(ErrorCode::PAYMENT_FAIL, $result['err_code_des']);
}
return true;
}
/**
* 支付参数加签
* @param $parameters

1
app/Service/v3/Interfaces/PaymentServiceInterface.php

@ -7,4 +7,5 @@ interface PaymentServiceInterface
public function do($globalOrderId, $money, $userId, $notifyUrl);
public function check();
public function undo();
public function payToWx($money, $tradeNo, $openId, $userName, $desc = '', $checkName = 'NO_CHECK');
}

7
config/autoload/wechat.php

@ -14,5 +14,10 @@ return [
'notify_url' => [
'online' => env('SITE_HOST') . '/v3/wechat/notify/online',
'offline' => env('SITE_HOST') . '/v3/wechat/notify/offline',
]
],
'withdrawal' => [
'is_direct' => env('WITHDRAW_IS_DIRECT'),
'min_amount' => env('WITHDRAW_MIN_AMOUNT'),
'max_amount' => env('WITHDRAW_MAX_AMOUNT'),
],
];

1
config/routes.php

@ -138,6 +138,7 @@ Router::addGroup('/v3/', function () {
Router::post('user/oflOrders', 'App\Controller\v3\OrderListController@offlineForUser');
Router::post('shopCart/delete', 'App\Controller\v3\ShopCartUpdateController@delete');
Router::post('withdraw/pageByStore', 'App\Controller\v3\WithdrawController@pageByStore');
Router::post('withdraw/applyByStore', 'App\Controller\v3\WithdrawController@applyByStore');
},['middleware' => [\App\Middleware\Auth\ApiMiddleware::class, \App\Middleware\Auth\UserMiddleware::class]]);
// 微信支付回调

Loading…
Cancel
Save