소스 검색

支付回调

warr.qian 2 년 전
부모
커밋
9589306659

+ 32 - 0
.gitignore

@@ -0,0 +1,32 @@
+
+#Ignore thumbnails created by Windows
+Thumbs.db
+#Ignore files built by Visual Studio
+*.obj
+*.exe
+*.pdb
+*.user
+*.aps
+*.pch
+*.vspscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.cache
+*.ilk
+*.log
+[Bb]in
+[Dd]ebug*/
+*.lib
+*.sbr
+obj/
+[Rr]elease*/
+_ReSharper*/
+[Tt]est[Rr]esult*
+.vs/
+#Nuget packages folder
+packages/

+ 4 - 3
Common/AlipayCommon.cs

@@ -38,6 +38,7 @@ namespace WingPaymentService.Common
         {
             try
             {
+                var serverUrl = $"{_protocol}://{_gatewayHost}/gateway.do";
                 // 组装业务参数model
                 AlipayTradePagePayModel model = new AlipayTradePagePayModel
                 {
@@ -49,7 +50,7 @@ namespace WingPaymentService.Common
                 // 1. 创建IAopClient实例
                 IAopClient client = new DefaultAopClient
                 (
-                    _gatewayHost,
+                    serverUrl,
                     _appId, //请更换为您的AppId
                     _merchantPrivateKey, //请更换为您的PKCS1格式的应用私钥
                     "json",
@@ -60,14 +61,14 @@ namespace WingPaymentService.Common
                 );
                 Aop.Api.Request.AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
                 // 设置异步通知接收地址
-                request.SetNotifyUrl($"/PaymentApi/UnityPay/AlipayNotify");
+                request.SetNotifyUrl(_notifyUrl);
                 request.SetProdCode("FAST_INSTANT_TRADE_PAY");
                 request.SetBizModel(model);
                 // 3. 发起请求并处理响应
                 Aop.Api.Response.AlipayTradePagePayResponse response = client.SdkExecute(request);
                 if (!response.IsError)
                 {
-                    var url = $"{_gatewayHost}?{response.Body}";
+                    var url = $"{serverUrl}?{response.Body}";
                     Logger.WriteLineInfo($"AlipayPagePay success pay url:{url}");
                     return url;
                 }

+ 10 - 15
Common/WeChat/WxPayApi.cs

@@ -17,7 +17,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public async Task<WxPayData> Micropay(WxPayData inputObj, int timeOut = 10)
         {
-            string url = "https://api.mch.weixin.qq.com/pay/micropay";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/pay/micropay";
             //检测必填参数
             if (!inputObj.IsSet("body"))
             {
@@ -70,7 +70,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public async Task<WxPayData> OrderQuery(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/pay/orderquery";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/pay/orderquery";
             //检测必填参数
             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
             {
@@ -112,7 +112,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public async Task<WxPayData> Reverse(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/secapi/pay/reverse";
             //检测必填参数
             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
             {
@@ -153,7 +153,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public async Task<WxPayData> Refund(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/secapi/pay/refund";
             //检测必填参数
             if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
             {
@@ -212,7 +212,7 @@ namespace WingPaymentService.Common.WeChat
 	    */
         public async Task<WxPayData> RefundQuery(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/pay/refundquery";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/pay/refundquery";
             //检测必填参数
             if (!inputObj.IsSet("out_refund_no") && !inputObj.IsSet("out_trade_no") &&
                 !inputObj.IsSet("transaction_id") && !inputObj.IsSet("refund_id"))
@@ -253,7 +253,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public async Task<WxPayData> DownloadBill(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/pay/downloadbill";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/pay/downloadbill";
             //检测必填参数
             if (!inputObj.IsSet("bill_date"))
             {
@@ -298,7 +298,7 @@ namespace WingPaymentService.Common.WeChat
 	    */
         public async Task<WxPayData> ShortUrl(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/tools/shorturl";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/tools/shorturl";
             //检测必填参数
             if (!inputObj.IsSet("long_url"))
             {
@@ -337,7 +337,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public async Task<WxPayData> UnifiedOrder(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/pay/unifiedorder";
             //检测必填参数
             if (!inputObj.IsSet("out_trade_no"))
             {
@@ -366,12 +366,7 @@ namespace WingPaymentService.Common.WeChat
                 throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
             }
 
-            //异步通知url未设置,则使用配置文件中的url
-            if (!inputObj.IsSet("notify_url"))
-            {
-                inputObj.SetValue("notify_url", WxPayConfig.GetConfig().GetNotifyUrl());//异步通知url
-            }
-
+            inputObj.SetValue("notify_url", WxPayConfig.GetConfig().GetNotifyUrl());//异步通知url
             inputObj.SetValue("appid", WxPayConfig.GetConfig().GetAppId());//公众账号ID
             inputObj.SetValue("mch_id", WxPayConfig.GetConfig().GetMchId());//商户号
             inputObj.SetValue("spbill_create_ip", WxPayConfig.GetConfig().GetIp());//终端ip	  	    
@@ -407,7 +402,7 @@ namespace WingPaymentService.Common.WeChat
 	    */
         public async Task<WxPayData> CloseOrder(WxPayData inputObj, int timeOut = 6)
         {
-            string url = "https://api.mch.weixin.qq.com/pay/closeorder";
+            string url = $"{WxPayConfig.GetConfig().GetServerUrl()}/pay/closeorder";
             //检测必填参数
             if (!inputObj.IsSet("out_trade_no"))
             {

+ 9 - 2
Common/WeChat/WxPayConfigData.cs

@@ -7,13 +7,15 @@ namespace WingPaymentService.Common.WeChat
     public class WxPayConfigData : IWxPayIConfig
     {
         private readonly string _serverIP = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "ServerIP").Value;
-        private readonly string _serverUrl = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "ServerUrl").Value;
+        private readonly string _protocol = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "Protocol").Value;
+        private readonly string _gatewayHost = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "GatewayHost").Value;
         private readonly string _appId = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "AppId").Value;
         private readonly string _mchId = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "MchId").Value;
         private readonly string _key = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "Key").Value;
         private readonly string _appSecret = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "AppSecret").Value;
         private readonly string _sslCertData = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "SSLCertData").Value;
         private readonly string _sslCertPassword = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "SSLCertPassword").Value;
+        private readonly string _notifyUrl = ConfigurationManager.GetParammeter<StringParameter>("WeChat", "NotifyUrl").Value;
 
         //=======【基本信息设置】=====================================
         /* 微信公众号信息配置
@@ -41,6 +43,11 @@ namespace WingPaymentService.Common.WeChat
         }
 
 
+        public string GetServerUrl()
+        {
+            var serverUrl = $"{_protocol}://{_gatewayHost}";
+            return serverUrl;
+        }
 
         //=======【证书路径设置】===================================== 
         /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)
@@ -64,7 +71,7 @@ namespace WingPaymentService.Common.WeChat
         */
         public string GetNotifyUrl()
         {
-            return _serverUrl+"/PaymentApi/UnityPay/WechatNotify";
+            return _notifyUrl;
         }
 
         //=======【商户系统后台机器IP】===================================== 

+ 1 - 2
Common/WeChat/WxPayIConfig.cs

@@ -15,8 +15,7 @@
         string GetMchId();
         string GetKey();
         string GetAppSecret();
-
-
+        string GetServerUrl();
 
         //=======【证书路径设置】===================================== 
         /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)

+ 88 - 23
Service/PaymentService.cs

@@ -1,7 +1,4 @@
-using System.Net;
-using System.Net.Cache;
 using System;
-using System.Text;
 using System.Web;
 using WingServerCommon.Service;
 using WingInterfaceLibrary.Interface;
@@ -16,6 +13,7 @@ using WingServerCommon.Log;
 using WingPaymentService.Common;
 using WingInterfaceLibrary.Enum;
 using WingInterfaceLibrary.Request;
+using WingPaymentService.Common.WeChat;
 
 namespace WingPaymentService.Service
 {
@@ -85,6 +83,11 @@ namespace WingPaymentService.Service
             });
         }
 
+        /// <summary>
+        /// 发起支付请求
+        /// </summary>
+        /// <param name="request"></param>
+        /// <returns></returns>
         public async Task<PayInfoDTO> GoToPayAsync(GoToPayRequest request)
         {
             if (!string.IsNullOrWhiteSpace(request.OrderCode))
@@ -125,31 +128,26 @@ namespace WingPaymentService.Service
             };
         }
 
-        public async Task<PayCallbackDTO> PayCallbackAsync(string request)
+        /// <summary>
+        /// 支付后回调
+        /// </summary>
+        /// <param name="src">来源</param>
+        /// <param name="request">请求信息</param>
+        /// <returns></returns>
+        public async Task<PayCallbackDTO> PayCallbackAsync(string src, string request)
         {
             try
             {
-                Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
-                var uriParams = HttpUtility.UrlDecode(request);
-                if (uriParams != null)
+                switch (src)
                 {
-                    var paramsArr = uriParams.Split('&');
-                    foreach (string param in paramsArr)
-                    {
-                        var keyValue = param.Split('=');
-                        var key = keyValue[0];
-                        var value = keyValue.Length > 1 ? keyValue[1] : string.Empty;
-                        keyValuePairs.Add(key, value);
-                    }
+                    case "Alipay":
+                        await AlipayCallback(request);
+                        break;
+                    case "WeChat":
+                        await WeChatCallback(request);
+                        break;
                 }
-                var paymentRecordCode = keyValuePairs.GetValueOrDefault("PaymentRecordCode");
-                var payStatus = keyValuePairs.GetValueOrDefault("trade_status") == "TRADE_SUCCESS" ? WingInterfaceLibrary.Enum.PayStatusEnum.Paid : WingInterfaceLibrary.Enum.PayStatusEnum.NoPay;
-                var updateRecordInfo = new UpdatePaymentRecordDBRequest();
-                updateRecordInfo.Code = paymentRecordCode;
-                updateRecordInfo.PayTime = DateTime.UtcNow;
-                updateRecordInfo.PayStatus = payStatus;
-                updateRecordInfo.PayResContent = uriParams;
-                await _paymentDBService.UpdatePaymentRecordAsync(updateRecordInfo);
+
                 return new PayCallbackDTO { IsSuccess = true };
             }
             catch (Exception ex)
@@ -159,7 +157,74 @@ namespace WingPaymentService.Service
             }
         }
 
+        private async Task<bool> AlipayCallback(string request)
+        {
+            Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
+            var uriParams = HttpUtility.UrlDecode(request);
+            if (uriParams != null)
+            {
+                var paramsArr = uriParams.Split('&');
+                foreach (string param in paramsArr)
+                {
+                    var keyValue = param.Split('=');
+                    var key = keyValue[0];
+                    var value = keyValue.Length > 1 ? keyValue[1] : string.Empty;
+                    keyValuePairs.Add(key, value);
+                }
+            }
+            var payOutTradeNo = keyValuePairs.GetValueOrDefault("out_trade_no");
+            var totalAmount = keyValuePairs.GetValueOrDefault("total_amount");
+            var paymentRecordCode = keyValuePairs.GetValueOrDefault("pay_record_code");
+            var payStatus = keyValuePairs.GetValueOrDefault("trade_status") == "TRADE_SUCCESS" ? WingInterfaceLibrary.Enum.PayStatusEnum.Paid : WingInterfaceLibrary.Enum.PayStatusEnum.NoPay;
+            await UpdatePayStatus(paymentRecordCode, payStatus, uriParams);
+            if(payStatus == PayStatusEnum.Paid)
+            {
+                return await UpdateOrderStatus(payOutTradeNo, payStatus, totalAmount);
+            }
+            return false;
+        }
+
+        private async Task<bool> WeChatCallback(string request)
+        {
+            //转换数据格式, 取消签名校验,签名调用方自己调用,兼容支付和退款
+            WxPayData data = new WxPayData();
+            var paramValues = data.FromXml(request,false);//回调不用签名校验
+            var payOutTradeNo = paramValues.GetValueOrDefault("out_trade_no")?.ToString();
+            var totalAmount = (double.Parse(paramValues.GetValueOrDefault("total_fee")?.ToString())/100).ToString("0.00");
+            var payRecordCode = paramValues.GetValueOrDefault("pay_record_code")?.ToString();
+            var payStatus = paramValues.GetValueOrDefault("result_code")?.ToString() == "SUCCESS" ? PayStatusEnum.Paid : PayStatusEnum.NoPay;
+            await UpdatePayStatus(payRecordCode, payStatus, request);
+            if(payStatus == PayStatusEnum.Paid)
+            {
+                return await UpdateOrderStatus(payOutTradeNo, payStatus, totalAmount);
+            }
+            return false;
+        }
 
+        private async Task<bool> UpdateOrderStatus(string orderCode, PayStatusEnum payStatus, string totalAmount)
+        {
+            var orderInfo = await _paymentDBService.GetOrderDetailAsync(new GetOrderDetailDBRequest{ OrderCode = orderCode});
+            if(orderInfo.OrderAmount.ToString("0.00") != totalAmount)
+            {
+                Logger.WriteLineError($"OrderCode:{orderInfo.Code} pay status {payStatus}, total amount error, order amount {orderInfo.OrderAmount.ToString("0.00")} paid amount {totalAmount}");
+                return false;
+            }
+            var result = await _paymentDBService.UpdateOrderAsync(new UpdateOrderDBRequest{
+                OrderCode = orderCode,
+                PayStatus = payStatus
+            });
+            return result.IsSuccess;
+        }
+
+        private async Task<UpdatePaymentRecordResultDTO> UpdatePayStatus(string paymentRecordCode, PayStatusEnum payStatus, string payResContent)
+        {
+            var updateRecordInfo = new UpdatePaymentRecordDBRequest();
+            updateRecordInfo.Code = paymentRecordCode;
+            updateRecordInfo.PayTime = DateTime.UtcNow;
+            updateRecordInfo.PayStatus = payStatus;
+            updateRecordInfo.PayResContent = payResContent;
+            return await _paymentDBService.UpdatePaymentRecordAsync(updateRecordInfo);
+        }
         /// <summary>
         /// 客户端用户验证
         /// </summary>

+ 1 - 1
bin/Debug/net6.0/WingPaymentService.deps.json

@@ -172,7 +172,7 @@
     "WingInterfaceLibrary/1.1.3.1-warr": {
       "type": "package",
       "serviceable": true,
-      "sha512": "sha512-zZ6yr/OlwfE1A+iOaFMMcuXBDeN4QspaxGS1xEZhsSYJBldTkcY6OU52y/TSLOUyG3xWZriL1tpXUULF16cOVQ==",
+      "sha512": "sha512-Bvh4Xu14yrfiDO3dJsTc1TXqxWtXRHGHR86p/JqUclca56hJNZd/jT6JlRu4eOuUuXz1d4KlI6PJ9SggP9UGWw==",
       "path": "winginterfacelibrary/1.1.3.1-warr",
       "hashPath": "winginterfacelibrary.1.1.3.1-warr.nupkg.sha512"
     },

BIN
bin/Debug/net6.0/WingPaymentService.dll


BIN
bin/Debug/net6.0/WingPaymentService.pdb


BIN
obj/Debug/net6.0/WingPaymentService.assets.cache


BIN
obj/Debug/net6.0/WingPaymentService.csproj.AssemblyReference.cache


BIN
obj/Debug/net6.0/WingPaymentService.dll


BIN
obj/Debug/net6.0/WingPaymentService.pdb


BIN
obj/Debug/net6.0/ref/WingPaymentService.dll


BIN
obj/Debug/net6.0/refint/WingPaymentService.dll


+ 1 - 1
obj/project.assets.json

@@ -757,7 +757,7 @@
       ]
     },
     "WingInterfaceLibrary/1.1.3.1-warr": {
-      "sha512": "zZ6yr/OlwfE1A+iOaFMMcuXBDeN4QspaxGS1xEZhsSYJBldTkcY6OU52y/TSLOUyG3xWZriL1tpXUULF16cOVQ==",
+      "sha512": "Bvh4Xu14yrfiDO3dJsTc1TXqxWtXRHGHR86p/JqUclca56hJNZd/jT6JlRu4eOuUuXz1d4KlI6PJ9SggP9UGWw==",
       "type": "package",
       "path": "winginterfacelibrary/1.1.3.1-warr",
       "files": [