* Date: 2019-2-20
*/
namespace app\user\model;
use think\Model;
use think\Config;
use think\Db;
/**
* 会员
*/
class Pay extends Model
{
private $home_lang = 'cn';
private $key = ''; // key密钥
//初始化
protected function initialize()
{
// 需要调用`Model`的`initialize`方法
parent::initialize();
$this->home_lang = get_home_lang();
}
/**
* 虚拟网盘支付后自动发货,收货
* @param array $where =[ 'users_id'=>'','lang'=> $this->home_lang,'order_id'=> ''] 用户id 语言 订单id
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function afterVirtualProductPay($orderData = [])
{
//判断是否为需要自动发货的虚拟商品 archives表prom_type=2,3
$details_data = \think\Db::name('shop_order_details')->where([
'order_id' => $orderData['order_id'],
'users_id' => $orderData['users_id'],
])->select();
$autoSendGoods = true;//多商品合并的订单,需要先判断是否都是需要自动发货的
foreach ($details_data as &$key) {
if ($key['prom_type'] == 0 || $key['prom_type'] == 1 || $key['prom_type'] == 4) {
$autoSendGoods = false;
break; //只要存在一个需要手动发货的就结束循环,并且不进入自动发货
}
}
//直接发货
if ($autoSendGoods) {
//自动确认收货
$times = getTime();
$confirmOrder = \think\Db::name('shop_order')->where([
'order_id' => $orderData['order_id'],
'users_id' => $orderData['users_id'],
])->update([
'order_status' => 3,
'express_time' => $times,
'confirm_time' => $times,
'update_time' => $times,
// 'virtual_delivery' => $virtual_delivery, //注释,每次取出的时候再拼接
]);
if (false !== $confirmOrder) {
AddOrderAction($orderData['order_id'], 0, session('admin_id'), 2, 1, 1, '虚拟商品自动发货成功!', '发货成功');
AddOrderAction($orderData['order_id'], 0, session('admin_id'), 3, 1, 1, '虚拟商品自动收货成功!', '确认订单已收货');
if (function_exists('diy_push_buy_cloudminipro')) diy_push_buy_cloudminipro($orderData);
}
}
return $autoSendGoods;
}
// 处理充值订单,超过指定时间修改为已取消订单,针对未付款订单
public function UpdateOrderData($users_id)
{
$time = getTime() - Config::get('global.get_order_validity');
$where = array(
'users_id' => $users_id,
'status' => 1,
'add_time' => array('<', $time),
);
$data = [
'status' => 4, // 订单取消
'update_time' => getTime(),
];
Db::name('users_money')->where($where)->update($data);
}
/*
* 微信端H5支付,手机微信直接调起微信支付
* @params string $openid : 用户的openid
* @params string $out_trade_no : 商户订单号
* @params number $total_fee : 订单金额,单位分
* return string $ReturnData : 微信支付所需参数数组
*/
public function getWechatPay($openid, $out_trade_no, $total_fee, $PayInfo, $is_applets = 0, $transaction_type = 2)
{
if (isMobile() && isWeixin()) {
$thirdparty = Db::name('users')->where(['users_id'=>session('users_id')])->getField('thirdparty');
if (0 === intval($thirdparty)) $openid = model('ShopPublicHandle')->weChatauthorizeCookie(session('users_id'));
}
// 获取微信配置信息
$where = [
'pay_id' => 1,
'pay_mark' => 'wechat'
];
$pay_wechat_config = Db::name('pay_api_config')->where($where)->getField('pay_info');
if (empty($pay_wechat_config)) {
$pay_wechat_config = getUsersConfigData('pay.pay_wechat_config');
if (empty($pay_wechat_config)) return false;
}
$wechat = unserialize($pay_wechat_config);
// 支付密钥
$this->key = $wechat['key'];
// 小程序配置
if (1 === $is_applets) {
$MiniproValue = Db::name('weapp_minipro0002')->where('type', 'minipro')->getField('value');
if (empty($MiniproValue)) return false;
$MiniproValue = !empty($MiniproValue) ? json_decode($MiniproValue, true) : [];
$wechat['appid'] = $MiniproValue['appId'];
// 支付备注
$body = "小程序支付";
} else {
// 支付备注
$body = "微信支付";
}
// 支付备注
if (1 == config('global.opencodetype')) {
$web_name = tpCache('web.web_name');
$web_name = !empty($web_name) ? "[{$web_name}]" : "";
$body = $web_name . $body;
}
//支付数据
$data['body'] = $body . "订单号:{$out_trade_no}";
$data['attach'] = "wechat|,|is_notify|,|" . $transaction_type . '|,|' . session('users_id');
$data['out_trade_no'] = $out_trade_no;
$data['total_fee'] = $total_fee * 100;
$data['nonce_str'] = getTime();
$data['spbill_create_ip'] = $this->get_client_ip();
$data['appid'] = $wechat['appid'];
$data['mch_id'] = $wechat['mchid'];
$data['trade_type'] = "JSAPI";
$data['notify_url'] = request()->domain() . ROOT_DIR . '/index.php'; // 异步地址
$data['openid'] = $openid;
$sign = $this->getParam($data);
$dataXML = "
".$data['appid']."
".$data['attach']."
".$data['body']."
".$data['mch_id']."
".$data['nonce_str']."
".$data['notify_url']."
".$data['openid']."
".$data['out_trade_no']."
".$data['spbill_create_ip']."
".$data['total_fee']."
".$data['trade_type']."
".$sign."
";
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if (isset($ret['return_code']) && $ret['return_code'] == 'SUCCESS' && $ret['return_msg'] == 'OK') {
$timeStamp = getTime();
$ReturnData = [
'appId' => $wechat['appid'],
'timeStamp' => "$timeStamp",
'nonceStr' => $this->GetRandomString(12),
'package' => 'prepay_id='.$ret['prepay_id'],
'signType' => 'MD5',
];
$ReturnSign = $this->getParam($ReturnData);
$ReturnData['paySign'] = $ReturnSign;
return $ReturnData;
} else if (isset($ret['return_code']) && $ret['return_code'] == 'FAIL') {
return $ret;
} else {
return $ret;
}
}
/*
* 微信H5支付,手机浏览器调起微信支付
* @params string $openid : 用户的openid
* @params string $out_trade_no : 商户订单号
* @params number $total_fee : 订单金额,单位分
* return string $mweb_url : 二维码URL链接
*/
public function getMobilePay($out_trade_no,$total_fee,$body="支付",$attach="手机浏览器微信H5支付")
{
// 获取微信配置信息
$where = [
'pay_id' => 1,
'pay_mark' => 'wechat'
];
$pay_wechat_config = Db::name('pay_api_config')->where($where)->getField('pay_info');
if (empty($pay_wechat_config)) {
$pay_wechat_config = getUsersConfigData('pay.pay_wechat_config');
if (empty($pay_wechat_config)) return false;
}
$wechat = unserialize($pay_wechat_config);
$this->key = $wechat['key'];
//支付数据
$data['out_trade_no'] = $out_trade_no;
$data['total_fee'] = $total_fee * 100;
$data['spbill_create_ip'] = $this->get_client_ip();
$data['attach'] = $attach;
$data['body'] = $body;
$data['appid'] = $wechat['appid'];
$data['mch_id'] = $wechat['mchid'];
$data['nonce_str'] = getTime();
$data['trade_type'] = "MWEB";
$data['scene_info'] = '{"h5_info":{"type":"Wap","wap_url":'.url("users/Pay/mobile_pay_notify").',"wap_name":"支付"}}';
$data['notify_url'] = url('users/Pay/mobile_pay_notify');
$sign = $this->getParam($data);
$dataXML = "
".$data['appid']."
".$data['attach']."
".$data['body']."
".$data['mch_id']."
".$data['nonce_str']."
".$data['notify_url']."
".$data['out_trade_no']."
".$data['scene_info']."
".$data['spbill_create_ip']."
".$data['total_fee']."
".$data['trade_type']."
".$sign."
";
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if(isset($ret['return_code']) && $ret['return_code'] == 'SUCCESS' && $ret['return_msg'] == 'OK') {
if (!empty($ret['err_code'])) {
return $ret['err_code_des'];
}
return $ret['mweb_url'];
} else {
return $ret;
}
}
/*
* 微信二维码支付
* @params string $openid : 用户的openid
* @params string $out_trade_no : 商户订单号
* @params number $total_fee : 订单金额,单位分
* return string $code_url : 二维码URL链接
*/
public function payForQrcode($out_trade_no,$total_fee,$body="支付",$attach="微信扫码支付")
{
// 获取微信配置信息
$where = [
'pay_id' => 1,
'pay_mark' => 'wechat'
];
$pay_wechat_config = Db::name('pay_api_config')->where($where)->getField('pay_info');
if (empty($pay_wechat_config)) {
$pay_wechat_config = getUsersConfigData('pay.pay_wechat_config');
if (empty($pay_wechat_config)) return false;
}
$wechat = unserialize($pay_wechat_config);
$this->key = $wechat['key'];
// 支付备注
if (1 == config('global.opencodetype')) {
$web_name = tpCache('web.web_name');
$web_name = !empty($web_name) ? "[{$web_name}]" : "";
$body = $web_name.$body;
}
//支付数据
$data['out_trade_no'] = $out_trade_no;
$data['total_fee'] = $total_fee * 100;
$data['spbill_create_ip'] = $this->get_client_ip();
$data['attach'] = $attach;
$data['body'] = $body."订单号:{$out_trade_no}";
$data['appid'] = $wechat['appid'];
$data['mch_id'] = $wechat['mchid'];
$data['nonce_str'] = getTime();
$data['trade_type'] = "NATIVE";
$data['notify_url'] = url('user/Pay/pay_deal_with');
$sign = $this->getParam($data);
$dataXML = "
".$data['appid']."
".$data['attach']."
".$data['body']."
".$data['mch_id']."
".$data['nonce_str']."
".$data['notify_url']."
".$data['out_trade_no']."
".$data['spbill_create_ip']."
".$data['total_fee']."
".$data['trade_type']."
".$sign."
";
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if(isset($ret['return_code']) && $ret['return_code'] == 'SUCCESS' && $ret['return_msg'] == 'OK') {
return $ret['code_url'];
} else {
return $ret;
}
}
// 获取客户端IP
private function get_client_ip()
{
if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
$ip = getenv('REMOTE_ADDR');
} elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
$ip = $_SERVER['REMOTE_ADDR'];
}
return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches [0] : '';
}
//对参数排序,生成MD5加密签名
private function getParam($paramArray, $isencode=false)
{
$paramStr = '';
ksort($paramArray);
$i = 0;
foreach ($paramArray as $key => $value) {
if ($key == 'Signature') {
continue;
}
if ($i == 0) {
$paramStr .= '';
} else {
$paramStr .= '&';
}
$paramStr .= $key . '=' . ($isencode ? urlencode($value) : $value);
++$i;
}
$stringSignTemp=$paramStr."&key=".$this->key;
$sign=strtoupper(md5($stringSignTemp));
return $sign;
}
//POST提交数据
private function https_post($url,$data)
{
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
// curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
if (curl_errno($ch)) {
return 'Errno: '.curl_error($ch);
}
curl_close($ch);
return $result;
}
/*
* XML转array
* @params xml $xml : xml 数据
* return array $data : 转义后的array数组
*/
private function xmlToArray($xml)
{
libxml_disable_entity_loader(true);
$xmlstring = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring),true);
return $val;
}
/*
* 支付宝新版支付,生成支付链接方法。
* @params string $data : 订单表数据,必须传入
* return string $alipay_url : 支付宝支付链接
*/
public function getNewAliPayPayUrl($data)
{
// 引入SDK文件
vendor('alipay.pagepay.service.AlipayTradeService');
vendor('alipay.pagepay.buildermodel.AlipayTradePagePayContentBuilder');
// 获取支付宝配置信息
$where = [
'pay_id' => 2,
'pay_mark' => 'alipay'
];
$PayInfo = Db::name('pay_api_config')->where($where)->getField('pay_info');
if (empty($PayInfo)) return false;
$alipay = unserialize($PayInfo);
$type = $data['transaction_type'];
// 参数拼装
$config['app_id'] = $alipay['app_id'];
$config['merchant_private_key'] = $alipay['merchant_private_key'];
$config['transaction_type'] = $type;
// 异步地址
$notify_url = request()->domain().ROOT_DIR.'/index.php?transaction_type='.$type.'&is_notify=1';
$config['notify_url'] = $notify_url;
// 同步地址
$return_url = url('user/Pay/alipay_return', ['transaction_type'=>$type,'is_notify'=>2], true, true);
$config['return_url'] = $return_url;
$config['charset'] = 'UTF-8';
$config['sign_type'] = 'RSA2';
$config['gatewayUrl'] = 'https://openapi.alipay.com/gateway.do';
$config['alipay_public_key'] = $alipay['alipay_public_key'];
// 实例化
$payRequestBuilder = new \AlipayTradePagePayContentBuilder;
$aop = new \AlipayTradeService($config);
$out_trade_no = trim($data['unified_number']);//商户订单号,商户网站订单系统中唯一订单号,必填
$subject = '支付';//订单名称,必填
$total_amount = trim($data['unified_amount']);//付款金额,必填
$body = '支付宝支付';//商品描述,可空
if (1 == config('global.opencodetype')) {
$web_name = tpCache('web.web_name');
$web_name = !empty($web_name) ? "[{$web_name}]" : "";
$subject = $web_name.$subject;
$body = $web_name.$body;
}
//构造参数
$payRequestBuilder->setBody($body."订单号:{$out_trade_no}");
$payRequestBuilder->setSubject($subject."订单号:{$out_trade_no}");
$payRequestBuilder->setTotalAmount($total_amount);
$payRequestBuilder->setOutTradeNo($out_trade_no);
// 调用SDK进行支付宝支付
$response = $aop->pagePay($payRequestBuilder,$config['return_url'],$config['notify_url']);
}
/*
* 支付宝旧版支付,生成支付链接方法。
* @params string $data : 订单表数据,必须传入
* @params string $alipay : 支付宝配置信息,通过 getUsersConfigData 方法调用数据
* return string $alipay_url : 支付宝支付链接
*/
public function getOldAliPayPayUrl($data, $alipay)
{
// 重要参数,支付宝配置信息
if (empty($alipay)) {
$where = [
'pay_id' => 2,
'pay_mark' => 'alipay'
];
$alipay = Db::name('pay_api_config')->where($where)->getField('pay_info');
if (empty($alipay)) {
$alipay = getUsersConfigData('pay.pay_alipay_config');
if (empty($alipay)) return false;
}
$alipay = unserialize($alipay);
}
// 参数设置
$order['out_trade_no'] = $data['unified_number']; //订单号
$order['price'] = $data['unified_amount']; //订单金额
$charset = 'utf-8'; //编码格式
$real_method = '2'; //调用方式
$agent = 'C4335994340215837114'; //代理机构
$seller_email = $alipay['account'];//支付宝用户账号
$security_check_code = $alipay['code']; //交易安全校验码
$partner = $alipay['id']; //合作者身份ID
switch ($real_method){
case '0':
$service = 'trade_create_by_buyer';
break;
case '1':
$service = 'create_partner_trade_by_buyer';
break;
case '2':
$service = 'create_direct_pay_by_user';
break;
}
$type = $data['transaction_type']; //自定义,用于验证
// 异步地址
$notify_url = request()->domain().ROOT_DIR.'/index.php?transaction_type='.$type.'&is_notify=1';
// 同步地址
$return_url = url('user/Pay/alipay_return', ['transaction_type'=>$type,'is_notify'=>2], true, true);
// 参数拼装
$parameter = array(
'agent' => $agent,
'service' => $service,
//合作者ID
'partner' => $partner,
'_input_charset' => $charset,
'notify_url' => $notify_url,
'return_url' => $return_url,
/* 业务参数 */
'subject' => "支付订单号:".$order['out_trade_no'],
'out_trade_no' => $order['out_trade_no'],
'price' => $order['price'],
'quantity' => 1,
'payment_type' => 1,
/* 物流参数 */
'logistics_type' => 'EXPRESS',
'logistics_fee' => 0,
'logistics_payment' => 'BUYER_PAY_AFTER_RECEIVE',
/* 买卖双方信息 */
'seller_email' => $seller_email,
);
ksort($parameter);
reset($parameter);
$param = '';
$sign = '';
foreach ($parameter AS $key => $val) {
$param .= "$key=" . urlencode($val) . "&";
$sign .= "$key=$val&";
}
$param = substr($param, 0, -1);
$sign = substr($sign, 0, -1) . $security_check_code;
$alipay_url = 'https://www.alipay.com/cooperate/gateway.do?' . $param . '&sign=' . MD5($sign) . '&sign_type=MD5';
return $alipay_url;
}
// 获取随机字符串
// 长度 length
// 结果 str
public function GetRandomString($length)
{
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
}