微信支付JSAPI模式及退款CodeIgniter集成篇

2024-01-09 20:18

本文主要是介绍微信支付JSAPI模式及退款CodeIgniter集成篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


微信支付接口文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1

首先你得知道这个jsapi是不能离开微信进行调用支付的,明白了这个道理我们好下手,页面是在微信内显示并通过jsapi调用微信支付组件进行支付。

可以看看我们上一篇文章,主要是Native扫码支付模式二

我们仍然继续使用wechatpay.php这个支付集成类,简单方便好理解,不过如果应用jsapi的话这个类有个bug

在我们构造jsapi需要的参数时有个时间戳,我们用time()生成的,会报微信支付调用JSAPI缺少参数:timeStamp

修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  * 获取js支付使用的第二个参数
  */
public  function  get_package( $prepay_id ) {
     $data  array ();
     $data [ "appId" ] =  $this ->_config[ "appid" ];
       //改动地方,把它变成字符串
     $time =time();
     $data [ "timeStamp" ] =  "\"" . $time . "\"" ;
     $data [ "nonceStr" ]  =  $this ->get_nonce_string();
     $data [ "package" ]   =  "prepay_id=$prepay_id" ;
     $data [ "signType" ]  =  "MD5" ;
     $data [ "paySign" ]   =  $this ->sign( $data );
     return  $data ;
}

 其实这个方法就是获取jsapi的支付参数了

一、微信JSAPI支付

不能忘记配置授权目录,调用jsapi我是在http://xxx.com/index.php/home下我配置了这个

首先我们还是要调用统一下单接口,获取我们要的参数(如果此类的配置放置位置等不会的请参考上篇文章),此为pay方法,在调用统一下单接口的时候我们需要知道需要哪些参数

1、要获取openid,这个我是项目用了一个微信API的类库,https://github.com/dodgepudding/wechat-php-sdk,主要是用了这里面的方法

此项目有朋友专门的对接了CodeIgniter框架的扩展类库,可以直接用,目录结构,我们直接上代码吧

1
2
3
4
5
6
public  function  __construct()
{
     parent::__construct();
     $this ->load->library( 'CI_Wechat' ); //由于我的项目是时刻都跟微信绑在一起,所以直接加载在构造函数里了,不用每个方法都加载了。
     $this ->load->library( 'pagination' );
}

 CI_Model内容大家看下上面的类库源码,还有里面如何配置的,下面我们看看如何获取openid

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function  oauthurl()
{
     $oauth_url  $this ->ci_wechat->getOauthRedirect(base_url() .  'index.php/home/oauth' , 1);
     header( 'Location: '  $oauth_url );
     exit ();
}
function  oauth()
{
     if  (!isset( $_GET [ 'code' ])) {
         //触发微信返回code码
         $baseUrl  = urlencode( 'http://'  $_SERVER [ 'HTTP_HOST' ] .  $_SERVER [ 'PHP_SELF' ] .  $_SERVER [ 'QUERY_STRING' ]);
         $url  $this ->__CreateOauthUrlForCode( $baseUrl );
         Header( "Location: $url" );
         exit ();
     else  {
         $json  $this ->ci_wechat->getOauthAccessToken();
         $openid  $json [ 'openid' ];
         //注册用户,成功后可以抢单
         //return $this->_isRegistered($_SESSION['user']['openid']);
         return  $openid ;
     }
}

 以上两个方法就是获取openid的,获取之后我是保存在session里的,我每个页面都判断是否获取了openid如果没有获取直接

1
$this ->session->set_userdata( 'openid' $this ->oauth());

 这样保证一直能得到openid

2、构造JSAPI支付所需参数(统一下单的参数构造)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$this ->load->model( 'publist' ); //获取订单信息
$pub  $this ->publist->GetList( array ( 'id'  =>  $_SESSION [ 'orderid' ]));
//微信支付配置的参数配置读取
$this ->load->config( 'wxpay_config' );
$wxconfig [ 'appid' ]= $this ->config->item( 'appid' );
$wxconfig [ 'mch_id' ]= $this ->config->item( 'mch_id' );
$wxconfig [ 'apikey' ]= $this ->config->item( 'apikey' );
$wxconfig [ 'appsecret' ]= $this ->config->item( 'appsecret' );
$wxconfig [ 'sslcertPath' ]= $this ->config->item( 'sslcertPath' );
$wxconfig [ 'sslkeyPath' ]= $this ->config->item( 'sslkeyPath' );
$this ->load->library( 'Wechatpay' , $wxconfig );
//商户交易单号
$out_trade_no  $pub ->listno;
$total_fee = $pub ->fee;
$openid = $_SESSION [ 'openid' ];
$param [ 'body' ]= "黑人牙膏" ;
$param [ 'attach' ]= $pub ->id;
$param [ 'detail' ]= "黑人牙膏-" . $out_trade_no ;
$param [ 'out_trade_no' ]= $out_trade_no ;
$param [ 'total_fee' ]= $total_fee *100;
$param [ "spbill_create_ip" ] = $_SERVER [ 'REMOTE_ADDR' ];
$param [ "time_start" ] =  date ( "YmdHis" );
$param [ "time_expire" ] = date ( "YmdHis" , time() + 600);
$param [ "goods_tag" ] =  "黑人牙膏" ;
$param [ "notify_url" ] = base_url(). "index.php/home/notify" ;
$param [ "trade_type" ] =  "JSAPI" ;
$param [ "openid" ] =  $openid ;
//统一下单,获取结果,结果是为了构造jsapi调用微信支付组件所需参数
$result = $this ->wechatpay->unifiedOrder( $param );
//如果结果是成功的我们才能构造所需参数,首要判断预支付id
if  (isset( $result [ "prepay_id" ]) && ! empty ( $result [ "prepay_id" ])) {
     //调用支付类里的get_package方法,得到构造的参数
     $data [ 'parameters' ]=json_encode( $this ->wechatpay->get_package( $result [ 'prepay_id' ]));
     $data [ 'notifyurl' ]= $param [ "notify_url" ];
     $data [ 'fee' ]= $total_fee ;
     $data [ 'pubid' ]= $_SESSION [ 'orderid' ];
     $this ->load->view( 'home/header' );
     //要有个页面将以上数据传递过去并展示给用户
     $this ->load->view( 'home/pay' $data );
     $this ->load->view( 'home/footer' );
}       

 3、支付页面,views视图pay.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?php
$jsApiParameters  $parameters ; //参数赋值
?>
<script type= "text/javascript" >
     //调用微信JS api 支付
     function  jsApiCall()
     {
         WeixinJSBridge.invoke(
             'getBrandWCPayRequest' ,
             <?php  echo  $jsApiParameters ; ?>,
             function (res){
                 WeixinJSBridge.log(res.err_msg);
                 if (res.err_msg ==  "get_brand_wcpay_request:ok"  ){
                     $.alert( '支付成功' );
                     //我在这里选择了前台只要支付成功将单号传递更新数据
                     $.ajax({
                         url: '<?php  echo $notifyurl.' / '.$pubid;?>' ,
                         dataType: 'json' ,
                         success :  function (ret){
                             if (ret==1){
                                 //成功后返回我的订单页面
                                 location.href= "<?php echo base_url().'index.php/home/myorder';?>" ;
                             }
                         }
                     });
                 } else
                 {
                     //$.alert('支付失败');
                 }
                 //alert(res.err_code+res.err_desc+res.err_msg);
             }
         );
     }
     function  callpay()
     {
         if  (typeof WeixinJSBridge ==  "undefined" ){
             if ( document.addEventListener ){
                 document.addEventListener( 'WeixinJSBridgeReady' , jsApiCall, false);
             } else  if  (document.attachEvent){
                 document.attachEvent( 'WeixinJSBridgeReady' , jsApiCall);
                 document.attachEvent( 'onWeixinJSBridgeReady' , jsApiCall);
             }
         } else {
             jsApiCall();
         }
     }
</script>
<div  class = "hd" >
     <h1  class = "page_title" >支付佣金</h1>
     <p  class = "page_desc" >请认真核对佣金金额</p>
</div>
<div  class = "weui_cells" >
     <div  class = "weui_cell" >
         <div  class = "weui_cell_hd weui_cell_primary" >
             该笔订单支付金额为<span style= "color:#f00;font-size:50px" ><?php  echo  $fee ; ?></span>元钱
         </div>
     </div>
</div>
<button  class = "weui_btn weui_btn_primary"  type= "button"  onclick= "callpay()"  >立即支付</button>

 以上代码可以用微信web开发者工具,使用方式自己看看吧,有了这个工具调试不再难

4、支付成功跳转页面,我们看notify方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function  notify()
{
     $id  $this ->uri->segment(3);
     if  (isset( $_SESSION [ 'openid' ])) {
         $this ->load->model( 'publist' ); //更新业务逻辑
         $rs  $this ->publist->UpdateList( array ( 'id'  =>  $id 'feestatus'  => 1));
         if  ( $rs  > 0) {
             echo  1;
             exit ;
         else  {
             echo  0;
             exit ;
         }
     }
}

 这样我们的支付流程就彻底走完了。

二、当我们支付完之后,有些单子可以退单的,如何将款项也退回呢

以上场景要弄明白了

我们申请退款需要参数有哪些?我们看看支付类里的退款方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
  * 申请退款 - 使用商户订单号
  * @param $out_trade_no 商户订单号
  * @param $out_refund_no 退款单号
  * @param $total_fee 总金额(单位:分)
  * @param $refund_fee 退款金额(单位:分)
  * @param $op_user_id 操作员账号
  * @return array
  */
public  function  refund( $out_trade_no , $out_refund_no , $total_fee , $refund_fee , $op_user_id ){
     $data  array ();
     $data [ "appid" ] =  $this ->_config[ "appid" ];
     $data [ "mch_id" ] =  $this ->_config[ "mch_id" ];
     $data [ "nonce_str" ] =  $this ->get_nonce_string();
     $data [ "out_trade_no" ] =  $out_trade_no ;
     $data [ "out_refund_no" ] =  $out_refund_no ;
     $data [ "total_fee" ] =  $total_fee ;
     $data [ "refund_fee" ] =  $refund_fee ;
     $data [ "op_user_id" ] =  $op_user_id ;
     $result  $this ->post(self::URL_REFUND,  $data ,true);
     return  $result ;
}

 商户订单号,商户提供的退单号,付款金额,退款金额(不能退的比实际付款的多),操作员(一般商户号)

控制器内写退款方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//申请退款
function  refund( $id = "" )
{
     if ( $id == "" ){
         //方便我手动调用退单
         $id  $this ->uri->segment(3);
     }
     if  (isset( $id ) &&  $id  !=  "" ) {
         $this ->load->model( 'publist' );
         //1、取消订单可以退款。2、失败订单可以退款
         $pub  $this ->publist->GetList( array ( 'id'  =>  $id ));
         if  ( $pub ->liststatus == 3 ||  $pub ->liststatus == 4) {
             $listno  $pub ->listno;
             $fee  $pub ->fee * 100;
             $this ->load->config( 'wxpay_config' );
             $wxconfig [ 'appid' ]= $this ->config->item( 'appid' );
             $wxconfig [ 'mch_id' ]= $this ->config->item( 'mch_id' );
             $wxconfig [ 'apikey' ]= $this ->config->item( 'apikey' );
             $wxconfig [ 'appsecret' ]= $this ->config->item( 'appsecret' );
             $wxconfig [ 'sslcertPath' ]= $this ->config->item( 'sslcertPath' );
             $wxconfig [ 'sslkeyPath' ]= $this ->config->item( 'sslkeyPath' );
             $this ->load->library( 'Wechatpay' , $wxconfig );
             if  (isset( $listno ) &&  $listno  !=  "" ) {
                 $out_trade_no  $listno ;
                 $total_fee  $fee ;
                 $refund_fee  $fee ;
                 //自定义商户退单号
                 $out_refund_no = $wxconfig [ 'mch_id' ]. date ( "YmdHis" );
                     $result = $this ->wechatpay->refund( $out_trade_no , $out_refund_no , $total_fee , $refund_fee , $wxconfig [ 'mch_id' ]);
                 log::DEBUG(json_encode( $result ));
                 if  (isset( $result [ "return_code" ]) &&  $result [ "return_code" ]= "SUCCESS" &&isset( $result [ "result_code" ]) &&  $result [ "result_code" ]= "SUCCESS" ) {
                     echo  "<script>$.toast('退款成功')</script>" ;
                 }
                 //佣金状态更改为已退款
                 $this ->publist->UpdateList( array ( 'id' => $id , 'liststatus' =>3, 'listoutno' => $out_refund_no ));
                 redirect( 'home/myorder' );
             }
         }
     }
}

 试试就好了,很快就可以接到退款消息

以上是这几天摸索出来的东西,分享给大家。


文章来源:http://www.cnblogs.com/24la/p/wxpay-jsapi-refund.html

这篇关于微信支付JSAPI模式及退款CodeIgniter集成篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/588308

相关文章

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

SpringCloud集成AlloyDB的示例代码

《SpringCloud集成AlloyDB的示例代码》AlloyDB是GoogleCloud提供的一种高度可扩展、强性能的关系型数据库服务,它兼容PostgreSQL,并提供了更快的查询性能... 目录1.AlloyDBjavascript是什么?AlloyDB 的工作原理2.搭建测试环境3.代码工程1.

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

SpringBoot集成SOL链的详细过程

《SpringBoot集成SOL链的详细过程》Solanaj是一个用于与Solana区块链交互的Java库,它为Java开发者提供了一套功能丰富的API,使得在Java环境中可以轻松构建与Solana... 目录一、什么是solanaj?二、Pom依赖三、主要类3.1 RpcClient3.2 Public

SpringBoot3集成swagger文档的使用方法

《SpringBoot3集成swagger文档的使用方法》本文介绍了Swagger的诞生背景、主要功能以及如何在SpringBoot3中集成Swagger文档,Swagger可以帮助自动生成API文档... 目录一、前言1. API 文档自动生成2. 交互式 API 测试3. API 设计和开发协作二、使用

SpringBoot如何集成Kaptcha验证码

《SpringBoot如何集成Kaptcha验证码》本文介绍了如何在Java开发中使用Kaptcha生成验证码的功能,包括在pom.xml中配置依赖、在系统公共配置类中添加配置、在控制器中添加生成验证... 目录SpringBoot集成Kaptcha验证码简介实现步骤1. 在 pom.XML 配置文件中2.

W外链微信推广短连接怎么做?

制作微信推广链接的难点分析 一、内容创作难度 制作微信推广链接时,首先需要创作有吸引力的内容。这不仅要求内容本身有趣、有价值,还要能够激起人们的分享欲望。对于许多企业和个人来说,尤其是那些缺乏创意和写作能力的人来说,这是制作微信推广链接的一大难点。 二、精准定位难度 微信用户群体庞大,不同用户的需求和兴趣各异。因此,制作推广链接时需要精准定位目标受众,以便更有效地吸引他们点击并分享链接

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)