扣款失败后,重试扣款
This commit is contained in:
parent
6f331a22d5
commit
ce08f7866d
|
@ -65,7 +65,7 @@ class AgreementPaySendSms extends Command
|
||||||
// 开始发送扣款短信
|
// 开始发送扣款短信
|
||||||
$res = AliSms::sendSms(['phone_numbers' => $collection->mobile], 3);
|
$res = AliSms::sendSms(['phone_numbers' => $collection->mobile], 3);
|
||||||
$redis->set($cacheKey, true, 'ex', $cacheKeys['ttl']);
|
$redis->set($cacheKey, true, 'ex', $cacheKeys['ttl']);
|
||||||
if ($res['code'] == "OK") {
|
if ($res['code'] == 200) {
|
||||||
$this->successCount += 1;
|
$this->successCount += 1;
|
||||||
$output->writeln("短信发送受理成功");
|
$output->writeln("短信发送受理成功");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\cmd;
|
||||||
|
|
||||||
|
use app\model\Order;
|
||||||
|
use app\model\Sign;
|
||||||
|
use app\service\AgreementService;
|
||||||
|
use think\Collection;
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\Output;
|
||||||
|
use think\facade\Log;
|
||||||
|
|
||||||
|
class PayOrderRetry extends Command
|
||||||
|
{
|
||||||
|
protected int $count = 0;
|
||||||
|
protected int $successCount = 0;
|
||||||
|
protected int $failedCount = 0;
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('PayOrderRetry')->setDescription('重试扣款失败的订单');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有失败订单每天重试一次,重试到订单创建时间的月底。如果还是失败就进行解约操作
|
||||||
|
* 每天11点执行
|
||||||
|
* @param Input $input
|
||||||
|
* @param Output $output
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function execute(Input $input, Output $output)
|
||||||
|
{
|
||||||
|
// 本月内的支付失败订单
|
||||||
|
// 获取本月的开始时间
|
||||||
|
$startOfMonth = new \DateTime('first day of this month 00:00:00');
|
||||||
|
$startOfMonthFormatted = $startOfMonth->format('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
// 获取本月的结束时间
|
||||||
|
$endOfMonth = new \DateTime('last day of this month 23:59:59');
|
||||||
|
$endOfMonthFormatted = $endOfMonth->format('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
Order::where(['pay_status' => Order::PAY_STATUS_FAIL])->whereBetweenTime('create_time', strtotime($startOfMonthFormatted), strtotime($endOfMonthFormatted))
|
||||||
|
->where(['is_retry' => Order::RETRY_STATUS_NO])
|
||||||
|
->field('id,order_number,agreement_id,user_id')->chunk(100, function (Collection $orderCollection) use (&$output) {
|
||||||
|
// 拉取支付失败的订单
|
||||||
|
foreach ($orderCollection as $order) {
|
||||||
|
// 查询签约状态是否取消
|
||||||
|
$signInfo = Sign::getByAgreementId($order->agreement_id);
|
||||||
|
if ($signInfo->isEmpty() || $signInfo->sign_status != Order::STATUS_SIGNED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$res = AgreementService::RetryPayOrder($order->order_number, $signInfo->agreement_id);
|
||||||
|
if ($res['respCode'] == 1000) {
|
||||||
|
$this->successCount += 1;
|
||||||
|
$output->writeln("受理成功,等待支付通知");
|
||||||
|
} else {
|
||||||
|
$this->failedCount += 1;
|
||||||
|
$output->writeln("用户" . $order->user_id . "扣款失败:" . $res['respMsg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Log::info(sprintf("扣款job执行情况:执行成功,累计 %s, 受理成功 %s, 失败 %s", $this->count, $this->successCount, $this->failedCount));
|
||||||
|
$output->writeln(sprintf("重试扣款失败的订单执行成功,累计 %s, 受理成功 %s, 失败 %s", $this->count, $this->successCount, $this->failedCount));
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace app\front;
|
namespace app\front;
|
||||||
|
|
||||||
use app\config\ResponseCode;
|
|
||||||
use app\service\CmbService;
|
use app\service\CmbService;
|
||||||
use app\service\OrderService;
|
use app\service\OrderService;
|
||||||
use app\service\RechargeService;
|
use app\service\RechargeService;
|
||||||
|
@ -12,7 +11,11 @@ class Order extends Base
|
||||||
{
|
{
|
||||||
public function list(Request $request): \think\Response
|
public function list(Request $request): \think\Response
|
||||||
{
|
{
|
||||||
|
if (empty($request->user_id)) {
|
||||||
|
return responseOk();
|
||||||
|
}
|
||||||
$params['user_id'] = $request->user_id;
|
$params['user_id'] = $request->user_id;
|
||||||
|
$params['is_retry'] = \app\model\Order::RETRY_STATUS_NO;
|
||||||
return responseOk(app()->make(OrderService::class)->list($params));
|
return responseOk(app()->make(OrderService::class)->list($params));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ class Order extends BaseModel
|
||||||
const REFUND_STATUS_WAIT = 1;
|
const REFUND_STATUS_WAIT = 1;
|
||||||
const REFUND_STATUS_SUCCESS = 2;
|
const REFUND_STATUS_SUCCESS = 2;
|
||||||
const REFUND_STATUS_FAIL = 3;
|
const REFUND_STATUS_FAIL = 3;
|
||||||
|
// 重试状态
|
||||||
|
const RETRY_STATUS_NO = 0; // 未重试
|
||||||
|
const RETRY_STATUS_YES = 1; // 已重试
|
||||||
|
|
||||||
const STATUS_TEXT = [
|
const STATUS_TEXT = [
|
||||||
self::STATUS_WAIT_SIGN => '待签约',
|
self::STATUS_WAIT_SIGN => '待签约',
|
||||||
|
|
|
@ -216,6 +216,68 @@ class AgreementService extends BaseService
|
||||||
return CmbHttpUtils::doPost($funcName, $requestParams);
|
return CmbHttpUtils::doPost($funcName, $requestParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扣款失败,重试
|
||||||
|
*
|
||||||
|
* @param string $orderNumber
|
||||||
|
* @param string $agreementId
|
||||||
|
* @return array|mixed|string
|
||||||
|
*/
|
||||||
|
public static function RetryPayOrder(string $orderNumber, string $agreementId)
|
||||||
|
{
|
||||||
|
// 判断订单状态是否正确
|
||||||
|
$order = Order::getByOrderNumber($orderNumber);
|
||||||
|
if ($order->isEmpty() || $order->pay_status != Order::PAY_STATUS_FAIL || $order->is_retry == Order::RETRY_STATUS_YES) {
|
||||||
|
return ['respCode' => 1000, 'respMsg' => '处理成功'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理订单再次扣款
|
||||||
|
// 创建新的订单
|
||||||
|
$productId = $order->product_id;
|
||||||
|
$product = Product::getBySupplierProductId($productId);
|
||||||
|
$newOrder = [
|
||||||
|
'user_id' => $order->user_id,
|
||||||
|
'order_number' => StringUtil::makeOrderNumber(),
|
||||||
|
'account' => $order->account,
|
||||||
|
'type' => $order->type,
|
||||||
|
'product_id' => $order->product_id,
|
||||||
|
'price' => $order->price,
|
||||||
|
'bonus' => $order->bonus,
|
||||||
|
'agreement_id' => $order->agreement_id,
|
||||||
|
'order_status' => Order::STATUS_SIGNED
|
||||||
|
];
|
||||||
|
|
||||||
|
// 生成重试订单
|
||||||
|
Db::startTrans();
|
||||||
|
try {
|
||||||
|
// 创建新订单
|
||||||
|
Order::create($newOrder);
|
||||||
|
// 更新老订单
|
||||||
|
$order->is_retry = Order::RETRY_STATUS_YES;
|
||||||
|
$order->retry_order_num = $newOrder['order_number'];
|
||||||
|
$res = $order->save();
|
||||||
|
if (!$res) {
|
||||||
|
throw new \Exception("重试支付,更新老订单失败,订单号:" . $orderNumber);
|
||||||
|
}
|
||||||
|
Db::commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Db::rollback();
|
||||||
|
Log::error("Job:PayOrderRetry,错误信息:" . $e->getMessage());
|
||||||
|
return ['respCode' => 1001, 'respMsg' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扣款参数
|
||||||
|
$requestParams = [
|
||||||
|
'agreementId' => $agreementId,
|
||||||
|
'billNo' => $newOrder['order_number'],
|
||||||
|
'amount' => $newOrder['price'] * 100,
|
||||||
|
'notifyUrl' => config('cmb.pay_notify_url'),
|
||||||
|
'productName' => $product['name']
|
||||||
|
];
|
||||||
|
$funcName = 'agreementPay';
|
||||||
|
return CmbHttpUtils::doPost($funcName, $requestParams);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 协议扣款回调处理
|
* 协议扣款回调处理
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
@ -252,6 +314,10 @@ class AgreementService extends BaseService
|
||||||
if ($encryptData['result'] == 2) {
|
if ($encryptData['result'] == 2) {
|
||||||
RechargeService::rechargeOrder($orderNumber); // 支付成功,到直连天下充值
|
RechargeService::rechargeOrder($orderNumber); // 支付成功,到直连天下充值
|
||||||
}
|
}
|
||||||
|
// 支付失败
|
||||||
|
if ($encryptData['result'] == 3 && BaseService::isLastDayOfMonth()) {
|
||||||
|
CmbService::releaseMerchant($order->agreement_id);
|
||||||
|
}
|
||||||
if ($res) {
|
if ($res) {
|
||||||
return ['respCode' => 1000, 'respMsg' => '处理成功'];
|
return ['respCode' => 1000, 'respMsg' => '处理成功'];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -59,4 +59,14 @@ class BaseService
|
||||||
//找不到方法,自动调用模型中基类方法
|
//找不到方法,自动调用模型中基类方法
|
||||||
return call_user_func_array([$this->model, $name], $arguments);
|
return call_user_func_array([$this->model, $name], $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isLastDayOfMonth()
|
||||||
|
{
|
||||||
|
$date = date('Y-m-d');
|
||||||
|
// 获取该月的最后一天
|
||||||
|
$lastDayOfMonth = date('Y-m-t', strtotime($date));
|
||||||
|
|
||||||
|
// 比较给定日期和该月的最后一天
|
||||||
|
return $date === $lastDayOfMonth;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -167,7 +167,8 @@ class CmbService extends BaseService
|
||||||
if ($res['result'] == 2) { // 扣款成功
|
if ($res['result'] == 2) { // 扣款成功
|
||||||
RechargeService::rechargeOrder($orderNumber);
|
RechargeService::rechargeOrder($orderNumber);
|
||||||
}
|
}
|
||||||
if ($res['result'] == 3) { // 扣款失败 解约
|
// 月底不进行重试,失败直接解约
|
||||||
|
if ($res['result'] == 3 && BaseService::isLastDayOfMonth()) { // 扣款失败 解约
|
||||||
self::releaseMerchant($order->agreement_id);
|
self::releaseMerchant($order->agreement_id);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -25,7 +25,7 @@ class OrderService extends BaseService
|
||||||
|
|
||||||
public function list($params)
|
public function list($params)
|
||||||
{
|
{
|
||||||
return $this->model->searchPages(['order_number', 'type', 'status', 'pay_status', 'create_at', 'user_id'], $params)->toArray();
|
return $this->model->searchPages(['order_number', 'type', 'status', 'create_at', 'user_id', 'is_retry'], $params)->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,6 +10,8 @@ return [
|
||||||
'getPayOrder' => \app\cmd\GetPayOrder::class,
|
'getPayOrder' => \app\cmd\GetPayOrder::class,
|
||||||
'getRefundOrder' => \app\cmd\getRefundOrder::class,
|
'getRefundOrder' => \app\cmd\getRefundOrder::class,
|
||||||
'queryAgreeStatus' => \app\cmd\QueryAgreeStatus::class,
|
'queryAgreeStatus' => \app\cmd\QueryAgreeStatus::class,
|
||||||
'queryRechargeOrder' =>\app\cmd\QueryRechargeOrder::class
|
'queryRechargeOrder' =>\app\cmd\QueryRechargeOrder::class,
|
||||||
|
'payOrderRetry' =>\app\cmd\PayOrderRetry::class,
|
||||||
|
'agreementPaySendSms' =>\app\cmd\AgreementPaySendSms::class
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue