微信小程序BtoB支付(门店管理) php代码实现

255 阅读3分钟

这里感谢链接,基于此代码写出此文章

微信小程序B2B支付 php版_微信b2b支付-CSDN博客

相关微信文档(文档相当相当不完善!至少对于我这样的菜鸡来说、先要仔细看一遍微信文档

小程序B2b门店助手

微信小程序需要准备的:

1.开通BtoB商户号并与小程序绑定

2.小程序端在开发管理中开启消息推送功能、开通时选择明文、JSON(消息推送类似一个支付回调地址,在支付或退款完成之后微信服务器会给到推送事件、可以在接收推送事件时进行业务流程,要先写好一个能访问的接口)

3.在门店BtoB助手支付管理中获取 沙箱AppKey和现网AppKey

(注)需获取用户session_key,每次登录时获取session_key要记录下来,每次登录session_key会变化

获取支付参数(注意用户的session_key、注意env和appkey匹配)

    public function payB()
    {
        $appkey = '';   //appKey、在小程序页面获取
        $session_key = $this->user['session_key'];
        $signData = [];
        $signData['mchid'] = 'xxxxxxxxxxx'; //商户号
        $signData['out_trade_no'] = 'xxxxxxxxxxxxxxxxxxxx';
        $signData['description'] = 'XXXXXXXX';
        $signData['amount'] = [
            'order_amount' => intval($order->pay_price * 100),
            'currency' => 'CNY'
        ];
        $signData['env'] = 0;
        $postdata = json_encode($signData,256);

        $paySign = $this->calc_pay_sig('requestCommonPayment',$postdata,$appkey);
        $signature = $this->calc_signature($postdata,$session_key);

        return $this->renderSuccess('', [
            'signData' => $postdata,
            'mode' => 'retail_pay_goods',
            'paySig' => $paySign,
            'signature' => $signature,
        ]);
    }
    //签名算法
    public function calc_pay_sig($uri, $post_body, $appkey)
    {
        $temp = $uri . '&' . $post_body;
        return hash_hmac('sha256', $temp, $appkey);
    }

    //用户登录态signature签名算法
    public function calc_signature($post_body, $session_key)
    {
        return hash_hmac('sha256', $post_body, $session_key);
    }

接收后端参数,uniapp前端调起

wx.requestCommonPayment({
    signData: result.data.signData,
    mode: result.data.mode,
    paySig: result.data.paySig,
    signature: result.data.signature,
    success: res => {
            // console.log(22222222);
            paySuccess(result, self, success);
    },
    fail: res => {
            console.log(res.errMsg);
            console.log(3334445689,res);
            self.showError('订单未支付成功', () => {
                    payError(result, fail);
            });
    },
});

支付成功或退款成功后的信息通知

//采用的明文模式(密文的获取到数据需要先进行解密)  json格式数据推送
public function actionWx_msg_notify()
{
    $signature = empty($_GET["signature"]) ? '' : $_GET["signature"];
    $timestamp = empty($_GET["timestamp"]) ? '' : $_GET["timestamp"];
    $nonce = empty($_GET["nonce"]) ? '' : $_GET["nonce"];
    $echostr = empty($_GET["echostr"]) ? '' : $_GET["echostr"];

    $token = "AAA";
    $tmpArr = array($token, $timestamp, $nonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode( $tmpArr );
    $tmpStr = sha1( $tmpStr );

    if( $tmpStr == $signature && $echostr){
        echo $echostr;
        exit;
    } else {
        $input = file_get_contents("php://input");
        $data = json_decode($input,true);
        $Event = $data['Event'] ?? '';
        switch ($Event) {
            case 'retail_pay_notify'://b2b订单支付回调
                // 订单状态,枚举值
                // ORDER_INIT:订单初始化
                // ORDER_PRE_PAY:订单预下单成功,待支付
                // ORDER_PAY_SUCC:订单支付成功
                // ORDER_CLOSE:订单已关闭
                // ORDER_REFUND_PROCESSING:订单正在退款中
                // ORDER_REFUND:订单已有退款
                $pay_status = $data['pay_status'] ?? '';//订单状态
                if ($pay_status == 'ORDER_PAY_SUCC') {
                    //订单支付成功
                    $pay_time = $data['pay_time'];//支付时间
                    $out_trade_no = $data['out_trade_no'];//商户订单号
                    $pay_amount = round($data['amount']['pay_amount'] / 100,2);//支付金额
                    $transactionid = $data['wxpay_transaction_id'];//微信支付订单号
                    //Todo  业务处理 

                    //

                    echo 'success';
                    exit;
                }
                break;
            case 'retail_refund_notify':
                $refund_status = $data['refund_status'] ?? '';
                if($refund_status == 'REFUND_SUCC') {
                    //Todo  业务处理
                    $out_trade_no = $data['out_trade_no'];
                    echo 'success';
                    exit;
                }

                break;
        }

    }
}

退款及查询订单(注:退款需要订单状态为完成,我的经验是在支付3分钟后微信订单会转为完成,这里需要先查询微信端订单状态再退款)

坑1:退款appkey必须使用现网

坑2:退款 订单号或者小程序订单号必须传其中一个!


//查询微信端订单状态
$signData['mchid'] = 'xxxxxxxxxx';
$signData['out_trade_no'] = 'xxxxxxxxxxxxxxx';

$postdata = json_encode($signData,256);
$appkey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$uri = '/retail/B2b/getorder';
$pay_sig = $this->calc_pay_sig($uri, $postdata, $appkey);

$accessToken = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$apiUrl = "https://api.weixin.qq.com/retail/B2b/getorder?access_token=$token&pay_sig=$pay_sig";
// $params = json_encode($post_data, JSON_UNESCAPED_UNICODE);
// 执行请求, 256
$result = json_decode($this->post($apiUrl, $postdata),true);
//退款
$post_data = [
    'mchid' => 'xxx',
    'out_trade_no' => xxxxxxxxxx,
    'out_refund_no' => xxxxxxxxxxx,
    'refund_amount' => 200,
    'refund_from' => 2
];
$appkey = 'xxxxxxxxxxxxxxxxxxxxxxxx';
$post_body = json_encode($post_data, 256);
$pay_sig = $this->calc_pay_sig('/retail/B2b/refund', $post_body, $appkey);
$apiUrl = "https://api.weixin.qq.com/retail/B2b/refund?access_token=$token&pay_sig=$pay_sig";
// $params = json_encode($post_data, JSON_UNESCAPED_UNICODE);
// 执行请求
$result = $this->post($apiUrl, $post_body);
// 返回结果
$response = json_decode($result, true);
//curl请求
protected function post($url, $data = [], $useCert = false, $sslCert = [])
{
    $header = [
        'Content-type: application/json;'
    ];
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    if ($useCert == true) {
        // 设置证书:cert 与 key 分别属于两个.pem文件
        curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);
        curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);
    }
    $result = curl_exec($curl);
    curl_close($curl);
    return $result;
}