PaymentService.cs 11 KB

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