| <?php |
| namespace lib; |
|
|
| use Exception; |
|
|
| class Payment { |
|
|
| |
| static public function makeSign($data, $key) { |
| ksort($data); |
| $signStr = ''; |
| foreach ($data as $k => $v) { |
| if($k != 'sign' && $k != 'sign_type' && $v != ''){ |
| $signStr .= $k . '=' . $v . '&'; |
| } |
| } |
| $signStr = substr($signStr, 0, -1); |
| $sign = md5($signStr . $key); |
| return $sign; |
| } |
|
|
| |
| static public function verifySign($data, $key) { |
| if(!isset($data['sign'])) return false; |
| $sign = self::makeSign($data, $key); |
| return $sign === $data['sign']; |
| } |
|
|
| |
| static public function echoDefault($result){ |
| global $cdnpublic,$order,$conf,$sitename,$ordername; |
| $type = $result['type']; |
| if(!$type) return false; |
| switch($type){ |
| case 'jump': |
| $html_text = '<script>window.location.replace(\''.$result['url'].'\');</script>'; |
| if(isset($result['submit']) && $result['submit']){ |
| submitTemplate($html_text); |
| }else{ |
| echo $html_text; |
| } |
| break; |
| case 'html': |
| $html_text = $result['data']; |
| if(isset($result['submit']) && $result['submit'] && substr($html_text, 0, 6) == '<form '){ |
| submitTemplate($html_text); |
| }else{ |
| echo $html_text; |
| } |
| break; |
| case 'json': |
| echo json_encode($result['data']); |
| break; |
| case 'page': |
| include_once SYSTEM_ROOT.'txprotect.php'; |
| if(isset($result['data'])) extract($result['data']); |
| if($conf['pageordername']==1)$order['name']=$ordername?$ordername:'onlinepay'; |
| include PAYPAGE_ROOT.$result['page'].'.php'; |
| break; |
| case 'qrcode': |
| case 'scheme': |
| if($result['page'] == 'wxpay_mini') $result['page'] = 'wxpay_h5'; |
| include_once SYSTEM_ROOT.'txprotect.php'; |
| $code_url = $result['url']; |
| if($conf['pageordername']==1)$order['name']=$ordername?$ordername:'onlinepay'; |
| if($conf['wework_payopen'] == 1 && ($result['page'] == 'wxpay_wap' && strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')===false || $result['page'] == 'wxpay_qrcode' && checkmobile())){ |
| $code_url_wxkf = self::getWxkfPayUrl($code_url); |
| if($code_url_wxkf){ |
| $code_url = $code_url_wxkf; |
| include PAYPAGE_ROOT.'wxpay_h5.php'; |
| break; |
| } |
| } |
| include PAYPAGE_ROOT.$result['page'].'.php'; |
| break; |
| case 'return': |
| returnTemplate($result['url']); |
| break; |
| case 'error': |
| sysmsg($result['msg']); |
| break; |
| default:break; |
| } |
| } |
|
|
| |
| static public function echoJson($result){ |
| global $order,$siteurl; |
| if(!$result) return false; |
| $type = $result['type']; |
| if(!$type) return false; |
| $json['code'] = 1; |
| $json['trade_no'] = TRADE_NO; |
| switch($type){ |
| case 'jump': |
| $json['payurl'] = $result['url']; |
| break; |
| case 'html': |
| $json['html'] = $result['data']; |
| break; |
| case 'qrcode': |
| $json['qrcode'] = $result['url']; |
| break; |
| case 'scheme': |
| $json['urlscheme'] = $result['url']; |
| break; |
| case 'error': |
| $json['code'] = -2; |
| $json['msg'] = $result['msg']; |
| break; |
| default: |
| $json['payurl'] = $siteurl.'pay/submit/'.TRADE_NO.'/'; |
| break; |
| } |
| exit(json_encode($json)); |
| } |
|
|
| |
| static public function processOrder($isnotify, $order, $api_trade_no, $buyer){ |
| global $DB,$conf,$siteurl; |
| if($order['status']==0 || $order['status']==4){ |
| if($DB->exec("UPDATE `pre_order` SET `status`=1 WHERE `trade_no`='".$order['trade_no']."'")){ |
|
|
| $data = ['endtime'=>'NOW()', 'date'=>'CURDATE()']; |
| if(!empty($api_trade_no)) $data['api_trade_no'] = $api_trade_no; |
| if(!empty($buyer)) $data['buyer'] = $buyer; |
| if($order['settle']>0) $data['settle'] = $order['settle']; |
| $DB->update('order', $data, ['trade_no'=>$order['trade_no']]); |
| $order['api_trade_no'] = $api_trade_no; |
|
|
| processOrder($order, $isnotify); |
| } |
| }elseif(empty($order['api_trade_no']) && !empty($api_trade_no)){ |
| $data = ['api_trade_no'=>$api_trade_no]; |
| if(!empty($buyer)) $data['buyer'] = $buyer; |
| $DB->update('order', $data, ['trade_no'=>$order['trade_no']]); |
| } |
| if($isnotify && $order['settle']>0){ |
| $DB->update('order', ['settle'=>$order['settle']], ['trade_no'=>$order['trade_no']]); |
| } |
| if(!$isnotify){ |
| include_once SYSTEM_ROOT.'txprotect.php'; |
| if($order['status'] == 2){ |
| $jumpurl = '/payerr.html'; |
| returnTemplate($jumpurl); |
| return; |
| } |
| |
| if(!empty($order['endtime']) && time() - strtotime($order['endtime']) > 300){ |
| $jumpurl = '/payok.html'; |
| }else{ |
| $url=creat_callback($order); |
| $jumpurl = $url['return']; |
| } |
| returnTemplate($jumpurl); |
| } |
| } |
|
|
| |
| static public function updateOrder($trade_no, $api_trade_no, $buyer = null, $status = null){ |
| global $DB; |
| $data = ['api_trade_no'=>$api_trade_no]; |
| if(!empty($buyer)) $data['buyer'] = $buyer; |
| if($status) $data['status'] = $status; |
| $DB->update('order', $data, ['trade_no'=>$trade_no]); |
| } |
|
|
| |
| static public function updateOrderExt($trade_no, $data){ |
| global $DB; |
| $DB->update('order', ['ext'=>serialize($data)], ['trade_no'=>$trade_no]); |
| } |
|
|
| |
| static public function updateOrderCombine($trade_no){ |
| global $DB; |
| $DB->update('order', ['combine'=>1], ['trade_no'=>$trade_no]); |
| } |
|
|
| |
| static public function updateOrderProfits($order, $plugin){ |
| global $DB; |
| $support_plugins = ['alipay', 'alipaysl', 'alipayd', 'wxpayn', 'wxpaynp']; |
| if(in_array($plugin, $support_plugins)){ |
| $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid`='{$order['uid']}' AND `status`=1"); |
| if(!$psreceiver) $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver` WHERE `channel`='{$order['channel']}' AND `uid` IS NULL AND `status`=1"); |
| if($psreceiver){ |
| if(!$psreceiver['minmoney'] || $order['realmoney']>=$psreceiver['minmoney']){ |
| $DB->update('order', ['profits'=>$psreceiver['id']], ['trade_no'=>$order['trade_no']]); |
| return intval($psreceiver['id']); |
| } |
| } |
| } |
| return 0; |
| } |
|
|
| |
| static public function updateOrderProfits2($order, $plugin){ |
| return; |
| global $DB; |
| $support_plugins = ['adapay']; |
| if(in_array($plugin, $support_plugins)){ |
| $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver2` WHERE `channel`='{$order['channel']}' AND `uid`='{$order['uid']}' AND `status`=1"); |
| if(!$psreceiver) $psreceiver = $DB->getRow("SELECT * FROM `pre_psreceiver2` WHERE `channel`='{$order['channel']}' AND `uid` IS NULL AND `status`=1"); |
| if($psreceiver){ |
| if(!$psreceiver['minmoney'] || $order['realmoney']>=$psreceiver['minmoney']){ |
| $DB->update('order', ['profits2'=>$psreceiver['id']], ['trade_no'=>$order['trade_no']]); |
| return intval($psreceiver['id']); |
| } |
| } |
| } |
| return 0; |
| } |
|
|
| |
| public static function alipaydSettle($trade_no, $api_trade_no, $realmoney, $combine = 0, $ext = null){ |
| global $channel; |
| $alipay_config = require(PLUGIN_ROOT.'alipayd/inc/config.php'); |
| $alipaySevice = new \Alipay\AlipayTradeService($alipay_config); |
| if($combine == 1){ |
| if(!$ext) throw new Exception('子单支付结果数据不存在'); |
| $sub_orders = unserialize($ext); |
| $failnum = 0; |
| $errmsg = ''; |
| foreach($sub_orders as &$sub_order){ |
| if($sub_order['settle'] == 0){ |
| try{ |
| $alipaySevice->settle_confirm($sub_order['trade_no'], $sub_order['total_amount']); |
| $sub_order['settle'] == 1; |
| }catch(Exception $e){ |
| $failnum++; |
| $errmsg .= $e->getMessage().','; |
| } |
| } |
| } |
| \lib\Payment::updateOrderExt($trade_no, $sub_orders); |
| if($failnum > 0) throw new Exception('部分子单结算失败,失败数量:'.$failnum.',失败原因:'.$errmsg); |
| return true; |
| } |
| return $alipaySevice->settle_confirm($api_trade_no, $realmoney); |
| } |
|
|
| |
| public static function wxpaynpSettle($trade_no, $api_trade_no){ |
| global $channel; |
| $wechatpay_config = require(PLUGIN_ROOT.'/wxpaynp/inc/config.php'); |
| if($wechatpay_config['ecommerce']){ |
| if(!$order['profits']){ |
| $client = new \WeChatPay\V3\ProfitsharingService($wechatpay_config); |
| return $client->unfreeze($trade_no, $api_trade_no); |
| }else{ |
| throw new Exception('当前订单需要分账,请进入分账订单页面确认分账'); |
| } |
| }else{ |
| throw new Exception('非电商收付通订单'); |
| } |
| } |
|
|
| |
| public static function alipayPreAuthPay($trade_no){ |
| global $channel, $order, $conf; |
| $alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php'); |
| $alipaySevice = new \Alipay\AlipayTradeService($alipay_config); |
| $bizContent = [ |
| 'out_order_no' => $trade_no, |
| 'out_request_no' => $trade_no, |
| ]; |
| $result = $alipaySevice->preAuthQuery($bizContent); |
| |
| if(!isset($result['auth_no'])) throw new Exception('预授权订单查询失败'); |
| if($result['rest_amount'] == 0) throw new Exception('剩余冻结金额为0'); |
| if($result['order_status'] == 'AUTHORIZED'){ |
| $auth_no = $result['auth_no']; |
| $ordername = !empty($conf['ordername'])?ordername_replace($conf['ordername'],$order['name'],$order['uid'],$trade_no):$order['name']; |
| $bizContent = [ |
| 'out_trade_no' => $trade_no, |
| 'total_amount' => $result['rest_amount'], |
| 'subject' => $ordername, |
| 'product_code' => 'PREAUTH_PAY', |
| 'auth_no' => $auth_no, |
| 'auth_confirm_mode' => 'COMPLETE' |
| ]; |
| return $aop->scanPay($bizContent); |
| }else{ |
| throw new Exception('该笔订单非已授权状态,无需支付'); |
| } |
| } |
|
|
| |
| public static function alipayUnfreeze($trade_no){ |
| global $channel; |
| $alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php'); |
| $alipaySevice = new \Alipay\AlipayTradeService($alipay_config); |
| $bizContent = [ |
| 'out_order_no' => $trade_no, |
| 'out_request_no' => $trade_no, |
| ]; |
| $result = $alipaySevice->preAuthQuery($bizContent); |
| |
| if(!isset($result['auth_no'])) throw new Exception('预授权订单查询失败'); |
| if($result['rest_amount'] == 0) throw new Exception('剩余冻结金额为0'); |
| if($result['order_status'] == 'AUTHORIZED'){ |
| $auth_no = $result['auth_no']; |
| $bizContent = [ |
| 'auth_no' => $auth_no, |
| 'out_request_no' => date("YmdHis").rand(11111,99999), |
| 'amount' => $result['rest_amount'], |
| 'remark' => '解冻资金' |
| ]; |
| return $alipaySevice->preAuthUnfreeze($bizContent); |
| }else{ |
| throw new Exception('该笔订单非已授权状态,无需解冻'); |
| } |
| } |
|
|
| |
| public static function alipayRedPacketTransfer($payee_user_id, $money, $order_id){ |
| global $channel, $conf; |
| $out_biz_no = date("YmdHis").rand(11111,99999); |
| $alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php'); |
| $alipaySevice = new \Alipay\AlipayTransferService($alipay_config); |
| $alipaySevice->redPacketTansfer($out_biz_no, $money, $payee_user_id, $conf['sitename'], $order_id); |
| } |
|
|
| |
| public static function alipayRedPacketRefund($trade_no, $money){ |
| global $channel; |
| $out_biz_no = date("YmdHis").rand(11111,99999); |
| $alipay_config = require(PLUGIN_ROOT.$channel['plugin'].'/inc/config.php'); |
| $alipaySevice = new \Alipay\AlipayTransferService($alipay_config); |
| $alipaySevice->redPacketRefund($out_biz_no, $trade_no, $money); |
| } |
|
|
| |
| public static function lockPayData($trade_no, $func){ |
| global $DB; |
| $DB->beginTransaction(); |
| $data = $DB->getColumn("SELECT ext FROM pre_order WHERE trade_no=:trade_no FOR UPDATE", [':trade_no'=>$trade_no]); |
| if($data) { |
| $DB->rollBack(); |
| return unserialize($data); |
| } |
| try{ |
| $data = $func(); |
| }catch(\Exception $e){ |
| $DB->rollBack(); |
| throw $e; |
| } |
| if($data){ |
| $DB->update('order', ['ext'=>serialize($data)], ['trade_no' => $trade_no]); |
| } |
| $DB->commit(); |
| return $data; |
| } |
|
|
| |
| public static function getWxkfPayUrl($pay_url){ |
| global $order, $DB, $conf; |
|
|
| $cookiesid = $_COOKIE['mysid']; |
| if(!$cookiesid||!preg_match('/^[0-9a-z]{32}$/i', $cookiesid)){ |
| $cookiesid = getSid(); |
| setcookie("mysid", $cookiesid, time() + 2592000, '/'); |
| } |
|
|
| if($conf['wework_paykfid'] > 0){ |
| $wxkfaccount = $DB->getRow("SELECT * FROM pre_wxkfaccount WHERE id=:id", [':id'=>$conf['wework_paykfid']]); |
| }elseif($conf['wework_paymsgmode'] == 1){ |
| $usekflist = $DB->getAll("SELECT DISTINCT aid FROM pre_wxkflog WHERE `sid`=:sid AND addtime>=:addtime AND status=1", [':sid'=>$cookiesid, ':addtime'=>date("Y-m-d H:i:s", strtotime('-48 hours'))]); |
| $usekfids = [0]; |
| foreach($usekflist as $usekf){ |
| $usekfids[] = intval($usekf['aid']); |
| } |
| $wxkfaccount = $DB->getRow("SELECT A.* FROM pre_wxkfaccount A LEFT JOIN pre_wework B ON A.wid=B.id WHERE A.id NOT IN (".implode(",", $usekfids).") AND B.status=1 ORDER BY A.usetime ASC LIMIT 1"); |
| }else{ |
| $wxkfaccount = $DB->getRow("SELECT A.* FROM pre_wxkfaccount A LEFT JOIN pre_wework B ON A.wid=B.id WHERE B.status=1 ORDER BY A.usetime ASC LIMIT 1"); |
| } |
| if(!$wxkfaccount) return false; |
|
|
| $DB->insert('wxkflog', ['trade_no'=>$order['trade_no'], 'aid'=>$wxkfaccount['id'], 'sid'=>$cookiesid, 'payurl'=>$pay_url, 'addtime'=>'NOW()']); |
| $scene_param = 'orderid='.$order['trade_no'].'&money='.$order['realmoney']; |
| try{ |
| if(!empty($wxkfaccount['url'])){ |
| $kfurl = $wxkfaccount['url']; |
| $DB->update('wxkfaccount', ['usetime'=>'NOW()'], ['id'=>$wxkfaccount['id']]); |
| }else{ |
| $wework = new wechat\WeWorkAPI($wxkfaccount['wid']); |
| $kfurl = $wework->getKFURL($wxkfaccount['openkfid'], 'pay'); |
| $DB->update('wxkfaccount', ['url'=>$kfurl, 'usetime'=>'NOW()'], ['id'=>$wxkfaccount['id']]); |
| } |
| $kfurl .= '&scene_param='.urlencode($scene_param); |
| return $kfurl; |
| }catch(\Exception $e){ |
| sysmsg($e->getMessage()); |
| } |
| } |
| } |
|
|