/*********************************************************************** * Project: CoreCms * ProjectName: 核心内容管理系统 * Web: https://www.corecms.net * Author: 大灰灰 * Email: jianweie@163.com * CreateTime: 2021/1/31 21:45:10 * Description: 暂无 ***********************************************************************/ using System; using System.Collections.Generic; using System.Threading.Tasks; using CoreCms.Net.Auth.HttpContextUser; using CoreCms.Net.Caching.AccressToken; using CoreCms.Net.Configuration; using CoreCms.Net.IServices; using CoreCms.Net.Model.Entities; using CoreCms.Net.Model.ViewModels.UI; using CoreCms.Net.Utility.Extensions; using CoreCms.Net.WeChat.Service.HttpClients; using Essensoft.Paylink.Alipay.Domain; using Essensoft.Paylink.WeChatPay; using Essensoft.Paylink.WeChatPay.V2; using Essensoft.Paylink.WeChatPay.V2.Request; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using QRCoder; using SKIT.FlurlHttpClient.Wechat.Api; using SKIT.FlurlHttpClient.Wechat.Api.Models; namespace CoreCms.Net.Services { /// /// 微信支付 接口实现 /// public class WeChatPayServices : BaseServices, IWeChatPayServices { private readonly IWeChatPayClient _client; private readonly IOptions _optionsAccessor; private readonly IHttpContextUser _user; private readonly IServiceProvider _serviceProvider; private readonly WeChat.Service.HttpClients.IWeChatApiHttpClientFactory _weChatApiHttpClientFactory; private readonly ICoreCmsUserServices _userServices; private readonly ICoreCmsUserWeChatInfoServices _userWeChatInfoServices; public WeChatPayServices(IHttpContextUser user , IWeChatPayClient client , IOptions optionsAccessor , ICoreCmsUserServices userServices , ICoreCmsUserWeChatInfoServices userWeChatInfoServices, IServiceProvider serviceProvider, IWeChatApiHttpClientFactory weChatApiHttpClientFactory) { _client = client; _optionsAccessor = optionsAccessor; _user = user; _userServices = userServices; _userWeChatInfoServices = userWeChatInfoServices; _serviceProvider = serviceProvider; _weChatApiHttpClientFactory = weChatApiHttpClientFactory; } /// /// 发起支付 /// /// 实体数据 /// public async Task PubPay(CoreCmsBillPayments entity) { using var container = _serviceProvider.CreateScope(); var orderServices = container.ServiceProvider.GetService(); var billPaymentsServices = container.ServiceProvider.GetService(); var checkBeforeAddOrderServices = container.ServiceProvider.GetService(); var transactionComponentOrderServices = container.ServiceProvider.GetService(); var jm = new WebApiCallBack(); var payment = await billPaymentsServices.QueryByClauseAsync(p => p.paymentId == entity.paymentId); var checkBeforeAddOrder = await checkBeforeAddOrderServices.QueryByClauseAsync(p => p.orderId == payment.sourceId); if (checkBeforeAddOrder != null && checkBeforeAddOrder.requireOrder == (int)GlobalEnumVars.RequireOrderType.需要) { var order = await transactionComponentOrderServices.QueryByClauseAsync(p => p.outOrderId == payment.sourceId); //获取小程序认证 var accessToken = WeChatCacheAccessTokenHelper.GetWxOpenAccessToken(); var client = _weChatApiHttpClientFactory.CreateWxOpenClient(); var getPaymentParameters = new ShopOrderGetPaymentParametersRequest(); getPaymentParameters.AccessToken = accessToken; getPaymentParameters.OpenId = order.openid; getPaymentParameters.OrderId = order.orderId; getPaymentParameters.OutOrderId = order.outOrderId; var shopOrderGetPayment = await client.ExecuteShopOrderGetPaymentParametersAsync(getPaymentParameters); if (shopOrderGetPayment.IsSuccessful()) { jm.data = new { shopOrderGetPayment.PaymentParameters, checkBeforeAddOrder, entity.paymentId }; jm.status = true; await transactionComponentOrderServices.UpdateAsync(p => new WeChatTransactionComponentOrder() { paymentId = entity.paymentId }, p => p.outOrderId == payment.sourceId); } else { jm.status = false; jm.msg = shopOrderGetPayment.ErrorMessage; } return jm; } else { var weChatPayUrl = AppSettingsConstVars.PayCallBackWeChatPayUrl; if (string.IsNullOrEmpty(weChatPayUrl)) { jm.msg = "未获取到配置的通知地址"; return jm; } var tradeType = GlobalEnumVars.WeiChatPayTradeType.JSAPI.ToString(); if (!string.IsNullOrEmpty(entity.parameters)) { var jobj = (JObject)JsonConvert.DeserializeObject(entity.parameters); if (jobj != null && jobj.ContainsKey("trade_type")) tradeType = GetTradeType(jobj["trade_type"].ObjectToString()); } var openId = string.Empty; if (tradeType == GlobalEnumVars.WeiChatPayTradeType.JSAPI.ToString()) { var userAccount = await _userServices.QueryByIdAsync(_user.ID); if (userAccount == null) { jm.msg = "用户账户获取失败"; return jm; } if (userAccount.userWx <= 0) { jm.msg = "账户关联微信用户信息获取失败"; return jm; } var user = await _userWeChatInfoServices.QueryByClauseAsync(p => p.id == userAccount.userWx); if (user == null) { jm.msg = "微信用户信息获取失败"; return jm; } openId = user.openid; } var orderRequest = new WeChatPayUnifiedOrderRequest { Body = entity.payTitle.Length > 40 ? entity.payTitle[..40] : entity.payTitle, OutTradeNo = entity.paymentId, TotalFee = Convert.ToInt32(entity.money * 100), SpBillCreateIp = entity.ip, NotifyUrl = weChatPayUrl, TradeType = tradeType, //OpenId = openId }; if (tradeType == GlobalEnumVars.WeiChatPayTradeType.JSAPI.ToString()) { orderRequest.OpenId = openId; } var response = await _client.ExecuteAsync(orderRequest, _optionsAccessor.Value); if (response.ReturnCode == WeChatPayCode.Success && response.ResultCode == WeChatPayCode.Success) { //App微信支付 if (tradeType == GlobalEnumVars.WeiChatPayTradeType.APP.ToString()) { var reqApp = new WeChatPayAppSdkRequest() { PrepayId = response.PrepayId }; var parameter = await _client.ExecuteAsync(reqApp, _optionsAccessor.Value); parameter.Add("paymentId", entity.paymentId); jm.status = true; jm.msg = "创建微信APP支付环境成功"; jm.data = parameter; jm.otherData = response; } //JsApi通用微信支付 else if (tradeType == GlobalEnumVars.WeiChatPayTradeType.JSAPI.ToString()) { // 将参数(parameter)给 公众号前端 让他在微信内H5调起支付(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6) var req = new WeChatPayJsApiSdkRequest { Package = "prepay_id=" + response.PrepayId }; var parameter = await _client.ExecuteAsync(req, _optionsAccessor.Value); parameter.Add("paymentId", entity.paymentId); jm.status = true; jm.msg = "创建JSAPI支付环境成功"; jm.data = parameter; //jm.otherData = response; } //扫码支付 else if (tradeType == GlobalEnumVars.WeiChatPayTradeType.NATIVE.ToString()) { jm.status = true; jm.msg = "创建微信扫码支付环境成功"; jm.data = new { response, entity.paymentId }; //确定是否存在扫码的图片,然后转成base64到前端进行扫码支付 if (!string.IsNullOrEmpty(response.CodeUrl) && response.CodeUrl.Contains("weixin://wxpay/bizpayurl?pr=")) { using var qrGenerator = new QRCodeGenerator(); using var qrCodeData = qrGenerator.CreateQrCode(response.CodeUrl, QRCodeGenerator.ECCLevel.L); using var pngByteQrCode = new PngByteQRCode(qrCodeData); var pngBytes = pngByteQrCode.GetGraphic(20, false); var stringBase64Str = Convert.ToBase64String(pngBytes); jm.otherData = stringBase64Str; } } //H5支付 else if (tradeType == GlobalEnumVars.WeiChatPayTradeType.MWEB.ToString()) { jm.status = true; jm.msg = "创建H5支付环境成功"; jm.data = response; } } else { jm.status = false; jm.msg = "微信建立支付请求失败"; //jm.otherData = response; } return jm; } } /// /// 用户退款 /// /// 退款单数据 /// 支付单数据 /// public async Task Refund(CoreCmsBillRefund refundInfo, CoreCmsBillPayments paymentInfo) { var jm = new WebApiCallBack(); var weChatRefundUrl = AppSettingsConstVars.PayCallBackWeChatRefundUrl; if (string.IsNullOrEmpty(weChatRefundUrl)) { jm.msg = "未获取到配置的通知地址"; return jm; } var request = new WeChatPayRefundRequest { OutRefundNo = refundInfo.refundId, TransactionId = paymentInfo.tradeNo, OutTradeNo = paymentInfo.paymentId, TotalFee = Convert.ToInt32(paymentInfo.money * 100), RefundFee = Convert.ToInt32(refundInfo.money * 100), NotifyUrl = weChatRefundUrl }; var response = await _client.ExecuteAsync(request, _optionsAccessor.Value); if (response.ReturnCode == WeChatPayCode.Success && response.ResultCode == WeChatPayCode.Success) { jm.status = true; jm.msg = "退款成功"; jm.data = response; } else { jm.status = false; jm.msg = "退款失败:" + response.ErrCodeDes; jm.data = response; } return jm; } private static string GetTradeType(string tradeType) { if (tradeType != GlobalEnumVars.WeiChatPayTradeType.JSAPI.ToString() && tradeType != GlobalEnumVars.WeiChatPayTradeType.JSAPI_OFFICIAL.ToString() && tradeType != GlobalEnumVars.WeiChatPayTradeType.NATIVE.ToString() && tradeType != GlobalEnumVars.WeiChatPayTradeType.APP.ToString() && tradeType != GlobalEnumVars.WeiChatPayTradeType.MWEB.ToString() ) return "JSAPI"; if (tradeType == GlobalEnumVars.WeiChatPayTradeType.JSAPI_OFFICIAL.ToString()) return "JSAPI"; return tradeType; } } }