Files
appraisal_center_api/app/api/controller/PayController.php
2026-04-16 11:17:18 +08:00

104 lines
3.5 KiB
PHP

<?php
namespace app\api\controller;
use support\Request;
use app\common\model\Order;
use app\common\model\PaymentTransaction;
use app\common\model\WechatMerchant;
use app\common\service\OrderFlowService;
use app\common\service\WechatPayV3Client;
use Illuminate\Database\Capsule\Manager as DB;
class PayController
{
public function wechatNotify(Request $request)
{
$body = (string)$request->rawBody();
$timestamp = (string)$request->header('Wechatpay-Timestamp', '');
$nonce = (string)$request->header('Wechatpay-Nonce', '');
$signature = (string)$request->header('Wechatpay-Signature', '');
if ($timestamp === '' || $nonce === '' || $signature === '') {
return json(['code' => 'FAIL', 'message' => 'missing headers'], 400);
}
$merchants = WechatMerchant::where('status', 1)->get();
if ($merchants->count() === 0) {
return json(['code' => 'FAIL', 'message' => 'no merchant'], 500);
}
$client = new WechatPayV3Client($merchants->first());
$ok = $client->verifyPlatformSignature($timestamp, $nonce, $body, $signature);
if (!$ok) {
return json(['code' => 'FAIL', 'message' => 'invalid signature'], 400);
}
$payload = json_decode($body, true) ?: [];
$resource = $payload['resource'] ?? null;
if (!is_array($resource)) {
return json(['code' => 'FAIL', 'message' => 'invalid body'], 400);
}
$decrypt = null;
$matchedMerchant = null;
foreach ($merchants as $m) {
$apiV3Key = (string)($m->api_v3_key ?? '');
if ($apiV3Key === '') continue;
try {
$decrypt = $client->decryptNotifyResource($resource, $apiV3Key);
$matchedMerchant = $m;
break;
} catch (\Throwable $e) {
}
}
if (!$decrypt || !$matchedMerchant) {
return json(['code' => 'FAIL', 'message' => 'decrypt failed'], 400);
}
$outTradeNo = (string)($decrypt['out_trade_no'] ?? '');
$tradeState = (string)($decrypt['trade_state'] ?? '');
if ($outTradeNo === '') {
return json(['code' => 'FAIL', 'message' => 'missing out_trade_no'], 400);
}
$tx = PaymentTransaction::where('out_trade_no', $outTradeNo)->first();
if (!$tx) {
return json(['code' => 'SUCCESS', 'message' => 'OK']);
}
if ($tradeState !== 'SUCCESS') {
return json(['code' => 'SUCCESS', 'message' => 'OK']);
}
DB::beginTransaction();
try {
$tx->status = 'paid';
$tx->paid_at = date('Y-m-d H:i:s');
$tx->raw_json = $decrypt;
$tx->save();
$order = Order::find($tx->order_id);
if ($order) {
$order->pay_channel = 'wechat';
$order->pay_status = 'paid';
$order->pay_merchant_id = (int)$matchedMerchant->id;
$order->pay_out_trade_no = $outTradeNo;
if (!$order->pay_time) {
$order->pay_time = date('Y-m-d H:i:s');
}
$order->save();
OrderFlowService::payOrder($order);
}
DB::commit();
} catch (\Throwable $e) {
DB::rollBack();
return json(['code' => 'FAIL', 'message' => 'server error'], 500);
}
return json(['code' => 'SUCCESS', 'message' => 'OK']);
}
}