PaymentService.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. using System;
  2. using System.Web;
  3. using WingServerCommon.Service;
  4. using WingInterfaceLibrary.Interface;
  5. using System.Threading.Tasks;
  6. using WingInterfaceLibrary.DTO.Payment;
  7. using WingInterfaceLibrary.Request.Payment;
  8. using WingInterfaceLibrary.Result;
  9. using System.Collections.Generic;
  10. using WingInterfaceLibrary.Interface.DBInterface;
  11. using WingInterfaceLibrary.DB.Request;
  12. using WingServerCommon.Log;
  13. using WingPaymentService.Common;
  14. using WingInterfaceLibrary.Enum;
  15. using WingInterfaceLibrary.Request;
  16. using WingPaymentService.Common.WeChat;
  17. namespace WingPaymentService.Service
  18. {
  19. public class PaymentService : JsonRpcService, IPaymentService
  20. {
  21. private IAuthenticationService _authenticationService;
  22. private IPaymentDBService _paymentDBService;
  23. private AlipayCommon _alipayCommon;
  24. private WeChatCommon _weChatCommon;
  25. public override void Load(JsonRpcClientPool jsonRpcClientPool)
  26. {
  27. _alipayCommon = new AlipayCommon();
  28. _weChatCommon = new WeChatCommon();
  29. base.Load(jsonRpcClientPool);
  30. _paymentDBService = GetProxy<IPaymentDBService>();
  31. _authenticationService = GetProxy<IAuthenticationService>();
  32. }
  33. /// <summary>
  34. /// 购买接口
  35. /// </summary>
  36. /// <param name="request"></param>
  37. /// <returns></returns>
  38. public async Task<CreateOrderResultDTO> CreateOrderAsync(CreateOrderRequest request)
  39. {
  40. var dbRequest = new CreateOrderDBRequest();
  41. dbRequest.OrderAmount = request.OrderAmount;
  42. dbRequest.OrderTitle = request.OrderTitle;
  43. dbRequest.OrderType = request.OrderType;
  44. if (string.IsNullOrWhiteSpace(request.OrderUserCode))
  45. {
  46. request.OrderUserCode = await ValidateTokenAsync(request.Token);
  47. if (string.IsNullOrWhiteSpace(request.OrderUserCode))
  48. {
  49. ThrowCustomerException(CustomerRpcCode.UserNotFind, "UserNotFind");
  50. }
  51. }
  52. dbRequest.OrderUserCode = request.OrderUserCode;
  53. dbRequest.PayStatus = PayStatusEnum.NoPay;
  54. dbRequest.PayTime = DateTime.UtcNow;
  55. dbRequest.ProductCode = request.ProductCode;
  56. dbRequest.TPORderCode = request.TPORderCode;
  57. return await _paymentDBService.CreateOrderAsync(dbRequest);
  58. }
  59. /// <summary>
  60. /// 订单详情接口
  61. /// </summary>
  62. /// <param name="request"></param>
  63. /// <returns></returns>
  64. public async Task<OrderDetailDTO> GetOrderDetailAsync(GetOrderDetailRequest request)
  65. {
  66. return await _paymentDBService.GetOrderDetailAsync(new GetOrderDetailDBRequest { OrderCode = request.OrderCode });
  67. }
  68. /// <summary>
  69. /// 订单列表接口
  70. /// </summary>
  71. /// <param name="request"></param>
  72. /// <returns></returns>
  73. public async Task<PageResult<OrderDetailDTO>> GetOrderPagesAsync(GetOrderPagesRequest request)
  74. {
  75. return await _paymentDBService.GetOrderPagesAsync(new GetOrderPagesDBRequest
  76. {
  77. CurrentPage = request.PageIndex,
  78. PageSize = request.PageSize,
  79. KeyWord = request.KeyWord
  80. });
  81. }
  82. /// <summary>
  83. /// 发起支付请求
  84. /// </summary>
  85. /// <param name="request"></param>
  86. /// <returns></returns>
  87. public async Task<PayInfoDTO> GoToPayAsync(GoToPayRequest request)
  88. {
  89. if (!string.IsNullOrWhiteSpace(request.OrderCode))
  90. {
  91. var orderInfo = await _paymentDBService.GetOrderDetailAsync(new GetOrderDetailDBRequest { OrderCode = request.OrderCode });
  92. if (orderInfo != null && orderInfo.OrderAmount > 0)
  93. {
  94. string payUrl = string.Empty;
  95. switch (request.PayType)
  96. {
  97. case PayTypeEnum.Alipay_PAGE:
  98. payUrl = _alipayCommon.AlipayPagePay(orderInfo.OrderTitle, orderInfo.OrderAmount, orderInfo.Code);
  99. break;
  100. case PayTypeEnum.Alipay_WAP:
  101. payUrl = _alipayCommon.AlipayWapPay(orderInfo.OrderTitle, orderInfo.OrderAmount, orderInfo.Code);
  102. break;
  103. case PayTypeEnum.WeChat_PAGE:
  104. payUrl = await _weChatCommon.GetWebPayUrlAsync(orderInfo.OrderTitle, orderInfo.OrderAmount, orderInfo.Code, string.Empty, string.Empty);
  105. break;
  106. case PayTypeEnum.WeChat_WAP:
  107. payUrl = await _weChatCommon.GetWapPayUrlAsync(orderInfo.OrderTitle, orderInfo.OrderAmount, orderInfo.Code, string.Empty, string.Empty);
  108. break;
  109. }
  110. if (!string.IsNullOrWhiteSpace(payUrl))
  111. {
  112. return new PayInfoDTO
  113. {
  114. IsSuccess = true,
  115. PayUrl = payUrl
  116. };
  117. }
  118. }
  119. }
  120. return new PayInfoDTO
  121. {
  122. IsSuccess = false,
  123. PayUrl = string.Empty
  124. };
  125. }
  126. /// <summary>
  127. /// 支付后回调
  128. /// </summary>
  129. /// <param name="src">来源</param>
  130. /// <param name="request">请求信息</param>
  131. /// <returns></returns>
  132. public async Task<PayCallbackDTO> PayCallbackAsync(string src, string request)
  133. {
  134. try
  135. {
  136. switch (src)
  137. {
  138. case "Alipay":
  139. await AlipayCallback(request);
  140. break;
  141. case "WeChat":
  142. await WeChatCallback(request);
  143. break;
  144. }
  145. return new PayCallbackDTO { IsSuccess = true };
  146. }
  147. catch (Exception ex)
  148. {
  149. Logger.WriteLineError($"PayCallback error {ex}");
  150. return new PayCallbackDTO { IsSuccess = false };
  151. }
  152. }
  153. private async Task<bool> AlipayCallback(string request)
  154. {
  155. Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
  156. var uriParams = HttpUtility.UrlDecode(request);
  157. if (uriParams != null)
  158. {
  159. var paramsArr = uriParams.Split('&');
  160. foreach (string param in paramsArr)
  161. {
  162. var keyValue = param.Split('=');
  163. var key = keyValue[0];
  164. var value = keyValue.Length > 1 ? keyValue[1] : string.Empty;
  165. keyValuePairs.Add(key, value);
  166. }
  167. }
  168. var payOutTradeNo = keyValuePairs.GetValueOrDefault("out_trade_no");
  169. var totalAmount = keyValuePairs.GetValueOrDefault("total_amount");
  170. var paymentRecordCode = keyValuePairs.GetValueOrDefault("pay_record_code");
  171. var payStatus = keyValuePairs.GetValueOrDefault("trade_status") == "TRADE_SUCCESS" ? WingInterfaceLibrary.Enum.PayStatusEnum.Paid : WingInterfaceLibrary.Enum.PayStatusEnum.NoPay;
  172. await UpdatePayStatus(paymentRecordCode, payStatus, uriParams);
  173. if(payStatus == PayStatusEnum.Paid)
  174. {
  175. return await UpdateOrderStatus(payOutTradeNo, payStatus, totalAmount);
  176. }
  177. return false;
  178. }
  179. private async Task<bool> WeChatCallback(string request)
  180. {
  181. //转换数据格式, 取消签名校验,签名调用方自己调用,兼容支付和退款
  182. WxPayData data = new WxPayData();
  183. var paramValues = data.FromXml(request,false);//回调不用签名校验
  184. var payOutTradeNo = paramValues.GetValueOrDefault("out_trade_no")?.ToString();
  185. var totalAmount = (double.Parse(paramValues.GetValueOrDefault("total_fee")?.ToString())/100).ToString("0.00");
  186. var payRecordCode = paramValues.GetValueOrDefault("pay_record_code")?.ToString();
  187. var payStatus = paramValues.GetValueOrDefault("result_code")?.ToString() == "SUCCESS" ? PayStatusEnum.Paid : PayStatusEnum.NoPay;
  188. await UpdatePayStatus(payRecordCode, payStatus, request);
  189. if(payStatus == PayStatusEnum.Paid)
  190. {
  191. return await UpdateOrderStatus(payOutTradeNo, payStatus, totalAmount);
  192. }
  193. return false;
  194. }
  195. private async Task<bool> UpdateOrderStatus(string orderCode, PayStatusEnum payStatus, string totalAmount)
  196. {
  197. var orderInfo = await _paymentDBService.GetOrderDetailAsync(new GetOrderDetailDBRequest{ OrderCode = orderCode});
  198. if(orderInfo.OrderAmount.ToString("0.00") != totalAmount)
  199. {
  200. Logger.WriteLineError($"OrderCode:{orderInfo.Code} pay status {payStatus}, total amount error, order amount {orderInfo.OrderAmount.ToString("0.00")} paid amount {totalAmount}");
  201. return false;
  202. }
  203. var result = await _paymentDBService.UpdateOrderAsync(new UpdateOrderDBRequest{
  204. OrderCode = orderCode,
  205. PayStatus = payStatus
  206. });
  207. return result.IsSuccess;
  208. }
  209. private async Task<UpdatePaymentRecordResultDTO> UpdatePayStatus(string paymentRecordCode, PayStatusEnum payStatus, string payResContent)
  210. {
  211. var updateRecordInfo = new UpdatePaymentRecordDBRequest();
  212. updateRecordInfo.Code = paymentRecordCode;
  213. updateRecordInfo.PayTime = DateTime.UtcNow;
  214. updateRecordInfo.PayStatus = payStatus;
  215. updateRecordInfo.PayResContent = payResContent;
  216. return await _paymentDBService.UpdatePaymentRecordAsync(updateRecordInfo);
  217. }
  218. /// <summary>
  219. /// 客户端用户验证
  220. /// </summary>
  221. /// <param name="request"></param>
  222. /// <returns>User Code</returns>
  223. private async Task<string> ValidateTokenAsync(string token)
  224. {
  225. var request = new TokenRequest() { Token = token };
  226. var result = await _authenticationService.GetTokenAsync(request);
  227. return result.ClientId; //return User code
  228. }
  229. private void ThrowCustomerException(CustomerRpcCode customerRpcCodeEnum, string msg)
  230. {
  231. ThrowRpcException((int)customerRpcCodeEnum, msg);
  232. }
  233. }
  234. }