|
|
@@ -7,6 +7,7 @@ use App\Models\PaymentOrder;
|
|
|
use Exception;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
+use App\Services\Payment\JdPayService;
|
|
|
use App\Services\Payment\QianBaoService;
|
|
|
use App\Services\Payment\SanJinService;
|
|
|
use App\Services\ConfigService;
|
|
|
@@ -199,10 +200,12 @@ class PaymentOrderService extends BaseService
|
|
|
$max = 0;
|
|
|
$min = 0;
|
|
|
$rate = 0;
|
|
|
+ $selectedProduct = null;
|
|
|
|
|
|
$geText = '';
|
|
|
foreach ($product as $k => $v) {
|
|
|
if ($v['type'] == $paymentType) {
|
|
|
+ $selectedProduct = $v;
|
|
|
if ($v['type'] == 'zfbge') {
|
|
|
if (in_array($amount, $v['fixed'])) {
|
|
|
$channel = $k;
|
|
|
@@ -234,7 +237,7 @@ class PaymentOrderService extends BaseService
|
|
|
}
|
|
|
|
|
|
// 没有找到支付通道
|
|
|
- if (empty($channel)) {
|
|
|
+ if (empty($channel) && !JdPayService::isChannel($paymentType)) {
|
|
|
// $text = "发起充值失败 \n";
|
|
|
// $text .= "最低充值:" . $min . " \n";
|
|
|
// $text .= "最高充值:" . $max . " \n";
|
|
|
@@ -248,6 +251,51 @@ class PaymentOrderService extends BaseService
|
|
|
return $result;
|
|
|
}
|
|
|
|
|
|
+ if (JdPayService::isChannel($paymentType) || JdPayService::isChannel($channel)) {
|
|
|
+ $channel = JdPayService::CHANNEL;
|
|
|
+ $bankName = $selectedProduct['name'] ?? 'JD钱包';
|
|
|
+ $data = [];
|
|
|
+ $data['type'] = self::TYPE_PAY;
|
|
|
+ $data['member_id'] = $memberId;
|
|
|
+ $data['amount'] = JdPayService::amount($amount);
|
|
|
+ $data['channel'] = $channel;
|
|
|
+ $data['fee'] = $amount * $rate;
|
|
|
+ $data['bank_name'] = $bankName;
|
|
|
+ $order_no = self::createOrderNo('jd' . $data['type'] . '_', $memberId);
|
|
|
+ $data['order_no'] = $order_no;
|
|
|
+ $data['callback_url'] = JdPayService::getNotifyUrl();
|
|
|
+ $data['remark'] = '充值费率:' . $rate;
|
|
|
+ $data['status'] = self::STATUS_STAY;
|
|
|
+
|
|
|
+ $ret = JdPayService::pay($amount, $order_no);
|
|
|
+ Log::channel('payment')->info('JD支付发起', $ret);
|
|
|
+ if (($ret['code'] ?? 0) == 200) {
|
|
|
+ $item = $ret['data'] ?? [];
|
|
|
+ $payUrl = $item['url'] ?? '';
|
|
|
+ $data['status'] = self::STATUS_PROCESS;
|
|
|
+ $data['pay_no'] = $item['orderNo'] ?? '';
|
|
|
+ $data['pay_url'] = $payUrl;
|
|
|
+ $data['pay_data'] = json_encode($ret, JSON_UNESCAPED_UNICODE);
|
|
|
+ static::$MODEL::create($data);
|
|
|
+
|
|
|
+ if ($payUrl) {
|
|
|
+ $result['image'] = asset(self::createPaymentQrCode($payUrl));
|
|
|
+ }
|
|
|
+ $text = "{$bankName}充值确认 \n";
|
|
|
+ $text .= "请使用浏览器扫码或者复制支付地址到浏览器打开 \n";
|
|
|
+ $text .= "支付地址:{$payUrl}\n";
|
|
|
+ $text .= "支付金额:" . $amount . " RMB \n";
|
|
|
+ $text .= "请按实际支付金额进行付款,否则影响到账 \n";
|
|
|
+ $text .= "支付完成后请耐心等待,支付到账会第一时间通知您! \n";
|
|
|
+ $result['text'] = $text;
|
|
|
+ $result['url'] = $payUrl;
|
|
|
+ } else {
|
|
|
+ $result['text'] = $ret['message'] ?? 'JD支付发起失败';
|
|
|
+ $result['code'] = 20002;
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
$data = [];
|
|
|
$data['type'] = self::TYPE_PAY;
|
|
|
$data['member_id'] = $memberId;
|
|
|
@@ -296,8 +344,49 @@ class PaymentOrderService extends BaseService
|
|
|
*/
|
|
|
public static function receivePay($params)
|
|
|
{
|
|
|
+ if (($params['userCode'] ?? '') === JdPayService::getMerchantId()) {
|
|
|
+ $info = self::findOne(['order_no' => $params['orderCode'] ?? ''])
|
|
|
+ ?: static::$MODEL::where('pay_no', $params['orderCode'] ?? '')->first();
|
|
|
+ if (!$info || $info->type != self::TYPE_PAY) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!JdPayService::verifyPayNotify($params)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (bccomp(JdPayService::amount($info->amount), JdPayService::amount($params['amount'] ?? 0), 2) !== 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if ($info->status != self::STATUS_PROCESS) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ $info->callback_data = json_encode($params, JSON_UNESCAPED_UNICODE);
|
|
|
+ $info->state = $params['status'];
|
|
|
+ if ((string)$params['status'] === JdPayService::PAY_STATUS_SUCCESS) {
|
|
|
+ $info->status = self::STATUS_SUCCESS;
|
|
|
+ $wallet = WalletService::findOne(['member_id' => $info->member_id]);
|
|
|
+ $balance = $wallet->available_balance;
|
|
|
+ $available_balance = bcadd($balance, JdPayService::amount($info->amount), 10);
|
|
|
+ $wallet->available_balance = $available_balance;
|
|
|
+ $wallet->save();
|
|
|
+
|
|
|
+ BalanceLogService::addLog($info->member_id, $info->amount, $balance, $available_balance, '三方充值', $info->id, '');
|
|
|
+ self::rechargesBibiReturn($info->member_id, $info->amount, $info->id);
|
|
|
+
|
|
|
+ $text = "✅ 支付成功 \n";
|
|
|
+ $text .= "充值金额:{$info->amount} RMB \n";
|
|
|
+ $text .= "订单号:{$info->order_no} \n";
|
|
|
+ $text .= "您充值的金额已到账,请注意查收!";
|
|
|
+ self::sendMessage($info->member_id, $text);
|
|
|
+ } elseif ((string)$params['status'] === JdPayService::PAY_STATUS_FAIL) {
|
|
|
+ $info->status = self::STATUS_FAIL;
|
|
|
+ }
|
|
|
+ $info->save();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
// 判断商户号
|
|
|
- if ($params['mchId'] == SanJinService::getMerchantId()) {
|
|
|
+ if (($params['mchId'] ?? '') == SanJinService::getMerchantId()) {
|
|
|
$must = ['mchId', 'productId', 'tradeNo', 'outTradeNo', 'amount', 'payAmount', 'state', 'createTime', 'payTime'];
|
|
|
|
|
|
|
|
|
@@ -433,9 +522,20 @@ class PaymentOrderService extends BaseService
|
|
|
if (!$order) throw new Exception("订单不存在_{$orderId}", HttpStatus::CUSTOM_ERROR);
|
|
|
$amount = $order->amount;
|
|
|
$amount = number_format($amount, 2, '.', '');
|
|
|
- $ret = QianBaoService::payout($amount, $order->order_no, $order->bank_name, $order->account, $order->card_no);
|
|
|
- Log::error('第三方代付接口调用:' . json_encode($ret, JSON_UNESCAPED_UNICODE));
|
|
|
- if ($ret['code'] != 200) throw new Exception($ret['msg'], HttpStatus::CUSTOM_ERROR);
|
|
|
+ if (JdPayService::isChannel($order->channel)) {
|
|
|
+ self::assertJdBalanceEnough($amount);
|
|
|
+ $ret = JdPayService::remit($amount, $order->order_no, $order->card_no);
|
|
|
+ Log::channel('payment')->info('JD下发接口调用', $ret);
|
|
|
+ if (($ret['code'] ?? 0) != 200) {
|
|
|
+ throw new Exception($ret['message'] ?? 'JD下发失败', HttpStatus::CUSTOM_ERROR);
|
|
|
+ }
|
|
|
+ $order->pay_no = $ret['data']['orderNo'] ?? '';
|
|
|
+ $order->pay_data = json_encode($ret, JSON_UNESCAPED_UNICODE);
|
|
|
+ } else {
|
|
|
+ $ret = QianBaoService::payout($amount, $order->order_no, $order->bank_name, $order->account, $order->card_no);
|
|
|
+ Log::error('第三方代付接口调用:' . json_encode($ret, JSON_UNESCAPED_UNICODE));
|
|
|
+ if ($ret['code'] != 200) throw new Exception($ret['msg'], HttpStatus::CUSTOM_ERROR);
|
|
|
+ }
|
|
|
$order->status = self::STATUS_PROCESS;
|
|
|
$order->save();
|
|
|
} catch (Exception $e) {
|
|
|
@@ -499,7 +599,7 @@ class PaymentOrderService extends BaseService
|
|
|
$data['bank_name'] = $bank_name;
|
|
|
$data['account'] = $account;
|
|
|
$data['card_no'] = $card_no;
|
|
|
- $data['callback_url'] = QianBaoService::getNotifyUrl();
|
|
|
+ $data['callback_url'] = JdPayService::isChannel($channel) ? JdPayService::getRemitNotifyUrl() : QianBaoService::getNotifyUrl();
|
|
|
$data['status'] = self::STATUS_STAY;
|
|
|
$data['remark'] = '提现费率:0.2%+2';
|
|
|
|
|
|
@@ -534,13 +634,34 @@ class PaymentOrderService extends BaseService
|
|
|
}
|
|
|
|
|
|
// 调用三方支付接口(在事务外)
|
|
|
- $ret = QianBaoService::payout($amount, $order_no, $bank_name, $account, $card_no);
|
|
|
- Log::error('第三方代付接口调用:' . json_encode($ret, JSON_UNESCAPED_UNICODE));
|
|
|
- if ($ret['code'] == 200) {
|
|
|
+ if (JdPayService::isChannel($channel)) {
|
|
|
+ try {
|
|
|
+ self::assertJdBalanceEnough($amount);
|
|
|
+ $ret = JdPayService::remit($amount, $order_no, $card_no);
|
|
|
+ Log::channel('payment')->info('JD下发接口调用', $ret);
|
|
|
+ $success = (($ret['code'] ?? 0) == 200);
|
|
|
+ $failureMessage = $ret['message'] ?? 'JD下发失败';
|
|
|
+ } catch (Exception $e) {
|
|
|
+ $ret = ['message' => $e->getMessage()];
|
|
|
+ $success = false;
|
|
|
+ $failureMessage = $e->getMessage();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $ret = QianBaoService::payout($amount, $order_no, $bank_name, $account, $card_no);
|
|
|
+ Log::error('第三方代付接口调用:' . json_encode($ret, JSON_UNESCAPED_UNICODE));
|
|
|
+ $success = (($ret['code'] ?? 0) == 200);
|
|
|
+ $failureMessage = $ret['msg'] ?? '代付失败';
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($success) {
|
|
|
// 更新提现记录状态为处理中
|
|
|
DB::beginTransaction();
|
|
|
try {
|
|
|
$info->status = self::STATUS_PROCESS;
|
|
|
+ if (JdPayService::isChannel($channel)) {
|
|
|
+ $info->pay_no = $ret['data']['orderNo'] ?? '';
|
|
|
+ $info->pay_data = json_encode($ret, JSON_UNESCAPED_UNICODE);
|
|
|
+ }
|
|
|
$info->save();
|
|
|
DB::commit();
|
|
|
|
|
|
@@ -573,14 +694,14 @@ class PaymentOrderService extends BaseService
|
|
|
|
|
|
// 更新提现记录状态为失败
|
|
|
$info->status = self::STATUS_FAIL;
|
|
|
- $info->remark = $ret['msg'];
|
|
|
+ $info->remark = $failureMessage;
|
|
|
$info->save();
|
|
|
|
|
|
// 记录退款日志
|
|
|
BalanceLogService::addLog($memberId, $default_amount, $available_balance, $balance, '三方提现', $id, '提现失败退款');
|
|
|
|
|
|
DB::commit();
|
|
|
- $result['text'] = $ret['msg'];
|
|
|
+ $result['text'] = $failureMessage;
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
DB::rollBack();
|
|
|
@@ -604,8 +725,24 @@ class PaymentOrderService extends BaseService
|
|
|
*/
|
|
|
public static function receiveOrder($params)
|
|
|
{
|
|
|
+ if (($params['userCode'] ?? '') === JdPayService::getMerchantId()) {
|
|
|
+ $info = self::findOne(['order_no' => $params['customerOrderCode'] ?? ''])
|
|
|
+ ?: static::$MODEL::where('pay_no', $params['orderCode'] ?? '')->first();
|
|
|
+ if (!$info || $info->type != self::TYPE_PAYOUT) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (!JdPayService::verifyRemitNotify($params)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (bccomp(JdPayService::amount($info->amount), JdPayService::amount($params['amount'] ?? 0), 2) !== 0) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ self::onSubmitJdPayout($params, $info);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
// 判断商户号是否一致
|
|
|
- if ($params['merchantNum'] == QianBaoService::getMerchantId()) {
|
|
|
+ if (($params['merchantNum'] ?? '') == QianBaoService::getMerchantId()) {
|
|
|
|
|
|
$info = self::findOne(['order_no' => $params['orderNo']]);
|
|
|
if ($info) {
|
|
|
@@ -638,6 +775,60 @@ class PaymentOrderService extends BaseService
|
|
|
* @param {*} $params
|
|
|
* @return {*}
|
|
|
*/
|
|
|
+ public static function onSubmitJdPayout($params, $info)
|
|
|
+ {
|
|
|
+ if ($info->status != self::STATUS_PROCESS) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $memberId = $info->member_id;
|
|
|
+ $amount = JdPayService::amount($params['amount'] ?? $info->amount);
|
|
|
+ $data = [];
|
|
|
+ $chat_id = $info->member_id;
|
|
|
+ $data['callback_data'] = json_encode($params, JSON_UNESCAPED_UNICODE);
|
|
|
+ DB::beginTransaction();
|
|
|
+ try {
|
|
|
+ if ((string)$params['status'] === JdPayService::REMIT_STATUS_SUCCESS) {
|
|
|
+ $data['status'] = self::STATUS_SUCCESS;
|
|
|
+ $res = static::$MODEL::where(['id' => $info->id])->update($data);
|
|
|
+ if ($res) {
|
|
|
+ $text = "✅ 提现通知 \n";
|
|
|
+ $text .= "提现平台:{$info->bank_name} \n";
|
|
|
+ $text .= "收款人:{$info->account} \n";
|
|
|
+ $text .= "收款地址:{$info->card_no} \n";
|
|
|
+ $text .= "提现金额:{$info->amount} \n";
|
|
|
+ $text .= "提现成功,金额已到账,请注意查收!";
|
|
|
+ self::sendMessage($chat_id, $text);
|
|
|
+ }
|
|
|
+ } elseif ((string)$params['status'] === JdPayService::REMIT_STATUS_FAIL) {
|
|
|
+ $data['status'] = self::STATUS_FAIL;
|
|
|
+ $res = static::$MODEL::where(['id' => $info->id])->update($data);
|
|
|
+
|
|
|
+ $wallet = WalletService::findOne(['member_id' => $info->member_id]);
|
|
|
+ $balance = $wallet->available_balance;
|
|
|
+ $available_balance = bcadd($balance, $amount, 10);
|
|
|
+ $wallet->available_balance = $available_balance;
|
|
|
+ $wallet->save();
|
|
|
+
|
|
|
+ BalanceLogService::addLog($memberId, $amount, $balance, $available_balance, '三方提现', $info->id, '提现失败退款');
|
|
|
+ if ($res) {
|
|
|
+ $text = "❌ 提现通知 \n";
|
|
|
+ $text .= "提现平台:{$info->bank_name} \n";
|
|
|
+ $text .= "收款人:{$info->account} \n";
|
|
|
+ $text .= "收款地址:{$info->card_no} \n";
|
|
|
+ $text .= "提现金额:{$info->amount} \n";
|
|
|
+ $text .= "提现失败,金额已返回钱包,请注意查收!";
|
|
|
+ self::sendMessage($chat_id, $text);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ DB::commit();
|
|
|
+ } catch (Exception $e) {
|
|
|
+ DB::rollBack();
|
|
|
+ Log::error('JD提现回调处理异常: ' . $e->getMessage(), $params);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public static function onSubmitPayout($params, $info)
|
|
|
{
|
|
|
$memberId = $info->member_id;
|
|
|
@@ -706,6 +897,37 @@ class PaymentOrderService extends BaseService
|
|
|
$msg['code'] = self::NOT;
|
|
|
$info = self::findOne(['id' => $id]);
|
|
|
if ($info && $info->status == self::STATUS_PROCESS) {
|
|
|
+ if (JdPayService::isChannel($info->channel)) {
|
|
|
+ $ret = JdPayService::queryPayOrder($info->pay_no ?? '', $info->order_no);
|
|
|
+ Log::channel('payment')->info('JD支付查询订单', $ret);
|
|
|
+ if (($ret['code'] ?? 0) == 200) {
|
|
|
+ $item = $ret['data'] ?? [];
|
|
|
+ if ((string)($item['status'] ?? '') === JdPayService::PAY_STATUS_SUCCESS) {
|
|
|
+ $info->status = self::STATUS_SUCCESS;
|
|
|
+ $info->state = $item['status'];
|
|
|
+ $info->callback_data = json_encode($ret, JSON_UNESCAPED_UNICODE);
|
|
|
+ $info->save();
|
|
|
+
|
|
|
+ $wallet = WalletService::findOne(['member_id' => $info->member_id]);
|
|
|
+ $balance = $wallet->available_balance;
|
|
|
+ $available_balance = bcadd($balance, $info->amount, 10);
|
|
|
+ $wallet->available_balance = $available_balance;
|
|
|
+ $wallet->save();
|
|
|
+
|
|
|
+ BalanceLogService::addLog($info->member_id, $info->amount, $balance, $available_balance, '三方充值', $info->id, '');
|
|
|
+ self::rechargesBibiReturn($info->member_id, $info->amount, $info->id);
|
|
|
+
|
|
|
+ $msg['code'] = self::YES;
|
|
|
+ $msg['msg'] = '支付成功';
|
|
|
+ } else {
|
|
|
+ $msg['msg'] = '支付中';
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $msg['msg'] = '查询失败:' . ($ret['message'] ?? '');
|
|
|
+ }
|
|
|
+ return $msg;
|
|
|
+ }
|
|
|
+
|
|
|
$ret = SanJinService::queryOrder($info->order_no);
|
|
|
Log::error('三斤支付查询订单:', $ret);
|
|
|
if ($ret['code'] == 0) {
|
|
|
@@ -741,6 +963,19 @@ class PaymentOrderService extends BaseService
|
|
|
|
|
|
}
|
|
|
|
|
|
+ private static function assertJdBalanceEnough($amount): void
|
|
|
+ {
|
|
|
+ $ret = JdPayService::balance();
|
|
|
+ Log::channel('payment')->info('JD余额查询', $ret);
|
|
|
+ if (($ret['code'] ?? 0) != 200) {
|
|
|
+ throw new Exception($ret['message'] ?? 'JD余额查询失败', HttpStatus::CUSTOM_ERROR);
|
|
|
+ }
|
|
|
+ $balance = $ret['data']['balance'] ?? null;
|
|
|
+ if ($balance === null || bccomp((string)$balance, JdPayService::amount($amount), 2) < 0) {
|
|
|
+ throw new Exception('JD商户余额不足', HttpStatus::CUSTOM_ERROR);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public static function syncPayOrder()
|
|
|
{
|
|
|
$list = static::$MODEL::where('state', 0)->where('type', self::TYPE_PAY)->take(100)->get();
|
|
|
@@ -762,4 +997,4 @@ class PaymentOrderService extends BaseService
|
|
|
// }
|
|
|
}
|
|
|
|
|
|
-}
|
|
|
+}
|