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']); } }