WxPayApi.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. using Gateway.Payment.Shared;
  2. using System;
  3. using System.Security.Cryptography.X509Certificates;
  4. using Microsoft.Extensions.Logging;
  5. using Microsoft.Extensions.DependencyInjection;
  6. namespace Wechat.PayAPI
  7. {
  8. public class WxPayApi
  9. {
  10. public static ILogger Log = Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance;
  11. /**
  12. * 提交被扫支付API
  13. * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,
  14. * 由商户收银台或者商户后台调用该接口发起支付。
  15. * @param WxPayData inputObj 提交给被扫支付API的参数
  16. * @param int timeOut 超时时间
  17. * @throws WxPayException
  18. * @return 成功时返回调用结果,其他抛异常
  19. */
  20. public static WxPayData Micropay(WxPayData inputObj, WxPayConfig config, int timeOut = 10)
  21. {
  22. string url = "https://api.mch.weixin.qq.com/pay/micropay";
  23. if (config == null)
  24. {
  25. throw new WxPayException("微信支付,缺少WxPayConfig!");
  26. }
  27. //检测必填参数
  28. if (!inputObj.IsSet("body"))
  29. {
  30. throw new WxPayException("提交被扫支付API接口中,缺少必填参数body!");
  31. }
  32. else if (!inputObj.IsSet("out_trade_no"))
  33. {
  34. throw new WxPayException("提交被扫支付API接口中,缺少必填参数out_trade_no!");
  35. }
  36. else if (!inputObj.IsSet("total_fee"))
  37. {
  38. throw new WxPayException("提交被扫支付API接口中,缺少必填参数total_fee!");
  39. }
  40. else if (!inputObj.IsSet("auth_code"))
  41. {
  42. throw new WxPayException("提交被扫支付API接口中,缺少必填参数auth_code!");
  43. }
  44. inputObj.SetValue("spbill_create_ip", config.IP);//终端ip
  45. inputObj.SetValue("appid", config.APPID);//公众账号ID
  46. inputObj.SetValue("mch_id", config.MCHID);//商户号
  47. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  48. !string.IsNullOrEmpty(config.SUBMCHID))
  49. {
  50. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  51. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  52. }
  53. inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
  54. inputObj.SetValue("sign", inputObj.MakeSign(config));//签名
  55. string xml = inputObj.ToXml();
  56. var start = DateTime.Now;//请求开始时间
  57. Log.LogDebug("WxPayApi", "MicroPay request : " + xml);
  58. string response = HttpService.Post(xml, url, config, null, timeOut);//调用HTTP通信接口以提交数据到API
  59. Log.LogDebug("WxPayApi", "MicroPay response : " + response);
  60. var end = DateTime.Now;
  61. int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
  62. //将xml格式的结果转换为对象以返回
  63. WxPayData result = new WxPayData();
  64. result.FromXml(config, response);
  65. ReportCostTime(url, timeCost, result, config);//测速上报
  66. return result;
  67. }
  68. /**
  69. *
  70. * 查询订单
  71. * @param WxPayData inputObj 提交给查询订单API的参数
  72. * @param int timeOut 超时时间
  73. * @throws WxPayException
  74. * @return 成功时返回订单查询结果,其他抛异常
  75. */
  76. public static WxPayData OrderQuery(WxPayData inputObj, WxPayConfig config, int timeOut = 6)
  77. {
  78. string url = "https://api.mch.weixin.qq.com/pay/orderquery";
  79. //检测必填参数
  80. if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
  81. {
  82. throw new WxPayException("订单查询接口中,out_trade_no、transaction_id至少填一个!");
  83. }
  84. inputObj.SetValue("appid", config.APPID);//公众账号ID
  85. inputObj.SetValue("mch_id", config.MCHID);//商户号
  86. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  87. !string.IsNullOrEmpty(config.SUBMCHID))
  88. {
  89. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  90. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  91. }
  92. inputObj.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
  93. inputObj.SetValue("sign", inputObj.MakeSign(config));//签名
  94. string xml = inputObj.ToXml();
  95. var start = DateTime.Now;
  96. //Log.LogDebug("WxPayApi", "OrderQuery request : " + xml);
  97. string response = HttpService.Post(xml, url, config, null, timeOut);//调用HTTP通信接口提交数据
  98. //Log.LogDebug("WxPayApi", "OrderQuery response : " + response);
  99. var end = DateTime.Now;
  100. int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
  101. //将xml格式的数据转化为对象以返回
  102. WxPayData result = new WxPayData();
  103. result.FromXml(config, response);
  104. ReportCostTime(url, timeCost, result, config);//测速上报
  105. return result;
  106. }
  107. /**
  108. *
  109. * 撤销订单API接口
  110. * @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个
  111. * @param int timeOut 接口超时时间
  112. * @throws WxPayException
  113. * @return 成功时返回API调用结果,其他抛异常
  114. */
  115. public static WxPayData Reverse(WxPayData inputObj, WxPayConfig config, X509Certificate2 certification, int timeOut = 6)
  116. {
  117. string url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
  118. //检测必填参数
  119. if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
  120. {
  121. throw new WxPayException("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!");
  122. }
  123. inputObj.SetValue("appid", config.APPID);//公众账号ID
  124. inputObj.SetValue("mch_id", config.MCHID);//商户号
  125. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  126. !string.IsNullOrEmpty(config.SUBMCHID))
  127. {
  128. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  129. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  130. }
  131. inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
  132. inputObj.SetValue("sign", inputObj.MakeSign(config));//签名
  133. string xml = inputObj.ToXml();
  134. var start = DateTime.Now;//请求开始时间
  135. Log.LogDebug("WxPayApi", "Reverse request : " + xml);
  136. string response = HttpService.Post(xml, url, config, certification, timeOut);
  137. Log.LogDebug("WxPayApi", "Reverse response : " + response);
  138. var end = DateTime.Now;
  139. int timeCost = (int)((end - start).TotalMilliseconds);
  140. WxPayData result = new WxPayData();
  141. result.FromXml(config, response);
  142. ReportCostTime(url, timeCost, result, config);//测速上报
  143. return result;
  144. }
  145. /**
  146. *
  147. * 申请退款
  148. * @param WxPayData inputObj 提交给申请退款API的参数
  149. * @param int timeOut 超时时间
  150. * @throws WxPayException
  151. * @return 成功时返回接口调用结果,其他抛异常
  152. */
  153. public static WxPayData Refund(WxPayData inputObj, WxPayConfig config,
  154. X509Certificate2 certification, int timeOut = 6)
  155. {
  156. string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
  157. //检测必填参数
  158. if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
  159. {
  160. throw new WxPayException("退款申请接口中,out_trade_no、transaction_id至少填一个!");
  161. }
  162. else if (!inputObj.IsSet("out_refund_no"))
  163. {
  164. throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!");
  165. }
  166. else if (!inputObj.IsSet("total_fee"))
  167. {
  168. throw new WxPayException("退款申请接口中,缺少必填参数total_fee!");
  169. }
  170. else if (!inputObj.IsSet("refund_fee"))
  171. {
  172. throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!");
  173. }
  174. else if (!inputObj.IsSet("op_user_id"))
  175. {
  176. throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!");
  177. }
  178. inputObj.SetValue("appid", config.APPID);//公众账号ID
  179. inputObj.SetValue("mch_id", config.MCHID);//商户号
  180. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  181. !string.IsNullOrEmpty(config.SUBMCHID))
  182. {
  183. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  184. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  185. }
  186. inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
  187. inputObj.SetValue("sign", inputObj.MakeSign(config));//签名
  188. string xml = inputObj.ToXml();
  189. var start = DateTime.Now;
  190. Log.LogDebug("WxPayApi", "Refund request : " + xml);
  191. string response = HttpService.Post(xml, url, config, certification, timeOut);//调用HTTP通信接口提交数据到API
  192. Log.LogDebug("WxPayApi", "Refund response : " + response);
  193. var end = DateTime.Now;
  194. int timeCost = (int)((end - start).TotalMilliseconds);//获得接口耗时
  195. //将xml格式的结果转换为对象以返回
  196. WxPayData result = new WxPayData();
  197. result.FromXml(config, response);
  198. ReportCostTime(url, timeCost, result, config);//测速上报
  199. return result;
  200. }
  201. /**
  202. *
  203. * 查询退款
  204. * 提交退款申请后,通过该接口查询退款状态。退款有一定延时,
  205. * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
  206. * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
  207. * @param WxPayData inputObj 提交给查询退款API的参数
  208. * @param int timeOut 接口超时时间
  209. * @throws WxPayException
  210. * @return 成功时返回,其他抛异常
  211. */
  212. public static WxPayData RefundQuery(WxPayData inputObj, WxPayConfig config, int timeOut = 6)
  213. {
  214. string url = "https://api.mch.weixin.qq.com/pay/refundquery";
  215. //检测必填参数
  216. if(!inputObj.IsSet("out_refund_no") && !inputObj.IsSet("out_trade_no") &&
  217. !inputObj.IsSet("transaction_id") && !inputObj.IsSet("refund_id"))
  218. {
  219. throw new WxPayException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!");
  220. }
  221. inputObj.SetValue("appid", config.APPID);//公众账号ID
  222. inputObj.SetValue("mch_id", config.MCHID);//商户号
  223. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  224. !string.IsNullOrEmpty(config.SUBMCHID))
  225. {
  226. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  227. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  228. }
  229. inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
  230. inputObj.SetValue("sign",inputObj.MakeSign(config));//签名
  231. string xml = inputObj.ToXml();
  232. var start = DateTime.Now;//请求开始时间
  233. Log.LogDebug("WxPayApi", "RefundQuery request : " + xml);
  234. string response = HttpService.Post(xml, url, config, null, timeOut);//调用HTTP通信接口以提交数据到API
  235. Log.LogDebug("WxPayApi", "RefundQuery response : " + response);
  236. var end = DateTime.Now;
  237. int timeCost = (int)((end-start).TotalMilliseconds);//获得接口耗时
  238. //将xml格式的结果转换为对象以返回
  239. WxPayData result = new WxPayData();
  240. result.FromXml(config, response);
  241. ReportCostTime(url, timeCost, result, config);//测速上报
  242. return result;
  243. }
  244. /**
  245. * 下载对账单
  246. * @param WxPayData inputObj 提交给下载对账单API的参数
  247. * @param int timeOut 接口超时时间
  248. * @throws WxPayException
  249. * @return 成功时返回,其他抛异常
  250. */
  251. public static WxPayData DownloadBill(WxPayData inputObj, WxPayConfig config, int timeOut = 6)
  252. {
  253. string url = "https://api.mch.weixin.qq.com/pay/downloadbill";
  254. //检测必填参数
  255. if (!inputObj.IsSet("bill_date"))
  256. {
  257. throw new WxPayException("对账单接口中,缺少必填参数bill_date!");
  258. }
  259. inputObj.SetValue("appid", config.APPID);//公众账号ID
  260. inputObj.SetValue("mch_id", config.MCHID);//商户号
  261. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  262. !string.IsNullOrEmpty(config.SUBMCHID))
  263. {
  264. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  265. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  266. }
  267. inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
  268. inputObj.SetValue("sign", inputObj.MakeSign(config));//签名
  269. string xml = inputObj.ToXml();
  270. Log.LogDebug("WxPayApi", "DownloadBill request : " + xml);
  271. string response = HttpService.Post(xml, url, config, null, timeOut);//调用HTTP通信接口以提交数据到API
  272. Log.LogDebug("WxPayApi", "DownloadBill result : " + response);
  273. WxPayData result = new WxPayData();
  274. //若接口调用失败会返回xml格式的结果
  275. if (response.Substring(0, 5) == "<xml>")
  276. {
  277. result.FromXml(config, response);
  278. }
  279. //接口调用成功则返回非xml格式的数据
  280. else
  281. result.SetValue("result", response);
  282. return result;
  283. }
  284. /**
  285. *
  286. * 转换短链接
  287. * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),
  288. * 减小二维码数据量,提升扫描速度和精确度。
  289. * @param WxPayData inputObj 提交给转换短连接API的参数
  290. * @param int timeOut 接口超时时间
  291. * @throws WxPayException
  292. * @return 成功时返回,其他抛异常
  293. */
  294. public static WxPayData ShortUrl(WxPayData inputObj, WxPayConfig config, int timeOut = 6)
  295. {
  296. string url = "https://api.mch.weixin.qq.com/tools/shorturl";
  297. //检测必填参数
  298. if(!inputObj.IsSet("long_url"))
  299. {
  300. throw new WxPayException("需要转换的URL,签名用原串,传输需URL encode!");
  301. }
  302. inputObj.SetValue("appid", config.APPID);//公众账号ID
  303. inputObj.SetValue("mch_id", config.MCHID);//商户号
  304. inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
  305. inputObj.SetValue("sign",inputObj.MakeSign(config));//签名
  306. string xml = inputObj.ToXml();
  307. var start = DateTime.Now;//请求开始时间
  308. Log.LogDebug("WxPayApi", "ShortUrl request : " + xml);
  309. string response = HttpService.Post(xml, url, config, null, timeOut);
  310. Log.LogDebug("WxPayApi", "ShortUrl response : " + response);
  311. var end = DateTime.Now;
  312. int timeCost = (int)((end - start).TotalMilliseconds);
  313. WxPayData result = new WxPayData();
  314. result.FromXml(config, response);
  315. ReportCostTime(url, timeCost, result, config);//测速上报
  316. return result;
  317. }
  318. /**
  319. *
  320. * 统一下单
  321. * @param WxPaydata inputObj 提交给统一下单API的参数
  322. * @param int timeOut 超时时间
  323. * @throws WxPayException
  324. * @return 成功时返回,其他抛异常
  325. */
  326. public static WxPayData UnifiedOrder(WxPayData inputObj, WxPayConfig config, int timeOut = 6)
  327. {
  328. string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  329. //检测必填参数
  330. if (!inputObj.IsSet("out_trade_no"))
  331. {
  332. throw new WxPayException("缺少统一支付接口必填参数out_trade_no!");
  333. }
  334. else if (!inputObj.IsSet("body"))
  335. {
  336. throw new WxPayException("缺少统一支付接口必填参数body!");
  337. }
  338. else if (!inputObj.IsSet("total_fee"))
  339. {
  340. throw new WxPayException("缺少统一支付接口必填参数total_fee!");
  341. }
  342. else if (!inputObj.IsSet("trade_type"))
  343. {
  344. throw new WxPayException("缺少统一支付接口必填参数trade_type!");
  345. }
  346. //关联参数
  347. if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
  348. {
  349. throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
  350. }
  351. if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("product_id"))
  352. {
  353. throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
  354. }
  355. //异步通知url未设置,则使用配置文件中的url
  356. if (!inputObj.IsSet("notify_url"))
  357. {
  358. inputObj.SetValue("notify_url", config.NOTIFY_URL);//异步通知url
  359. }
  360. if (!inputObj.IsSet("openid")) // native pay
  361. {
  362. inputObj.SetValue("appid", config.APPID);//公众账号ID
  363. inputObj.SetValue("mch_id", config.MCHID);//商户号
  364. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  365. !string.IsNullOrEmpty(config.SUBMCHID))
  366. {
  367. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  368. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  369. }
  370. }
  371. else // mini program pay
  372. {
  373. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  374. !string.IsNullOrEmpty(config.SUBMCHID))
  375. {
  376. var openId = inputObj.GetValue("openid").ToString();
  377. inputObj.SetValue("openid", null);
  378. inputObj.SetValue("sub_openid", openId);
  379. inputObj.SetValue("mch_id", config.MCHID);//商户号
  380. inputObj.SetValue("appid", config.APPID);//公众账号ID
  381. inputObj.SetValue("sub_appid", config.MINI_PROGRAM_APPID);//公众账号ID
  382. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  383. }
  384. else
  385. {
  386. inputObj.SetValue("mch_id", config.MCHID);//商户号
  387. inputObj.SetValue("appid", config.MINI_PROGRAM_APPID);//公众账号ID
  388. }
  389. }
  390. inputObj.SetValue("spbill_create_ip", config.IP);//终端ip
  391. inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
  392. //签名
  393. inputObj.SetValue("sign", inputObj.MakeSign(config));
  394. string xml = inputObj.ToXml();
  395. var start = DateTime.Now;
  396. Log.LogDebug("WxPayApi", "UnfiedOrder request : " + xml);
  397. string response = HttpService.Post(xml, url, config, null, timeOut);
  398. Log.LogDebug("WxPayApi", "UnfiedOrder response : " + response);
  399. var end = DateTime.Now;
  400. int timeCost = (int)((end - start).TotalMilliseconds);
  401. WxPayData result = new WxPayData();
  402. result.FromXml(config, response);
  403. ReportCostTime(url, timeCost, result, config);//测速上报
  404. return result;
  405. }
  406. /**
  407. *
  408. * 关闭订单
  409. * @param WxPayData inputObj 提交给关闭订单API的参数
  410. * @param int timeOut 接口超时时间
  411. * @throws WxPayException
  412. * @return 成功时返回,其他抛异常
  413. */
  414. public static WxPayData CloseOrder(WxPayData inputObj, WxPayConfig config, int timeOut = 6)
  415. {
  416. string url = "https://api.mch.weixin.qq.com/pay/closeorder";
  417. //检测必填参数
  418. if(!inputObj.IsSet("out_trade_no"))
  419. {
  420. throw new WxPayException("关闭订单接口中,out_trade_no必填!");
  421. }
  422. inputObj.SetValue("appid", config.APPID);//公众账号ID
  423. inputObj.SetValue("mch_id", config.MCHID);//商户号
  424. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  425. !string.IsNullOrEmpty(config.SUBMCHID))
  426. {
  427. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  428. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  429. }
  430. inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
  431. inputObj.SetValue("sign",inputObj.MakeSign(config));//签名
  432. string xml = inputObj.ToXml();
  433. var start = DateTime.Now;//请求开始时间
  434. string response = HttpService.Post(xml, url, config, null, timeOut);
  435. var end = DateTime.Now;
  436. int timeCost = (int)((end - start).TotalMilliseconds);
  437. WxPayData result = new WxPayData();
  438. result.FromXml(config, response);
  439. ReportCostTime(url, timeCost, result, config);//测速上报
  440. return result;
  441. }
  442. /**
  443. *
  444. * 测速上报
  445. * @param string interface_url 接口URL
  446. * @param int timeCost 接口耗时
  447. * @param WxPayData inputObj参数数组
  448. */
  449. private static void ReportCostTime(string interface_url, int timeCost, WxPayData inputObj, WxPayConfig config)
  450. {
  451. //如果不需要进行上报
  452. if(config.REPORT_LEVENL == 0)
  453. {
  454. return;
  455. }
  456. //如果仅失败上报
  457. if(config.REPORT_LEVENL == 1 && inputObj.IsSet("return_code") && inputObj.GetValue("return_code").ToString() == "SUCCESS" &&
  458. inputObj.IsSet("result_code") && inputObj.GetValue("result_code").ToString() == "SUCCESS")
  459. {
  460. return;
  461. }
  462. //上报逻辑
  463. WxPayData data = new WxPayData();
  464. data.SetValue("interface_url",interface_url);
  465. data.SetValue("execute_time_",timeCost);
  466. //返回状态码
  467. if(inputObj.IsSet("return_code"))
  468. {
  469. data.SetValue("return_code",inputObj.GetValue("return_code"));
  470. }
  471. //返回信息
  472. if(inputObj.IsSet("return_msg"))
  473. {
  474. data.SetValue("return_msg",inputObj.GetValue("return_msg"));
  475. }
  476. //业务结果
  477. if(inputObj.IsSet("result_code"))
  478. {
  479. data.SetValue("result_code",inputObj.GetValue("result_code"));
  480. }
  481. //错误代码
  482. if(inputObj.IsSet("err_code"))
  483. {
  484. data.SetValue("err_code",inputObj.GetValue("err_code"));
  485. }
  486. //错误代码描述
  487. if(inputObj.IsSet("err_code_des"))
  488. {
  489. data.SetValue("err_code_des",inputObj.GetValue("err_code_des"));
  490. }
  491. //商户订单号
  492. if(inputObj.IsSet("out_trade_no"))
  493. {
  494. data.SetValue("out_trade_no",inputObj.GetValue("out_trade_no"));
  495. }
  496. //设备号
  497. if(inputObj.IsSet("device_info"))
  498. {
  499. data.SetValue("device_info",inputObj.GetValue("device_info"));
  500. }
  501. try
  502. {
  503. Report(data, config);
  504. }
  505. catch (WxPayException ex)
  506. {
  507. //不做任何处理
  508. }
  509. }
  510. /**
  511. *
  512. * 测速上报接口实现
  513. * @param WxPayData inputObj 提交给测速上报接口的参数
  514. * @param int timeOut 测速上报接口超时时间
  515. * @throws WxPayException
  516. * @return 成功时返回测速上报接口返回的结果,其他抛异常
  517. */
  518. public static WxPayData Report(WxPayData inputObj, WxPayConfig config,int timeOut = 1)
  519. {
  520. string url = "https://api.mch.weixin.qq.com/payitil/report";
  521. //检测必填参数
  522. if(!inputObj.IsSet("interface_url"))
  523. {
  524. throw new WxPayException("接口URL,缺少必填参数interface_url!");
  525. }
  526. if(!inputObj.IsSet("return_code"))
  527. {
  528. throw new WxPayException("返回状态码,缺少必填参数return_code!");
  529. }
  530. if(!inputObj.IsSet("result_code"))
  531. {
  532. throw new WxPayException("业务结果,缺少必填参数result_code!");
  533. }
  534. if(!inputObj.IsSet("user_ip"))
  535. {
  536. throw new WxPayException("访问接口IP,缺少必填参数user_ip!");
  537. }
  538. if(!inputObj.IsSet("execute_time_"))
  539. {
  540. throw new WxPayException("接口耗时,缺少必填参数execute_time_!");
  541. }
  542. inputObj.SetValue("appid",config.APPID);//公众账号ID
  543. inputObj.SetValue("mch_id",config.MCHID);//商户号
  544. if (!string.IsNullOrEmpty(config.SUBAPPID) &&
  545. !string.IsNullOrEmpty(config.SUBMCHID))
  546. {
  547. inputObj.SetValue("sub_appid", config.SUBAPPID);//公众账号ID
  548. inputObj.SetValue("sub_mch_id", config.SUBMCHID);//商户号
  549. }
  550. inputObj.SetValue("user_ip",config.IP);//终端ip
  551. inputObj.SetValue("time",DateTime.Now.ToString("yyyyMMddHHmmss"));//商户上报时间
  552. inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
  553. inputObj.SetValue("sign",inputObj.MakeSign(config));//签名
  554. string xml = inputObj.ToXml();
  555. Log.LogInformation("WxPayApi", "Report request : " + xml);
  556. string response = HttpService.Post(xml, url, config, null, timeOut);
  557. Log.LogInformation("WxPayApi", "Report response : " + response);
  558. WxPayData result = new WxPayData();
  559. result.FromXml(config, response);
  560. return result;
  561. }
  562. /**
  563. * 根据当前系统时间加随机序列来生成订单号
  564. * @return 订单号
  565. */
  566. public static string GenerateOutTradeNo(WxPayConfig config)
  567. {
  568. var ran = new Random();
  569. return string.Format("{0}{1}{2}", config.MCHID, DateTime.Now.ToString("yyyyMMddHHmmss"), ran.Next(999));
  570. }
  571. /**
  572. * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数
  573. * @return 时间戳
  574. */
  575. public static string GenerateTimeStamp()
  576. {
  577. TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
  578. return Convert.ToInt64(ts.TotalSeconds).ToString();
  579. }
  580. /**
  581. * 生成随机串,随机串包含字母或数字
  582. * @return 随机串
  583. */
  584. public static string GenerateNonceStr()
  585. {
  586. return Guid.NewGuid().ToString().Replace("-", "");
  587. }
  588. }
  589. }