Payment.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. <?php
  2. /*
  3. * 支付相关处理
  4. */
  5. namespace app\home\controller;
  6. use think\facade\View;
  7. use think\facade\Lang;
  8. use think\facade\Db;
  9. /**
  10. * ============================================================================
  11. *
  12. * ============================================================================
  13. *
  14. * ----------------------------------------------------------------------------
  15. *
  16. * ============================================================================
  17. * 控制器
  18. */
  19. class Payment extends BaseMall {
  20. public function initialize() {
  21. parent::initialize(); // TODO: Change the autogenerated stub
  22. Lang::load(base_path() . 'home/lang/'.config('lang.default_lang').'/buy.lang.php');
  23. }
  24. private function use_predeposit($order_info, $post, $virtual = 0) {
  25. if ($virtual==1) {
  26. $logic_buy = model('buyvirtual', 'logic');
  27. } elseif($virtual==2){
  28. $logic_buy = model('storejoinin');
  29. }else {
  30. $logic_buy = model('buy_1', 'logic');
  31. }
  32. if (empty($post['password'])) {
  33. return $order_info;
  34. }
  35. $member_model = model('member');
  36. $buyer_info = $member_model->getMemberInfoByID(session('member_id'));
  37. if ($buyer_info['member_paypwd'] == '' || $buyer_info['member_paypwd'] != md5($post['password'])) {
  38. return $order_info;
  39. }
  40. if ($buyer_info['available_rc_balance'] == 0) {
  41. $post['rcb_pay'] = null;
  42. }
  43. if ($buyer_info['available_predeposit'] == 0) {
  44. $post['pd_pay'] = null;
  45. }
  46. try {
  47. Db::startTrans();
  48. if (!empty($post['rcb_pay'])) {
  49. $order_info = $logic_buy->rcbPay($order_info, $post, $buyer_info);
  50. }
  51. if (!empty($post['pd_pay'])) {
  52. $order_info = $logic_buy->pdPay($order_info, $post, $buyer_info);
  53. }
  54. Db::commit();
  55. } catch (\Exception $e) {
  56. Db::rollback();
  57. exit($e->getMessage());
  58. }
  59. return $order_info;
  60. }
  61. private function get_order_info($result) {
  62. //计算本次需要在线支付的订单总金额
  63. $pay_amount = 0;
  64. $pay_order_id_list = array();
  65. if (!empty($result['data']['order_list'])) {
  66. foreach ($result['data']['order_list'] as $order_info) {
  67. if ($order_info['order_state'] == ORDER_STATE_NEW || $order_info['order_state'] == ORDER_STATE_DEPOSIT || $order_info['order_state'] == ORDER_STATE_REST) {
  68. $pay_amount += ($order_info['order_state'] == ORDER_STATE_DEPOSIT?$order_info['presell_deposit_amount']:($order_info['order_amount'] - $order_info['presell_deposit_amount'] + $order_info['presell_rcb_amount'] + $order_info['presell_pd_amount'])) - $order_info['pd_amount'] - $order_info['rcb_amount'];
  69. $pay_order_id_list[] = $order_info['order_id'];
  70. }
  71. }
  72. }
  73. if (round($pay_amount,2) == 0) {
  74. $result['data']['pay_end'] = 1;
  75. } else {
  76. $result['data']['pay_end'] = 0;
  77. }
  78. $result['data']['api_pay_amount'] = ds_price_format($pay_amount);
  79. //临时注释
  80. if (!empty($pay_order_id_list)) {
  81. $update = model('order')->editOrder(array('payment_time'=>TIMESTAMP), array(array('order_id', 'in', $pay_order_id_list)));
  82. // if (!$update) {
  83. // exit('更新订单信息发生错误,请重新支付');//因为微信支付时会重定向获取openid所以会更新两次
  84. // }
  85. }
  86. //如果是开始支付尾款,则把支付单表重置了未支付状态,因为支付接口通知时需要判断这个状态
  87. if (isset($result['data']['if_buyer_repay'])) {
  88. $update = model('order')->editOrderpay(array('api_paystate' => 0), array('pay_id' => $result['data']['pay_id']));
  89. if (!$update) {
  90. exit(lang('order_pay_fail'));
  91. }
  92. $result['data']['api_paystate'] = 0;
  93. }
  94. return $result;
  95. }
  96. private function get_vr_order_info($result) {
  97. //计算本次需要在线支付的订单总金额
  98. $pay_amount = 0;
  99. if ($result['data']['order_state'] == ORDER_STATE_NEW) {
  100. $pay_amount += $result['data']['order_amount'] - $result['data']['pd_amount'] - $result['data']['rcb_amount'];
  101. }
  102. if ($pay_amount == 0) {
  103. $result['data']['pay_end'] = 1;
  104. } else {
  105. $result['data']['pay_end'] = 0;
  106. }
  107. $result['data']['api_pay_amount'] = ds_price_format($pay_amount);
  108. //临时注释
  109. //$update = model('order')->editOrder(array('api_pay_time'=>TIMESTAMP),array('order_id'=>$result['data']['order_id']));
  110. //if(!$update) {
  111. // return array('error' => '更新订单信息发生错误,请重新支付');
  112. //}
  113. //计算本次需要在线支付的订单总金额
  114. $pay_amount = $result['data']['order_amount'] - $result['data']['pd_amount'] - $result['data']['rcb_amount'];
  115. $result['data']['api_pay_amount'] = ds_price_format($pay_amount);
  116. return $result;
  117. }
  118. private function get_sj_order_info($result) {
  119. //计算本次需要在线支付的订单总金额
  120. $pay_amount = 0;
  121. if ($result['data']['joinin_state'] == STORE_JOIN_STATE_VERIFY_SUCCESS) {
  122. $pay_amount += $result['data']['paying_amount'] - $result['data']['pd_amount'] - $result['data']['rcb_amount'];
  123. }
  124. if ($pay_amount == 0) {
  125. $result['data']['pay_end'] = 1;
  126. } else {
  127. $result['data']['pay_end'] = 0;
  128. }
  129. $result['data']['api_pay_amount'] = ds_price_format($pay_amount);
  130. return $result;
  131. }
  132. /**
  133. * 店铺入驻
  134. */
  135. public function sj_order() {
  136. $storejoinin_model = model('storejoinin');
  137. $joinin_detail = $storejoinin_model->getOneStorejoinin(array('member_id' => session('member_id')));
  138. if(!$joinin_detail){
  139. $this->error('店铺入驻不存在');
  140. }
  141. $payment_code = input('post.payment_code');
  142. $url = (string)url('Seller/index');
  143. $pay_sn=$joinin_detail['pay_sn'];
  144. if(!$pay_sn){
  145. $pay_sn=makePaySn(session('member_id'));
  146. $storejoinin_model->editStorejoinin(array('pay_sn'=>$pay_sn), array('member_id' => session('member_id'),'pay_sn'=>''));
  147. }
  148. $logic_payment = model('payment', 'logic');
  149. $result = $logic_payment->getPaymentInfo($payment_code);
  150. if (!$result['code']) {
  151. $this->error($result['msg'], $url);
  152. }
  153. $payment_info = $result['data'];
  154. //计算所需支付金额等支付单信息
  155. $result = $logic_payment->getSjOrderInfo($pay_sn);
  156. if (!$result['code']) {
  157. $this->error($result['msg'], $url);
  158. }
  159. if ($result['data']['joinin_state'] != STORE_JOIN_STATE_VERIFY_SUCCESS || empty($result['data']['api_pay_amount'])) {
  160. $this->error(lang('no_payment_required_this_order'), $url);
  161. }
  162. $result['data'] = $this->use_predeposit($result['data'], input('param.'), 2);
  163. $result = $this->get_sj_order_info($result);
  164. if ($result['data']['pay_end'] == 1) {
  165. $this->redirect($url);return;
  166. }
  167. //转到第三方API支付
  168. $this->_api_pay($result['data'], $payment_info);
  169. }
  170. /**
  171. * 实物商品订单
  172. */
  173. public function real_order() {
  174. $pay_sn = input('post.pay_sn');
  175. $payment_code = input('post.payment_code');
  176. $url = (string)url('Memberorder/index');
  177. if (!preg_match('/^\d{20}$/', $pay_sn)) {
  178. $this->error(lang('param_error'), $url);
  179. }
  180. $logic_payment = model('payment', 'logic');
  181. $result = $logic_payment->getPaymentInfo($payment_code);
  182. if (!$result['code']) {
  183. $this->error($result['msg'], $url);
  184. }
  185. $payment_info = $result['data'];
  186. //计算所需支付金额等支付单信息
  187. $result = $logic_payment->getRealOrderInfo($pay_sn, session('member_id'));
  188. if (!$result['code']) {
  189. $this->error($result['msg'], $url);
  190. }
  191. if ($result['data']['api_paystate'] || empty($result['data']['api_pay_amount'])) {
  192. $this->error(lang('no_payment_required_this_order'), $url);
  193. }
  194. $result['data']['order_list'] = $this->use_predeposit($result['data']['order_list'], input('param.'), 0);
  195. $result = $this->get_order_info($result);
  196. if ($result['data']['pay_end'] == 1) {
  197. //站内支付了全款
  198. $this->redirect($url);return;
  199. }
  200. //转到第三方API支付
  201. $this->_api_pay($result['data'], $payment_info);
  202. }
  203. /**
  204. * 虚拟商品购买
  205. */
  206. public function vr_order() {
  207. $order_sn = input('post.order_sn');
  208. $payment_code = input('post.payment_code');
  209. $url = (string)url('Membervrorder/index');
  210. if (!preg_match('/^\d{20}$/', $order_sn)) {
  211. $this->error(lang('param_error'));
  212. }
  213. $logic_payment = model('payment', 'logic');
  214. $result = $logic_payment->getPaymentInfo($payment_code);
  215. if (!$result['code']) {
  216. $this->error($result['msg'], $url);
  217. }
  218. $payment_info = $result['data'];
  219. //计算所需支付金额等支付单信息
  220. $result = $logic_payment->getVrOrderInfo($order_sn, session('member_id'));
  221. if (!$result['code']) {
  222. $this->error($result['msg'], $url);
  223. }
  224. if ($result['data']['order_state'] != ORDER_STATE_NEW || empty($result['data']['api_pay_amount'])) {
  225. $this->error(lang('no_payment_required_this_order'), $url);
  226. }
  227. $result['data'] = $this->use_predeposit($result['data'], input('param.'), 1);
  228. $result = $this->get_vr_order_info($result);
  229. if ($result['data']['pay_end'] == 1) {
  230. $this->redirect($url);return;
  231. }
  232. //转到第三方API支付
  233. $this->_api_pay($result['data'], $payment_info);
  234. }
  235. /**
  236. * 预存款充值
  237. */
  238. public function pd_order() {
  239. $pdr_sn = input('param.pdr_sn');
  240. $payment_code = input('param.payment_code');
  241. $url = (string)url('Predeposit/index');
  242. if (!preg_match('/^\d{20}$/', $pdr_sn)) {
  243. $this->error(lang('param_error'), $url);
  244. }
  245. $logic_payment = model('payment', 'logic');
  246. $result = $logic_payment->getPaymentInfo($payment_code);
  247. if (!$result['code']) {
  248. $this->error($result['msg'], $url);
  249. }
  250. $payment_info = $result['data'];
  251. $result = $logic_payment->getPdOrderInfo($pdr_sn, session('member_id'));
  252. if (!$result['code']) {
  253. $this->error($result['msg'], $url);
  254. }
  255. if ($result['data']['pdr_payment_state'] || empty($result['data']['api_pay_amount'])) {
  256. $this->error(lang('no_payment_required'), $url);
  257. }
  258. //转到第三方API支付
  259. $this->_api_pay($result['data'], $payment_info);
  260. }
  261. /**
  262. * 第三方在线支付接口
  263. *
  264. */
  265. private function _api_pay($order_info, $payment_info) {
  266. try{
  267. $payment_api = new $payment_info['payment_code']($payment_info);
  268. }catch(\Exception $e){
  269. $this->error($e->getMessage());
  270. }
  271. if (in_array($payment_info['payment_code'],array('wxpay_native','allinpay'))) {
  272. if (!extension_loaded('curl')) {
  273. $this->error(lang('please_check_system_configuration'));
  274. }
  275. if (array_key_exists('order_list', $order_info)) {
  276. View::assign('order_list', $order_info['order_list']);
  277. View::assign('args', 'buyer_id=' . session('member_id') . '&pay_id=' . $order_info['pay_id']);
  278. } else {
  279. View::assign('order_list', array());
  280. if ($order_info['order_type'] == 'pd_order') {
  281. View::assign('args', 'buyer_id=' . session('member_id') . '&pdr_sn=' . $order_info['pdr_sn']);
  282. } else {
  283. View::assign('args', 'buyer_id=' . session('member_id') . '&order_id=' . (isset($order_info['order_id']) ? $order_info['order_id'] : ''));
  284. }
  285. }
  286. View::assign('api_pay_amount', $order_info['api_pay_amount']);
  287. try{
  288. $pay_url=base64_encode(ds_encrypt($payment_api->get_payform($order_info), MD5_KEY));
  289. }catch(\Exception $e){
  290. $this->error($e->getMessage());
  291. }
  292. View::assign('pay_url', $pay_url);
  293. View::assign('nav_list', rkcache('nav', true));
  294. if($payment_info['payment_code']=='wxpay_native'){
  295. $pay_method=lang('pay_method_wechat');
  296. }elseif($payment_info['payment_code']=='allinpay'){
  297. $paytype=input('param.paytype');
  298. switch($paytype){
  299. case 'W01':
  300. $pay_method=lang('pay_method_wechat');
  301. break;
  302. case 'A01':
  303. $pay_method=lang('pay_method_alipay');
  304. break;
  305. case 'Q01':
  306. $pay_method=lang('pay_method_tenpay');
  307. break;
  308. case 'U01':
  309. $pay_method=lang('pay_method_unionpay');
  310. break;
  311. default:
  312. $this->error(lang('please_check_system_configuration'));
  313. }
  314. }
  315. View::assign('pay_method',$pay_method);
  316. echo View::fetch($this->template_dir . 'wxpay');
  317. } else {
  318. try{
  319. $pay_url=$payment_api->get_payform($order_info);
  320. }catch(\Exception $e){
  321. $this->error($e->getMessage());
  322. }
  323. @header("Location: " . $pay_url);
  324. }
  325. exit();
  326. }
  327. /**
  328. * 二维码显示(微信扫码支付)
  329. */
  330. public function qrcode() {
  331. $data = base64_decode(input('data'));
  332. $data = ds_decrypt($data, MD5_KEY, 30);
  333. include_once root_path(). 'extend/qrcode/phpqrcode.php';
  334. \QRcode::png($data);
  335. }
  336. /**
  337. * 扫码支付结果判断
  338. */
  339. public function query_state() {
  340. if (intval(input('param.pay_id')) > 0) {
  341. $info = model('order')->getOrderpayInfo(array(
  342. 'pay_id' => intval(input('param.pay_id')),
  343. 'buyer_id' => intval(input('param.buyer_id'))
  344. ));
  345. exit(json_encode(array(
  346. 'state' => ($info['api_paystate'] == '1'), 'pay_sn' => $info['pay_sn'], 'type' => 'real_order'
  347. )));
  348. } elseif (intval(input('param.order_id')) > 0) {
  349. $info = model('vrorder')->getVrorderInfo(array(
  350. 'order_id' => intval(input('param.order_id')),
  351. 'buyer_id' => intval(input('param.buyer_id'))
  352. ));
  353. exit(json_encode(array(
  354. 'state' => ($info['order_state'] == '20'), 'pay_sn' => $info['order_sn'], 'type' => 'vr_order'
  355. )));
  356. } else {
  357. $result = model('payment', 'logic')->getPdOrderInfo(input('param.pdr_sn'), input('param.buyer_id'));
  358. exit(json_encode(array('state' => $result['code'] && $result['data']['pdr_payment_state'], 'pdr_sn' => $result['code']?$result['data']['pay_sn']:'', 'type' => 'pd_order')));
  359. }
  360. }
  361. /**
  362. *
  363. * @param type $payment_code 共用回调方法
  364. * @param type $show_code 实际支付方式名称
  365. */
  366. public function notify($payment_code,$show_code='') {
  367. $logic_payment = model('payment', 'logic');
  368. $result = $logic_payment->getPaymentInfo($payment_code);
  369. $payment_info = $result['data'];
  370. if($show_code){
  371. $result = $logic_payment->getPaymentInfo($show_code);
  372. $payment_info['payment_config'] = array_merge($payment_info['payment_config'],$result['data']['payment_config']);
  373. }
  374. //创建支付接口对象
  375. $payment_api = new $payment_code($payment_info);
  376. //对进入的参数进行远程数据判断
  377. $verify = $payment_api->verify_notify();
  378. if ($verify['trade_status'] != 1) {
  379. exit;
  380. }
  381. $out_trade_no = $verify['out_trade_no']; #内部订单号
  382. $trade_no = $verify['trade_no']; #交易订单号
  383. $order_type = $verify['order_type']; #交易类型
  384. $update_result = $logic_payment->updateOrder($out_trade_no, $trade_no, $order_type, $show_code?$show_code:$payment_code);
  385. exit($update_result ? 'success' : 'fail');
  386. }
  387. /**
  388. * 支付接口同步返回路径
  389. */
  390. public function alipay_return() {
  391. $this->return_verify('alipay');
  392. }
  393. /**
  394. * 银联同步通知
  395. */
  396. public function unionpay_return() {
  397. $this->return_verify('unionpay');
  398. }
  399. public function return_verify($payment_code){
  400. $logic_payment = model('payment', 'logic');
  401. //取得支付方式
  402. $result = $logic_payment->getPaymentInfo($payment_code);
  403. if (!$result['code']) {
  404. $this->error($result['msg'], 'Memberorder/index');
  405. }
  406. $payment_info = $result['data'];
  407. //创建支付接口对象
  408. $payment_api = new $payment_info['payment_code']($payment_info);
  409. //返回参数判断
  410. $verify = $payment_api->return_verify();
  411. if (!$verify || $verify['trade_status']=='0') {
  412. $this->error(lang('payment_data_validation_failed'), 'Memberorder/index');
  413. }
  414. $order_type=$verify['order_type'];
  415. $out_trade_no=$verify['out_trade_no'];
  416. $order_amount=$verify['total_fee'];
  417. //支付成功后跳转
  418. if ($order_type == 'real_order') {
  419. $pay_ok_url = HOME_SITE_URL . '/buy/pay_ok?pay_sn=' . $out_trade_no . '&pay_amount=' . ds_price_format($order_amount);
  420. } elseif ($order_type == 'sj_order') {
  421. $pay_ok_url = HOME_SITE_URL . '/Seller/index.html';
  422. } elseif ($order_type == 'vr_order') {
  423. $pay_ok_url = HOME_SITE_URL . '/buyvirtual/pay_ok?order_sn=' . $out_trade_no . '&order_amount=' . ds_price_format($order_amount);
  424. } elseif ($order_type == 'pd_order') {
  425. $pay_ok_url = HOME_SITE_URL . '/predeposit/index';
  426. }
  427. header("Location:$pay_ok_url");
  428. exit;
  429. }
  430. /**
  431. * 通联异步通知
  432. */
  433. public function allinpay_notify(){
  434. $this->notify('allinpay');
  435. }
  436. /**
  437. * 银联异步通知
  438. */
  439. public function unionpay_notify(){
  440. $this->notify('unionpay');
  441. }
  442. /**
  443. * 微信扫码支付异步通知
  444. */
  445. public function wxpay_native_notify() {
  446. $this->notify('wxpay_native');
  447. }
  448. /**
  449. * 小程序支付异步通知
  450. */
  451. public function wxpay_minipro_notify() {
  452. $this->notify('wxpay_native','wxpay_minipro');
  453. }
  454. /**
  455. * 微信支付支付异步通知
  456. */
  457. public function wxpay_jsapi_notify() {
  458. $this->notify('wxpay_native','wxpay_jsapi');
  459. }
  460. /**
  461. * 微信H5支付异步通知
  462. */
  463. public function wxpay_h5_notify() {
  464. $this->notify('wxpay_native','wxpay_h5');
  465. }
  466. /**
  467. * 微信APP支付异步通知
  468. */
  469. public function wxpay_app_notify() {
  470. $this->notify('wxpay_native','wxpay_app');
  471. }
  472. /**
  473. * 通知处理(支付宝异步对账)
  474. */
  475. public function alipay_notify() {
  476. $this->notify('alipay');
  477. }
  478. /**
  479. * 支付宝APP支付异步通知
  480. */
  481. public function alipay_app_notify() {
  482. $this->notify('alipay','alipay_app');
  483. }
  484. /**
  485. * 支付宝wap支付异步通知
  486. */
  487. public function alipay_h5_notify() {
  488. $this->notify('alipay','alipay_h5');
  489. }
  490. }