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. Qt学习笔记-界面设置入门

    首先我们看的是qt类表.相当于是一个族谱.这个文档可以在网上搜到. 首先第一个是QObjiect. 然后是QWidget => 相当于是windowsget缩写. 同理: QColorDialo ...

  2. 关于客户和供应商预制凭证添加WBS字段

    客户和供应商的预制凭证的对应标准屏幕SAPLF0400301和SAPLF0400302并没有提供WBS字段,有的需求需要增强WBS字段到屏幕上,本文会介绍增强WBS字段的步骤,也请读者多多指教.为了不 ...

  3. jupyter安装插件Nbextensions,实现代码提示功能(终极方法)

    jupyter安装插件,实现代码提示功能 第一步 pip install jupyter_contrib_nbextensions -i https://mirrors.tuna.tsinghua.e ...

  4. PPT 转 word

    可以wps  直接转 打开wps   在页面里直接点击右键  可以导出wps

  5. LAMP架构之PHP-FPM 服务器 转

    安装PHP 解决依赖关系 # 请配置好yum源(系统安装源及epel源)后执行如下命令: yum -y groupinstall "Desktop Platform Development& ...

  6. 【Nginx学习笔记】-初识Nginx

    Nginx 目录 Nginx Nginx 特点 Nginx 基本功能 Nginx 使用场景 Nginx 安装/卸载 Docker 方式运行 Ubuntu上安装 卸载Nginx Nginx 命令 Ngi ...

  7. Solon rpc 之 SocketD 协议 - 消息加密模式

    Solon rpc 之 SocketD 协议系列 Solon rpc 之 SocketD 协议 - 概述 Solon rpc 之 SocketD 协议 - 消息上报模式 Solon rpc 之 Soc ...

  8. linux mysql source 导入大文件报错解决办法

    找到mysql的配置文件目录 my.cnf interactive_timeout = 120wait_timeout = 120max_allowed_packet = 500M 在导入过程中可能会 ...

  9. 【Java基础】Java 语言概述

    Java 语言概述 主要应用场景 JavaEE.大数据.Android 开发方向. 基础知识概述 编程语言核心结构 变量.基本语法.分支.循环.数组.- Java 面向对象的核心逻辑 OOP.封装.继 ...

  10. SpringBoot魔法堂:@MatrixVariable参数注解使用详解

    前言 RFC3986定义URI的路径(Path)中可包含name-value片段,扩充了以往仅能通过查询字符串(Query String)设置可选参数的囧境. 假如现在需要设计一个用于"搜索 ...