Wechat.php 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. <?php
  2. namespace app\index\controller;
  3. use app\index\model\activity\ActivityOrderModel;
  4. use app\index\model\AuthCompanyModel;
  5. use app\index\model\hotel\OrderModel;
  6. use app\index\model\hotel\RoomModel;
  7. use app\index\model\ProductModel;
  8. use app\index\model\ProductOrderDetailModel;
  9. use app\index\model\ProductOrderModel;
  10. use app\index\model\WxPayRecordModel;
  11. use app\index\service\HelperService;
  12. use app\index\service\wechat\JsApi_pub;
  13. use app\index\service\wechat\MicroPay_pub;
  14. use app\index\service\wechat\OrderQuery_pub;
  15. use app\index\service\wechat\Refund_pub;
  16. use app\index\service\wechat\UnifiedOrder_pub;
  17. use app\index\service\wechat\WxPayConfig;
  18. use think\Config;
  19. use think\Controller;
  20. use think\Validate;
  21. use think\Cache;
  22. class Wechat extends Controller
  23. {
  24. /**
  25. * 商城接口微信支付
  26. * @return mixed
  27. */
  28. public function wxPay(){
  29. $param = $this->request->param();
  30. if(isset($param['pay_notify_url'])){
  31. session('pay_notify_url',$param['pay_notify_url']);
  32. }
  33. if(isset($param['order_no'])){
  34. session('order_no',$param['order_no']);
  35. }
  36. if(!session('order_no')){
  37. die('order_no is empty');
  38. }
  39. $order_no = session('order_no');
  40. $companyCode = $this->_validCompanyCode($param);
  41. WxPayConfig::$companyCode();
  42. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  43. //使用jsapi接口
  44. $jsApi = new JsApi_pub();
  45. //通过code获得openid
  46. if (!isset($_GET['code'])) {
  47. $url = $jsApi->createOauthOpenidForCode("http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$JS_API_CALL_URL, rand(100,1000));
  48. header("Location: $url");
  49. exit;
  50. } else {
  51. $code = $_GET['code'];
  52. $jsApi->setCode($code);
  53. $openInfo = $jsApi->getOpenidInfo();
  54. if(!isset($openInfo['openid'])){
  55. HelperService::addLog($openInfo);
  56. header("HTTP/1.1 301 Moved Permanently");
  57. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=支付调用失败(openid)&err_detail=重复支付;网络连接失败");
  58. exit;
  59. }
  60. $openid = $openInfo['openid'];
  61. }
  62. $orderModel = new ProductOrderModel();
  63. $order = $orderModel->getOne(['order_no'=>$order_no]);
  64. if(!$order){
  65. HelperService::returnJson(['code'=>'400','msg'=>'order_no is error']);
  66. }
  67. $unifiedOrder = new UnifiedOrder_pub();
  68. $money = intval($order['total_price']);
  69. if($money<=0){
  70. $order['error_msg'] = "money is fail";
  71. HelperService::addLog($order);
  72. header("HTTP/1.1 301 Moved Permanently");
  73. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=支付调用失败(money)&err_detail=重复支付;网络连接失败");
  74. exit;
  75. }
  76. //设置统一支付接口参数
  77. $unifiedOrder->setParameter("openid", "$openid"); //商品描述
  78. $unifiedOrder->setParameter("body",WxPayConfig::$PAY_TIPS."[".date('Y-m-d H:i:s')."]"); //商品描述
  79. //自定义订单号,此处仅作举例
  80. $out_trade_no = substr($companyCode,0,6).'_'.$order_no."_".date('his');
  81. $unifiedOrder->setParameter("out_trade_no", $out_trade_no); //商户订单号
  82. $unifiedOrder->setParameter("total_fee", $money); //总金额
  83. $unifiedOrder->setParameter("notify_url", "http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$NOTIFY_URL); //通知地址
  84. $unifiedOrder->setParameter("trade_type", "JSAPI"); //交易类型
  85. $prepay_id = $unifiedOrder->getPrepayId($out_trade_no.'_'.time());
  86. $jsApi->setPrepayId($prepay_id);
  87. $jsApiParameters = $jsApi->getParameters();
  88. $notify_url = base64_decode(session('pay_notify_url'));
  89. $this->getProductInfoByOrderNo($order_no);
  90. require_once(APP_PATH.'/index/view/wechat/wxPay.php');
  91. }
  92. /**
  93. * 平台版支付接口
  94. */
  95. public function PlatformWxPay(){
  96. $param = $this->request->param();
  97. HelperService::addLog($param);
  98. if(isset($param['pay_notify_url'])){
  99. session('pay_notify_url',$param['pay_notify_url']);
  100. }
  101. if(isset($param['order_no']) && isset($param['total_price'])){
  102. session('order_no',$param['order_no']);
  103. session('total_price',$param['total_price']);
  104. }
  105. if(isset($param['note'])){
  106. session('note',$param['note']);
  107. }
  108. if(!session('order_no')){
  109. die('order_no or total_price is empty');
  110. }
  111. $order_no = session('order_no');
  112. $companyCode = $this->_validCompanyCode($param);
  113. WxPayConfig::$companyCode();
  114. $wxPayRecordModel = new WxPayRecordModel();
  115. $wxPayRecord = $wxPayRecordModel->where(['order_no'=>$order_no,'out_trade_no'=>['like',"{$companyCode}_%"]])->find();
  116. if(!empty($wxPayRecord)){
  117. $notify_url = base64_decode(session('pay_notify_url'));
  118. header("HTTP/1.1 301 Moved Permanently");
  119. header("Location: $notify_url");
  120. exit;
  121. }
  122. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  123. //使用jsapi接口
  124. $jsApi = new JsApi_pub();
  125. //通过code获得openid
  126. if (!isset($_GET['code'])) {
  127. $url = $jsApi->createOauthOpenidForCode("http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$platform_API_CALL_URL, rand(100,1000));
  128. header("Location: $url");
  129. exit;
  130. } else {
  131. $code = $_GET['code'];
  132. $jsApi->setCode($code);
  133. $openInfo = $jsApi->getOpenidInfo();
  134. if(!isset($openInfo['openid'])){
  135. HelperService::addLog($openInfo);
  136. $notify_url = base64_decode(session('pay_notify_url'));
  137. header("HTTP/1.1 301 Moved Permanently");
  138. header("Location: $notify_url");
  139. exit;
  140. }
  141. $openid = $openInfo['openid'];
  142. }
  143. $unifiedOrder = new UnifiedOrder_pub();
  144. $money = intval(session('total_price'));
  145. if($money<=0){
  146. $order['error_msg'] = "money is fail";
  147. $order['money'] = session('total_price');
  148. HelperService::addLog($order);
  149. header("HTTP/1.1 301 Moved Permanently");
  150. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=支付调用失败(total_price)&err_detail=重复支付;网络连接失败");
  151. exit;
  152. }
  153. //设置统一支付接口参数
  154. $unifiedOrder->setParameter("openid", "$openid"); //商品描述
  155. $unifiedOrder->setParameter("body",WxPayConfig::$PAY_TIPS.session('note')."[". substr($order_no, -8)."]"); //商品描述
  156. if(WxPayConfig::$PAY_TIPS.session('note')){
  157. $unifiedOrder->setParameter("attach",WxPayConfig::$PAY_TIPS.session('note')); //附加信息
  158. }
  159. //自定义订单号,此处仅作举例
  160. $out_trade_no = substr($companyCode,0,6).'_'.$order_no."_".date('his');
  161. $unifiedOrder->setParameter("out_trade_no", $out_trade_no); //商户订单号
  162. $unifiedOrder->setParameter("total_fee", $money); //总金额
  163. $unifiedOrder->setParameter("notify_url", "http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$PLATFORM_NOTIFY_URL); //通知地址
  164. $unifiedOrder->setParameter("trade_type", "JSAPI"); //交易类型
  165. $prepay_id = $unifiedOrder->getPrepayId($out_trade_no.'_'.time());
  166. $jsApi->setPrepayId($prepay_id);
  167. $jsApiParameters = $jsApi->getParameters();
  168. $notify_url = base64_decode(session('pay_notify_url'));
  169. require_once(APP_PATH.'/index/view/wechat/wxPlatformPay.php');
  170. }
  171. private function getInput(){
  172. $params = file_get_contents("php://input");
  173. return json_decode($params,true);
  174. }
  175. /**
  176. * 平台版退款接口
  177. */
  178. public function PlatformRefund(){
  179. $params = $this->getInput();
  180. $rule = [
  181. 'out_trade_no'=>'require',
  182. //'out_refund_no'=>'require',
  183. 'total_fee'=>'require',
  184. 'refund_fee'=>'require',
  185. 'op_user_id'=>'require',
  186. 'companyCode'=>'require'
  187. ];
  188. $companyCode = $this->_validCompanyCode($params);
  189. WxPayConfig::$companyCode();
  190. $validate = new Validate($rule);
  191. if(!$validate->check($params)){
  192. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError()],$params);
  193. }
  194. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  195. $Refund = new Refund_pub();
  196. $Refund->setParameter('out_trade_no',$params['out_trade_no']);
  197. $Refund->setParameter('out_refund_no',uniqid());
  198. $Refund->setParameter('total_fee',$params['total_fee']);
  199. $Refund->setParameter('refund_fee',$params['refund_fee']);
  200. $Refund->setParameter('op_user_id',$params['op_user_id']);
  201. $data = $Refund->getResult();
  202. $msg = isset($data['result_code'])?$data['result_code']:'fail';
  203. HelperService::returnJson(['code'=>200,'msg'=>"{$msg}",'data'=>$data]);
  204. }
  205. /**
  206. * 微信退款异步通知
  207. */
  208. public function refundNotify(){
  209. $param = file_get_contents("php://input");
  210. $params = (array)simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA);
  211. $time = date('Y-m-d H:i:s');
  212. file_put_contents('refundNotify.wx',"[$time]",FILE_APPEND);
  213. file_put_contents('refundNotify.wx',json_encode($params),FILE_APPEND);
  214. file_put_contents('refundNotify.wx',"\n",FILE_APPEND);
  215. die('success');
  216. }
  217. /**
  218. * 微信刷卡支付
  219. */
  220. public function microPay(){
  221. $params = $this->getInput();
  222. $rule = [
  223. 'order_no'=>'require|max:32',
  224. 'body'=>'require|max:120',//购买说明
  225. 'attach'=>'max:120',//购买附属说明
  226. 'total_fee'=>'require|number',//付款金额
  227. 'spbill_create_ip'=>'require|max:16',
  228. 'goods_tag'=>'max:32',//优惠详情
  229. 'limit_pay'=>'max:32',
  230. 'companyCode'=>'require',
  231. 'auth_code'=>'require|max:128',
  232. 'notify_url'=>'require'
  233. ];
  234. $companyCode = $this->_validCompanyCode($params);
  235. WxPayConfig::$companyCode();
  236. $validate = new Validate($rule);
  237. if(!$validate->check($params)){
  238. HelperService::returnJson(['code'=>400,'msg'=>$validate->getError()],$params);
  239. }
  240. $out_trade_no = "{$params['companyCode']}_{$params['order_no']}_".rand(100,999);
  241. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  242. $Refund = new MicroPay_pub();
  243. $Refund->setParameter('out_trade_no',$out_trade_no);
  244. $Refund->setParameter('body',$params['body']);
  245. isset($params['attach'])?$Refund->setParameter('attach',$params['attach']):'';
  246. $Refund->setParameter('total_fee',$params['total_fee']);
  247. $Refund->setParameter('spbill_create_ip',$params['spbill_create_ip']);
  248. isset($params['goods_tag'])?$Refund->setParameter('goods_tag',$params['goods_tag']):'';
  249. isset($params['limit_pay'])?$Refund->setParameter('limit_pay',$params['limit_pay']):'';
  250. $Refund->setParameter('auth_code',$params['auth_code']);
  251. $data = $Refund->getResult();
  252. $msg = isset($data['result_code'])?$data['result_code']:'fail';
  253. $WxPayRecordModel = new WxPayRecordModel();
  254. $WxPayRecordModel->insert([
  255. 'out_trade_no'=> $out_trade_no,
  256. 'order_no'=>"{$params['order_no']}",
  257. 'total_fee'=>"{$params['total_fee']}",
  258. 'pay_type'=>"MICRO",
  259. 'add_ts'=>time(),
  260. 'notify_url'=>"{$params['notify_url']}"
  261. ]);
  262. file_put_contents("cronOrderQuery.mp","\n sync1、".date('Y-m-d H:i:s'),FILE_APPEND);
  263. file_put_contents("cronOrderQuery.mp","\n sync2、".json_encode($data),FILE_APPEND);
  264. if(strtolower($msg) == 'success' && isset($data['trade_type']) && strtoupper($data['trade_type'])== 'MICROPAY' && isset($data['transaction_id'])){
  265. $WxPayRecordModel = new WxPayRecordModel();
  266. $WxPayRecordModel->where(['out_trade_no'=>"{$out_trade_no}"])->update(['wechat_msg'=>json_encode($data)]);
  267. $openid = isset($data['openid'])?$data['openid']:'';
  268. $total_fee = isset($data['total_fee'])?$data['total_fee']:'';
  269. HelperService::addLog("{$params['notify_url']}?order_no={$params['order_no']}&out_trade_no={$out_trade_no}&openid={$openid}&total_fee={$total_fee}&msg=success&transaction_id={$data['transaction_id']}&bank=".HelperService::BankList("{$data['bank_type']}"));
  270. $res = HelperService::httpPost("{$params['notify_url']}?order_no={$params['order_no']}&out_trade_no={$out_trade_no}&openid={$openid}&total_fee={$total_fee}&msg=success&transaction_id={$data['transaction_id']}&bank=".HelperService::BankList("{$data['bank_type']}"));
  271. file_put_contents("cronOrderQuery.mp","\n sync3、".date('Y-m-d H:i:s'),FILE_APPEND);
  272. file_put_contents("cronOrderQuery.mp","\n sync3-1、{$params['notify_url']}?order_no={$params['order_no']}&out_trade_no={$out_trade_no}&openid={$openid}&total_fee={$total_fee}&msg=success&transaction_id={$data['transaction_id']}&bank=".HelperService::BankList("{$data['bank_type']}"),FILE_APPEND);
  273. if($res === false){
  274. file_put_contents("cronOrderQuery.mp","\n sync4、".HelperService::$_httpErr,FILE_APPEND);
  275. }
  276. file_put_contents("cronOrderQuery.mp","\n sync5、".json_encode($res),FILE_APPEND);
  277. }
  278. HelperService::returnJson(['code'=>200,'msg'=>"{$msg}",'data'=>$data]);
  279. }
  280. public function cronOrderQuery(){
  281. while(true){
  282. $WxPayRecordModel = new WxPayRecordModel();
  283. $last_ts = time() - 7200;
  284. $WxPayRecordList = $WxPayRecordModel->where("pay_type='MICRO' and add_ts>{$last_ts} and wechat_msg is null")->select();
  285. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  286. foreach($WxPayRecordList as $item){
  287. $exOrder = explode('_',$item['out_trade_no']);
  288. $exOrder = current($exOrder);
  289. WxPayConfig::$exOrder();
  290. $OrderQuery = new OrderQuery_pub();
  291. $OrderQuery->setParameter('out_trade_no',$item['out_trade_no']);
  292. $data = $OrderQuery->getResult();
  293. $msg = isset($data['result_code'])?$data['result_code']:'fail';
  294. file_put_contents("cronOrderQuery.mp","\n notify1、{$item['out_trade_no']}-".date('Y-m-d H:i:s'),FILE_APPEND);
  295. file_put_contents("cronOrderQuery.mp","\n notify2、".json_encode($data),FILE_APPEND);
  296. if(strtolower($msg) == 'success' && isset($data['trade_type']) && strtoupper($data['trade_type'])== 'MICROPAY' && isset($data['transaction_id'])){
  297. $WxPayRecordModel = new WxPayRecordModel();
  298. $WxPayRecordModel->where(['out_trade_no'=>"{$item['out_trade_no']}"])->update(['wechat_msg'=>json_encode($data)]);
  299. $openid = isset($data['openid'])?$data['openid']:'';
  300. $total_fee = isset($data['total_fee'])?$data['total_fee']:'';
  301. HelperService::addLog("{$item['notify_url']}?order_no={$item['order_no']}&out_trade_no={$item['out_trade_no']}&openid={$openid}&total_fee={$total_fee}&msg=success&transaction_id={$data['transaction_id']}&bank=".HelperService::BankList("{$data['bank_type']}"));
  302. $res = HelperService::httpPost("{$item['notify_url']}?order_no={$item['order_no']}&out_trade_no={$item['out_trade_no']}&openid={$openid}&total_fee={$total_fee}&msg=success&transaction_id={$data['transaction_id']}&bank=".HelperService::BankList("{$data['bank_type']}"));
  303. file_put_contents("cronOrderQuery.mp","\n notify3、".date('Y-m-d H:i:s'),FILE_APPEND);
  304. if($res === false){
  305. file_put_contents("cronOrderQuery.mp","\n notify4、".HelperService::$_httpErr,FILE_APPEND);
  306. }
  307. file_put_contents("cronOrderQuery.mp","\n notify5、success",FILE_APPEND);
  308. }elseif(strtolower($msg) == 'fail' || (isset($data['trade_state']) && strtoupper($data['trade_state']) != 'USERPAYING')){
  309. $WxPayRecordModel = new WxPayRecordModel();
  310. $WxPayRecordModel->where(['out_trade_no'=>"{$item['out_trade_no']}"])->update(['wechat_msg'=>json_encode($data)]);
  311. $openid = isset($data['openid'])?$data['openid']:'';
  312. $total_fee = isset($data['total_fee'])?$data['total_fee']:'';
  313. HelperService::addLog("{$item['notify_url']}?order_no={$item['order_no']}&out_trade_no={$item['out_trade_no']}&openid={$openid}&total_fee={$total_fee}&msg=fail");
  314. $res = HelperService::httpPost("{$item['notify_url']}?order_no={$item['order_no']}&out_trade_no={$item['out_trade_no']}&openid={$openid}&total_fee={$total_fee}&msg=fail");
  315. file_put_contents("cronOrderQuery.mp","\n notify3、".date('Y-m-d H:i:s'),FILE_APPEND);
  316. if($res === false){
  317. file_put_contents("cronOrderQuery.mp","\n notify4、".HelperService::$_httpErr,FILE_APPEND);
  318. }
  319. file_put_contents("cronOrderQuery.mp","\n notify5、fail",FILE_APPEND);
  320. }
  321. }
  322. sleep(1);
  323. }
  324. }
  325. /**
  326. * 活动接口微信支付
  327. * @return mixed
  328. */
  329. public function ActivityWxPay(){
  330. $param = $this->request->param();
  331. if(isset($param['pay_notify_url'])){
  332. session('pay_notify_url',$param['pay_notify_url']);
  333. }
  334. if(isset($param['order_no'])){
  335. session('order_no',$param['order_no']);
  336. }
  337. if(!session('order_no')){
  338. die('order_no is empty');
  339. }
  340. $order_no = session('order_no');
  341. $companyCode = $this->_validCompanyCode($param);
  342. WxPayConfig::$companyCode();
  343. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  344. //使用jsapi接口
  345. $jsApi = new JsApi_pub();
  346. //通过code获得openid
  347. if (!isset($_GET['code'])) {
  348. $url = $jsApi->createOauthOpenidForCode("http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$activity_API_CALL_URL, rand(100,1000));
  349. header("Location: $url");
  350. exit;
  351. } else {
  352. $code = $_GET['code'];
  353. $jsApi->setCode($code);
  354. $openInfo = $jsApi->getOpenidInfo();
  355. if(!isset($openInfo['openid'])){
  356. HelperService::addLog($openInfo);
  357. header("HTTP/1.1 301 Moved Permanently");
  358. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=支付调用失败(openid)&err_detail=重复支付;网络连接失败");
  359. exit;
  360. }
  361. $openid = $openInfo['openid'];
  362. }
  363. $orderModel = new ActivityOrderModel();
  364. $order = $orderModel->getOne(['activity_order_no'=>$order_no]);
  365. if(!$order){
  366. HelperService::returnJson(['code'=>'400','msg'=>'order_no is error']);
  367. }
  368. $unifiedOrder = new UnifiedOrder_pub();
  369. $money = intval($order['total_price']);
  370. if($money<=0){
  371. $order['error_msg'] = "money is fail";
  372. HelperService::addLog($order);
  373. header("HTTP/1.1 301 Moved Permanently");
  374. header("Location: http://{$_SERVER['HTTP_HOST']}/index/wechat/warmError.html?err_msg=支付调用失败(money)&err_detail=重复支付;网络连接失败");
  375. exit;
  376. }
  377. //设置统一支付接口参数
  378. $unifiedOrder->setParameter("openid", "$openid"); //商品描述
  379. $unifiedOrder->setParameter("body",WxPayConfig::$PAY_TIPS."[".date('Y-m-d H:i:s')."]"); //商品描述
  380. //自定义订单号,此处仅作举例
  381. $out_trade_no = substr($companyCode,0,6).'_'.$order_no."_".date('his');
  382. $unifiedOrder->setParameter("out_trade_no", $out_trade_no); //商户订单号
  383. $unifiedOrder->setParameter("total_fee", $money); //总金额
  384. $unifiedOrder->setParameter("notify_url", "http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$NOTIFY_ACTIVITY_URL); //通知地址
  385. $unifiedOrder->setParameter("trade_type", "JSAPI"); //交易类型
  386. $prepay_id = $unifiedOrder->getPrepayId($out_trade_no.'_'.time());
  387. $jsApi->setPrepayId($prepay_id);
  388. $jsApiParameters = $jsApi->getParameters();
  389. $notify_url = base64_decode(session('pay_notify_url'));
  390. require_once(APP_PATH.'/index/view/wechat/wxPay.php');
  391. }
  392. /**
  393. * 酒店接口微信支付
  394. * @return mixed
  395. */
  396. public function HotelWxPay(){
  397. $param = $this->request->param();
  398. HelperService::addLog("param".json_encode($param));
  399. if(isset($param['pay_notify_url'])){
  400. session('pay_notify_url',$param['pay_notify_url']);
  401. }
  402. if(isset($param['order_no'])){
  403. session('order_no',$param['order_no']);
  404. }
  405. if(!session('order_no')){
  406. die('order_no is empty');
  407. }
  408. $order_no = session('order_no');
  409. $companyCode = $this->_validCompanyCode($param);
  410. WxPayConfig::$companyCode();
  411. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  412. //使用jsapi接口
  413. $jsApi = new JsApi_pub();
  414. //通过code获得openid
  415. if (!isset($_GET['code'])) {
  416. $url = $jsApi->createOauthOpenidForCode("http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$hotel_API_CALL_URL, rand(10000,99999));
  417. HelperService::addLog("url:$url");
  418. header("Location: $url");
  419. exit;
  420. } else {
  421. $code = $_GET['code'];
  422. HelperService::addLog($code);
  423. $jsApi->setCode($code);
  424. $openInfo = $jsApi->getOpenidInfo();
  425. HelperService::addLog('code here');
  426. if(!isset($openInfo['openid'])){
  427. HelperService::addLog($openInfo);
  428. header("HTTP/1.1 301 Moved Permanently");
  429. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=支付调用失败(openid)&err_detail=重复支付;网络连接失败");
  430. exit;
  431. }
  432. $openid = $openInfo['openid'];
  433. }
  434. $orderModel = new OrderModel();
  435. $order = $orderModel->getOne(['order_no'=>$order_no]);
  436. if(!$order){
  437. HelperService::returnJson(['code'=>'400','msg'=>'order_no is error']);
  438. }
  439. $unifiedOrder = new UnifiedOrder_pub();
  440. $money = intval($order['total_price']);
  441. if($money<=0){
  442. $order['error_msg'] = "money is fail";
  443. HelperService::addLog($order);
  444. header("HTTP/1.1 301 Moved Permanently");
  445. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=支付调用失败(money)&err_detail=重复支付;网络连接失败");
  446. exit;
  447. }
  448. //设置统一支付接口参数
  449. $unifiedOrder->setParameter("openid", "$openid"); //商品描述
  450. $unifiedOrder->setParameter("body",WxPayConfig::$PAY_TIPS."[".date('Y-m-d H:i:s')."]"); //商品描述
  451. //自定义订单号,此处仅作举例
  452. $out_trade_no = substr($companyCode,0,6).'_'.$order_no."_".date('his');
  453. $unifiedOrder->setParameter("out_trade_no", $out_trade_no); //商户订单号
  454. $unifiedOrder->setParameter("total_fee", $money); //总金额
  455. $unifiedOrder->setParameter("notify_url", "http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$NOTIFY_HOTEL_URL); //通知地址
  456. $unifiedOrder->setParameter("trade_type", "JSAPI"); //交易类型
  457. $prepay_id = $unifiedOrder->getPrepayId($out_trade_no.'_'.time());
  458. $jsApi->setPrepayId($prepay_id);
  459. $jsApiParameters = $jsApi->getParameters();
  460. $notify_url = base64_decode(session('pay_notify_url'));
  461. $this->getRoomInfoByOrderNo($order_no);
  462. require_once(APP_PATH.'/index/view/wechat/wxPay.php');
  463. exit;
  464. }
  465. /**
  466. * 商城微信支付异步调用
  467. */
  468. public function notifyUrl(){
  469. $param = file_get_contents("php://input");
  470. $params = (array)simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA);
  471. try {
  472. $arr = ['total_fee', 'out_trade_no'];
  473. foreach ($arr as $value) {
  474. if (!isset($params[$value])) {
  475. HelperService::returnJson(['code' => 400, 'msg' => "$value don't find"],$param);
  476. }
  477. }
  478. $tradeNoArr = explode('_', $params['out_trade_no']);
  479. $companyCode = $tradeNoArr[0];
  480. $orderNo = isset($tradeNoArr[1]) ? $tradeNoArr[1] : 0;
  481. $companyCode = $this->_validCompanyCode(['companyCode' => $companyCode]);
  482. $orderModel = new ProductOrderModel();
  483. $orderModel->startTrans();
  484. $order = $orderModel->upInfo(['order_no' => $orderNo,'status'=>0], ['status' => 1,'pay_time'=>time(),'out_trade_no'=>$params['out_trade_no']]);
  485. if ($order === false) {
  486. HelperService::addLog('update orderModel error('.$orderModel->getLastSql().')',$params);
  487. die('update orderModel error');
  488. }
  489. //查询当前订单中含有的商品信息
  490. $orderDetailModel = new ProductOrderDetailModel();
  491. $productModel = new ProductModel();
  492. $orderDetail = $orderDetailModel->where(['order_no'=>$orderNo])->select();
  493. foreach($orderDetail as $item_detail){
  494. $product_id = $item_detail['product_id'];
  495. $num = $item_detail['num'];
  496. $productModel->upInfo(['product_id'=>$product_id],[
  497. 'remain_num'=>['exp',"`remain_num`-$num"],
  498. 'sales_num'=>['exp',"`sales_num`+$num"],
  499. ]);
  500. }
  501. $orderModel->commit();
  502. $data = [
  503. 'order_no' => $orderNo,
  504. 'total_fee' => $params['total_fee'],
  505. 'out_trade_no' => $params['out_trade_no'],
  506. 'add_ts' => time(),
  507. ];
  508. $wxPayRecordModel = new WxPayRecordModel();
  509. $res = $wxPayRecordModel->insertGetId($data);
  510. if ($res === false) {
  511. HelperService::addLog('insert wx_pay_record fail('.$wxPayRecordModel->getLastSql().')',$params);
  512. die('insert wx_pay_record fail');
  513. }
  514. HelperService::addLog('success',$params);
  515. if(session('SmsConfig')){
  516. $url = session('SmsConfig')['reback_url']."?type=MALL&order_no=$orderNo";
  517. $res = HelperService::httpPost($url);
  518. //file_put_contents('wxPayRecord.mp',"[".date('Y-m-d H:i:s')."]".json_encode($res)."[url:$url]"."\n\n",FILE_APPEND);
  519. }
  520. die('success');
  521. }catch (\Exception $ex){
  522. file_put_contents('wxPayRecord.mp',"[".date('Y-m-d H:i:s')."]".$ex->getMessage()."+".$ex->getFile()."+".$ex->getLine().json_encode($params)."\n\n",FILE_APPEND);
  523. }
  524. }
  525. /**
  526. * 商城微信支付异步调用
  527. */
  528. public function activityNotifyUrl(){
  529. $param = file_get_contents("php://input");
  530. $params = (array)simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA);
  531. try {
  532. $arr = ['total_fee', 'out_trade_no'];
  533. foreach ($arr as $value) {
  534. if (!isset($params[$value])) {
  535. HelperService::returnJson(['code' => 400, 'msg' => "$value don't find"],$param);
  536. }
  537. }
  538. $tradeNoArr = explode('_', $params['out_trade_no']);
  539. $companyCode = $tradeNoArr[0];
  540. $orderNo = isset($tradeNoArr[1]) ? $tradeNoArr[1] : 0;
  541. $companyCode = $this->_validCompanyCode(['companyCode' => $companyCode]);
  542. $orderModel = new ActivityOrderModel();
  543. $order = $orderModel->upInfo(['activity_order_no' => $orderNo,'status'=>0], ['status' => 1,'pay_time'=>time(),'out_trade_no'=>$params['out_trade_no']]);
  544. if ($order === false) {
  545. HelperService::addLog('update orderModel error('.$orderModel->getLastSql().')',$params);
  546. die('update orderModel error');
  547. }
  548. $data = [
  549. 'order_no' => $orderNo,
  550. 'total_fee' => $params['total_fee'],
  551. 'out_trade_no' => $params['out_trade_no'],
  552. 'add_ts' => time(),
  553. ];
  554. $wxPayRecordModel = new \app\index\model\activity\WxPayRecordModel();
  555. $res = $wxPayRecordModel->insertGetId($data);
  556. if ($res === false) {
  557. HelperService::addLog('insert wx_pay_record fail('.$wxPayRecordModel->getLastSql().')',$params);
  558. die('insert wx_pay_record fail');
  559. }
  560. HelperService::addLog('success',$params);
  561. if(session('SmsConfig')){
  562. $url = session('SmsConfig')['reback_url']."?type=MALL&order_no=$orderNo";
  563. HelperService::httpPost($url);
  564. }
  565. die('success');
  566. }catch (\Exception $ex){
  567. file_put_contents('wxPayRecord.mp',"[".date('Y-m-d H:i:s')."]".$ex->getMessage().json_encode($params)."\n\n",FILE_APPEND);
  568. }
  569. }
  570. /**
  571. * 商城微信支付异步调用
  572. */
  573. public function platformNotifyUrl(){
  574. $param = file_get_contents("php://input");
  575. $params = (array)simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA);
  576. try {
  577. $arr = ['total_fee', 'out_trade_no'];
  578. foreach ($arr as $key=>$value) {
  579. if (!isset($params[$value])) {
  580. HelperService::returnJson(['code' => 400, 'msg' => "参数错误($key)"],$param);
  581. }
  582. }
  583. $tradeNoArr = explode('_', $params['out_trade_no']);
  584. if(count($tradeNoArr)<2){
  585. HelperService::returnJson(['code' => 400, 'msg' => "参数错误(trade)"],$param);
  586. }
  587. $companyCode = $tradeNoArr[0];
  588. $orderNo = isset($tradeNoArr[1]) ? $tradeNoArr[1] : 0;
  589. $companyCode = $this->_validCompanyCode(['companyCode' => $companyCode]);
  590. $data = [
  591. 'order_no' => $orderNo,
  592. 'total_fee' => $params['total_fee'],
  593. 'out_trade_no' => $params['out_trade_no'],
  594. 'add_ts' => time(),
  595. 'wechat_msg'=>json_encode($params)
  596. ];
  597. $wxPayRecordModel = new WxPayRecordModel();
  598. $res = $wxPayRecordModel->insertGetId($data);
  599. if ($res === false) {
  600. HelperService::addLog('insert wx_pay_record fail('.$wxPayRecordModel->getLastSql().')',$params);
  601. die('insert wx_pay_record fail');
  602. }
  603. HelperService::addLog('success',$params);
  604. if(session('SmsConfig')){
  605. $url = session('SmsConfig')['reback_url']."?type=MALL&order_no=$orderNo&total_price={$params['total_fee']}&out_trade_no={$params['out_trade_no']}&bank=".HelperService::BankList("{$params['bank_type']}");
  606. $is_ssl = false;
  607. if(strpos($url,'https://')===0){
  608. $is_ssl = true;
  609. }
  610. $times = 3;
  611. while($times--){
  612. $res1 = HelperService::httpPost($url,'',$is_ssl);
  613. \think\Log::record("推送记录url:".$url."=>data:". json_encode($res1));
  614. if($res1 !== false){
  615. break;
  616. }
  617. }
  618. HelperService::addLog($res1,['url'=>$url]);
  619. if(isset(session('SmsConfig')['reback_url2'])){
  620. $is_ssl = false;
  621. if(strpos($url,'https://')===0){
  622. $is_ssl = true;
  623. }
  624. $url = session('SmsConfig')['reback_url2']."?type=MALL&order_no=$orderNo&total_price={$params['total_fee']}&out_trade_no={$params['out_trade_no']}";
  625. $res1 = HelperService::httpPost($url,'',$is_ssl);
  626. HelperService::addLog($res1,['url'=>$url]);
  627. }
  628. }
  629. die('success');
  630. }catch (\Exception $ex){
  631. file_put_contents('wxPayRecord.mp',"[".date('Y-m-d H:i:s')."]".$ex->getMessage().json_encode($params)."\n\n",FILE_APPEND);
  632. }
  633. }
  634. /**
  635. * 商城微信支付异步调用
  636. */
  637. public function hotelNotifyUrl(){
  638. $param = file_get_contents("php://input");
  639. $params = (array)simplexml_load_string($param, 'SimpleXMLElement', LIBXML_NOCDATA);
  640. //file_put_contents('wxPayRecord.mp',"[".date('Y-m-d H:i:s')."]".json_encode($params)."\n\n",FILE_APPEND);
  641. try {
  642. $arr = ['total_fee', 'out_trade_no'];
  643. foreach ($arr as $value) {
  644. if (!isset($params[$value])) {
  645. HelperService::returnJson(['code' => 400, 'msg' => "$value don't find"],$param);
  646. }
  647. }
  648. $tradeNoArr = explode('_', $params['out_trade_no']);
  649. $companyCode = $tradeNoArr[0];
  650. $orderNo = isset($tradeNoArr[1]) ? $tradeNoArr[1] : 0;
  651. $companyCode = $this->_validCompanyCode(['companyCode' => $companyCode]);
  652. $orderModel = new OrderModel();
  653. $order = $orderModel->upInfo(['order_no' => $orderNo,'status'=>0], ['status' => 1,'pay_time'=>time(),'out_trade_no'=>$params['out_trade_no']]);
  654. if ($order === false) {
  655. HelperService::addLog('update orderModel error('.$orderModel->getLastSql().')',$params);
  656. die('update orderModel error');
  657. }
  658. $data = [
  659. 'order_no' => $orderNo,
  660. 'total_fee' => $params['total_fee'],
  661. 'out_trade_no' => $params['out_trade_no'],
  662. 'add_ts' => time(),
  663. ];
  664. $wxPayRecordModel = new \app\index\model\hotel\WxPayRecordModel();
  665. $res = $wxPayRecordModel->insertGetId($data);
  666. if ($res === false) {
  667. HelperService::addLog('insert wx_pay_record fail('.$wxPayRecordModel->getLastSql().')',$params);
  668. die('insert wx_pay_record fail');
  669. }
  670. HelperService::addLog('success',$params);
  671. if(session('SmsConfig')){
  672. $url = session('SmsConfig')['reback_url']."?type=MALL&order_no=$orderNo";
  673. HelperService::httpPost($url);
  674. }
  675. die('success');
  676. }catch (\Exception $ex){
  677. file_put_contents('wxPayRecord.mp',"[".date('Y-m-d H:i:s')."]".$ex->getMessage().json_encode($params)."\n\n",FILE_APPEND);
  678. }
  679. }
  680. public function warmError(){
  681. $params = $this->request->param();
  682. $err_msg = isset($params['err_msg'])?$params['err_msg']:'';
  683. $err_detail = isset($params['err_detail'])?$params['err_detail']:'';
  684. $this->assign('err_msg',$err_msg);
  685. if(!empty($err_detail)){
  686. $str = '可能原因如下:<br/>';
  687. $err_detail_arr = explode(';',$err_detail);
  688. foreach($err_detail_arr as $key=>$detail){
  689. $str .= ($key+1)."、{$detail}<br/>";
  690. }
  691. $this->assign('err_detail',$str);
  692. }
  693. return $this->fetch('common/error');
  694. }
  695. /**
  696. * 微信授权
  697. */
  698. public function authorize(){
  699. $param = $this->request->param();
  700. if(isset($param['notify_url'])){
  701. session('wx_authorize_notify',$param['notify_url']);
  702. }
  703. if(!session('wx_authorize_notify')){
  704. die("I don't know wx_authorize_notify.");
  705. }
  706. $companyCode = $this->_validCompanyCode($param);
  707. require_once(APP_PATH.'/index/service/wechat/WxPayPubHelper.php');
  708. $JsApi = new JsApi_pub();
  709. WxPayConfig::$companyCode();
  710. //第一步调用起授权拿到Code
  711. if(!isset($param['code'])){
  712. //触发微信返回code码
  713. $url = $JsApi->createOauthOpenidAndMoreUrlForCode("http://{$_SERVER['HTTP_HOST']}".WxPayConfig::$Authorize_URL, rand(100,1000));
  714. header("HTTP/1.1 301 Moved Permanently");
  715. header("Location: $url");
  716. exit;
  717. }
  718. //第二步得到openid
  719. $code = $param['code'];
  720. $JsApi->setCode($code);
  721. $openInfo = $JsApi->getOpenidInfo();
  722. //第三步授权
  723. $access_token = isset($openInfo['access_token'])?$openInfo['access_token']:'';
  724. $openid = isset($openInfo['openid'])?$openInfo['openid']:'';
  725. $this->_attention($openid,$companyCode);
  726. $result = $JsApi->getOauthUserInfo($access_token,$openid);
  727. $url = base64_decode(session('wx_authorize_notify'));
  728. $params = @http_build_query($result);
  729. if(empty($result)){
  730. HelperService::addLog($result,$param);
  731. header("HTTP/1.1 301 Moved Permanently");
  732. header("Location: $url");
  733. }
  734. header("Location: $url?$params");
  735. exit;
  736. }
  737. public function _attention($openid,$companyCode){
  738. $biz = WxPayConfig::$BIZ;
  739. \think\Log::record('WX_SUBSCRIBE:'. $biz);
  740. if(empty($biz)){
  741. return true;
  742. }
  743. // 获取公众号的access_token,此access_token不是用户授权后的access_token
  744. $accessToken = $this->_getToken($companyCode);
  745. $subscribe_msg = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$accessToken."&openid=".$openid;
  746. $subscribe_info = HelperService::httpPost($subscribe_msg,'',true);
  747. $subscribe_info = json_decode($subscribe_info,true);
  748. \think\Log::record('WX_SUBSCRIBE:'. $subscribe_msg. "=>".json_encode($subscribe_info));
  749. if(isset($subscribe_info['subscribe']) && $subscribe_info['subscribe']){
  750. return true;
  751. }else{
  752. die('<html><head><title>长按关注公众号</title></head><body><span style="font-size:20px;display:block;text-align:center;margin:100px 0;"> </span><img src="'.$biz.'" style="width:80%;display:block;margin:0 auto;"/></body></html>');
  753. }
  754. }
  755. private function _getToken($companyCode,$is_force=false){
  756. WxPayConfig::$companyCode();
  757. $token = Cache::get('access_token_'.$companyCode);
  758. if(!empty($token) && $is_force==false){
  759. HelperService::returnJson([
  760. 'code'=>200,
  761. 'msg'=>'cache',
  762. 'data'=>"$token"
  763. ]);
  764. }
  765. //判断有没有当前公司的access_token
  766. $request_token = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".WxPayConfig::$APPID."&secret=".WxPayConfig::$APPSECRET;
  767. $token_json = HelperService::httpPost($request_token,'',true);
  768. if($token_json === false){
  769. HelperService::returnJson([
  770. 'code'=>400,
  771. 'msg'=>'token is error',
  772. 'data'=>"$token_json"
  773. ]);
  774. }
  775. $tokenArr = json_decode($token_json,true);
  776. if(!isset($tokenArr['access_token'])){
  777. HelperService::returnJson([
  778. 'code'=>400,
  779. 'msg'=>'wechat return',
  780. 'data'=>"$token_json",
  781. 'url'=>$request_token
  782. ]);
  783. }
  784. $token = $tokenArr['access_token'];
  785. return $token;
  786. }
  787. private function _validCompanyCode($param){
  788. if(isset($param['companyCode'])){
  789. $AuthCompanyModel = new AuthCompanyModel();
  790. $companyCode = $param['companyCode'];
  791. $company = $AuthCompanyModel->getInfo(['company_code'=>['like',"$companyCode%"]]);
  792. if(empty($company)){
  793. die("I don't have this companyCode.");
  794. }
  795. session('company_db_json',$company['db_json']);
  796. session('SmsConfig',json_decode($company['sms_json'],true));
  797. session('companyCode',$param['companyCode']);
  798. }
  799. if(!session('companyCode')){
  800. die("I don't know companyCode.");
  801. }
  802. $companyCode = session('companyCode');
  803. $this->_loadConfig();
  804. return $companyCode;
  805. }
  806. private function _loadConfig(){
  807. $db_json = session('company_db_json');
  808. if(empty($db_json)){
  809. return true;
  810. }
  811. $db_arr = json_decode($db_json,true);
  812. foreach($db_arr as $k=>$v){
  813. $data = [
  814. 'type' => 'mysql',
  815. 'hostname' => '127.0.0.1',
  816. 'database' => 'test',
  817. 'username' => 'root',
  818. 'password' => '',
  819. 'hostport' => '3306',
  820. 'params' => [],
  821. 'charset' => 'utf8',
  822. 'prefix' => '',
  823. ];
  824. $data['type'] = $v['type'];
  825. $data['hostname'] = $v['hostname'];
  826. $data['database'] = $v['database'];
  827. $data['username'] = $v['username'];
  828. $data['password'] = $v['password'];
  829. Config::set($v['config_name'],$data);
  830. }
  831. }
  832. /**
  833. * 通过订单信息检查商品数量是否足够
  834. * @param $order_no
  835. * @return bool
  836. */
  837. private function getProductInfoByOrderNo($order_no){
  838. $orderDetailModel = new ProductOrderDetailModel();
  839. $productModel = new ProductModel();
  840. $orderDetail = $orderDetailModel->where(['order_no'=>$order_no])->select();
  841. foreach($orderDetail as $item_detail){
  842. $product_id = $item_detail['product_id'];
  843. $num = $item_detail['num'];
  844. $res = $productModel->where(['product_id'=>$product_id,'remain_num'=>['egt',$num],'status'=>0])->find();
  845. if(!$res){
  846. HelperService::addLog(['msg'=>"getProductInfoByOrderNo($order_no)"]);
  847. header("HTTP/1.1 301 Moved Permanently");
  848. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=产品数量不足($order_no/$product_id/$num)&err_detail=请联系卖家");
  849. exit;
  850. }
  851. }
  852. return true;
  853. }
  854. /**
  855. * 判断酒店的房间信息是否足够
  856. * @param $order_no
  857. * @return bool
  858. */
  859. private function getRoomInfoByOrderNo($order_no){
  860. $orderModel = new OrderModel();
  861. $order = $orderModel->where(['order_no'=>$order_no])->find();
  862. $num = $order['total_room_num'];
  863. $start_date = strtotime($order['start_date']);
  864. $end_date = strtotime($order['end_date']);
  865. $room_id = $order['room_id'];
  866. $roomModel = new RoomModel();
  867. $room = $roomModel->where(['room_id'=>$room_id])->find();
  868. $room_num = $room['total_number'];
  869. for($date=$start_date;$date<$end_date;$date+=86400){
  870. $current_num = $this->getRoomNumByDate($room_id,$date);
  871. if($room_num < $current_num + $num){
  872. HelperService::addLog(['msg'=>"getRoomInfoByOrderNo($order_no)"]);
  873. header("HTTP/1.1 301 Moved Permanently");
  874. header("Location: http://".$_SERVER['HTTP_HOST']."/index/wechat/warmError.html?err_msg=房间剩余数目不足&err_detail=请联系店家($order_no)");
  875. exit;
  876. }
  877. }
  878. return true;
  879. }
  880. private function getRoomNumByDate($room_id,$date){
  881. $OrderModel = new OrderModel();
  882. $next_date = $date + 86400;
  883. $room_num = $OrderModel->where("room_id = $room_id and add_time >= $date and add_time < $next_date and (status =1 or status=6)")->sum('total_room_num');
  884. return $room_num;
  885. }
  886. }