add_balance: function() {
var that = this;
var total_payed_price = this.data.recharge;
var rc_id = this.data.rc_id;
getData.getData(\'rechargePay\', {
openid: app.globalData.openid,
total_payed_price: total_payed_price,
rc_id: rc_id,
method: \'POST\'
}, function(res) {
if (res.errno) {
wx.showToast({
title: res.errdesc
});
return;
}
var data = res.data;
wx.requestPayment({
\'timeStamp\': data.timeStamp.toString(),
\'nonceStr\': data.nonceStr,
\'package\': data.package,
\'signType\': \'MD5\',
\'paySign\': data.sign,
\'success\': function(res) {
console.log(\'支付成功\');
},
\'fail\': function(res) {
console.log(\'支付失败\');
return;
},
\'complete\': function(res) {
console.log(\'支付完成\');
console.log(res);
var url = that.data.url;
console.log(\'get url\', url);
if (res.errMsg == \'requestPayment:ok\') {
wx.showModal({
title: \'提示\',
content: \'充值成功\'
});
if (url) {
setTimeout(function() {
// 直接跳转,当前页面出栈
wx.redirectTo({
url: \'/pages\' + url
});
}, 2000)
} else {
setTimeout(() => {
wx.navigateBack()
}, 2000)
}
}
return;
}
});
})
}
上述是小程序端的操作。
下面是php的操作。
<?php
namespace Api\Action;
use Vendor\Func\Http;
/**
* 充值相关接口
*/
class RechargeAction extends CommonAction
{
/**
* 获取充值项
*/
public function get_recharge_config(){
$recharge_config = M(\'recharge_config\');
$recharge_config_list = $recharge_config->where(array(\'status\'=>1,\'is_show\'=>1))->field(\'id,recharge,amount\')->select();
$this->json->setAttr(\'data\',$recharge_config_list);
$this->json->Send();
}
/***
* 余额充值微信支付
*/
public function pay(){
if (!$openid = trim($_POST[\'openid\'])){
$this->json->setErr(10001,\'缺少参数\');
$this->json->Send();
}
if(!$rc_id = $_POST[\'rc_id\']){
$this->json->setErr(10001,\'没有余额充值id\');
$this->json->Send();
}
$total_payed_price = (float)$_POST[\'total_payed_price\']; // 实际支付金额
if ($total_payed_price <= 0){
$this->json->setErr(10002,\'支付金额不可为0或负数\');
$this->json->Send();
}
$recharge_config = M(\'recharge_config\');
$recharge_flag = $recharge_config->where(array(\'id\'=>$rc_id,\'status\'=>1,\'is_show\'=>1))->find();
if (!$recharge_config) {
$this->json->setErr(10002,\'充值项不存在\');
$this->json->Send();
}
$money_amount = $recharge_flag[\'amount\']; // 应到账金额
$user = M(\'user\');
$user_info = $user->where(array(\'openid\'=>$openid))->find();
if (!$user_info){
$this->json->setErr(10001,\'用户信息不存在\');
$this->json->Send();
}
$uid = $user_info[\'id\'];
$user_balance = $user_info[\'balance\'];
// step1 生成订单
$order_info = $this->makeorder($uid,$total_payed_price,$money_amount,$user_balance);
$order_num = $order_info[\'order_num\'];
$products_name = $order_info[\'products_name\'];
// step2 unifiedorder
$unifiedorder = $this->unifiedorder($openid,$order_num,$total_payed_price*100,$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;
// step3 将数据package下放到小程序中
$this->json->setAttr(\'data\',$data);
$this->json->Send();
}
/***
* 生成充值订单
*/
private function makeorder($uid,$total_payed_price,$money_amount,$user_balance){
$recharge_order = M(\'recharge_order\');
$now = time();
$order_num = \'cz\'.$uid.substr($now,3).rand(1000,9999);
$order_add_data = [
\'order_num\' => $order_num,
\'amount\' => $money_amount, //订单价格
\'balance\' => ($user_balance+$money_amount),
\'uid\' => $uid,
\'status\' => 1, //未到账
\'total_payed_price\' => $total_payed_price,
\'create_time\' => $now, //订单生成时间
];
$order_add_flag = $recharge_order->add($order_add_data);
if (!$order_add_flag){
$this->json->setErr(10003,\'生成订单失败\');
$this->json->Send();
}
$return_data[\'order_num\'] = $order_num;
$return_data[\'products_name\'] =\'余额充值\';
return $return_data;
}
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\' => C(\'APP_NAME\').\'-附加信息\',
\'out_trade_no\' => $trade_no, //订单号
\'fee_type\' => \'CNY\',
\'total_fee\' => $total_fee,
\'spbill_create_ip\' => $_SERVER[\'REMOTE_ADDR\'],
\'goods_tag\' => C(\'APP_NAME\').\'-商品标记\',
\'notify_url\' => C(\'RECHARGE_URL\'),
\'trade_type\' => \'JSAPI\',
\'openid\' => $openid
];
$sign = $this->MakeSign($data);
$data[\'sign\'] = $sign;
$xml = $this->ToXml($data);
$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);
$values = json_decode(json_encode(simplexml_load_string($xml, \'SimpleXMLElement\', LIBXML_NOCDATA)), true);
return $values;
}
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 createNonceStr($length = 16) {
$chars = \'abcdefghijklmnopqrstuvwxyz0123456789\';
$str = \'\';
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
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\'];
$data = $this->FromXml($xml);
// 保存微信服务器返回的签名sign
$data_sign = $data[\'sign\'];
// sign不参与签名算法
unset($data[\'sign\']);
$sign = $this->MakeSign($data);
// 判断签名是否正确 判断支付状态
if ( ($sign===$data_sign) && ($data[\'return_code\']==\'SUCCESS\') && ($data[\'result_code\']==\'SUCCESS\') ) {
//获取服务器返回的数据
$order_num = $data[\'out_trade_no\']; //订单单号
$openid = $data[\'openid\']; //付款人openID
$total_fee = $data[\'total_fee\']; //付款金额
$transaction_id = $data[\'transaction_id\']; //微信支付流水号
$user = M(\'user\');
$user_info = $user->where(array(\'openid\'=>$openid))->find();
$save_data = array(
\'total_payed_price\' => $total_fee/100, //实际到帐金额
\'transaction_id\' => $transaction_id,
\'pay_time\' => time(),
\'status\' => 2,
);
// 开启事务
M()->startTrans();
$error_count = 0;
// step 1 修改充值订单数据
$recharge_order = M(\'recharge_order\');
$recharge_order_info = $recharge_order->where(array(\'order_num\'=>$order_num,\'uid\'=>$user_info[\'id\']))->find();
$recharge_amount= $recharge_order_info[\'amount\'];
$recharge_save_flag = $recharge_order->where(array(\'order_num\'=>$order_num,\'uid\'=>$user_info[\'id\']))->save($save_data);
if(!$recharge_save_flag){
$error_count++;
}
// step 2 修改充值订单数据
$save_balance = $user_info[\'balance\']+$recharge_amount;
$balance_save_flag = $user->where(array(\'openid\'=>$openid))->save([\'balance\'=>$save_balance]);
if (!$balance_save_flag) {
$error_count++;
}
// step 3 增加充值记录
$balance_record = M(\'balance_record\');
$balance_record_data = [
\'uid\' => $user_info[\'id\'],
\'amount\' => $recharge_amount,
\'balance\' => $save_balance,
\'type\' => 1, // 增加
\'from\' => 1, // 充值
\'remark\' => \'余额充值\', // 充值
\'create_time\' => time(),
];
$add_flag = $balance_record->add($balance_record_data);
if (!$add_flag) {
$error_count ++;
}
if ($error_count > 0) {
M()->rollback();
$result = -2;
} else {
M()->commit();
$result = 0;
}
}else{
$result = -1;
}
// 返回状态给微信服务器
$str = \'\';
if ($result === 0) { // 成功之后不会再回调
$str=\'<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>\';
} elseif ($result === -1){ // 失败后会继续发送几次回调
$str=\'<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>\';
} elseif ($result === -2) { // 失败后会继续发送几次回调
$str=\'<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[操作失败]]></return_msg></xml>\';
}
exit($str);
}
}