$value) { $parts[] = $name . '=' . $value; } $parts[] = 'key=' . $key; return hash('sha256', implode('&', $parts)); } public static function pay($amount, string $orderNo, string $memberNo, string $channel): array { $data = self::signedData([ 'appId' => self::getDepositMerchantId(), 'merchantMemberNo' => $memberNo, 'merchantOrderNo' => $orderNo, 'amount' => self::amount($amount), 'paymentMethod' => self::paymentMethod($channel), 'notifyUrl' => self::getDepositNotifyUrl(), 'timestamp' => time(), 'version' => 'v1', ], (string)config('app.no_pay_deposit_key')); return self::post((string)config('app.no_pay_deposit_gateway'), $data, self::getDepositMerchantId()); } public static function queryPayOrder(string $orderNo, string $memberNo): array { $data = self::signedData([ 'appId' => self::getDepositMerchantId(), 'merchantOrderNo' => $orderNo, 'merchantMemberNo' => $memberNo, 'timestamp' => time(), 'version' => 'v1', ], (string)config('app.no_pay_deposit_key')); return self::post((string)config('app.no_pay_deposit_query_gateway'), $data, self::getDepositMerchantId()); } public static function withdraw($amount, string $orderNo, string $memberNo, string $accountName, string $qAccount): array { $data = self::signedData([ 'appId' => self::getWithdrawMerchantId(), 'merchantOrderNo' => $orderNo, 'merchantMemberNo' => $memberNo, 'amount' => self::amount($amount), 'accountName' => $accountName, 'notifyUrl' => self::getWithdrawNotifyUrl(), 'qAccount' => $qAccount, 'timestamp' => time(), 'version' => 'v1', ], (string)config('app.no_pay_withdraw_key')); return self::post((string)config('app.no_pay_withdraw_gateway'), $data, self::getWithdrawMerchantId()); } public static function verifyDepositNotify(array $params): bool { return self::verifyNotify($params, self::getDepositMerchantId(), (string)config('app.no_pay_deposit_key')); } public static function verifyWithdrawNotify(array $params): bool { return self::verifyNotify($params, self::getWithdrawMerchantId(), (string)config('app.no_pay_withdraw_key')); } private static function signedData(array $data, string $key): array { $data['sign'] = self::signature($data, $key); return $data; } private static function verifyNotify(array $params, string $merchantId, string $key): bool { if ($merchantId === '' || ($params['appId'] ?? '') !== $merchantId || empty($params['sign'])) { return false; } return hash_equals(self::signature($params, $key), strtolower((string)$params['sign'])); } private static function post(string $url, array $data, string $merchantId): array { $logData = $data; unset($logData['sign'], $logData['password']); Log::info('NO钱包接口请求', [ 'url' => $url, 'merchant_id' => $merchantId, 'data' => $logData, ]); try { $response = (new Client(['timeout' => 10.0]))->post($url, [ 'json' => $data, 'headers' => [ 'Accept' => 'application/json', 'appId' => $merchantId, 'language' => 'zh_CN', ], ]); $body = $response->getBody()->getContents(); Log::info('NO钱包接口响应', [ 'url' => $url, 'merchant_id' => $merchantId, 'http_status' => $response->getStatusCode(), 'body' => $body, ]); return json_decode($body, true) ?: []; } catch (RequestException $e) { $response = $e->getResponse(); $body = $response ? $response->getBody()->getContents() : ''; Log::error('NO钱包接口请求失败', [ 'url' => $url, 'merchant_id' => $merchantId, 'http_status' => $response ? $response->getStatusCode() : null, 'body' => $body, 'error' => $e->getMessage(), ]); throw $e; } catch (\Throwable $e) { Log::error('NO钱包接口异常', [ 'url' => $url, 'merchant_id' => $merchantId, 'error' => $e->getMessage(), ]); throw $e; } } public static function getWhere(array $search = []): array { return []; } }