微信支付调试
parent
1c5ad9517b
commit
1cd6aa6656
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Endpoint\Callback\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Events\OrderPaid;
|
||||||
|
use App\Exceptions\BizException;
|
||||||
|
use App\Models\Order;
|
||||||
|
use App\Models\OrderRefundLog;
|
||||||
|
use App\Services\Payment\WxpayService;
|
||||||
|
use App\Services\PayService;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class WxpayController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 支付结果通知
|
||||||
|
*
|
||||||
|
* @param \App\Services\Payment\WxpayService $wxpayService
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function paidNotify(WxpayService $wxpayService, Request $request)
|
||||||
|
{
|
||||||
|
return $wxpayService->payment()->handlePaidNotify(function ($message, $fail) use ($request) {
|
||||||
|
$this->log('paid notify--------'.$request->url(), $message);
|
||||||
|
|
||||||
|
// 通信失败
|
||||||
|
if (data_get($message, 'return_code') !== 'SUCCESS') {
|
||||||
|
return $fail('通信失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$payLog = DB::transaction(function () use ($message) {
|
||||||
|
$payService = new PayService();
|
||||||
|
|
||||||
|
if (data_get($message, 'result_code') === 'SUCCESS') {
|
||||||
|
return $payService->handleSuccessByPaySerialNumber($message['out_trade_no'], [
|
||||||
|
'out_trade_no' => $message['transaction_id'],
|
||||||
|
'pay_at' => Carbon::parse($message['time_end']),
|
||||||
|
]);
|
||||||
|
} elseif (data_get($message, 'result_code') === 'FAIL') {
|
||||||
|
return $payService->handleFailedByPaySerialNumber($message['out_trade_no'], [
|
||||||
|
'out_trade_no' => $message['transaction_id'] ?? null,
|
||||||
|
'failed_reason' => '['.$message['err_code'].']'.$message['err_code_des'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$payable = $payLog?->payable;
|
||||||
|
|
||||||
|
if ($payable instanceof Order) {
|
||||||
|
OrderPaid::dispatchIf($payable->isPaid(), $payable);
|
||||||
|
}
|
||||||
|
} catch (ModelNotFoundException | BizException $e) {
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单退款结果通知
|
||||||
|
*
|
||||||
|
* @param \App\Services\Payment\WxpayService $wxpayService
|
||||||
|
* @return \Illuminate\Http\Response
|
||||||
|
*/
|
||||||
|
public function orderRefundedNotify(WxpayService $wxpayService)
|
||||||
|
{
|
||||||
|
return $wxpayService->payment()->handleRefundedNotify(function ($message, $reqInfo, $fail) {
|
||||||
|
$this->log('refund notify', $reqInfo);
|
||||||
|
|
||||||
|
// 通信失败
|
||||||
|
if (data_get($message, 'return_code') !== 'SUCCESS') {
|
||||||
|
return $fail('通信失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退款失败
|
||||||
|
if ($reqInfo['refund_status'] !== 'SUCCESS') {
|
||||||
|
$log = OrderRefundLog::where('sn', $reqInfo['out_refund_no'])->first();
|
||||||
|
|
||||||
|
$log?->update([
|
||||||
|
'status' => OrderRefundLog::STATUS_FAILED,
|
||||||
|
'failed_reason' => $reqInfo['refund_status'] === 'CHANGE' ? '退款异常' : '退款关闭',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信回调日志
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param array $context
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function log(string $message, array $context = [])
|
||||||
|
{
|
||||||
|
return Log::build([
|
||||||
|
'driver' => 'daily',
|
||||||
|
'path' => storage_path('logs/wxpay-notify.log'),
|
||||||
|
])->info($message, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
use App\Endpoint\Callback\Http\Controllers\AlipayController;
|
use App\Endpoint\Callback\Http\Controllers\AlipayController;
|
||||||
use App\Endpoint\Callback\Http\Controllers\Kuaidi100Controller;
|
use App\Endpoint\Callback\Http\Controllers\Kuaidi100Controller;
|
||||||
use App\Endpoint\Callback\Http\Controllers\WeChatPayController;
|
use App\Endpoint\Callback\Http\Controllers\WeChatPayController;
|
||||||
|
use App\Endpoint\Callback\Http\Controllers\WxpayController;
|
||||||
use App\Endpoint\Callback\Http\Controllers\YzkWeChatPayController;
|
use App\Endpoint\Callback\Http\Controllers\YzkWeChatPayController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
//快递100物流推送
|
//快递100物流推送
|
||||||
Route::post('kuaidi100', [Kuaidi100Controller::class, 'notify']);
|
Route::post('kuaidi100', [Kuaidi100Controller::class, 'notify']);
|
||||||
// 微信支付通知
|
// 微信支付通知
|
||||||
Route::post('wxpay/paid-notify', [WeChatPayController::class, 'paidNotify'])->name('wxpay.paid_notify');
|
Route::post('wxpay/paid-notify', [WxpayController::class, 'paidNotify'])->name('wxpay.paid_notify');
|
||||||
Route::post('wxpay/order-refund-notify', [WeChatPayController::class, 'orderRefundedNotify'])->name('wxpay.order_refund_notify');
|
Route::post('wxpay/order-refund-notify', [WeChatPayController::class, 'orderRefundedNotify'])->name('wxpay.order_refund_notify');
|
||||||
|
|
||||||
Route::post('alipay', AlipayController::class)->name('alipay.notify');
|
Route::post('alipay', AlipayController::class)->name('alipay.notify');
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ enum PayWay: string {
|
||||||
case WxpayApp = 'wxpay_app';
|
case WxpayApp = 'wxpay_app';
|
||||||
case WxpayH5 = 'wxpay_h5';
|
case WxpayH5 = 'wxpay_h5';
|
||||||
case WxpayJs = 'wxpay_jsapi';
|
case WxpayJs = 'wxpay_jsapi';
|
||||||
case WxpayMp = 'wxpay_mini_program';
|
case WxpayMp = 'wxpay_mp';
|
||||||
// 阿里支付
|
// 阿里支付
|
||||||
case AlipayApp = 'alipay_app';
|
case AlipayApp = 'alipay_app';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use App\Models\ProductSku;
|
||||||
use App\Models\ShippingAddress;
|
use App\Models\ShippingAddress;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\UserCoupon;
|
use App\Models\UserCoupon;
|
||||||
|
use App\Services\Payment\WxpayService;
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
|
@ -780,40 +781,50 @@ class OrderService
|
||||||
}
|
}
|
||||||
} while ($payLog === null);
|
} while ($payLog === null);
|
||||||
|
|
||||||
$data = [
|
|
||||||
'pay_sn' => $payLog->pay_sn,
|
|
||||||
];
|
|
||||||
|
|
||||||
// 如果支付方式为线下支付,或支付金额为 0,则按支付完成处理
|
// 如果支付方式为线下支付,或支付金额为 0,则按支付完成处理
|
||||||
if ($order->total_amount === 0 || $payLog->isOffline()) {
|
if ($order->total_amount === 0 || $payLog->isOffline()) {
|
||||||
(new PayService())->handleSuccess($payLog, [
|
(new PayService())->handleSuccess($payLog, [
|
||||||
'pay_at' => now(),
|
'pay_at' => now(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$data = null;
|
return [
|
||||||
|
'pay_sn' => $payLog->pay_sn,
|
||||||
|
'data' => null,
|
||||||
|
];
|
||||||
} elseif ($payLog->isWxpay()) {
|
} elseif ($payLog->isWxpay()) {
|
||||||
if (is_null($tradeType = WxpayTradeType::tryFromPayWay($payLog->pay_way))) {
|
if (is_null($tradeType = WxpayTradeType::tryFromPayWay($payLog->pay_way))) {
|
||||||
throw new BizException('支付方式 非法');
|
throw new BizException('支付方式 非法');
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = (new WeChatPayService())->pay([
|
$params = [
|
||||||
'body' => app_settings('app.app_name').'-商城订单',
|
'body' => app_settings('app.app_name').'-商城订单',
|
||||||
'out_trade_no' => $payLog->pay_sn,
|
'out_trade_no' => $payLog->pay_sn,
|
||||||
'total_fee' => $order->total_amount,
|
'total_fee' => $order->total_amount,
|
||||||
'trade_type' => $tradeType->value,
|
'trade_type' => $tradeType->value,
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
if ($tradeType === WxpayTradeType::JSAPI) {
|
||||||
|
$params['openid'] = 'o-BdO46p2hRnk-SQIXa1TEdBFtfs';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'pay_sn' => $payLog->pay_sn,
|
||||||
|
'data' => (new WxpayService())->pay($params),
|
||||||
|
];
|
||||||
} elseif ($payLog->isAlipay()) {
|
} elseif ($payLog->isAlipay()) {
|
||||||
$data = app(AlipayService::class)->pay([
|
$params = [
|
||||||
'subject' => app_settings('app.app_name').'-商城订单',
|
'subject' => app_settings('app.app_name').'-商城订单',
|
||||||
'out_trade_no' => $payLog->pay_sn,
|
'out_trade_no' => $payLog->pay_sn,
|
||||||
'total_amount' => bcdiv($order->total_amount, 100, 2),
|
'total_amount' => bcdiv($order->total_amount, 100, 2),
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
return [
|
||||||
|
'pay_sn' => $payLog->pay_sn,
|
||||||
|
'data' => app(AlipayService::class)->pay($params),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
throw new BizException('【-1】支付方式 非法');
|
||||||
'pay_way' => $payLog->pay_way,
|
|
||||||
'data' => $data,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Payment;
|
||||||
|
|
||||||
|
use App\Enums\PayWay;
|
||||||
|
use App\Enums\WxpayTradeType;
|
||||||
|
use App\Exceptions\WeChatPayException;
|
||||||
|
use EasyWeChat\Factory;
|
||||||
|
use EasyWeChat\Payment\Application;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
class WxpayService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<string, \EasyWeChat\Payment\Application>
|
||||||
|
*/
|
||||||
|
protected $payments = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付
|
||||||
|
*
|
||||||
|
* @param array $params
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function pay(array $params, string $paymentName = null): array
|
||||||
|
{
|
||||||
|
if (! isset($params['notify_url'])) {
|
||||||
|
$params['notify_url'] = url(route('wxpay.paid_notify', ['payment' => $paymentName], false), [], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! isset($params['trade_type'])) {
|
||||||
|
$params['trade_type'] = WxpayTradeType::App->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$app = $this->payment($paymentName);
|
||||||
|
|
||||||
|
$result = $app->order->unify($params);
|
||||||
|
|
||||||
|
$this->validateResult($result, $params);
|
||||||
|
|
||||||
|
return match ($params['trade_type']) {
|
||||||
|
PayWay::WxpayApp => $app->jssdk->appConfig($result['prepay_id']),
|
||||||
|
PayWay::WxpayH5 => Arr::only($result, ['mweb_url']),
|
||||||
|
default => $app->jssdk->bridgeConfig($result['prepay_id'], false),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $name
|
||||||
|
* @return \EasyWeChat\Payment\Application
|
||||||
|
*/
|
||||||
|
public function payment(?string $name = null): Application
|
||||||
|
{
|
||||||
|
$name = $name ?: 'default';
|
||||||
|
|
||||||
|
return $this->payments[$name] = $this->get($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @return \EasyWeChat\Payment\Application
|
||||||
|
*/
|
||||||
|
protected function get(string $name): Application
|
||||||
|
{
|
||||||
|
return $this->payments[$name] ?? $this->resolve($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @return \EasyWeChat\Payment\Application
|
||||||
|
*
|
||||||
|
* @throws \App\Exceptions\WeChatPayException
|
||||||
|
*/
|
||||||
|
protected function resolve(string $name): Application
|
||||||
|
{
|
||||||
|
$config = config("wechat.payment.{$name}");
|
||||||
|
|
||||||
|
if (empty($config)) {
|
||||||
|
throw new WeChatPayException("支付 [{$name}] 配置未找到");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Factory::payment($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验响应结果
|
||||||
|
*
|
||||||
|
* @param array $result
|
||||||
|
* @param array $raw
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \App\Exceptions\WeChatPayException
|
||||||
|
*/
|
||||||
|
protected function validateResult(array $result, array $raw = [])
|
||||||
|
{
|
||||||
|
if (Arr::get($result, 'return_code') !== 'SUCCESS') {
|
||||||
|
throw new WeChatPayException(Arr::get($result, 'return_msg', '请求失败'), $raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Arr::get($result, 'result_code') !== 'SUCCESS') {
|
||||||
|
throw new WeChatPayException(sprintf(
|
||||||
|
'[%s] %s',
|
||||||
|
Arr::get($result, 'err_code', '-1'),
|
||||||
|
Arr::get($result, 'err_code_des', '结果异常')
|
||||||
|
), $raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue