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