退款流程

更新时间:2023-03-12 15:19:28 阅读: 评论:0

足球竞技-假发刘海

退款流程
2023年3月12日发(作者:七夕节是什么时候)

微信⼩程序⽀付及退款整体流程

最近做了微信⽀付及退款⼀系列操作,微信⽂档写的也⽐较简略,⽹上博客也并不详细,也踩了⼀些坑,在这⾥记录下。当然主要还是得根

据微信⼩程序⽂档⼀步⼀步来。

⼀、tPayment

发起微信⽀付。了解更多信息,请查看

所谓的发起微信⽀付,指的是⽤户侧这边唤起微信⽀付窗⼝的api,这个api需要按规范传参数

tPayment({

timeStamp:'',

nonceStr:'',

package:'',

signType:'MD5',

paySign:'',

success(res){},

fail(res){}

})

这些参数均需要从后台获取。那么我们进⼊“微信⽀付接⼝⽂档”查看是怎么个流程

⼆、微信⽀付具体流程

⽂档也写的很清楚,不细说,主要看下⾯这个流程

商户系统和微信⽀付系统主要交互:

1、⼩程序内调⽤登录接⼝,获取到⽤户的openid,api参见公共api【】

2、商户rver调⽤⽀付统⼀下单,api参见公共api【】

3、商户rver调⽤再次签名,api参见公共api【】

4、商户rver接收⽀付通知,api参见公共api【】

5、商户rver查询⽀付结果,api参见公共api【】

1、调⽤获取code,然后通过code,调取微信三⽅接⼝,获取openid。如果⽤户系统有openid记录,可以省略这步操作。

主要是因为下⾯的统⼀下单api⾥的参数配置:

openid参数:trade_type=JSAPI,此参数必传,⽤户在商户appid下的唯⼀标识。openid如何获取,可参考【】。

2、统⼀下单api、⼆次签名api返回参数

看⽂档⾥的参数,传那些参数,调⽤微信三⽅接⼝即可。⼀般不会有啥问题,主要问题也会在于2次签名。

实例代码如下

//统⼀下单

letunifiedorder=async(params={},ctx)=>{

letbody='......'//商品描述

letnotify_url='https://....../wxPayBack'//⽀付成功的回调地址可访问不带参数

letnonce_str=ceStr()//随机数

letout_trade_no=ode//商户订单号(⽤户系统⾃定义的商户订单号)

lettotal_fee=ay*100//订单价格单位是分

letbodyData=''

bodyData+=`${}`//⼩程序ID

bodyData+=`${_id}`//商户号

bodyData+=`${body}`//商品描述

bodyData+=`${nonce_str}`//随机字符串

bodyData+=`${notify_url}`//⽀付成功的回调地址

bodyData+=`${}`//⽤户标识(openid,JSAPI⽅式⽀付时必需传该参数)

bodyData+=`${out_trade_no}`//商户订单号

bodyData+=`${}`//终端IP

bodyData+=`${total_fee}`//总⾦额单位为分

bodyData+='JSAPI'//交易类型⼩程序取值:JSAPI

//签名(根据上⾯这些参数,有个签名算法,⽂档⾥也有描述)

varsign=njsapi(

,

body,

_id,

nonce_str,

notify_url,

,

out_trade_no,

,

total_fee

);

bodyData+=''+sign+''

bodyData+=''

//微信⼩程序统⼀下单接⼝

varurlStr='/pay/unifiedorder'

letoption={

method:'POST',

uri:urlStr,

body:bodyData

}

letresult=awaitrp(option)

letreturnValue={}

parString(result,function(err,result){

if(_code[0]=='SUCCESS'){

_trade_no=out_trade_no;//商户订单号

//⼩程序客户端⽀付需要nonceStr,timestamp,package,paySign这四个参数

tr=_str[0];//随机字符串

amp=(newDate().getTime()/1000)+'';

e='prepay_id='+_id[0];//统⼀下单接⼝返回的prepay_id参数值

n=njs(

,

tr,

e,

'MD5',

amp

)//签名

//emitToSocket(total_fee)

={

success:true,

msg:'操作成功',

data:returnValue

}

}el{

=_msg[0]

={

success:fal,

msg:'操作失败',

data:returnValue

}

}

})

}

写的⼀个微信⽀付的配置项

constcryptoMO=require('crypto')//MD5算法

/*微信参数AppID和Secret*/

constwxConfig={

AppID:"......",//⼩程序ID

Secret:"......",//⼩程序Secret

Mch_id:"......",//商户号

Mch_key:"......",//商户key

//⽣成商户订单号

getWxPayOrdrID:function(){

letmyDate=newDate();

letyear=lYear();

letmouth=th()+1;

letday=e();

lethour=rs();

letminute=utes();

letcond=onds();

letmcond=liconds();//获取当前毫秒数(0-999)

if(mouth<10){/*⽉份⼩于10就在前⾯加个0*/

mouth=String(String(0)+String(mouth));

}

if(day<10){/*⽇期⼩于10就在前⾯加个0*/

day=String(String(0)+String(day));

}

if(hour<10){/*时⼩于10就在前⾯加个0*/

hour=String(String(0)+String(hour));

}

if(minute<10){/*分⼩于10就在前⾯加个0*/

minute=String(String(0)+String(minute));

}

if(cond<10){/*秒⼩于10就在前⾯加个0*/

cond=String(String(0)+String(cond));

}

if(mcond<10){

mcond=String(String('00')+String(cond));

}elif(mcond>=10&&mcond<100){

mcond=String(String(0)+String(cond));

}

letcurrentDate=String(year)+String(mouth)+String(day)+String(hour)+String(minute)+String(cond)+String(mcond);

returncurrentDate

},

//获取随机字符串

getNonceStr(){

().toString(36).substr(2,15)

},

//统⼀下单签名

paysignjsapi(appid,body,mch_id,nonce_str,notify_url,openid,out_trade_no,spbill_create_ip,total_fee){

letret={

appid:appid,

body:body,

mch_id:mch_id,

nonce_str:nonce_str,

notify_url:notify_url,

openid:openid,

out_trade_no:out_trade_no,

spbill_create_ip:spbill_create_ip,

total_fee:total_fee,

trade_type:'JSAPI'

}

letstr=(ret,true)

str=str+'&key='+_key

letmd5Str=Hash('md5').update(str,'utf-8').digest('hex')

md5Str=rCa()

returnmd5Str

},

raw(args,lower){

letkeys=(args)

keys=()

letnewArgs={}

h(key=>{

lower?newArgs[rCa()]=args[key]:newArgs[key]=args[key]

})

letstr=''

for(letkinnewArgs){

str+='&'+k+'='+newArgs[k]

}

str=(1)

returnstr

},

//⼩程序⽀付签名

paysignjs(appid,nonceStr,packages,signType,timeStamp){

letret={

appId:appid,

nonceStr:nonceStr,

package:packages,

signType:signType,

timeStamp:timeStamp

}

letstr=(ret)

str=str+'&key='+_key

letmd5Str=Hash('md5').update(str,'utf-8').digest('hex')

md5Str=rCa()

returnmd5Str

},

//校验⽀付成功回调签名

validPayBacksign(xml){

letret={}

let_paysign=[0]

for(letkeyinxml){

if(key!=='sign'&&xml[key][0])ret[key]=xml[key][0]

}

letstr=(ret,true)

str=str+'&key='+_key

letmd5Str=Hash('md5').update(str,'utf-8').digest('hex')

md5Str=rCa()

return_paysign===md5Str

},

//确认退款签名

refundOrderSign(appid,mch_id,nonce_str,op_ur_id,out_refund_no,out_trade_no,refund_fee,total_fee){

letret={

appid:appid,

mch_id:mch_id,

nonce_str:nonce_str,

op_ur_id:op_ur_id,

out_refund_no:out_refund_no,

out_trade_no:out_trade_no,

refund_fee:refund_fee,

total_fee:total_fee

}

letstr=(ret,true)

str=str+'&key='+_key

letmd5Str=Hash('md5').update(str,'utf-8').digest('hex')

md5Str=rCa()

returnmd5Str

}

}

这个配置项⾥的就是raw⽅法得注意下,有个区分,有的签名是key值全⼩写,有的签名就是⽀付⼆次签名校验的时候,key值是要保持驼

峰,所以加了点区分。

当时在此处确实遇到了问题,查了很多博客,解决办法都模棱两可并没有效。其实,微信提供了签名校验⼯具,可以将⾃⼰的参数传⼊

看和⽣成的是否⼀致,然后就可以单步调试看是哪⾥出了问题,⽐较⽅便快捷。

从上⾯代码也可以看出流程:

根据⽂档需要传的参数——⽣成下单签名——签名与参数⼀起传⼊——调⽤微信统⼀下单api——返回下单接⼝的XML——解析

XML返回数据参数,再次⽣成签名——数据返回前台供tPayment()调⽤

⾄此微信⽀付就可以正常唤起窗⼝付款了。但是还有个重要的问题,就是下单成功通知。也就是下统⼀下单⾥传⼊的notify_url:⽀付

成功回答地址

3、⽀付成功结果通知

我们需要提供⼀个接⼝供微信⽀付成功回调:'POST/order/wxPayBack':wxPayBack,//微信⽀付成功回调

constparString=require('xml2js').parString//xml转js对象

letwxPayBack=async(ctx,next)=>{

('wxPayBack',)//我们可以打印看下微信返回的xml长啥样

parString(,function(err,result){

payBack(,ctx)

})

}

letpayBack=async(xml,ctx)=>{

if(_code[0]=='SUCCESS'){

letout_trade_no=_trade_no[0]//商户订单号

lettotal_free=_fee[0]//付款总价

('订单:',out_trade_no,'价格:',total_free)

if(ayBacksign(xml)){

letout_order=({

where:{

orderCode:out_trade_no

}

})

if(out_order&&(out_ay*100)-total_free===0&&out_tate===1){

({orderState:2},{

where:{

orderCode:out_trade_no

}

})

//emitToSocket(total_fee)

=``

}

}

}

=``

}

ayBacksign(xml),这⾥⼀定要校验下⽀付成功的回调签名。校验规则就是微信返回的xml⾥除了sign不放⼊参数校验外,

其他的均要拿出key-value值进⾏⽣产md5加密,然后与微信返回的sign值⽐对即可。

校验成功之后,修改订单表对应数据的状态即可。

三、申请退款和确认退款

申请退款其实没什么说的,就是⽤户侧申请退款,然后更改⽤户侧订单的状态,主要说⼀下商家确认退款给买家的流程。

特别需要注意的是:请求需要双向证书。详见

实例代码:

//确认退款

letconfirmRefund=async(ctx,next)=>{

let_body=

letout_trade_no=_ode//商户订单号

letnonce_str=ceStr()

lettotal_fee=_ay*100//订单价格单位是分

letrefund_fee=_ay*100

letbodyData='';

bodyData+=''++'';

bodyData+=''+_id+'';

bodyData+=''+nonce_str+'';

bodyData+=''+_id+'';

bodyData+=''+nonce_str+'';

bodyData+=''+out_trade_no+'';

bodyData+=''+total_fee+'';

bodyData+=''+refund_fee+'';

//签名

letsign=OrderSign(

,

_id,

nonce_str,

_id,

nonce_str,//商户退款单号给⼀个随机字符串即可out_refund_no

out_trade_no,

refund_fee,

total_fee

)

bodyData+=''+sign+''

bodyData+=''

letagentOptions={

pfx:leSync((__dirname,'/wx_pay/apiclient_cert.p12')),

passphra:_id,

}

//微信⼩程序退款接⼝

leturlStr='/capi/pay/refund'

letoption={

method:'POST',

uri:urlStr,

body:bodyData,

agentOptions:agentOptions

}

letresult=awaitrp(option)

parString(result,function(err,result){

if(_code[0]=='SUCCESS'){

refundBack(_)

={

success:true,

msg:'操作成功'

}

}el{

={

success:fal,

msg:_code_des[0]

}

}

})

}

letrefundBack=async(orderId)=>{

({orderState:8},{

where:{id:orderId}

})

letorderfoods=l({

where:{orderId:orderId}

})

h(food=>{

dealFood(food,'plus')

})

}

可以看到:随机字符串nonce_str,商户退款单号out_refund_no,我们⽤的是同⼀个随机串。

然后经过校验之后,获取证书内容及商户号,作为参数传给微信提供的申请退款接⼝接⼝。返回退款成功之后,做⾃⼰⽤户侧的相关

业务处理即可。

本文发布于:2023-03-12 15:19:27,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/1678605568227118.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:退款流程.doc

本文 PDF 下载地址:退款流程.pdf

上一篇:表扬信怎么写
下一篇:返回列表
标签:退款流程
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图