微信小程序支付、退款
本文中使用的编程语言是PHP,PHP框架是thinkPHP3.2.3.
一、支付类,含有支付、退款等接口。
<?php
/**
* 微信支付类
* Created by PhpStorm.
* User: 科技
* Date: 2020/4/26
* Time: 10:30
*/
namespace Api;
class WxPayController
{
/**
* 小程序appid
* @var string
*/
private $appId;
/**
* 小程序secret
* @var string
*/
private $appSecret;
/**
* 商户平台商户id
* @var string
*/
private $mchId;
/**
* 商户平台密钥key
* @var string
*/
private $key;
/**
* 支付回掉地址
* @var string
*/
private $notifyUrl;
/**
* 获取用户唯一标识open_id api 接口地址
* @var string
*/
private $code2SessionApiUrl;
/**
* 统一下单api 接口地址
* @var string
*/
private $unifiedOrderApiUrl;
/**
* 错误信息
* @var string
*/
public $errorInfo;
/**
* WxPay constructor.
*/
public function __construct()
{
$this->appId = C('APP_ID');
$this->appSecret = C("APP_SECRET");
$this->mchId = C("MCH_ID");
$this->key = C("KEY");
$this->notifyUrl = (isset($_SERVER['REQUEST_SCHEME']) ? ($_SERVER['REQUEST_SCHEME'] . '://') : '') . $_SERVER['HTTP_HOST'].'/Api/Pay/notifyPay.html';
$this->code2SessionApiUrl = 'https://api.weixin.qq.com/sns/jscode2session';
$this->unifiedOrderApiUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
}
/**
* 添加错误信息
* @param $err
*/
public function setError($err)
{
$this->errorInfo = $err;
}
/**
* 获取错误信息
* @return string
*/
public function getError()
{
return $this->errorInfo;
}
/**
* 获取支付签名
* @param $open_id
* @param $order_no
* @param $money
* @return array
*/
public function paySign($open_id, $order_no, $money)
{
if (!$open_id || !$order_no || !$money) {
$this->setError('参数错误');
return [];
}
$prepay_id = $this->unifiedorder($open_id, $order_no, $money);
if (!$prepay_id) {
return [];
}
$params = array(
'appId' => $this->appId,
'timeStamp' => time(),
'nonceStr' => encrypt(16),
'package' => 'prepay_id=' . $prepay_id,
'signType' => 'MD5',
);
$params['paySign'] = $this->getSign($params);
return $params;
}
/**
* 异步签名验证
* @param $data
* @return bool
*/
public function checkNotifySign($data)
{
if (!$data) {
return false;
}
$sign = $data['sign'];
unset($data['sign']);
if ($sign == $this->getSign($data)) {
return true;
}
return false;
}
/**
* 异步回调处理成功时返回内容
* @param $msg
* @return string
*/
public function notifyReturnSuccess($msg = 'OK')
{
return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[' . $msg . ']]></return_msg></xml>';
}
/**
* 异步回调处理失败时返回内容
* @param $msg
* @return string
*/
public function notifyReturnFail($msg = 'FAIL')
{
return '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[' . $msg . ']]></return_msg></xml>';
}
/**
* 统一下单
* @param $open_id
* @param $order_no
* @param $money
* @return string
*/
private function unifiedOrder($open_id, $order_no, $money)
{
$params = [
'appid' => $this->appId,
'mch_id' => $this->mchId,
'nonce_str' => encrypt(16),
'body' => '食品-订单', //商品简单描述
'out_trade_no' => $order_no, //商户系统内部订单号
'total_fee' => priceyuantofen($money), //订单总金额,单位为分
'spbill_create_ip' => get_client_ip(), //用户端ips
'notify_url' => $this->notifyUrl, //通知地址
'trade_type' => 'JSAPI', //交易类型
'openid' => $open_id, //用户标识
];
$params['sign'] = $this->getSign($params);
$xmlData = arrayToXml($params);
$returnXml = postXml($xmlData, $this->unifiedOrderApiUrl);
$returnArr = xmlToArray($returnXml);
if ($returnArr['return_code'] == 'FAIL') {
$this->setError($returnArr['return_msg']);
return '';
}
return $returnArr['prepay_id'];
}
/**
* 获取签名
* @param $params
* @return string
*/
private function getSign($params)
{
if (!$params) {
return '';
}
//step1: 排序
ksort($params);
//step2:格式化参数
$paramUrl = formatParams($params, false);
//step3:追加key
$paramUrl = $paramUrl . '&key=' . $this->key;
//step4: md5加密
$paramUrl = md5($paramUrl);
//step5:转化为大写
$sign = strtoupper($paramUrl);
return $sign;
}
/*
* 查询支付结果
* @param $params
* @return string
*
* */
public function query($out_trade_no)
{
//对外暴露的退款接口
$result = $this->wxQueryApi($out_trade_no);
return $result;
}
/*
* 查询支付结果
* */
private function wxQueryApi($out_trade_no)
{
//通过微信api进行退款流程
$parma = array(
'appid' => $this->appId,
'mch_id' => $this->mchId,
'nonce_str' => encrypt(16),
'out_trade_no' => $out_trade_no,
);
$parma['sign'] = $this->getSign($parma);
$xmldata = arrayToXml($parma);
$returnXml = postXml($xmldata, 'https://api.mch.weixin.qq.com/pay/orderquery');
$result = xmlToArray($returnXml);
return $result;
}
/*
* 微信退款
* @param $params
* @return string
*
* */
public function refund($out_trade_no, $total_fee, $refund_fee, $out_refund_no)
{
//对外暴露的退款接口
$result = $this->wxRefundApi($out_trade_no, $total_fee, $refund_fee, $out_refund_no);
return $result;
}
/*
* 退款接口
* */
private function wxRefundApi($out_trade_no, $total_fee, $refund_fee, $out_refund_no)
{
//通过微信api进行退款流程
$parma = array(
'appid' => $this->appId,
'mch_id' => $this->mchId,
'nonce_str' => encrypt(16),
'out_refund_no' => $out_refund_no,
'out_trade_no' => $out_trade_no,
'total_fee' => priceyuantofen($total_fee),
'refund_fee' => priceyuantofen($refund_fee),
'notify_url' => (isset($_SERVER['REQUEST_SCHEME']) ? ($_SERVER['REQUEST_SCHEME'] . '://') : '') . $_SERVER['HTTP_HOST'].'/Api/Pay/notifyRefund.html',
);
$parma['sign'] = $this->getSign($parma);
$xmldata = arrayToXml($parma);
$xmlresult = curl_post_ssl('https://api.mch.weixin.qq.com/secapi/pay/refund', $xmldata, '/apiclient_cert.pem', '/apiclient_key.pem');
$result = xmlToArray($xmlresult);
return $result;
}
/*
* 查看微信退款
* @param $params
* @return string
*
* */
public function seeRefund($order_number)
{
//对外暴露的退款接口
$result = $this->wxSeeRefundApi($order_number);
return $result;
}
/*
* 查看微信退款接口
* */
private function wxSeeRefundApi($order_number)
{
//通过微信api进行退款流程
$parma = array(
'appid' => $this->appId,
'mch_id' => $this->mchId,
'nonce_str' => encrypt(16),
'out_trade_no' => $order_number,
);
$parma['sign'] = $this->getSign($parma);
$xmldata = arrayToXml($parma);
$returnXml = postXml($xmldata, 'https://api.mch.weixin.qq.com/pay/refundquery');
$result = xmlToArray($returnXml);
return $result;
}
}
二、以上方法中所用的一些工具方法。
/**
* PHP精确计算 主要用于货币的计算用
* @param $n1 第一个数
* @param $symbol 计算符号 + - * / %
* @param $n2 第二个数
* @param string $scale 精度 默认为小数点后两位
* @return string
*/
function pricecalc($n1, $symbol, $n2, $scale = '2')
{
$res = "";
switch ($symbol) {
case "+"://加法
$res = bcadd($n1, $n2, $scale);
break;
case "-"://减法
$res = bcsub($n1, $n2, $scale);
break;
case "*"://乘法
$res = bcmul($n1, $n2, $scale);
break;
case "/"://除法
$res = bcdiv($n1, $n2, $scale);
break;
case "%"://求余、取模
$res = bcmod($n1, $n2, $scale);
break;
default:
$res = "";
break;
}
return $res;
}
/**
* 价格由元转分(用于微信支付单位转换)
* @param $price 金额
* @return int
*/
function priceyuantofen($price)
{
$price = intval(pricecalc(100, "*", $price));
return $price;
}
/**
* 价格由分转元
* @param $price 金额
* @return float
*/
function pricefentoyuan($price)
{
$price = pricecalc(priceformat($price), "/", 100);
return $price;
}
/**
* 价格格式化
*
* @param int $price
* @return string $price_format
*/
function priceformat($price)
{
$price_format = number_format($price, 2, '.', '');
return $price_format;
}
/**
* array to xml
* @param $arr
* @return string
*/
function arrayToXml($arr)
{
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
/**
* xml to array
* @param $xml
* @return mixed
*/
function xmlToArray($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
/**
* 格式化参数 array to key1=valve1&key2=value2
* @param $params
* @param $url_encode
* @return string
*/
function formatParams($params, $url_encode)
{
if (!$params) {
return '';
}
$paramUrl = "";
ksort($params);
foreach ($params as $k => $v) {
if ($url_encode) {
$v = urlencode($v);
}
$paramUrl .= $k . "=" . $v . "&";
}
if (strlen($paramUrl) > 0) {
$paramUrl = substr($paramUrl, 0, strlen($paramUrl) - 1);
}
return $paramUrl;
}
/**
* curl post xml
* @param $xml 参数
* @param $url 请求地址
* @param int $second 设置超时
* @return mixed
*/
function postXml($xml, $url, $second = 60)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
set_time_limit(0);
//运行curl
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
//需要使用证书的请求
//file_cert_pem,file_key_pem两个退款必须的文件
function curl_post_ssl($url, $vars, $file_cert_pem, $file_key_pem, $second = 30, $aHeader = array())
{
$ch = curl_init();
//超时时间
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//这里设置代理,如果有的话
//curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
//以下两种方式需选择一种
//第一种方法,cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
// curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert.pem');
curl_setopt($ch, CURLOPT_SSLCERT, __DIR__.$file_cert_pem);
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
// curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/private.pem');
curl_setopt($ch, CURLOPT_SSLKEY, __DIR__.$file_key_pem);
//第二种方式,两个文件合成一个.pem文件
// curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . '/all.pem');
//要求结果为字符串且输出到屏幕上
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
if (count($aHeader) >= 1) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
}
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);
$data = curl_exec($ch);
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
// echo "call faild, errorCode:$error\n";
// echo "curl出错,错误码:$error";
curl_close($ch);
return false;
}
}
要说明的是退款接口wxRefundApi
调用的curl_post_ssl
方法需要传两个以pem
结尾的文件,这两个文件需要传绝对路径,根据代码中的写法,只有把这两个文件放到curl_post_ssl
所在文件同一级目录下面,才能正确的找到。
三、支付回调类。
<?php
/**
* Created by PhpStorm.
* User: 科技
* Date: 2020/4/26
* Time: 10:52
*/
namespace Api\Controller;
use Api\WxPayController;
use Common\Model\OrderModel;
class PayController
{
/**
* 状态 0已取消 1已下单 2已支付 3用户申请退款 4订单已完成 5商家同意退款 6微信平台接受退款异步返回申请成功 7异步返回退款申请失败 8统一下单异步返回支付失败 9退款成功 10统一下单异步返回成功
*/
const STATUS_WAITING = 1;
const STATUS_FAILED = 2;
const STATUS_SUCCESS = 3;
const STATUS_LOSE = 4;
const STATUS_OTHER = 5;
const STATUS_PROCESSING = 6;
/**
* 错误信息
* @var string
*/
public $errorInfo;
/**
* 小程序支付异步回调
*
*/
public function notifyPay()
{
$xml = file_get_contents('php://input', 'r');
$resData = xmlToArray($xml);
$wxPay = new WxPayController();
M('pay_log')->add(['type'=>1,'data'=>json_encode($resData),'create_time'=>time()]);
if ($wxPay->checkNotifySign($resData)) {
$result = $this->updateNotifyPayOrder($resData['return_code'], $resData['openid'], $resData['out_trade_no'], pricefentoyuan($resData['total_fee']), $resData['transaction_id'], $resData);
if ($result) {
$resStr = $wxPay->notifyReturnSuccess();
} else {
$resStr = $wxPay->notifyReturnFail($this->errorInfo);
}
} else {
$resStr = $wxPay->notifyReturnFail('签名验证失败');
}
echo $resStr;
}
/**
* 支付成功修改数据库
* @param $result 支付状态
* @param $open_id open_id
* @param $out_trade_no 客户订单号
* @param $money 金额
* @param $wx_trade_no 微信支付订单号
* @param $data
* @return bool
* @throws \Exception
*/
public function updateNotifyPayOrder($result, $open_id, $out_trade_no, $money, $wx_trade_no, $data)
{
//记录异步通知日志
//订单查询
$orderInfo = (new orderModel())->getorderInfo(['order_number' => $out_trade_no], 'id,order_number,shop_id,pay_money,status,user_id');
if (empty($orderInfo)) {
$this->errorInfo = '订单不存在';
return false;
}
//如果订单状态为成功直接返回
if (in_array($orderInfo['status'],[2,10,4])) {
return true;
}
//订单支付状态为未处理
if ($orderInfo['status'] == 1 || $orderInfo['status'] == 8) {
//验证金额
if (bccomp($orderInfo['pay_money'],$money,2)) {
$this->errorInfo = '订单金额有误';
return false;
}
//判断订单支付状态
if ($result == 'SUCCESS') {
$model = new OrderModel();
//开启事务处理机制
$model->startTrans();
//修改订单状态为成功
$res_success = (new orderModel())->editOrder(['status' => 10], ['id' => $orderInfo['id']]);
if ($res_success) {
//如果都成立就提交
$model->commit();
return true;
}else {
//先将原先的预处理进行回滚
$model->rollback();
$this->errorInfo = '订单状态修改失败';
return false;
}
} else {
//修改订单状态为支付失败
$res = (new orderModel())->editOrder(['status' => 8], ['id' => $orderInfo['id']]);
if (!$res) {
$this->errorInfo = '订单状态修改失败';
return false;
}
}
}
$this->errorInfo = '订单处理失败!';
return false;
}
/**
* 小程序申请退款异步回调
*
*/
public function notifyRefund()
{
$xml = file_get_contents('php://input', 'r');
$resData = xmlToArray($xml);
$wxPay = new WxPayController();
M('pay_log')->add(['type'=>2,'data'=>json_encode($resData),'create_time'=>time()]);
if ($wxPay->checkNotifySign($resData)) {
$result = $this->updateNotifyRefundOrder($resData['return_code'], $resData['out_trade_no'], pricefentoyuan($resData['total_fee']), $resData['transaction_id'], $resData);
if ($result) {
$resStr = $wxPay->notifyReturnSuccess();
} else {
$resStr = $wxPay->notifyReturnFail($this->errorInfo);
}
} else {
$resStr = $wxPay->notifyReturnFail('签名验证失败');
}
echo $resStr;
}
/**
* 退款成功修改数据库
* @param $result 支付状态
* @param $open_id open_id
* @param $out_trade_no 客户订单号
* @param $money 金额
* @param $wx_trade_no 微信支付订单号
* @param $data
* @return bool
* @throws \Exception
*/
public function updateNotifyRefundOrder($result, $out_trade_no, $money, $wx_trade_no, $data)
{
//记录异步通知日志
//订单查询
$orderInfo = (new orderModel())->getorderInfo(['order_number' => $out_trade_no], 'id,order_number,pay_money,status,user_id');
if (empty($orderInfo)) {
$this->errorInfo = '订单不存在';
return false;
}
//如果订单状态为成功直接返回
if (in_array($orderInfo['status'],[5,6,4])) {
return true;
}
//订单支付状态为用户已经申请退款
if ($orderInfo['status'] == 3 ||$orderInfo['status'] == 7) {
//验证金额
if (bccomp($orderInfo['pay_money'],$money,2)) {
$this->errorInfo = '订单金额有误';
return false;
}
//判断订单支付状态
if ($result == 'SUCCESS') {
$model = new OrderModel();
//开启事务处理机制
$model->startTrans();
//修改订单状态为成功
$res_success = (new orderModel())->editOrder(['status' => 6], ['id' => $orderInfo['id']]);
if ($res_success) {
//如果都成立就提交
$model->commit();
return true;
}else {
//先将原先的预处理进行回滚
$model->rollback();
$this->errorInfo = '订单状态修改失败';
return false;
}
} else {
//修改订单状态为退款申请失败
$res = (new orderModel())->editOrder(['status' => 7], ['id' => $orderInfo['id']]);
if (!$res) {
$this->errorInfo = '订单状态修改失败';
return false;
}
}
}
$this->errorInfo = '订单处理失败!';
return false;
}
}
四、接口调用。
/**
* 订单支付,统一下单接口,获取支付签名
* @access public
* @param string $orderId 订单id
* @param string $token
* @return array
*/
public function pay()
{
try {
$orderInfo = $this->orderHandelCheck($this->data['orderId']);
if ($orderInfo['status'] != 1 ) {
$this->json(201, '订单不是待支付状态');
}
//调用支付类
$wxPay = new WxPayController();
//获取签名
$paySign = $wxPay->paySign($this->openid, $orderInfo['order_number'], $orderInfo['pay_money']);
if (!$paySign) {
$this->json(201, $wxPay->getError());
}
$this->json(200, '请求成功', $paySign);
} catch (\Exception $e) {
// $this->json($e->getMessage());
$this->json(0);
}
}
/**
* 查询订单支付结果,以进行下一步动作
* @access public
* @param int $orderId 订单id
* @param string $token
* @return array
*/
public function payResult()
{
try {
$orderInfo = $this->orderHandelCheck($this->data['orderId']);
if (!in_array($orderInfo['status'],[1,10])) {
if($orderInfo['status']==8){
$this->json(201, '统一下单接口返回失败');
}
$this->json(201, '订单不是待支付状态');
}
//调用支付类
$wxPay = new WxPayController();
//获取查询结果
$query_res = $wxPay->query($orderInfo['order_number']);
if ($query_res['return_code']=='SUCCESS') { //请求成功
if ($query_res['result_code']=='SUCCESS') { //订单接收成功
if ($query_res['trade_state']=='SUCCESS') { //交易状态
$model = new OrderModel();
//开启事务处理机制
$model->startTrans();
$ModelThink = new \Think\Model(); // 实例化一个model对象 没有对应任何数据表
$sql = sprintf("SELECT `id`,`order_number`,`shop_id`,`create_time`,`pay_money`,`status` FROM `pre_order` WHERE `id` = %s FOR UPDATE ", $orderInfo['id']);//查询语句
$orderInfo=$ModelThink->query($sql)[0];
//修改订单状态为成功
$res_success = (new orderModel())->editOrder(['pay_status' => 1, 'status' => 2], ['id' => $orderInfo['id']]);
if (!$res_success) {
//先将原先的预处理进行回滚
$model->rollback();
$this->json(201,'订单状态修改失败');
}
//保存账户余额表
$walletModel = new ShopWalletModel();
$shopWallet = $walletModel->getShopWalletInfo(['shop_id' => $orderInfo['shop_id']], 'account');
if ($shopWallet) {
if ($walletModel->editShopWallet(['account' => bcadd($shopWallet['account'], $orderInfo['pay_money'], 2)], ['shop_id' => $orderInfo['shop_id']])) { //修改钱包金额
if ((new ShopWalletFlowModel())->addShopWalletFlow(['shop_id' => $orderInfo['shop_id'], 'account' => $orderInfo['pay_money'], 'create_time' => time(), 'order_id' => $orderInfo['id']])) { //添加钱包流水
//如果都成立就提交
$model->commit();
$this->json(200, '支付成功');
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->json(201,'商户钱包流水添加失败!');
}
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->json(201,'账户信息保存失败!');
}
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->json(201,'商户钱包有误!');
}
}elseif($query_res['trade_state']=='REFUND'){
$this->json(201, '转入退款');
}elseif($query_res['trade_state']=='NOTPAY'){
$this->json(201, '未支付');
}elseif($query_res['trade_state']=='CLOSED'){
$this->json(201, '已关闭');
}elseif($query_res['trade_state']=='USERPAYING'){
$this->json(201, '用户支付中');
}elseif($query_res['trade_state']=='PAYERROR'){
$this->json(201, '支付失败');
}else{
$this->json(201, '交易状态未知');
}
}else{
$this->json(201, $query_res['err_code_des']);
}
}else{
$this->json(201, $query_res['return_msg']);
}
} catch (\Exception $e) {
$this->json(0);
}
}
/**
* 请求退款
* @access public
* @param string $orderId 订单id
* @param string $token
* @return array
*/
public function refund(){
$wxPay = new WxPayController();
//申请退款
$res_refund = $wxPay->refund($Order_info['order_number'], $Order_info['pay_money'], $Order_info['pay_money'], $Order_info['refund_number']);
if ($res_refund['return_code'] == 'SUCCESS') { //接口请求成功
if ($res_refund['result_code'] == 'SUCCESS') { //退款申请接受成功
if ($model->editOrder(['status' => 5, 'Refund' => ['status' => 2, 'handle_time' => time()]], ['id' => $id], 'Refund')) {
$this->success("提交成功,等待微信平台审核通过!", '', true);
}else{
$this->error("修改订单状态失败,请尽快联系管理员处理!!!", '', true);
}
} else {
$this->error("申请失败,微信接受退款失败," . $res_refund['err_code_des'], '', true);
}
}else{
$this->error("请求失败," . $res_refund['return_msg'], '', true);
}
}
/**
* 查询订单退款结果,以进行下一步动作
* @access public
* @param int $orderId 订单id
* @param string $token
* @return array
*/
function checkRefund(){
$wxPay = new WxPayController();
//退款进度
$see_res = $wxPay->seeRefund($order_info['order_number']);
if($see_res['return_code']=='SUCCESS'){ //请求成功
if($see_res['result_code']=='SUCCESS'){ //退款申请接收成功
if($see_res['refund_status_0']=='SUCCESS'){ //退款状态
$model = new OrderModel();
//由于要计算流水,开启事务
//开启事务处理机制
$model->startTrans();
$ModelThink = new \Think\Model(); // 实例化一个model对象 没有对应任何数据表
$sql = sprintf("SELECT `id`,`order_number`,`shop_id`,`create_time`,`pay_money`,`status` FROM `pre_order` WHERE `id` = %s FOR UPDATE ", $order_info['id']);//查询语句
$order_info=$ModelThink->query($sql)[0];
if ($model->editOrder(['status' => 9], ['id' => $id])) {
$walletModel = new ShopWalletModel();
$shopWallet = $walletModel->getShopWalletInfo(['shop_id' => $order_info['shop_id']], 'account');
if ($shopWallet) {
if ($walletModel->editShopWallet(['account' => bcsub($shopWallet['account'], $order_info['pay_money'], 2)], ['shop_id' => $order_info['shop_id']])) {
if ((new ShopWalletFlowModel())->addShopWalletFlow(['shop_id' => $order_info['shop_id'], 'account' => -$order_info['pay_money'], 'create_time' => time(), 'order_id' => $id, 'scene' => 2])) {
//如果都成立就提交
$model->commit();
$this->success("退款成功!", '', true);
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->error("流水添加失败,请重试或尽快联系管理员处理!!!", '', true);
}
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->error("钱包操作失败,请重试或尽快联系管理员处理!!!", '', true);
}
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->error("钱包有误,请重试或尽快联系管理员处理!!!", '', true);
}
} else {
//先将原先的预处理进行回滚
$model->rollback();
$this->error("修改订单状态失败!请重试或尽快联系管理员处理!!", '', true);
}
}elseif($see_res['refund_status_0']=='REFUNDCLOSE'){
$this->success("退款关闭,请尽快联系管理员处理!!!", '', true);
}elseif($see_res['refund_status_0']=='PROCESSING'){
$this->success("退款处理中!", '', true);
}elseif($see_res['refund_status_0']=='CHANGE'){
$this->success("退款退款异常,请尽快联系管理员处理!!!", '', true);
}
}else{
$this->error('退款申请接收失败,'.$see_res['err_code_des'], '', true);
}
}else{
$this->error('请求失败,'.$see_res['return_msg'], '', true);
}
}
接口使用的返回方法:
protected function json($code=0,$message='',$data=[])
{
if (empty($message)) {
//通用提示信息
switch ($code) {
case 200:
$message = '请求成功';
break;
case 0:
$message = '请求失败';
break;
case -2:
$message = '参数缺失';
break;
default:
$message = $message;
break;
}
}
return $this -> ajaxReturn(['code' => $code, 'message' => $message, 'data' => $data]);
}
本文参考的主要文章有:
每一次的结束都意味着新的开始