/*********************************************************************** * 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 CoreCms.Net.WeChat.Service.TransactionComponent.Enum; using CoreCms.Net.WeChat.Service.TransactionComponent.Models; 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 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 orderItemServices = container.ServiceProvider.GetService(); var billPaymentsServices = container.ServiceProvider.GetService(); var weChatTransactionComponentOrderServices = container.ServiceProvider.GetService(); var jm = new WebApiCallBack(); 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 > 50 ? entity.payTitle[..50] : entity.payTitle, OutTradeNo = entity.paymentId, TotalFee = Convert.ToInt32(entity.money * 100), SpBillCreateIp = entity.ip, NotifyUrl = weChatPayUrl, TradeType = tradeType, OpenId = openId }; var response = await _client.ExecuteAsync(orderRequest, _optionsAccessor.Value); if (response.ReturnCode == WeChatPayCode.Success && response.ResultCode == WeChatPayCode.Success) { var req = new WeChatPayJsApiSdkRequest { Package = "prepay_id=" + response.PrepayId }; var parameter = await _client.ExecuteAsync(req, _optionsAccessor.Value); // 将参数(parameter)给 公众号前端 让他在微信内H5调起支付(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6) parameter.Add("paymentId", entity.paymentId); if (entity.type == (int)GlobalEnumVars.BillPaymentsType.Common || entity.type == (int)GlobalEnumVars.BillPaymentsType.PinTuan || entity.type == (int)GlobalEnumVars.BillPaymentsType.Group || entity.type == (int)GlobalEnumVars.BillPaymentsType.Skill || entity.type == (int)GlobalEnumVars.BillPaymentsType.Bargain || entity.type == (int)GlobalEnumVars.BillPaymentsType.Giveaway || entity.type == (int)GlobalEnumVars.BillPaymentsType.Solitaire || entity.type == (int)GlobalEnumVars.BillPaymentsType.TransactionComponent) { var payment = await billPaymentsServices.QueryByClauseAsync(p => p.paymentId == entity.paymentId); if (payment != null) { var is_matched = 0; var sceneResponse = new ShopSceneCheckResponse(); #region 校验是否微信自定义交易组件 var orderModel = await orderServices.QueryByClauseAsync(p => p.orderId == payment.sourceId); var orderInfo = new OrderInfo(); //检查支付是否需要校验 if (orderModel.source == 3 && orderModel.scene > 0) { //获取小程序认证 var accessToken = WeChatCacheAccessTokenHelper.GetWxOpenAccessToken(); var client = _weChatApiHttpClientFactory.CreateWxOpenClient(); var sceneRequest = new ShopSceneCheckRequest(); sceneRequest.AccessToken = accessToken; sceneRequest.Scene = orderModel.scene; sceneResponse = await client.ExecuteShopSceneCheckAsync(sceneRequest); is_matched = sceneResponse.IsMatched ? 1 : 0; //if (sceneResponse.IsSuccessful() && sceneResponse.IsMatched == true) if (sceneResponse.IsSuccessful()) { //基础 orderInfo.create_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); orderInfo.type = 0; orderInfo.out_order_id = orderModel.orderId; var weChatUserInfo = await _userWeChatInfoServices.QueryByClauseAsync(p => p.userId == orderModel.userId, true); if (weChatUserInfo != null) { orderInfo.openid = weChatUserInfo.openid; } orderInfo.path = UniAppConst.OrderPath(orderModel.orderId); orderInfo.out_user_id = orderModel.userId.ToString(); //收货人信息 orderInfo.address_info = new AddressInfo(); orderInfo.address_info.receiver_name = orderModel.shipName; orderInfo.address_info.detailed_address = orderModel.shipAddress; orderInfo.address_info.tel_number = orderModel.shipMobile; //发货方式 orderInfo.delivery_detail = new DeliveryDetail(); if (orderModel.receiptType == (int)GlobalEnumVars.OrderReceiptType.Logistics) { orderInfo.delivery_detail.delivery_type = (int)DeliveryTypeEnum.正常快递; } else if (orderModel.receiptType == (int)GlobalEnumVars.OrderReceiptType.IntraCityService) { orderInfo.delivery_detail.delivery_type = (int)DeliveryTypeEnum.线下配送; } else if (orderModel.receiptType == (int)GlobalEnumVars.OrderReceiptType.SelfDelivery) { orderInfo.delivery_detail.delivery_type = (int)DeliveryTypeEnum.用户自提; } orderInfo.order_detail = new OrderDetail(); //订单详情 //支付信息 orderInfo.order_detail.pay_info = new PayInfo() { pay_method = "微信支付", prepay_id = entity.paymentId, prepay_time = entity.createTime.ToString("yyyy-MM-dd HH:mm:ss") }; //价格体系 orderInfo.order_detail.price_info = new PriceInfo() { order_price = Convert.ToInt32(orderModel.orderAmount * 100), freight = Convert.ToInt32(orderModel.costFreight * 100), discounted_price = Convert.ToInt32((orderModel.pointMoney + orderModel.orderDiscountAmount + orderModel.goodsDiscountAmount + orderModel.couponDiscountAmount) * 100), additional_price = 0, additional_remarks = "无", }; //商品信息 orderInfo.order_detail.product_infos = new List(); var orderItems = await orderItemServices.QueryListByClauseAsync(p => p.orderId == orderModel.orderId); foreach (var item in orderItems) { orderInfo.order_detail.product_infos.Add(new ProductInfoItem() { out_product_id = item.goodsId.ToString(), out_sku_id = item.productId.ToString(), head_img = item.imageUrl, product_cnt = item.nums, sale_price = Convert.ToInt32(item.amount * 100), path = UniAppConst.GoodDetail(item.goodsId.ToString()), title = item.name }); } var tcOrder = await weChatTransactionComponentOrderServices.QueryByClauseAsync(p => p.outOrderId == orderModel.orderId); if (tcOrder == null) { tcOrder = new WeChatTransactionComponentOrder { outOrderId = orderModel.orderId, createTime = DateTime.Now, openid = openId }; await weChatTransactionComponentOrderServices.InsertAsync(tcOrder); } } } jm.otherData = new { response, orderInfo, checkSceneResult = new { is_matched, sceneResponse } }; #endregion } else { } } else { jm.otherData = response; } jm.status = true; //jm.msg = "创建支付环境成功"; jm.data = parameter; } 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 = "退款失败"; 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; } } }