本文中使用的编程语言是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]);
}