Refund.cs 6.1 KB

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