支付回调提交

This commit is contained in:
wong
2025-09-24 15:03:34 +08:00
parent 55be0c18e2
commit 1cc5605291
2 changed files with 83 additions and 129 deletions

View File

@@ -33,25 +33,24 @@ class PaymentService
*/
public function createOrder(array $order)
{
Log::info('支付创建');
$params = [
'service' => 'unified.trade.native',
'sign_type' => PaymentUtil::SIGN_TYPE_MD5,
'mch_id' => Env::get('payment.mchId'),
'out_trade_no' => $order['orderNo'],
'body' => $order['goodsName'] ?? '',
'total_fee' => $order['money'] ?? 0,
'mch_create_ip' => Request::ip(),
'notify_url' => Env::get('payment.notify_url','127.0.0.1'),
'nonce_str' => PaymentUtil::generateNonceStr(),
'service' => 'unified.trade.native',
'sign_type' => PaymentUtil::SIGN_TYPE_MD5,
'mch_id' => Env::get('payment.mchId'),
'out_trade_no' => $order['orderNo'],
'body' => $order['goodsName'] ?? '',
'total_fee' => $order['money'] ?? 0,
'mch_create_ip' => Request::ip(),
'notify_url' => Env::get('payment.notify_url', '127.0.0.1'),
'nonce_str' => PaymentUtil::generateNonceStr(),
];
Db::startTrans();
try {
// 过滤空值签名
$secret = Env::get('payment.key');
$secret = Env::get('payment.key');
$params['sign_type'] = 'MD5';
$params['sign'] = PaymentUtil::generateSign($params, $secret, 'MD5');
$params['sign'] = PaymentUtil::generateSign($params, $secret, 'MD5');
$url = Env::get('payment.url');
if (empty($url)) {
@@ -76,14 +75,14 @@ class PaymentService
// XML POST 请求
$xmlBody = $this->arrayToXml($params);
$xmlBody = $this->arrayToXml($params);
$response = $this->postXml($url, $xmlBody);
$parsed = $this->parseXmlOrRaw($response);
$parsed = $this->parseXmlOrRaw($response);
if ($parsed['status'] == 0 && $parsed['result_code'] == 0) {
Db::commit();
return json(['code' => 200, 'msg' => '订单创建成功','data' => $parsed['code_url']]);
}else{
return json(['code' => 200, 'msg' => '订单创建成功', 'data' => $parsed['code_url']]);
} else {
Db::rollback();
return json(['code' => 500, 'msg' => '订单创建失败:' . $parsed['err_msg']]);
}
@@ -95,7 +94,6 @@ class PaymentService
}
/**
* POST 请求x-www-form-urlencoded
*/
@@ -202,112 +200,74 @@ class PaymentService
*/
public function notify()
{
Log::info('支付结果异步通知');
$rawBody = file_get_contents('php://input');
Log::info('[SwiftPass][notify] raw: ' . $rawBody);
//$rawBody = file_get_contents('php://input');
$rawBody = '<xml><bank_type><![CDATA[OTHERS]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<charset><![CDATA[UTF-8]]></charset>
<coupon_fee><![CDATA[0]]></coupon_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<mch_id><![CDATA[1030239780]]></mch_id>
<mdiscount><![CDATA[0]]></mdiscount>
<nonce_str><![CDATA[8c8993d51c1f4afcb4f8a265c4fe2084]]></nonce_str>
<op_user_id><![CDATA[1030239780]]></op_user_id>
<openid><![CDATA[o8jhotw0PnO8TLuRT9WurJ9dhpPU]]></openid>
<out_trade_no><![CDATA[20250924142316868008]]></out_trade_no>
<out_transaction_id><![CDATA[4200002761202509243272187350]]></out_transaction_id>
<pay_result><![CDATA[0]]></pay_result>
<result_code><![CDATA[0]]></result_code>
<sign><![CDATA[9F324511AF49B6261F62B1004D6350BF]]></sign>
<sign_type><![CDATA[MD5]]></sign_type>
<status><![CDATA[0]]></status>
<sub_appid><![CDATA[wx753bec1f52890a42]]></sub_appid>
<sub_openid><![CDATA[o6SVY6LB1obH6KD2uAtDMkqM9cgg]]></sub_openid>
<third_order_no><![CDATA[288550038027202509242227783238]]></third_order_no>
<time_end><![CDATA[20250924142412]]></time_end>
<total_fee><![CDATA[1]]></total_fee>
<trade_type><![CDATA[pay.wechat.jspay]]></trade_type>
<transaction_id><![CDATA[202509248102020491536020483421]]></transaction_id>
<version><![CDATA[2.0]]></version>
</xml>';
$payload = $this->parseXmlOrRaw($rawBody);
if (!is_array($payload) || empty($payload)) {
Log::error('[SwiftPass][notify] parse fail');
echo 'fail';
return;
return json_encode(['code' => 500, 'msg' => 'XML解析错误']);
}
// 基础字段
$status = (string)($payload['status'] ?? '');
$resultCode = (string)($payload['result_code'] ?? '');
$outTradeNo = (string)($payload['out_trade_no'] ?? '');
$totalFee = (int)($payload['total_fee'] ?? 0);
$mchIdNotify = (string)($payload['mch_id'] ?? '');
$signInNotify = (string)($payload['sign'] ?? '');
$signType = (string)($payload['sign_type'] ?? 'MD5');
if ($status !== '0' || $resultCode !== '0') {
Log::warning('[SwiftPass][notify] business not success', $payload);
echo 'fail';
return;
if ($payload['status'] != 0 || $payload['result_code'] != 0) {
$errMsg = (isset($payload['err_msg']) ? $payload['err_msg'] : isset($payload['err_msg'])) ? $payload['err_msg'] : '未知错误';
return json_encode(['code' => 500, 'msg' => $errMsg]);
}
// 验签
$secret = Env::get('payment.key');
if (empty($secret)) {
Log::error('[SwiftPass][notify] payment.key not configured');
echo 'fail';
return;
}
$verifyData = $payload;
unset($verifyData['sign']);
$calcSign = PaymentUtil::generateSign($verifyData, $secret, $signType ?: 'MD5');
if (strcasecmp($calcSign, $signInNotify) !== 0) {
Log::error('[SwiftPass][notify] sign mismatch', [
'calc' => $calcSign,
'recv' => $signInNotify,
]);
echo 'fail';
return;
}
// 校验商户号
$mchIdConfig = Env::get('payment.mchId');
if (!empty($mchIdConfig) && $mchIdConfig !== $mchIdNotify) {
Log::error('[SwiftPass][notify] mch_id mismatch', [
'config' => $mchIdConfig,
'notify' => $mchIdNotify,
]);
echo 'fail';
return;
}
// 业务处理:更新订单
Db::startTrans();
try {
/** @var Order|null $order */
$order = Order::where('orderNo', $outTradeNo)->lock(true)->find();
$outTradeNo = $payload['out_trade_no'];
$pay_result = $payload['pay_result'];
$time_end = $payload['time_end'];
$order = Order::where('orderNo', $outTradeNo)->find();
if (!$order) {
Db::rollback();
Log::error('[SwiftPass][notify] order not found', ['out_trade_no' => $outTradeNo]);
echo 'fail';
return;
return json_encode(['code' => 500, 'msg' => '该订单不存在']);
}
// 金额校验(单位:分)
if ((int)$order['money'] !== $totalFee) {
Db::rollback();
Log::error('[SwiftPass][notify] amount mismatch', [
'order_money' => (int)$order['money'],
'notify_fee' => $totalFee,
]);
echo 'fail';
return;
}
// 幂等:已支付直接返回成功
if ((int)$order['status'] === 1) {
if ($pay_result != 0) {
$order->payInfo = $payload['pay_info'];
$order->payType = $payload['trade_type'] == 'pay.wechat.jspay' ? 1 : 2;
$order->status = 3;
$order->save();
Db::commit();
echo 'success';
return;
return json_encode(['code' => 500, 'msg' => $payload['pay_info']]);
}
$transactionId = (string)($payload['transaction_id'] ?? '');
$timeEndStr = (string)($payload['time_end'] ?? '');
$paidAt = $this->parsePayTime($timeEndStr) ?: time();
$order->save([
'status' => 1,
'transactionId' => $transactionId,
'payTime' => $paidAt,
'updateTime' => time(),
]);
$order->status = 1;
$order->payTime = $this->parsePayTime($time_end);
$order->save();
Db::commit();
echo 'success';
return;
} catch (\Throwable $e) {
return json_encode(['code' => 200, 'msg' => '付款成功']);
} catch (\Exception $e) {
Db::rollback();
Log::error('[SwiftPass][notify] exception: ' . $e->getMessage());
echo 'fail';
return;
return json_encode(['code' => 500, 'msg' => '付款失败' . $e->getMessage()]);
}
}
@@ -338,7 +298,7 @@ class PaymentService
*/
public function queryOrder(array $query)
{
$outTradeNo = $query['out_trade_no'] ?? ($query['orderNo'] ?? '');
$outTradeNo = $query['out_trade_no'] ?? ($query['orderNo'] ?? '');
$transactionId = $query['transaction_id'] ?? '';
if ($outTradeNo === '' && $transactionId === '') {
@@ -346,11 +306,11 @@ class PaymentService
}
$params = [
'service' => 'unified.trade.query',
'mch_id' => Env::get('payment.mchId'),
'out_trade_no' => $outTradeNo ?: null,
'nonce_str' => PaymentUtil::generateNonceStr(),
'sign_type' => 'MD5',
'service' => 'unified.trade.query',
'mch_id' => Env::get('payment.mchId'),
'out_trade_no' => $outTradeNo ?: null,
'nonce_str' => PaymentUtil::generateNonceStr(),
'sign_type' => 'MD5',
];
// 过滤空值后签名
@@ -372,9 +332,9 @@ class PaymentService
}
// 请求网关
$xmlBody = $this->arrayToXml($filtered);
$xmlBody = $this->arrayToXml($filtered);
$response = $this->postXml($url, $xmlBody);
$parsed = $this->parseXmlOrRaw($response);
$parsed = $this->parseXmlOrRaw($response);
if (!is_array($parsed)) {
return json(['code' => 500, 'msg' => '响应解析失败', 'data' => $response]);
@@ -387,20 +347,20 @@ class PaymentService
if (($parsed['result_code'] ?? '') !== '0') {
return json(['code' => 200, 'msg' => '业务失败', 'data' => [
'err_code' => $parsed['err_code'] ?? '',
'err_msg' => $parsed['err_msg'] ?? '',
'err_msg' => $parsed['err_msg'] ?? '',
]]);
}
$tradeState = $parsed['trade_state'] ?? '';
$resp = [
'trade_state' => $tradeState,
'trade_state_desc'=> $parsed['trade_state_desc'] ?? '',
'transaction_id' => $parsed['transaction_id'] ?? '',
'out_trade_no' => $parsed['out_trade_no'] ?? $outTradeNo,
'total_fee' => isset($parsed['total_fee']) ? (int)$parsed['total_fee'] : null,
'time_end' => $parsed['time_end'] ?? '',
'buyer_logon_id' => $parsed['buyer_logon_id'] ?? '',
'bank_type' => $parsed['bank_type'] ?? '',
'trade_state' => $tradeState,
'trade_state_desc' => $parsed['trade_state_desc'] ?? '',
'transaction_id' => $parsed['transaction_id'] ?? '',
'out_trade_no' => $parsed['out_trade_no'] ?? $outTradeNo,
'total_fee' => isset($parsed['total_fee']) ? (int)$parsed['total_fee'] : null,
'time_end' => $parsed['time_end'] ?? '',
'buyer_logon_id' => $parsed['buyer_logon_id'] ?? '',
'bank_type' => $parsed['bank_type'] ?? '',
];
// 若已支付,同步本地订单
@@ -413,10 +373,10 @@ class PaymentService
$paidAt = $this->parsePayTime($resp['time_end'] ?? '') ?: time();
if ((int)$order['status'] !== 1) {
$order->save([
'status' => 1,
'status' => 1,
'transactionId' => $resp['transaction_id'] ?? '',
'payTime' => $paidAt,
'updateTime' => time(),
'payTime' => $paidAt,
'updateTime' => time(),
]);
}
}