<?php /** * Created by PhpStorm. * User: zb * Date: 17-10-9 * Time: 下午7:15 */ class PaysAction extends CommonAction { public function _initialize(){ parent::_initialize(); } public function pay(){ $openid = trim($_POST['openid']); $total_price = (float)$_POST['total_price'] * 100;//~~~~ $coupon_id = (int)$_POST['coupon_id']; $coupon_price = (float)$_POST['coupon_price'] * 100; $order_remark = trim($_POST['order_remark']); $old_order_num = trim($_POST['order_num']);//有order_num,再来一单购买 if ($old_order_num == 'undefined'){ $old_order_num = ''; } $product_id = (int)$_POST['product_id'];//有product_id,立即购买~~~~NaN,undefined在int转化后都为0; if (!$openid){ $this->json->setErr(10000,'缺少参数'); $this->json->Send(); } $user = M('user'); $tel_flag = $user->where(array('openid'=>$openid))->find(); if (!$tel_flag || !$tel_flag['id']){ $this->json->setErr(10001,'未绑定手机号'); $this->json->Send(); } $uid = $tel_flag['id']; if ($total_price <= 0){ $this->json->setErr(10002,'支付金额不可为0或负数'); $this->json->Send(); } $order_info = $this->makeorder($old_order_num,$product_id,$openid,$uid,$total_price,$coupon_id,$coupon_price,$order_remark); $order_num = $order_info['order_num']; $products_name = $order_info['products_name']; $unifiedorder = $this->unifiedorder($openid,$order_num,$total_price,$products_name); $data = [ 'appId' => C('APPID'), 'timeStamp' => time(), 'nonceStr' => $this->createNonceStr(), 'package' => 'prepay_id='.$unifiedorder['prepay_id'], 'signType' => 'MD5' ]; $sign = $this->MakeSign($data); $data['sign'] = $sign; $this->json->setAttr('data',$data); $this->json->Send(); } /*** 生成订单 优惠券处理 * @param $openid * @param $uid * @param $total_price * @param $coupon_id user_coupon中的id字段,而非coupon_id字段 * @param $coupon_price 用户实际获取优惠额度,而非一定是表格中的price字段; * @param $order_remark 用户提交订单的备注信息; * @param $old_order_num 如有此参数,再来一单购买 * @param $product_id 立即购买方式 * @param order表格中的status字段 1未支付;2已支付;3已申请退款;4已退款;5已完成 * @return string */ private function makeorder($old_order_num='',$product_id=0,$openid,$uid,$total_price,$coupon_id,$coupon_price,$order_remark){ $order = M('order'); $now = time(); if ($old_order_num && !$product_id){ $order_num = 'os'.$uid.substr($now,3).rand(1000,9999); //生成12位以上订单号~~~~如果开头有os,表示从order_shoppingcar转变而来 $shoppingcar = M('order_shoppingcar');//~~~~ }elseif($product_id && !$old_order_num){ $order_num = 'qs'.$uid.substr($now,3).rand(1000,9999); //生成12位以上订单号~~~~如果开头有qs,表示从quickbuy_shoppingcar转变而来 $shoppingcar = M('quickbuy_shoppingcar');//~~~~ }else{ $order_num = $uid.substr($now,3).rand(1000,9999); //生成12位以上订单号 $shoppingcar = M('shoppingcar');//~~~~ } $order_add_data = [ 'order_num' => $order_num, 'uid' => $uid, 'coupon_id' => $coupon_id, 'coupon_price' => $coupon_price, 'total_price' => $total_price,//订单价格 'status' => 1, 'addtime' => $now,//订单生成时间 'remark' => $order_remark ]; $order_add_flag = $order->add($order_add_data); // $sql = $order->getLastSql(); // $this->json->setAttr('sql',$sql); // $this->json->Send(); if (!$order_add_flag){ $this->json->setErr(10003,'生成订单失败'); $this->json->Send(); } $return_data['order_num'] = $order_num; $map = array( 'openid' => $openid, 'pnum' => array('gt',0) ); $shoppingcar_flag = $shoppingcar->where($map)->field('pid,pnum')->order('updatetime desc')->select(); $shoppingcar_count = count($shoppingcar_flag); $product = M('product'); $order_product = M('order_product'); $products_name = ''; for ($i=0;$i<$shoppingcar_count;$i++){ $product_flag = $product->where(array('id'=>$shoppingcar_flag[$i]['pid']))->find(); //如果该产品已下架或删除,购物车数据中该产品要剔除 if ($product_flag['status'] == '0' || ($product_flag['is_del'] == '1')){ unset($shoppingcar_flag[$i]); continue; } if (!$products_name){ $products_name .= $product_flag['title']; }else{ $products_name .= '-'.$product_flag['title']; } $product_add_data = [ 'order_id' => $order_add_flag, 'uid' => $uid, 'pid' => $shoppingcar_flag[$i]['pid'], 'pnum' => $shoppingcar_flag[$i]['pnum'], 'p_name' => $product_flag['title'], 'p_price' => $product_flag['price'], 'addtime' => $now ]; $product_add_flag = $order_product->add($product_add_data); if (!$product_add_flag){ $this->json->setErr(10004,'订单产品数据添加失败'); $this->json->Send(); } } $return_data['products_name'] = $products_name; return $return_data; } private function createNonceStr($length = 16) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str =""; for ( $i = 0; $i < $length; $i++ ) { $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1); } return $str; } public function unifiedorder($openid,$order_num,$total_fee,$products_name){ $trade_no = $order_num; $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; $data = [ 'appid' => C('APPID'), 'mch_id' => C('MCHID'), 'nonce_str' => $this->createNonceStr(), 'sign_type' => 'MD5', 'body' => $products_name, //商品名称组合 'attach' => '****-附加数据', //'detail' => '*****线上销售', 'out_trade_no' => $trade_no, //订单号 'fee_type' => 'CNY', 'total_fee' => $total_fee, //$total_fee, for test~~~ 'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], // 'time_start' => $this->getMillisecond(), 'goods_tag' => '******-商品标记', 'notify_url' => 'https://**************/api.php/Pays/order_notice', 'trade_type' => 'JSAPI', 'openid' => $openid ]; $sign = $this->MakeSign($data); $data['sign'] = $sign; $xml = $this->ToXml($data); vendor('Func.Http'); $result = $this->FromXml(Http::postXmlCurl($url,$xml)); return $result; } public function FromXml($xml) { if(!$xml){ throw new WxPayException("xml数据异常!"); } //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $this->values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $this->values; } private function getMillisecond() { //获取毫秒的时间戳 $time = explode ( " ", microtime () ); $time = $time[1] . ($time[0] * 1000); $time2 = explode( ".", $time ); $time = $time2[0]; return $time; } public function getSign(){ $appid = C('APPID'); $nocestr = $this->createNonceStr(); $timeStamp = time(); } public function ToXml($array) { if(!is_array($array) || count($array) <= 0) { return ; } $xml = '<xml version="1.0">'; foreach ($array as $key=>$val) { if (is_numeric($val)){ $xml.="<".$key.">".$val."</".$key.">"; }else{ $xml.="<".$key."><![CDATA[".$val."]]></".$key.">"; } } $xml.="</xml>"; return $xml; } private function MakeSign($data) { //签名步骤一:按字典序排序参数 ksort($data); $string = $this->ToUrlParams($data); //签名步骤二:在string后加入KEY $string = $string . "&key=".C('WEIXIN_PAY_KEY'); //签名步骤三:MD5加密 $string = md5($string); //签名步骤四:所有字符转为大写 $result = strtoupper($string); return $result; } private function ToUrlParams($array) { $buff = ""; foreach ($array as $k => $v) { if($k != "sign" && $v != "" && !is_array($v)){ $buff .= $k . "=" . $v . "&"; } } $buff = trim($buff, "&"); return $buff; } //微信支付回调 public function order_notice(){ $xml = $GLOBALS['HTTP_RAW_POST_DATA']; // 这句file_put_contents是用来查看服务器返回的XML数据 测试完可以删除了~~for test // vendor('Func.Func'); // $hostname = 'http://'.Func::getHostName(); // $path = $hostname.'/static/log2.txt'; // file_put_contents($path,$xml); //将服务器返回的XML数据转化为数组 //$data = self::xml2array($xml); $data = $this->FromXml($xml); // 保存微信服务器返回的签名sign $data_sign = $data['sign']; // sign不参与签名算法 unset($data['sign']); //$sign = self::makeSign($data); $sign = $this->makeSign($data); // 判断签名是否正确 判断支付状态 if ( ($sign===$data_sign) && ($data['return_code']=='SUCCESS') && ($data['result_code']=='SUCCESS') ) { $result = $data; //获取服务器返回的数据 $order_num = $data['out_trade_no']; //订单单号 $openid = $data['openid']; //付款人openID $total_fee = $data['total_fee']; //付款金额 $transaction_id = $data['transaction_id']; //微信支付流水号 $user = M('user'); $user_flag = $user->where(array('openid'=>$openid))->field('id')->find(); $uid = $user_flag['id']; $save_data = array( 'total_payed_price' => $total_fee, //实际到帐金额 'transaction_id' => $transaction_id, 'paytime' => time(), 'status' => 2 //1未支付;2已支付;3已申请退款;4已退款;5已完成 ); $order = M('order'); $order_save_flag = $order->where(array('order_num'=>$order_num,'uid'=>$uid))->save($save_data); //优惠券信息处理~~~~~发起订单还未必就支付~~~~~支付成功才处理 $order_coupon_flag = $order->where(array('order_num'=>$order_num,'uid'=>$uid))->field('coupon_id,id')->find(); $coupon_id = $order_coupon_flag['coupon_id']; if ($coupon_id){ $user_coupon = M('user_coupon'); $coupon_save_data = array( 'is_use' => 1, 'oid' => $order_coupon_flag['id'], //~~~~order订单的id 'update_time' => time() ); $user_coupon_save_flag = $user_coupon->where(array('id'=>$coupon_id))->save($coupon_save_data); $user_coupon_find_flag = $user_coupon->where(array('id'=>$coupon_id))->field('coupon_id')->find(); if ($user_coupon_save_flag){ $coupon = M('coupon'); $coupon->where(array('id'=>$user_coupon_find_flag['coupon_id']))->setInc('used_number','+1'); } } //购物车信息清理 // 1.订单号数字开头,立即购买方式,清空shoppingcar; // 2.订单号开头有sn,再来一单购买方式,清空order_shoppingcar(进入我的订单会清理),一定不要清理了shoppingcar // 2.订单号开头有qn,立即购买方式,清空quickbuy_shoppingcar(立即购买触发时间前会清理),一定不要清理了shoppingcar if (preg_match('/^(os)/',$order_num)){ $shoppingcar = M('order_shoppingcar'); }elseif(preg_match('/^(qs)/',$order_num)){ $shoppingcar = M('quickbuy_shoppingcar'); }else{ $shoppingcar = M('shoppingcar'); } $clear_data['pnum'] = 0; $shoppingcar->where(array('openid'=>$openid))->save($clear_data); }else{ $result = false; } // 返回状态给微信服务器 if ($result) { $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'; }else{ $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>'; } echo $str; return $result; } }
go_to_pay: function (e) {
var that = this;
var coupon_id = parseInt(e.currentTarget.dataset.coupon_id);//user_coupon的id
var coupon_price = e.currentTarget.dataset.coupon_price;//实际优惠价格
var total_price = e.currentTarget.dataset.total_price;
var products_name = e.currentTarget.dataset.products_name;
var order_num = e.currentTarget.dataset.order_num;//可以'',undefined
var product_id = parseInt(e.currentTarget.dataset.product_id);//undefined转化int->NaN
var input_order_remark = that.data.input_order_remark;
wx.request({
url: 'https://**************.net/api.php/Pays/pay',
header: { 'content-type': 'application/x-www-form-urlencoded' },
data: {
openid: app.globalData.open_id,
total_price: total_price,
order_num: order_num,
product_id: product_id,
coupon_id: coupon_id,
coupon_price: coupon_price,
order_remark: input_order_remark,
},
method: 'POST', //注意header
success: function (res) {
if (res.errno) {
wx.showToast(res.errdesc);
return;
}
var datas = res.data;
//console.log(typeof datas.data.timeStamp);
wx.requestPayment({
'timeStamp': datas.data.timeStamp.toString(),
'nonceStr': datas.data.nonceStr,
'package': datas.data.package,
'signType': 'MD5',
'paySign': datas.data.sign,
'success': function (res) {
console.log('支付成功');
console.log(res);
//return;
},
'fail': function (res) {
console.log('支付失败');
//console.log(res);
return;
},
'complete': function (res) {
console.log('支付完成');
console.log(res);
if (res.errMsg == 'requestPayment:ok') {
wx.navigateTo({
url: '/pages/pay/pay_success?products_name=' + products_name
})
}
return;
}
});
// console.log(res.data);
}
})
},