Payment.php 18 KB

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