Refund.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using System;
  2. using System.Security.Cryptography.X509Certificates;
  3. using System.Threading.Tasks;
  4. using WayneCloud.Models;
  5. using WayneCloud.Models.Models;
  6. namespace Wechat.PayAPI
  7. {
  8. public class Refund
  9. {
  10. private const int MAX_REFUND_RETRY_TIMES = 5;
  11. /***
  12. * 申请退款完整业务流程逻辑
  13. * @param transaction_id 微信订单号(优先使用)
  14. * @param out_trade_no 商户订单号
  15. * @param total_fee 订单总金额
  16. * @param refund_fee 退款金额
  17. * @return 退款结果
  18. */
  19. public static async Task<WxPayData> Run(string transaction_id, ElectronicOrderModel order)
  20. {
  21. try
  22. {
  23. // string out_trade_no, string total_fee, string refund_fee
  24. //set the default trade_status to PAYERROR
  25. order.TradeStatus = TradeStatus.PAYERROR;
  26. string out_refund_no = WxPayApi.GenerateOutTradeNo((WxPayConfig)order.Config);
  27. Log.Info("Refund", "Refund is processing, out_refund_no = " + out_refund_no);
  28. int retry_count = 0;
  29. bool use_unsettled_fund = true;
  30. while (true)
  31. {
  32. WxPayData result = await RequestRefund(transaction_id,
  33. order.BillNumber,
  34. order.TotalAmount.ToString(),
  35. order.NetAmount.ToString(),
  36. out_refund_no,
  37. use_unsettled_fund,
  38. (WxPayConfig)order.Config,
  39. (X509Certificate2)order.Certification);
  40. //如果提交退款接口调用失败,则抛异常
  41. if (!result.IsSet("return_code") || result.GetValue("return_code").ToString() == "FAIL")
  42. {
  43. string returnMsg = result.IsSet("return_msg") ? result.GetValue("return_msg").ToString() : "";
  44. Log.Error("MicroPay", "Micropay API interface call failure, result : " + result.ToXml());
  45. throw new WxPayException("Micropay API interface call failure, return_msg : " + returnMsg);
  46. }
  47. //签名验证
  48. result.CheckSign((WxPayConfig)order.Config);
  49. Log.Debug("MicroPay", "Micropay response check sign success");
  50. //退款成功
  51. if (result.GetValue("return_code").ToString() == "SUCCESS" &&
  52. result.GetValue("result_code").ToString() == "SUCCESS")
  53. {
  54. Log.Debug("MicroPay", "Micropay refund success, result : " + result.ToXml());
  55. order.TradeStatus = TradeStatus.SUCCESS;
  56. return result;
  57. }
  58. /******************************************************************
  59. * 剩下的都是接口调用成功,业务失败的情况
  60. * ****************************************************************/
  61. //1)业务结果明确失败
  62. if (result.GetValue("err_code").ToString() != "BIZERR_NEED_RETRY" &&
  63. result.GetValue("err_code").ToString() != "SYSTEMERROR" &&
  64. result.GetValue("err_code").ToString() != "NOTENOUGH")
  65. {
  66. Log.Error("MicroPay", "micropay API interface call success, business failure, result : " + result.ToXml());
  67. return result;
  68. }
  69. //2) 使用相同退款单号重试
  70. if (result.GetValue("err_code").ToString() == "NOTENOUGH")
  71. {
  72. use_unsettled_fund = !use_unsettled_fund;
  73. Log.Debug("MicroPay", "Switched to use the other fund source for refund, use_unsettled_fund = " + use_unsettled_fund);
  74. }
  75. retry_count++;
  76. if (retry_count <= MAX_REFUND_RETRY_TIMES)
  77. {
  78. Log.Debug("MicroPay", "Micropay refund retry, retry_count : " + retry_count);
  79. }
  80. else
  81. {
  82. Log.Error("MicroPay", "Micropay refund max retry times exceeded! Result : " + result.ToXml());
  83. return result;
  84. }
  85. }
  86. }
  87. catch (Exception e)
  88. {
  89. }
  90. return new WxPayData();
  91. }
  92. private static async Task<WxPayData> RequestRefund(
  93. string transaction_id,
  94. string out_trade_no,
  95. string total_fee,
  96. string refund_fee,
  97. string out_refund_no,
  98. bool use_unsettled_fund,
  99. WxPayConfig config,
  100. X509Certificate2 certification
  101. )
  102. {
  103. if (config == null)
  104. {
  105. throw new WxPayException("微信支付,缺少WxPayConfig!");
  106. }
  107. WxPayData data = new WxPayData();
  108. if (!string.IsNullOrEmpty(transaction_id))//微信订单号存在的条件下,则已微信订单号为准
  109. {
  110. data.SetValue("transaction_id", transaction_id);
  111. }
  112. else//微信订单号不存在,才根据商户订单号去退款
  113. {
  114. data.SetValue("out_trade_no", out_trade_no);
  115. }
  116. data.SetValue("total_fee", Convert.ToInt32(Decimal.Parse(total_fee) * 100));//订单总金额
  117. data.SetValue("refund_fee", Convert.ToInt32(Decimal.Parse(refund_fee) * 100));//退款金额
  118. data.SetValue("out_refund_no", out_refund_no);//商户退款单号
  119. data.SetValue("op_user_id", config.MCHID);//操作员,默认为商户号
  120. if (use_unsettled_fund)
  121. {
  122. data.SetValue("refund_account", "REFUND_SOURCE_UNSETTLED_FUNDS");
  123. }
  124. else
  125. {
  126. data.SetValue("refund_account", "REFUND_SOURCE_RECHARGE_FUNDS");
  127. }
  128. WxPayData result = await WxPayApi.Refund(data, config, certification);//提交退款申请给API,接收返回数据
  129. return result;
  130. }
  131. }
  132. }