using Hncore.Infrastructure.Common; using Hncore.Infrastructure.Extension; using Hncore.Infrastructure.Serializer; using Hncore.Infrastructure.WebApi; using Hncore.Pass.PaymentCenter.Domain; using Hncore.Pass.PaymentCenter.Pay.WxPay; using Hncore.Pass.PaymentCenter.Response; using Hncore.Pass.PaymentCenter.Response.PaymentRecord; using Hncore.Pass.PaymentCenter.Service; using Hncore.Pass.PaymentCenter.WeiFuTong; using Hncore.Pass.PaymentCenter.WeiFuTong.Notify; using Hncore.Pass.PaymentCenter.WxPay.WechatJsPay; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using System; using System.Linq; using System.Threading.Tasks; namespace Hncore.Pass.PaymentCenter.Controllers { [ApiVersion("1.0")] [Route("api/paymentcenter/v{version:apiVersion}/Payment/[action]")] public class PaymentController : PaymentControllerBase { private PaymentRecordService m_PaymentRecordService; private WeiFuTongService m_WeiFuTongService; private InternalNotifySerivce m_InternalNotifySerivce; private WxPayClient m_WxPayClient { get; set; } public PaymentController( PaymentRecordService _PaymentRecordService , InternalNotifySerivce internalNotifySerivce , TenantService _TenantService , WxPayClient _WxPayClient , WeiFuTongService weiFuTongService , IConfiguration _Configuration) : base(_TenantService, _Configuration) { // m_WeiFuTongService = weiFuTongService; m_PaymentRecordService = _PaymentRecordService; m_InternalNotifySerivce = internalNotifySerivce; m_WxPayClient = _WxPayClient; } private async Task QueryOrderByPaymentRecordAsync(PaymentRecord paymentRecord) { QueryOrderResponse result = null; //威富通的订单 if (paymentRecord.PaymentChannel == PaymentChannel.WeiFuTong || paymentRecord.PaymentChannel == PaymentChannel.QuanFuTong && paymentRecord.FromPos==0) { var mchInfo = await GetMchInfoAsync(paymentRecord.TenantId , paymentRecord.StoreId , paymentRecord.PaymentChannel); result = await m_WeiFuTongService.QueryOrderAsync(paymentRecord, mchInfo); await UofCommitAsync(); } return result; } /// /// 通用订单查询 /// /// /// [HttpGet] public async Task QueryOrder(string orderNo = "", int? recordId = 0) { PaymentRecord paymentRecord = null; if (recordId == null || recordId == 0) { paymentRecord = await m_PaymentRecordService.Query(false) .OrderByDescending(t => t.Id) .FirstOrDefaultAsync(t => t.OrderId == orderNo); } else if (recordId > 0) { paymentRecord = await m_PaymentRecordService.GetById(recordId.ToInt()); } CheckHelper.NotNull(paymentRecord, "支付记录不存在"); var result = await QueryOrderByPaymentRecordAsync(paymentRecord); if (result == null) { return Error("未知的支付渠道"); } return Success(result); } /// /// 根据orderid查询一条支付记录 /// /// /// [HttpGet] public async Task GetDetail([FromQuery] string orderId) { return Success(await QueryPaymentRecordByOrderIdResponse.Query( m_PaymentRecordService.Query(false) , orderId) ); } /// /// 威富通、全付通 接收通知 /// /// [HttpPost] public async Task HWCNotify() { try { string xml = ""; if (Request.Body.CanSeek) { Request.Body.Position = 0; } using (System.IO.StreamReader reader = new System.IO.StreamReader(Request.Body)) { xml = reader.ReadToEnd(); } LogHelper.Trace("收到威富通支付通知,原始数据:", $"{xml}"); var notifyEntity = XML.XmlDeserialize(xml); // 给支付平台的订单号为支付记录id int paymentRecordId = notifyEntity.OutTradeNo.ToInt(); var paymentRecord = await m_PaymentRecordService.GetById(paymentRecordId); var mchInfo = await GetMchInfoAsync(paymentRecord.TenantId, paymentRecord.StoreId, paymentRecord.PaymentChannel); Util.CheckSignFromXml(xml, mchInfo); if (notifyEntity.PayResult == 0) //支付成功 { paymentRecord.SetPaySuccessed(notifyEntity.TransactionId, notifyEntity.GetPaySuccessTime()); paymentRecord.SetPaymentTypeFromTradeType(notifyEntity.TradeType); } else { paymentRecord.SetPayFailed(); } await m_PaymentRecordService.Update(paymentRecord); var status = notifyEntity.PayResult == 0 ? "成功" : "失败"; LogHelper.Info("威富通回调信息:", $"支付记录Id:{paymentRecord.Id}\n订单号:{paymentRecord.OrderId}\n交易号:{paymentRecord.TransactionId}\n支付状态:{status}\n发起时间:{paymentRecord.RequestTime.Format("yyyy-MM-dd HH:mm:ss")}\n付款成功时间:{notifyEntity.GetPaySuccessTime().Format("yyyy-MM-dd HH:mm:ss")}\n收到通知时间:{DateTime.Now.Format("yyyy-MM-dd HH:mm:ss")}\n总用时:{(DateTime.Now - paymentRecord.RequestTime).TotalSeconds}秒"); if (notifyEntity.PayResult == 0) { //发起内部通知 await m_InternalNotifySerivce.Notify(paymentRecord); } } catch (Exception e) { LogHelper.Error("威富通通知处理失败", e); return "fail"; } return "success"; } /// /// 微信支付回调 接收通知 /// /// [HttpPost, AllowAnonymous] public async Task Notify() { try { string xml = ""; LogHelper.Trace("微信支付回调开始","Notify"); if (Request.Body.CanSeek) { Request.Body.Position = 0; } using (System.IO.StreamReader reader = new System.IO.StreamReader(Request.Body)) { xml = reader.ReadToEnd(); } LogHelper.Trace("微信支付回调,原始数据:", $"{xml}"); WxPayChecker payData = new WxPayChecker(); payData.FromXmlNoCheckSign(xml); if (!payData.IsSet("out_trade_no")) { return FailXml(); } // 给支付平台的订单号为支付记录id string orderId = payData["out_trade_no"]; string TransactionId = payData["transaction_id"]; var paymentRecord = await m_PaymentRecordService.GetOneByOrderId(orderId); if (paymentRecord.TransactionId.NotHas()) { paymentRecord.TransactionId = TransactionId; await m_PaymentRecordService.Update(paymentRecord); } var mchInfo = await GetMchInfoAsync(paymentRecord.TenantId, paymentRecord.StoreId, paymentRecord.PaymentChannel); payData.MchKey = mchInfo.Key; var queryRet = await m_WxPayClient.OrderQuery(new WxJsPayOrderQueryRequest() { AppId = paymentRecord.Appid, MchId = mchInfo.MchId, NonceStr = payData.GenerateNonceStr(), TransactionId = TransactionId }, mchInfo); if (!queryRet) return FailXml(); if (!payData.CheckSign()) return FailXml(); paymentRecord.PaymentStatus = PaymentStatus.OkPay; paymentRecord.UpdateTime = DateTime.Now; paymentRecord.PaymentCompletionTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); await m_PaymentRecordService.Update(paymentRecord); //发起内部通知 await m_InternalNotifySerivce.Notify(paymentRecord); } catch (Exception e) { LogHelper.Error("微信支付通知处理失败", e); return FailXml(); } return SuccessXml(); } public string FailXml() { return "FAIL "; } private string SuccessXml() { return "SUCCESS "; } } }