get_config(); return !empty($config['mch_id']) && !empty($config['key']); } public function create_payment(array $order): array { if (!$this->is_configured()) { return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')]; } $config = $this->get_config(); $order_number = $order['order_number'] ?? ''; $amount = (float) ($order['amount'] ?? 0); $subject = $order['subject'] ?? __('订单支付', 'aksrt'); $payment_type = $config['payment_type'] ?? 'native'; // native / jsapi / h5 try { $sdk = $this->create_sdk($config); $total_fee = (int) ($amount * 100); // 转为分 switch ($payment_type) { case 'jsapi': $request = new \Yurun\PaySDK\Weixin\JSAPI\Params\Pay\Request; $request->openid = $order['openid'] ?? ''; break; case 'h5': $request = new \Yurun\PaySDK\Weixin\H5\Params\Pay\Request; break; case 'native': default: $request = new \Yurun\PaySDK\Weixin\Native\Params\Pay\Request; break; } $request->body = $subject; $request->out_trade_no = $order_number; $request->total_fee = $total_fee; $request->fee_type = 'CNY'; $request->notify_url = home_url('/wp-json/aksrt/v1/payment/wechatpay/notify'); $request->spbill_create_ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'; $result = $sdk->execute($request); if ($sdk->checkResult()) { $result_data = [ 'success' => true, 'payment_data' => array_merge($result, ['order_number' => $order_number]), 'message' => __('微信支付订单已创建', 'aksrt'), ]; if ($payment_type === 'native' && !empty($result['code_url'])) { $result_data['payment_url'] = $result['code_url']; } elseif ($payment_type === 'h5' && !empty($result['h5_url'])) { $result_data['payment_url'] = $result['h5_url']; } return $result_data; } return ['success' => false, 'message' => $sdk->getError() ?: __('微信支付创建失败', 'aksrt')]; } catch (\Exception $e) { return ['success' => false, 'message' => $e->getMessage()]; } } public function verify_callback(WP_REST_Request $request): array { $config = $this->get_config(); try { $sdk = $this->create_sdk($config); // 读取原始请求体 $xml = file_get_contents('php://input'); $data = \Yurun\PaySDK\Lib\XML::fromString($xml); if ($sdk->verifyCallback($data)) { return [ 'success' => true, 'order_number' => $data['out_trade_no'] ?? '', 'amount' => (($data['total_fee'] ?? 0) / 100), 'transaction_id' => $data['transaction_id'] ?? '', 'status' => ($data['result_code'] ?? '') === 'SUCCESS' ? 'paid' : 'pending', ]; } return ['success' => false, 'message' => __('微信支付回调签名验证失败', 'aksrt')]; } catch (\Exception $e) { return ['success' => false, 'message' => $e->getMessage()]; } } /** * 输出微信支付回调响应 */ public function output_callback_response(array $result): void { if ($result['success'] ?? false) { echo ''; } else { echo ''; } exit; } public function query_status(string $order_number): array { if (!$this->is_configured()) { return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')]; } $config = $this->get_config(); try { $sdk = $this->create_sdk($config); $request = new \Yurun\PaySDK\Weixin\OrderQuery\Request; $request->out_trade_no = $order_number; $result = $sdk->execute($request); if ($sdk->checkResult()) { $trade_state = $result['trade_state'] ?? ''; $status = 'pending'; if ($trade_state === 'SUCCESS') { $status = 'paid'; } elseif (in_array($trade_state, ['CLOSED', 'REVOKED'])) { $status = 'cancelled'; } elseif ($trade_state === 'REFUND') { $status = 'refunded'; } return [ 'success' => true, 'status' => $status, 'transaction_id' => $result['transaction_id'] ?? '', ]; } return ['success' => false, 'message' => $sdk->getError() ?: __('查询失败', 'aksrt')]; } catch (\Exception $e) { return ['success' => false, 'message' => $e->getMessage()]; } } public function refund(string $order_number, float $amount): array { if (!$this->is_configured()) { return ['success' => false, 'message' => __('微信支付未配置', 'aksrt')]; } $config = $this->get_config(); try { $sdk = $this->create_sdk($config); // 先查询订单获取 transaction_id $query = new \Yurun\PaySDK\Weixin\OrderQuery\Request; $query->out_trade_no = $order_number; $query_result = $sdk->execute($query); if (!$sdk->checkResult() || empty($query_result['transaction_id'])) { return ['success' => false, 'message' => __('未找到支付记录', 'aksrt')]; } $refund_fee = (int) ($amount * 100); $request = new \Yurun\PaySDK\Weixin\Refund\Request; $request->out_trade_no = $order_number; $request->out_refund_no = 'REF_' . $order_number . '_' . time(); $request->total_fee = (int) ($query_result['total_fee'] ?? $refund_fee); $request->refund_fee = $refund_fee; $request->refund_desc = __('用户申请退款', 'aksrt'); $result = $sdk->execute($request); if ($sdk->checkResult()) { return [ 'success' => true, 'refund_id' => $result['refund_id'] ?? '', 'message' => __('退款成功', 'aksrt'), ]; } return ['success' => false, 'message' => $sdk->getError() ?: __('退款失败', 'aksrt')]; } catch (\Exception $e) { return ['success' => false, 'message' => $e->getMessage()]; } } private function get_config(): array { if (!class_exists('AKSRT_Settings')) { return []; } $all = AKSRT_Settings::get_all(); return [ 'mch_id' => (string) ($all['wechat_merchantid'] ?? ''), 'key' => (string) ($all['wechat_jsapi'] ?? ''), 'appid' => (string) ($all['wechat_appid'] ?? ''), 'appsecret' => (string) ($all['wechat_appsecret'] ?? ''), 'cert_path' => (string) ($all['wechat_cert_path'] ?? ''), 'key_path' => (string) ($all['wechat_key_path'] ?? ''), 'payment_type' => (string) ($all['wechat_payment_type'] ?? 'native'), ]; } private function create_sdk(array $config): \Yurun\PaySDK\Weixin\SDK { $params = new \Yurun\PaySDK\Weixin\Params\PublicParams; $params->appID = $config['appid'] ?? ''; $params->mch_id = $config['mch_id'] ?? ''; $params->key = $config['key'] ?? ''; $params->sign_type = $config['sign_type'] ?? 'HMAC-SHA256'; if (!empty($config['cert_path'])) { $params->certPath = $config['cert_path']; } if (!empty($config['key_path'])) { $params->keyPath = $config['key_path']; } return new \Yurun\PaySDK\Weixin\SDK($params); } }