feat: 收益全额直入商城余额、存量结转与奖项名称全局规范化对齐
这个提交包含在:
@@ -36,7 +36,7 @@ class Pay extends Common
|
||||
$payment = $this->request->post('payment');
|
||||
$openid = $this->request->post('openid', '');
|
||||
$money = $this->request->post('money', 0);
|
||||
$money = $money > 0 ? $money : 0;
|
||||
$money = floatval($money) > 0 ? round(floatval($money), 2) : 0;
|
||||
$platform = $this->request->header('platform');
|
||||
|
||||
list($order, $order_type) = $this->getOrderInstance($order_sn);
|
||||
@@ -65,30 +65,62 @@ class Pay extends Common
|
||||
// pay 实例
|
||||
$payOper = new PayOper();
|
||||
|
||||
if ($money && $order_type == 'order') {
|
||||
// 余额混合支付
|
||||
$order = Db::transaction(function () use ($payOper, $order, $order_type, $money) {
|
||||
$mixedPayRecord = null;
|
||||
if ($money > 0 && $order_type == 'order') {
|
||||
// 余额混合支付(行锁串行化保障并发资金安全)
|
||||
$order = Db::transaction(function () use ($order, $order_type, $money, $user, &$mixedPayRecord) {
|
||||
// 加锁读订单
|
||||
$order = $order->lock(true)->find($order->id);
|
||||
if (in_array($order->status, [$order::STATUS_PAID, $order::STATUS_COMPLETED])) {
|
||||
$this->error('订单已支付');
|
||||
}
|
||||
|
||||
// 余额支付
|
||||
$order = $payOper->money($order, $money, $order_type);
|
||||
// 事务内行级排他锁查验用户最新可用余额,杜绝并发快照双花
|
||||
$lockedUser = \app\admin\model\shopro\user\User::where('id', $user->id)->lock(true)->find();
|
||||
if (bccomp((string)$money, (string)$lockedUser->money, 2) === 1) {
|
||||
$this->error('账户可用余额不足以进行本次抵扣');
|
||||
}
|
||||
|
||||
$deductMoney = min($money, floatval($order->remain_pay_fee));
|
||||
if ($deductMoney <= 0) {
|
||||
return $order;
|
||||
}
|
||||
|
||||
// 使用锁定的实时用户对象执行余额扣减
|
||||
$lockedPayOper = new PayOper($lockedUser);
|
||||
$order = $lockedPayOper->money($order, $deductMoney, $order_type);
|
||||
|
||||
return $order;
|
||||
});
|
||||
|
||||
// 获取刚才产生的余额支付记录,用于异常情况冲正
|
||||
$mixedPayRecord = PayModel::where('order_id', $order->id)
|
||||
->where('order_type', $order_type)
|
||||
->where('pay_type', 'money')
|
||||
->order('id', 'desc')
|
||||
->find();
|
||||
|
||||
if (in_array($order->status, [$order::STATUS_PAID, $order::STATUS_COMPLETED])) {
|
||||
$this->success('订单支付成功', $order);
|
||||
}
|
||||
}
|
||||
|
||||
if ($payment == 'money' && $order_type == 'order') {
|
||||
// 余额支付
|
||||
$order = Db::transaction(function () use ($payOper, $order, $order_type) {
|
||||
// 纯余额支付
|
||||
$order = Db::transaction(function () use ($order, $order_type, $user) {
|
||||
// 加锁读订单
|
||||
$order = $order->lock(true)->find($order->id);
|
||||
if (in_array($order->status, [$order::STATUS_PAID, $order::STATUS_COMPLETED])) {
|
||||
$this->error('订单已支付');
|
||||
}
|
||||
|
||||
$order = $payOper->money($order, $order->remain_pay_fee, $order_type);
|
||||
$lockedUser = \app\admin\model\shopro\user\User::where('id', $user->id)->lock(true)->find();
|
||||
if (bccomp((string)$order->remain_pay_fee, (string)$lockedUser->money, 2) === 1) {
|
||||
$this->error('账户可用余额不足以付清该订单');
|
||||
}
|
||||
|
||||
$lockedPayOper = new PayOper($lockedUser);
|
||||
$order = $lockedPayOper->money($order, $order->remain_pay_fee, $order_type);
|
||||
|
||||
return $order;
|
||||
});
|
||||
@@ -146,7 +178,10 @@ class Pay extends Common
|
||||
}
|
||||
|
||||
if (empty($order_data['payer']['openid'])) {
|
||||
// 缺少 openid
|
||||
// 缺少 openid 时,若前面预扣了余额则冲正
|
||||
if ($mixedPayRecord) {
|
||||
$this->rollbackMixedMoney($order, $mixedPayRecord, $user, $order_type);
|
||||
}
|
||||
$this->error('miss_openid', -1);
|
||||
}
|
||||
}
|
||||
@@ -160,11 +195,18 @@ class Pay extends Common
|
||||
|
||||
try {
|
||||
$result = $payService->pay($order_data);
|
||||
} catch (\Yansongda\Pay\Exception\Exception $e) {
|
||||
$this->error('支付失败' . (config('app_debug') ? ":" . $e->getMessage() : ',请重试'));
|
||||
} catch (HttpResponseException $e) {
|
||||
$data = $e->getResponse()->getData();
|
||||
$message = $data ? ($data['msg'] ?? '') : $e->getMessage();
|
||||
} catch (\Exception $e) {
|
||||
// 第三方预支付异常,安全冲正本次混合支付预扣款
|
||||
if ($mixedPayRecord) {
|
||||
$this->rollbackMixedMoney($order, $mixedPayRecord, $user, $order_type);
|
||||
}
|
||||
|
||||
if ($e instanceof HttpResponseException) {
|
||||
$data = $e->getResponse()->getData();
|
||||
$message = $data ? ($data['msg'] ?? '') : $e->getMessage();
|
||||
} else {
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
$this->error('支付失败' . (config('app_debug') ? ":" . $message : ',请重试'));
|
||||
}
|
||||
@@ -183,6 +225,39 @@ class Pay extends Common
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 混合支付预下单异常时,冲正退回预扣余额
|
||||
*
|
||||
* @param \think\Model $order
|
||||
* @param \think\Model $mixedPayRecord
|
||||
* @param \think\Model $user
|
||||
* @param string $order_type
|
||||
* @return void
|
||||
*/
|
||||
protected function rollbackMixedMoney($order, $mixedPayRecord, $user, $order_type)
|
||||
{
|
||||
try {
|
||||
Db::transaction(function () use ($order, $mixedPayRecord, $user, $order_type) {
|
||||
\addons\shopro\service\Wallet::change($user, 'money', $mixedPayRecord->pay_fee, 'order_refund', [
|
||||
'order_id' => $order->id,
|
||||
'order_sn' => $order->order_sn,
|
||||
'order_type' => $order_type,
|
||||
'remark' => '混合支付预下单未完成,安全冲正退回'
|
||||
]);
|
||||
|
||||
$mixedPayRecord->status = PayModel::PAY_STATUS_REFUND;
|
||||
$mixedPayRecord->refund_fee = $mixedPayRecord->pay_fee;
|
||||
$mixedPayRecord->save();
|
||||
|
||||
$order = $order->lock(true)->find($order->id);
|
||||
$order->remain_pay_fee = bcadd((string)$order->remain_pay_fee, (string)$mixedPayRecord->pay_fee, 2);
|
||||
$order->save();
|
||||
});
|
||||
} catch (\Exception $e) {
|
||||
Log::write('混合支付预扣款冲正异常: ' . $e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
在新工单中引用
屏蔽一个用户