From de97de83348e2f95c2aff816a6e97e2639f461df Mon Sep 17 00:00:00 2001 From: weizong song Date: Mon, 5 Apr 2021 13:51:22 +0800 Subject: [PATCH] up --- .../Controllers/Manager/OrdersController.php | 60 +++- app/Libs/WxMicroPay.class.php | 85 ++++++ app/Libs/WxPayCommon.class.php | 263 ++++++++++++++++++ 3 files changed, 401 insertions(+), 7 deletions(-) create mode 100644 app/Libs/WxMicroPay.class.php create mode 100644 app/Libs/WxPayCommon.class.php diff --git a/app/Http/Controllers/Manager/OrdersController.php b/app/Http/Controllers/Manager/OrdersController.php index 5241600..6507044 100644 --- a/app/Http/Controllers/Manager/OrdersController.php +++ b/app/Http/Controllers/Manager/OrdersController.php @@ -6,6 +6,7 @@ namespace App\Http\Controllers\Manager; use AlicFeng\IdentityCard\InfoHelper; use App\Customer; use App\Events\OrderAssigned; +use App\Libs\WxMicroPay; use App\Models\Approval; use App\Models\ApprovalItems; use App\Models\Area; @@ -100,7 +101,7 @@ class OrdersController extends CommonController /** * @OA\Get( * path="/manager/get-badges", - * summary="获取首页数量角标", + * summary="V2-获取首页数量角标", * description="获取首页数量角标", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( @@ -216,7 +217,7 @@ class OrdersController extends CommonController /** * @OA\Get( * path="/manager/get-order/{id}", - * summary="获取订单详情", + * summary="V2-获取订单详情", * description="获取订单详情", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="id"), @@ -406,7 +407,7 @@ class OrdersController extends CommonController /** * @OA\Get( * path="/manager/get-paramedic/{id}", - * summary="获取护工详情", + * summary="V2-获取护工详情", * description="获取护工详情", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Parameter(name="id", in="path", @OA\Schema(type="integer"), required=true, description="id"), @@ -420,11 +421,11 @@ class OrdersController extends CommonController public function getParamedic($id) { $paramedic = (new Paramedic())->with([ - "project" => function($query) { - $query->select("id","name","address"); + "project" => function ($query) { + $query->select("id", "name", "address"); }, - "level" => function($query) { - $query->select("id","name"); + "level" => function ($query) { + $query->select("id", "name"); } ])->find($id); return response()->json($paramedic ? $paramedic->toArray() : null); @@ -559,6 +560,51 @@ class OrdersController extends CommonController } } + /** + * @OA\Get( + * path="/manager/scan-pay/{order_id}", + * summary="V2-扫用户支付码收款", + * description="扫用户支付码收款", + * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), + * @OA\Parameter(name="order_id", in="path", @OA\Schema(type="integer"), required=true, description="订单id"), + * @OA\Parameter(name="money", in="query", @OA\Schema(type="number"), required=true, description="支付金额"), + * @OA\Parameter(name="auth_code", in="query", @OA\Schema(type="string"), required=true, description="扫码后获取的支付码"), + * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=true, description="支付方式:weixin,alipay"), + * @OA\Response( + * response="200", + * description="扫用户支付码收款" + * ) + * ) + */ + public function scanPay($order_id) + { + $order = (new Orders())->find($order_id); + $recharge = (new Recharge())->create([ + "customer_id" => $order->customer->id, + "money" => request()->money, + "order_id" => $order->id, + "payment" => request()->type + ]); + $recharge = $recharge->getSerial(); + + switch (request()->type) { + case "weixin": + try { + $res = (new WxMicroPay())->pay($recharge); + return response()->json([ + "errorcode" => 0, + "errormsg" => "支付成功!" + ]); + } catch (\Exception $exception) { + return response()->json([ + "errorcode" => 60003, + "errormsg" => $exception->getMessage() + ]); + } + break; + } + } + /** * @OA\POST( * path="/manager/confirm-order/{id}", diff --git a/app/Libs/WxMicroPay.class.php b/app/Libs/WxMicroPay.class.php new file mode 100644 index 0000000..1261560 --- /dev/null +++ b/app/Libs/WxMicroPay.class.php @@ -0,0 +1,85 @@ +parameters["out_trade_no"]) { + throw new Exception("缺少必填参数out_trade_no!" . "
"); + } elseif (!$this->parameters["body"]) { + throw new Exception("缺少必填参数body!" . "
"); + } elseif (!$this->parameters["total_fee"]) { + throw new Exception("缺少必填参数total_fee!" . "
"); + } elseif (!$this->parameters["auth_code"]) { + throw new Exception("缺少必填参数auth_code!" . "
"); + } + } + + /** + * + * 扫码支付,并且确认结果,接口比较慢 + * @param $recharge + */ + public function pay(Recharge $recharge) + { + //提交被扫支付 + $this->setParameter("out_trade_no", $recharge->serial); + $this->setParameter("body", "充值{$recharge->money}元"); + $this->setParameter("total_fee", $recharge->money * 100); + $this->setParameter("auth_code", request()->auth_code); + + $this->checkParameters(); + $xml = $this->createXml(); + $result = $this->postXmlCurl($xml, $this->pay_url); + $result = $this->xmlToArray($result); + + //如果返回成功 + if (!array_key_exists("return_code", $result) || !array_key_exists("result_code", $result)) { + throw new Exception("接口调用失败"); + } + + return true; + + //取订单号 + $out_trade_no = $microPayInput->GetOut_trade_no(); + + //②、接口调用成功,明确返回调用失败 + if ($result["return_code"] == "SUCCESS" && + $result["result_code"] == "FAIL" && + $result["err_code"] != "USERPAYING" && + $result["err_code"] != "SYSTEMERROR") { + return false; + } + + //③、确认支付是否成功 + $queryTimes = 10; + while ($queryTimes > 0) { + $succResult = 0; + $queryResult = $this->query($out_trade_no, $succResult); + //如果需要等待1s后继续 + if ($succResult == 2) { + sleep(2); + continue; + } else if ($succResult == 1) {//查询成功 + return $queryResult; + } else {//订单交易失败 + break; + } + } + + //④、次确认失败,则撤销订单 + if (!$this->cancel($out_trade_no)) { + throw new WxpayException("撤销单失败!"); + } + + return false; + } +} diff --git a/app/Libs/WxPayCommon.class.php b/app/Libs/WxPayCommon.class.php new file mode 100644 index 0000000..fa055e5 --- /dev/null +++ b/app/Libs/WxPayCommon.class.php @@ -0,0 +1,263 @@ +app_id = env("WEIXINPAY_APPID"); + $this->key = env("WEIXINPAY_KEY"); + $this->merchant_id = env("WEIXINPAY_MCHID"); + $this->ssl_cert_path = env("WEIXINPAY_SSLCERT_PATH"); + $this->ssl_key_path = env("WEIXINPAY_KEY_PATH"); + } + + function trimString($value) + { + $ret = null; + if (null != $value) { + $ret = $value; + if (strlen($ret) == 0) { + $ret = null; + } + } + return $ret; + } + + /** + * 作用:设置请求参数 + */ + function setParameter($parameter, $parameterValue) + { + $this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue); + } + + function checkParameters() + { + //检测必填参数 + } + + /** + * 生成接口参数xml + */ + function createXml() + { + try { + $this->parameters["appid"] = $this->app_id;//公众账号ID + $this->parameters["mch_id"] = $this->merchant_id;//商户号 + $this->parameters["spbill_create_ip"] = $_SERVER['REMOTE_ADDR'];//终端ip + $this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串 + $this->parameters["sign"] = $this->getSign($this->parameters);//签名 + return $this->arrayToXml($this->parameters); + } catch (Exception $e) { + dd($e->getMessage()); + } + } + + /** + * 作用:产生随机字符串,不长于32位 + */ + public function createNoncestr($length = 32) + { + $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; + $str = ""; + for ($i = 0; $i < $length; $i++) { + $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); + } + return $str; + } + + /** + * 作用:生成签名 + */ + public function getSign($Obj) + { + foreach ($Obj as $k => $v) { + $Parameters[$k] = $v; + } + //签名步骤一:按字典序排序参数 + ksort($Parameters); + $String = $this->formatBizQueryParaMap($Parameters, false); + //echo '【string1】'.$String.'
'; + //签名步骤二:在string后加入KEY + $String = $String . "&key=" . $this->key; + //echo "【string2】".$String."
"; + //签名步骤三:MD5加密 + $String = md5($String); + //echo "【string3】 ".$String."
"; + //签名步骤四:所有字符转为大写 + $result_ = strtoupper($String); + //echo "【result】 ".$result_."
"; + return $result_; + } + + /** + * 作用:格式化参数,签名过程需要使用 + */ + function formatBizQueryParaMap($paraMap, $urlencode) + { + $buff = ""; + ksort($paraMap); + foreach ($paraMap as $k => $v) { + if ($urlencode) { + $v = urlencode($v); + } + //$buff .= strtolower($k) . "=" . $v . "&"; + $buff .= $k . "=" . $v . "&"; + } + $reqPar = ""; + if (strlen($buff) > 0) { + $reqPar = substr($buff, 0, strlen($buff) - 1); + } + return $reqPar; + } + + /** + * 作用:array转xml + */ + function arrayToXml($arr) + { + $xml = ""; + foreach ($arr as $key => $val) { + if (is_numeric($val)) { + $xml .= "<" . $key . ">" . $val . ""; + + } else + $xml .= "<" . $key . ">"; + } + $xml .= ""; + return $xml; + } + + /** + * 作用:将xml转为array + */ + public function xmlToArray($xml) + { + //将XML转为array + $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); + return $array_data; + } + + /** + * 作用:以post方式提交xml到对应的接口url + */ + public function postXmlCurl($xml, $url, $second = 30) + { + //初始化curl + $ch = curl_init(); + //设置超时 + curl_setopt($ch, CURLOPT_TIMEOUT, $second); + //这里设置代理,如果有的话 + //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); + //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); + //设置header + curl_setopt($ch, CURLOPT_HEADER, FALSE); + //要求结果为字符串且输出到屏幕上 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + //post提交方式 + curl_setopt($ch, CURLOPT_POST, TRUE); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); + //运行curl + $data = curl_exec($ch); + //返回结果 + if ($data) { + curl_close($ch); + return $data; + } else { + $error = curl_errno($ch); + echo "curl出错,错误码:$error" . "
"; + echo "错误原因查询
"; + curl_close($ch); + return false; + } + } + + /** + * 作用:使用证书,以post方式提交xml到对应的接口url + */ + function postXmlSSLCurl($xml, $url, $second = 30) + { + $ch = curl_init(); + //超时时间 + curl_setopt($ch, CURLOPT_TIMEOUT, $second); + //这里设置代理,如果有的话 + //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8'); + //curl_setopt($ch,CURLOPT_PROXYPORT, 8080); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); + //设置header + curl_setopt($ch, CURLOPT_HEADER, FALSE); + //要求结果为字符串且输出到屏幕上 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + //设置证书 + //使用证书:cert 与 key 分别属于两个.pem文件 + //默认格式为PEM,可以注释 + curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM'); + curl_setopt($ch, CURLOPT_SSLCERT, WxPayConfPub::SSLCERT_PATH); + //默认格式为PEM,可以注释 + curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM'); + curl_setopt($ch, CURLOPT_SSLKEY, WxPayConfPub::SSLKEY_PATH); + //post提交方式 + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); + $data = curl_exec($ch); + //返回结果 + if ($data) { + curl_close($ch); + return $data; + } else { + $error = curl_errno($ch); + echo "curl出错,错误码:$error" . "
"; + echo "错误原因查询
"; + curl_close($ch); + return false; + } + } + + /** + * + * 查询订单,WxPayOrderQuery中out_trade_no、transaction_id至少填一个 + * appid、mchid、spbill_create_ip、nonce_str不需要填入 + * @param WxPayConfigInterface $config 配置对象 + * @param WxPayOrderQuery $inputObj + * @param int $timeOut + * @return 成功时返回,其他抛异常 + * @throws WxPayException + */ + protected function orderQuery($config, $inputObj, $timeOut = 6) + { + $url = "https://api.mch.weixin.qq.com/pay/orderquery"; + //检测必填参数 + if (!$inputObj->IsOut_trade_noSet() && !$inputObj->IsTransaction_idSet()) { + throw new WxPayException("订单查询接口中,out_trade_no、transaction_id至少填一个!"); + } + $inputObj->SetAppid($config->GetAppId());//公众账号ID + $inputObj->SetMch_id($config->GetMerchantId());//商户号 + $inputObj->SetNonce_str(self::getNonceStr());//随机字符串 + + $inputObj->SetSign($config);//签名 + $xml = $inputObj->ToXml(); + + $startTimeStamp = self::getMillisecond();//请求开始时间 + $response = self::postXmlCurl($config, $xml, $url, false, $timeOut); + $result = WxPayResults::Init($config, $response); + self::reportCostTime($config, $url, $startTimeStamp, $result);//上报请求花费时间 + + return $result; + } +}