1、前言

上一篇写了《Core3.1 微信v3 JSAPI支付》,这个属于v3的接口规则,现在研究了下退款的接口我写的时候它属于v2接口规则文档。但凡微信支付文档里面写清楚点我也不会在这里记录一下。

2、干货

接口文档https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml 现在看看是v3接口的了 我的天,他们在逗我玩一样,v2的写好了v3就放出来了。命途多舛啊。 v2请求的是xml文档格式的,这里又要温习一下旧知识了。

当时我记得清清楚楚 就说了请求要加签名,证书双向验证。官网文档没有写。Net的怎么加载证书 就说了一句windows下面直接安装证书就好了。结果 都是Bad Request 还是人工咨询吧 到最后才把代码找给我。我问人工客户地址给我看看,他说没有地址(肺都气炸。。。)

3、代码

这是封装的一个请求 ,代码加在上篇文章里面的那个请求里面

     /// <summary>
///postXML请求
/// </summary>
/// <param name="url">地址</param>
/// <param name="requestString">参数(json格式)</param>
/// <param name="path">p12文件路径</param>
/// <param name="certPwd">密码</param>
/// <returns>string</returns>
public string PostXml(string url, string requestString,string path, string certPwd)
{
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12,
ServerCertificateCustomValidationCallback = (x, y, z, m) => true,
}; //var path = Path.Combine(AppContext.BaseDirectory, "cert\\iot3rd.p12");
handler.ClientCertificates.Add(new X509Certificate2(path, certPwd)); var client = new HttpClient(handler); var content = new StringContent(requestString);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
//GetAwaiter().GetResult();
var httpResponseMessage = client.PostAsync(url, content).Result.Content.ReadAsStringAsync().Result;
return httpResponseMessage;
}

最主要的就是加了认证文件,p12文件路径跟密码,一般密码都是商户号。这就是微信文档说的双向验证

拼接请求参数,官网文档有验证这个的。排序的话我自己手动固定排序的,就那几个字段ABCDEFG都可以看到0.0。

 /// <summary>
/// 退费需要的字符
/// </summary>
/// <param name="hospInfo"></param>
/// <param name="regOrder"></param>
/// <returns></returns>
private string RequestRetreatParmar(Entity.Models.HospInfo hospInfo, RegOrder regOrder)
{
var guid = Guid.NewGuid().ToString("N").Substring(0, 30);
var retreatNo = OrderHelper.GenerateNo("CFTF");
int money = Convert.ToInt32(regOrder.OwnFee * 100);
//签名
string message = $"appid={hospInfo.WxAppid}&mch_id={hospInfo.WxMchid}&nonce_str={guid}&out_refund_no={retreatNo}&refund_desc=客户预约挂号退款&refund_fee={money}&total_fee={money}&transaction_id={regOrder.PlatformTradeId}&key={hospInfo.WxKey}";
var signMd5 = SecurityHelper.MD5EncrytString(message).ToUpper();
var dto = new
{
xml= new
{
appid = hospInfo.WxAppid,
mch_id = hospInfo.WxMchid,
nonce_str = guid,
sign = signMd5,
transaction_id = regOrder.PlatformTradeId,
out_refund_no = retreatNo,
total_fee = money,
refund_fee = money,
refund_desc = "客户预约挂号退款",
}
};
var json = JsonConvert.SerializeObject(dto); return json;
}

我把这里MD5加密的代码也贴上

        /// md5加密
/// </summary>
/// <param name="inputString">字符串</param>
/// <returns>加密过的字符串(不可以解密)</returns>
public static string MD5EncrytString(string inputString)
{
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] buffer = Encoding.UTF8.GetBytes(inputString);
byte[] md5Buffer = md5.ComputeHash(buffer);
md5.Clear();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < md5Buffer.Length; i++)
{
sb.Append(md5Buffer[i].ToString("x2"));
}
return sb.ToString();
}

请求这里,只要Return_code等于SUCCESS下面就可以做自己的业务逻辑了。里面返回的字段肯定有一个是你自己写了传进去的。通过这个字段查询数据库完成自己的逻辑。

 //微信退费操作
var url = RequestUrl.PAYREFUND;
var json = RequestRetreatParmar(hospInfoMoidel, regOrderModel);
var xml = JsonConvert.DeserializeXmlNode(json);
var postData = xml.InnerXml;
var pathfile = _webHostEnvironment.WebRootPath + "/arsjkll/apiclient_cert.p12";
var wxPostResult = _httpClientFactoryHelper.PostXml(url, postData, pathfile, hospInfoMoidel.WxSslcertpassword);
SaveLog("WeChatTuiFei", wxPostResult);
var resultRep = wxPostResult.Replace("<![CDATA[", "").Replace("]]>", "");
XmlDocument doc = new XmlDocument();
doc.LoadXml(resultRep);
string jsonText = JsonConvert.SerializeXmlNode(doc);
SaveLog("WeChatTuiFei", jsonText);
var resultModel = JsonConvert.DeserializeObject<RetreatNoResulDtoXml>(jsonText);
var resultModelXml = resultModel.Xml;
if (resultModelXml.Result_Code == "SUCCESS")
{
regOrderModel.RefundNo = resultModelXml.Out_Refund_No;
regOrderModel.RefundState = 1;
regOrderModel.RefundResult = resultModelXml.Return_Code;
regOrderModel.RefundTime = DateTime.Now; payLogModel.RefundNo = resultModelXml.Out_Refund_No;
payLogModel.RefundState = 1;
payLogModel.RefundResult = resultModelXml.Return_Code;
payLogModel.RefundTime = DateTime.Now;
await _db.SaveChangesAsync();
return Result.ToSuccess(resultModel);
}
else
return Result.ToFail(resultModelXml.Return_Msg);

我这里没有用notify_url返回接口 直接得到结果。下面是接收的Dto

public class RetreatNoResulDtoXml
{
public RetreatNoResulDto Xml { get; set; }
}
/// <summary>
/// 退号|退费结果
/// </summary>
public class RetreatNoResulDto
{
/// <summary>
/// 返回状态码
/// SUCCESS:退款申请接收成功,结果通过退款查询接口查询
/// FAIL:提交业务失败
/// 此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
/// 示例值:SUCCESS
/// </summary>
public string Return_Code { get; set; }
/// <summary>
/// 返回信息
/// 返回信息,如非空,为错误原因
/// 签名失败
/// 参数格式校验错误
/// 示例值:签名失败
/// </summary>
public string Return_Msg { get; set; } //返回状态码(return_code)为SUCCESS的时候,包含以下字段 /// <summary>
/// 业务结果
/// SUCCESS/FAIL
/// 示例值:SUCCESS
/// </summary>
public string Result_Code { get; set; }
/// <summary>
/// 错误代码
/// 示例值:SYSTEMERROR
/// </summary>
public string Err_Code { get; set; }
/// <summary>
/// 错误代码描述
/// 结果信息描述
///示例值:系统错误
/// </summary>
public string Err_Code_Des { get; set; }
public string Appid { get; set; }
public string Mch_Id { get; set; }
public string Sub_Appid { get; set; }
public string Sub_Mch_Id { get; set; }
public string Nonce_Str { get; set; }
/// <summary>
/// 签名
/// </summary>
public string Sign { get; set; }
public string Transaction_Id { get; set; }
public string Out_Trade_No { get; set; }
public string Out_Refund_No { get; set; }
public string Refund_Id { get; set; }
public int Refund_Fee { get; set; }
public int Settlement_Refund_Fee { get; set; }
public int Total_Fee { get; set; }
public int Settlement_Total_Fee { get; set; }
public string Fee_Type { get; set; }
public int Cash_Fee { get; set; } }

返回的结果我存了日志  真不知道中间<![CDATA[SUCCESS]]> 这个花里胡哨的是咋想的 我直接 全部替换 ""  了。

<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
<appid><![CDATA[wx6ed9112323b1f1d3e04]]></appid>
<mch_id><![CDATA[16045678769]]></mch_id>
<nonce_str><![CDATA[9xonPINPBGO4y8WW]]></nonce_str>
<sign><![CDATA[DABC2420B7B03FBA4D0027A9EBBF54D7]]></sign>
<result_code><![CDATA[SUCCESS]]></result_code>
<transaction_id><![CDATA[42000009呜呜呜呜276477024]]></transaction_id>
<out_trade_no><![CDATA[YYGH20210129164746001]]></out_trade_no>
<out_refund_no><![CDATA[CFTF20210129164806002]]></out_refund_no>
<refund_id><![CDATA[50300407262021012905921959108]]></refund_id>
<refund_channel><![CDATA[]]></refund_channel>
<refund_fee>440</refund_fee>
<coupon_refund_fee>0</coupon_refund_fee>
<total_fee>440</total_fee>
<cash_fee>440</cash_fee>
<coupon_refund_count>0</coupon_refund_count>
<cash_refund_fee>440</cash_refund_fee>
</xml>

4、总结

看着几行代码 还给我排队等了好久终于问人工解决的,之前都没说请求头里面加载用户证书,可能是v3出来了没太在意吧。后面看看 v3接口 看样子应该跟统一下单一样了吧只要调用请求那个方法就可以了!

时间,抓起了就是黄金,虚度了就是流水;书,看了就是知识,没看就是废纸;理想,努力了才叫梦想,放弃了那只是妄想。努力,虽然未必会收获,但放弃,就一定一无所获。

Core3.1 微信v3 JSAPI支付 退款的更多相关文章

  1. Core3.1 微信v3 JSAPI支付

    1.前言 "小魏呀,这个微信支付还要多久?","快了快了老板,就等着最后一步了...","搞快点哈,就等着上线呢","...... ...

  2. 微信v3 JSAPI最新接口错误 get_brand_wcpay_request:fail

    WxPay.JsApiPay.php文件下 原始接口代码 /** * * 获取jsapi支付的参数 * @param array $UnifiedOrderResult 统一支付接口返回的数据 * @ ...

  3. 微信JSApi支付~集成到MVC环境后的最后一个坑(网上没有这种解决方案)

    返回目录 大叔第一人 之前写了关于微信的坑<微信JSApi支付~坑和如何填坑>,今天将微信的jsapi支付封装到了MVC环境里,当然也出现了一些新的坑,如支付参数应该是Json对象而不是J ...

  4. 微信支付系列(2)——jsapi支付源码解析

    版权声明:转载请注明出处:http://blog.csdn.net/m0sh1 http://www.share345.com 在微信支付 开发者文档页面 下载最新的 PHP SDK http://m ...

  5. 微信小程序支付及退款流程详解

    微信小程序的支付和退款流程 近期在做微信小程序时,涉及到了小程序的支付和退款流程,所以也大概的将这方面的东西看了一个遍,就在这篇博客里总结一下. 首先说明一下,微信小程序支付的主要逻辑集中在后端,前端 ...

  6. 微信小程序支付开发之申请退款

    微信小程序支付跟微信公众号支付类似,这里不另做记录,如果没有开发过支付,可以查看我关于微信支付的文章 重点记录微信小程序申请退款开发过程中遇到一些坑. 退款接口比支付接口接口多了一个 双向证书 证书介 ...

  7. 微信 之jsapi实现支付

    一.微信公众号号后台支付配置 附微信支付参考文档:https://pay.weixin.qq.com/wiki/doc/api/index.html 二.微信支付类封装 该类可以实现付款码支付.JSA ...

  8. 微信小程序支付以及微信退款开发

    最近公司项目急着测试,需要开发微信小程序+微信支付+微信退款,本着这几天的一些研究,决定记录一下开发的过程. 本着知识分享的原则,希望对大家有所帮助. 本篇针对的是微信小程序的支付开发,如果有对微信公 ...

  9. 网站如何接入微信公众号JSAPI支付PHP版

    1.首先,我们要有一个微信公众号(分类类型有订阅号,服务号,企业号)我们的微信公众号一定是个服务号只有它才有微信支付接口.. 并且这个微信公众号一定要进行微信认证才能申请微信支付接口. 2.申请JSA ...

随机推荐

  1. [leetcode]380. Insert Delete GetRandom O(1)设计数据结构,实现存,删,随机取的时间复杂度为O(1)

    题目: Design a data structure that supports all following operations in average O(1) time.1.insert(val ...

  2. 【转载】VUE的背景图引入

    我现在的项目要将登录页面的背景引一图片做为背景图片,按原jsp中的写法,发现无法找到背景图片,最后从网上查资料,采用上面的写法,成功显示出背景图片,参考网址 https://blog.csdn.net ...

  3. [论文阅读笔记] node2vec Scalable Feature Learning for Networks

    [论文阅读笔记] node2vec:Scalable Feature Learning for Networks 本文结构 解决问题 主要贡献 算法原理 参考文献 (1) 解决问题 由于DeepWal ...

  4. 接口的不同写法在Swagger上的不同

    接口请求方法类型 (1) 如果接口没有指定请求的 method 类型,例如 GET.POST.PUT.DELETE 等. Swagger中 (2)指定了请求方法后 Swagger中就只有一个GET请求 ...

  5. HarmonyOS分布式任务调度开发之--你必须知道的bundleName

    背景 最近基于HarmonyOS在写一个通讯录的项目,已经完成了一个java版本的通讯录,通讯录数据全部存储在sqlite数据库中.现在在着手写一个JS版本的通讯录,这时候关于JS版本中数据的读取,我 ...

  6. Sql Server Sum函数的特殊使用

    利用Sql Server的Sum函数开窗得到累计值 具体详解https://www.cnblogs.com/zhaoshujie/p/9594676.html 个人示例例子 DECLARE @Sale ...

  7. LeetCode707 设计链表

    设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ...

  8. CopyOnWriteArrayList设计思路与源码分析

    CopyOnWriteArrayList实现了List接口,RandomAccess,Cloneable,Serializable接口. CopyOnWriteArrayList特性 1.线程安全,在 ...

  9. 【MySQL】MySQL知识图谱

    MySQL 文章目录 MySQL 表 锁 索引 连接管理 事务 日志系统 简单记录 极客时间 - MySQL实战45讲 MySQL知识图谱 表 表 引擎选择 编码问题 表空间管理 字段设计 备份和恢复 ...

  10. QPinter 常用绘制图像的方法

    阅读本文大概需要 3 分钟 我们在开发软件的过程中,绘制图像功能必不可少,使用 Qt 绘制图像时非常简单,只需要传递几个参数就可以实现功能,在 Qt 中绘制图像的 api有好几个 void drawI ...