$this->merchant_no, 'orgNo' => 970936, ]; $rand = time() . '_' . stringUtil::charsShuffle(22); $baseRequestVO = [ 'reqData' => $arr, 'timestamp' => time(), 'reqId' => $rand, 'ver' => '1.0.0', ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v2/laep/industry/ewalletBalanceQuery'; return $this->post($url, $body, $authorization); } //申请主动结算 ssh public function applyInviteClear($params) { $subMerchantId = $params['subMerchantId']; $tradeMode = $params['tradeMode']; $arr = [ 'tradeMode' => $tradeMode, 'merchantNo' => $this->merchant_no, 'subMerchantId' => $subMerchantId, 'orderNo' => $orderNo, //机构代号 'orgCode' => '970936', 'version' => 'v1.0.0', ]; $rand = time() . '_' . stringUtil::charsShuffle(22); $baseRequestVO = [ 'reqData' => $arr, 'timestamp' => time(), 'reqId' => $rand, 'ver' => '1.0.0', ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v2/mms/sme/mrchAuthStateQuery'; return $this->post($url, $body, $authorization); } public function __construct($params) { $this->appid = $params['appid'] ?? ''; $this->serial_no = $params['serial_no'] ?? ''; $this->merchant_no = $params['merchant_no'] ?? ''; $this->term_no = $params['term_no'] ?? ''; $this->merchantPrivateKeyPath = $params['merchantPrivateKeyPath']; $this->lklCertificatePath = $params['lklCertificatePath']; if (getenv('YII_ENV') == 'production') { $this->preUrl = 'https://s2.lakala.com/api/v3/labs/trans/'; } else { //$this->preUrl = 'https://test.wsmsd.cn/sit/api/v3/labs/trans/'; $this->preUrl = 'https://s2.lakala.com/api/v3/labs/trans/'; } } //退款查询 public function refundQuery($params) { $orderSn = $params['orderSn']; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, //'out_trade_no' => $orderSn, 'trade_no' => $orderSn, ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v3/labs/query/tradequery'; return $this->post($url, $body, $authorization); } public function openStateQuery($params) { $subMerchantId = $params['subMerchantId']; $tradeMode = $params['tradeMode']; $arr = [ 'tradeMode' => $tradeMode, 'merchantNo' => $this->merchant_no, 'subMerchantId' => $subMerchantId, ]; $baseRequestVO = [ 'reqData' => $arr, 'timestamp' => time(), 'ver' => '1.0.0', ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v2/mms/sme/mrchAuthStateQuery'; return $this->post($url, $body, $authorization); } //收银台支付,APP支付和H5支付时使用 ssh 2023112 public function cashierPay($params) { $orderSn = $params['orderSn']; $amount = $params['amount']; $payWay = $params['payWay'] ?? 1; $payMode = $payWay==1?'ALIPAY':'WECHAT'; $notifyUrl = $params['notifyUrl']; $subject = $params['subject']; $capitalType = $params['capitalType']; $time = time() + 108000; $orderEfficientTime = date("YmdHis", $time); $bus = json_encode([['busi_type' => 'SCPAY', 'params' => ['pay_mode' => $payMode]]]); $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'out_order_no' => $orderSn, 'total_amount' => bcmul($amount, 100), 'order_info' => $subject, 'support_refund' => 1, 'notify_url' => $notifyUrl, 'order_efficient_time' => $orderEfficientTime, 'busi_type_param' => $bus, 'counter_param' => json_encode(['pay_mode' => $payMode]), 'counter_remark' => '{"capitalType":' . $capitalType . '}' ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v3/ccss/counter/order/create'; return $this->post($url, $body, $authorization); } //收银机订单查询 ssh 20231026 public function cashierQuery($params) { $out_order_no = $params['out_order_no']; $arr = [ 'merchant_no' => $this->merchant_no, 'out_order_no' => $out_order_no, ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v3/ccss/counter/order/query'; return $this->post($url, $body, $authorization); } public function query($params, $lklSn = 0) { $orderSn = $params['orderSn'] ?? ''; $tradeNo = $params['tradeNo'] ?? ''; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'location_info' => $location_info, ]; if ($lklSn == 0) { $arr['out_trade_no'] = $orderSn; } else { $arr['trade_no'] = $tradeNo; } $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v3/labs/query/tradequery'; return $this->post($url, $body, $authorization); } //被扫付款 public function scanPay($params) { $orderSn = $params['orderSn']; $amount = $params['amount']; $notifyUrl = $params['notifyUrl']; $subject = $params['subject']; $authCode = $params['authCode']; $capitalType = $params['capitalType']; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'out_trade_no' => $orderSn, 'total_amount' => bcmul($amount, 100), 'auth_code' => $authCode, 'location_info' => $location_info, 'subject' => $subject, 'notify_url' => $notifyUrl, 'remark' => '{"capitalType":' . $capitalType . '}', ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $url = 'https://s2.lakala.com/api/v3/labs/trans/micropay'; return $this->post($url, $body, $authorization); } //关掉 ssh 20231009 public function close($params) { $orderSn = $params['orderSn']; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'location_info' => $location_info, 'origin_out_trade_no' => $orderSn, ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $lklUrl = 'https://s2.lakala.com/api/v3/labs/relation/close'; return $this->post($lklUrl, $body, $authorization); } public function cashClose($params) { $orderSn = $params['orderSn']; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'location_info' => $location_info, 'out_order_no' => $orderSn, ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => '1.0', ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $lklUrl = 'https://s2.lakala.com/api/v3/ccss/counter/order/close'; return $this->post($lklUrl, $body, $authorization); } //退款 ssh 20231009 public function refund($params) { $orderSn = $params['orderSn'] ?? ''; $refundSn = $params['refundSn']; $refundReason = $params['refundReason']; $refundAmount = $params['refundAmount']; //这个参数必传,不然聚合收银合支付宝付款的退款不会成功 $thirdNo = $params['thirdNo'] ?? ''; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'out_trade_no' => $refundSn, 'refund_amount' => $refundAmount, 'location_info' => $location_info, 'refund_reason' => $refundReason, 'origin_out_trade_no' => $orderSn, 'origin_trade_no' => $thirdNo, ]; //原拉卡拉交易流水号,收银台接口下单的,发起退款时必传 if (isset($params['originTradeNo'])) { $arr['origin_trade_no'] = $params['originTradeNo']; } if (isset($params['originLogNo'])) { $arr['origin_log_no'] = $params['originLogNo']; } $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); $lklUrl = 'https://s2.lakala.com/api/v3/labs/relation/refund'; return $this->post($lklUrl, $body, $authorization); } //主扫交易,微信 public function driveWxPay($params) { $orderSn = $params['orderSn']; $amount = $params['amount']; $notifyUrl = $params['notifyUrl']; $subject = $params['subject']; $capitalType = $params['capitalType']; $wxAppId = $params['wxAppId'] ?? ''; $openId = $params['openId'] ?? ''; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'out_trade_no' => $orderSn, 'account_type' => 'WECHAT', 'trans_type' => 71, 'total_amount' => bcmul($amount, 100), 'location_info' => $location_info, 'subject' => $subject, 'notify_url' => $notifyUrl, 'remark' => '{"capitalType":' . $capitalType . '}', 'acc_busi_fields' => [ 'sub_appid' => $wxAppId, 'user_id' => $openId, 'timeout_express' => 30, ], ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); return $this->post($this->preUrl . 'preorder', $body, $authorization); } public function driveNativeWxPay($params) { $orderSn = $params['orderSn']; $amount = $params['amount']; $notifyUrl = $params['notifyUrl']; $subject = $params['subject']; $capitalType = $params['capitalType']; $wxAppId = $params['wxAppId'] ?? ''; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'out_trade_no' => $orderSn, 'account_type' => 'WECHAT', 'trans_type' => 71, 'total_amount' => bcmul($amount, 100), 'location_info' => $location_info, 'subject' => $subject, 'notify_url' => $notifyUrl, 'remark' => '{"capitalType":' . $capitalType . '}', 'acc_busi_fields' => [ 'timeout_express' => 30, 'sub_appid' => $wxAppId, ], ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); return $this->post($this->preUrl . 'preorder', $body, $authorization); } //主扫交易,支付宝 public function driveAliPay($params) { $orderSn = $params['orderSn']; $amount = $params['amount']; $notifyUrl = $params['notifyUrl']; $subject = $params['subject']; $capitalType = $params['capitalType']; $ip = $this->getClientIp(); $location_info = ['request_ip' => $ip]; $arr = [ 'merchant_no' => $this->merchant_no, 'term_no' => $this->term_no, 'out_trade_no' => $orderSn, 'account_type' => 'ALIPAY', 'trans_type' => '41', 'total_amount' => bcmul($amount, 100), 'location_info' => $location_info, 'subject' => $subject, 'notify_url' => $notifyUrl, 'remark' => '{"capitalType":' . $capitalType . '}', ]; $baseRequestVO = [ 'req_data' => $arr, 'req_time' => date("YmdHis"), 'version' => $this->version, ]; $body = json_encode($baseRequestVO, JSON_UNESCAPED_UNICODE); $authorization = $this->getAuthorization($body); return $this->post($this->preUrl . 'preorder', $body, $authorization); } //验签 public function signatureVerification($authorization, $body) { $authorization = str_replace($this->schema . " ", "", $authorization); $authorization = str_replace(",", "&", $authorization); $authorization = str_replace("\"", "", $authorization); $authorization = $this->convertUrlQuery($authorization); $authorization['signature'] = base64_decode($authorization['signature']); $message = $authorization['timestamp'] . "\n" . $authorization['nonce_str'] . "\n" . $body . "\n"; $key = openssl_get_publickey(file_get_contents($this->lklCertificatePath)); $flag = openssl_verify($message, $authorization['signature'], $key, OPENSSL_ALGO_SHA256); openssl_free_key($key); if ($flag) { return true; } return false; } //签名 public function getAuthorization($body) { $nonceStr = $this->randString(12); $timestamp = time(); $message = $this->appid . "\n" . $this->serial_no . "\n" . $timestamp . "\n" . $nonceStr . "\n" . $body . "\n"; $key = openssl_get_privatekey(file_get_contents($this->merchantPrivateKeyPath)); openssl_sign($message, $signature, $key, OPENSSL_ALGO_SHA256); openssl_free_key($key); return $this->schema . " appid=\"" . $this->appid . "\"," . "serial_no=\"" . $this->serial_no . "\"," . "timestamp=\"" . $timestamp . "\"," . "nonce_str=\"" . $nonceStr . "\"," . "signature=\"" . base64_encode($signature) . "\""; } //获取随机数 public function randString($length) { $characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; $randomString = ""; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, strlen($characters) - 1)]; } return $randomString; } //请求 public function post($url, $data, $authorization) { $headers = [ "Authorization: " . $authorization, "Accept: application/json", "Content-Type:application/json", ]; \Yii::info("请求参数:" . $data); $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);//设置HTTP头 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, 1); $res = curl_exec($ch); curl_close($ch); return json_decode($res, 1); } //签名参数转数组 private function convertUrlQuery($query) { $queryParts = explode('&', $query); $params = array(); foreach ($queryParts as $param) { $item = explode('=', $param); $params[$item[0]] = $item[1]; } if ($params['signature']) { $params['signature'] = substr($query, strrpos($query, 'signature=') + 10); } return $params; } public function getClientIp() { if (isset($_SERVER['REMOTE_ADDR'])) { $cip = $_SERVER['REMOTE_ADDR']; } elseif (getenv("REMOTE_ADDR")) { $cip = getenv("REMOTE_ADDR"); } elseif (getenv("HTTP_CLIENT_IP")) { $cip = getenv("HTTP_CLIENT_IP"); } else { if (getenv('YII_ENV') == 'production') { $cip = "114.55.169.20"; } else { $cip = "118.178.193.23"; } } return $cip; } }